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

Commit

Permalink
Add a optional json dump state to evm-bin (#9706)
Browse files Browse the repository at this point in the history
* Add a dump of the state at the end of transaction for --json-test.
Also fixes json-test output on finish, and allow to put both on err or
out (--out-only and --err-only).

* Dump state resolution from trie, function behind evm-bin feature to avoid misuse.

* Rename 'slow' method to 'to_pod_full'.
Use cache first in 'to_pod_full', for in between commits case.
Change dump activation to use a function pointer instead.

* Fix tests.

* Query and add storage values to dump.

* Switch to use `require` method, even if less efficient it is better in
this case to reuse existing code.
Reuse of `storage_at` was not easy in this case (could not iterate and
use the method at the same time (refcell mutable borrow panics) so
keeping code as is.

* Switch to returning error.
Use 'base_storage_root' instead of 'storage_root'.
Added a test, it will only execute with json-test in ci, or when launch
with the feature.

* Renaming of command line parameters.
Comments fixes.
Minor code changes.

* Fix evmbin cmd parsing test.

* README update.

* Fix extra space and avoid clone call on copiable address.

* Revert test submodule.

* Revert wasm-test submodule.

* Use map_or instead of map + unwrap_or

* restore tests submodule
  • Loading branch information
cheme authored and 5chdn committed Nov 25, 2018
1 parent 34d22a3 commit 832c4a7
Show file tree
Hide file tree
Showing 18 changed files with 368 additions and 95 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion ethcore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ unexpected = { path = "../util/unexpected" }
journaldb = { path = "../util/journaldb" }
keccak-hasher = { path = "../util/keccak-hasher" }
kvdb-rocksdb = "0.1.3"
serde = "1.0"
serde_derive = "1.0"
tempdir = {version="0.3", optional = true}

[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))'.dependencies]
Expand Down Expand Up @@ -103,13 +105,15 @@ evm-debug-tests = ["evm-debug", "evm/evm-debug-tests"]
# EVM debug traces are printed.
slow-blocks = []
# Run JSON consensus tests.
json-tests = ["ethcore-transaction/json-tests", "test-helpers", "tempdir"]
json-tests = ["ethcore-transaction/json-tests", "test-helpers", "tempdir", "to-pod-full"]
# Skip JSON consensus tests with pending issues.
ci-skip-issue = []
# Run memory/cpu heavy tests.
test-heavy = []
# Compile test helpers
test-helpers = ["tempdir"]
# Enables slow 'to-pod-full' method for use in tests and evmbin.
to-pod-full = []

[[bench]]
name = "builtin"
Expand Down
56 changes: 46 additions & 10 deletions ethcore/src/client/evm_test_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ use ethjson::spec::ForkSpec;
pub struct EvmTestClient<'a> {
state: state::State<state_db::StateDB>,
spec: &'a spec::Spec,
dump_state: fn(&state::State<state_db::StateDB>) -> Option<pod_state::PodState>,
}

fn no_dump_state(_: &state::State<state_db::StateDB>) -> Option<pod_state::PodState> {
None
}

impl<'a> fmt::Debug for EvmTestClient<'a> {
Expand All @@ -92,32 +97,51 @@ impl<'a> EvmTestClient<'a> {
}
}

/// Change default function for dump state (default does not dump)
pub fn set_dump_state_fn(&mut self, dump_state: fn(&state::State<state_db::StateDB>) -> Option<pod_state::PodState>) {
self.dump_state = dump_state;
}

/// Creates new EVM test client with in-memory DB initialized with genesis of given Spec.
pub fn new(spec: &'a spec::Spec) -> Result<Self, EvmTestError> {
let factories = Self::factories();
/// Takes a `TrieSpec` to set the type of trie.
pub fn new_with_trie(spec: &'a spec::Spec, trie_spec: trie::TrieSpec) -> Result<Self, EvmTestError> {
let factories = Self::factories(trie_spec);
let state = Self::state_from_spec(spec, &factories)?;

Ok(EvmTestClient {
state,
spec,
dump_state: no_dump_state,
})
}

/// Creates new EVM test client with in-memory DB initialized with given PodState.
pub fn from_pod_state(spec: &'a spec::Spec, pod_state: pod_state::PodState) -> Result<Self, EvmTestError> {
let factories = Self::factories();
/// Creates new EVM test client with an in-memory DB initialized with genesis of given chain Spec.
pub fn new(spec: &'a spec::Spec) -> Result<Self, EvmTestError> {
Self::new_with_trie(spec, trie::TrieSpec::Secure)
}

/// Creates new EVM test client with an in-memory DB initialized with given PodState.
/// Takes a `TrieSpec` to set the type of trie.
pub fn from_pod_state_with_trie(spec: &'a spec::Spec, pod_state: pod_state::PodState, trie_spec: trie::TrieSpec) -> Result<Self, EvmTestError> {
let factories = Self::factories(trie_spec);
let state = Self::state_from_pod(spec, &factories, pod_state)?;

Ok(EvmTestClient {
state,
spec,
dump_state: no_dump_state,
})
}

fn factories() -> Factories {
/// Creates new EVM test client with an in-memory DB initialized with given PodState.
pub fn from_pod_state(spec: &'a spec::Spec, pod_state: pod_state::PodState) -> Result<Self, EvmTestError> {
Self::from_pod_state_with_trie(spec, pod_state, trie::TrieSpec::Secure)
}

fn factories(trie_spec: trie::TrieSpec) -> Factories {
Factories {
vm: factory::VmFactory::new(VMType::Interpreter, 5 * 1024),
trie: trie::TrieFactory::new(trie::TrieSpec::Secure),
trie: trie::TrieFactory::new(trie_spec),
accountdb: Default::default(),
}
}
Expand Down Expand Up @@ -223,6 +247,7 @@ impl<'a> EvmTestClient<'a> {
return TransactResult::Err {
state_root: *self.state.root(),
error: error.into(),
end_state: (self.dump_state)(&self.state),
};
}

Expand All @@ -247,12 +272,17 @@ impl<'a> EvmTestClient<'a> {
&None,
false
).ok();

self.state.commit().ok();

let state_root = *self.state.root();

let end_state = (self.dump_state)(&self.state);

match result {
Ok(result) => {
TransactResult::Ok {
state_root: *self.state.root(),
state_root,
gas_left: initial_gas - result.receipt.gas_used,
outcome: result.receipt.outcome,
output: result.output,
Expand All @@ -263,12 +293,14 @@ impl<'a> EvmTestClient<'a> {
Some(executive::contract_address(scheme, &transaction.sender(), &transaction.nonce, &transaction.data).0)
} else {
None
}
},
end_state,
}
},
Err(error) => TransactResult::Err {
state_root: *self.state.root(),
state_root,
error,
end_state,
},
}
}
Expand All @@ -295,12 +327,16 @@ pub enum TransactResult<T, V> {
logs: Vec<log_entry::LogEntry>,
/// outcome
outcome: receipt::TransactionOutcome,
/// end state if needed
end_state: Option<pod_state::PodState>,
},
/// Transaction failed to run
Err {
/// State root
state_root: H256,
/// Execution error
error: ::error::Error,
/// end state if needed
end_state: Option<pod_state::PodState>,
},
}
2 changes: 1 addition & 1 deletion ethcore/src/json_tests/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ pub fn json_chain_test<H: FnMut(&str, HookType)>(json_data: &[u8], start_stop_ho
flushln!("{} fail", info);
failed.push(name.clone());
},
Ok(TransactResult::Err { state_root, ref error }) if state_root != post_root => {
Ok(TransactResult::Err { state_root, ref error, .. }) if state_root != post_root => {
println!("{} !!! State mismatch (got: {}, expect: {}", info, state_root, post_root);
println!("{} !!! Execution error: {:?}", info, error);
flushln!("{} fail", info);
Expand Down
4 changes: 4 additions & 0 deletions ethcore/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ extern crate vm;
extern crate wasm;
extern crate memory_cache;
extern crate journaldb;
extern crate serde;
#[cfg(any(test, feature = "json-tests", feature = "test-helpers"))]
extern crate tempdir;

Expand All @@ -134,6 +135,8 @@ extern crate macros;
extern crate rlp_derive;
#[macro_use]
extern crate trace_time;
#[macro_use]
extern crate serde_derive;

#[cfg_attr(test, macro_use)]
extern crate evm;
Expand Down Expand Up @@ -187,3 +190,4 @@ pub use types::*;
pub use executive::contract_address;
pub use evm::CreateContractAddress;
pub use blockchain::{BlockChainDB, BlockChainDBHandler};
pub use trie::TrieSpec;
11 changes: 10 additions & 1 deletion ethcore/src/pod_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,30 @@ use state::Account;
use ethjson;
use types::account_diff::*;
use rlp::{self, RlpStream};
use serde::Serializer;
use rustc_hex::ToHex;

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
/// 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 {
/// The balance of the account.
pub balance: U256,
/// The nonce of the account.
pub nonce: U256,
#[serde(serialize_with="opt_bytes_to_hex")]
/// The code of the account or `None` in the special case that it is unknown.
pub code: Option<Bytes>,
/// The storage of the account.
pub storage: BTreeMap<H256, H256>,
}

fn opt_bytes_to_hex<S>(opt_bytes: &Option<Bytes>, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.collect_str(&format_args!("0x{}",opt_bytes.as_ref().map_or("".to_string(), |b|b.to_hex())))
}

impl PodAccount {
/// Convert Account to a PodAccount.
/// NOTE: This will silently fail unless the account is fully cached.
Expand Down
4 changes: 2 additions & 2 deletions ethcore/src/pod_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ use types::state_diff::StateDiff;
use ethjson;

/// State of all accounts in the system expressed in Plain Old Data.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct PodState (BTreeMap<Address, PodAccount>);
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
pub struct PodState(BTreeMap<Address, PodAccount>);

impl PodState {
/// Contruct a new object from the `m`.
Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/state/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ mod tests {
assert!(raw.len() > compact_vec.len());
let again_raw = decompress(&compact_vec, snapshot_swapper());
assert_eq!(raw, again_raw.into_vec());
}
}

#[test]
fn storage_at() {
Expand Down
Loading

0 comments on commit 832c4a7

Please sign in to comment.