Allow calling contracts in genesis state. (#9375)

This commit is contained in:
Tomasz Drwięga 2018-08-20 14:05:01 +02:00 committed by Andrew Jones
parent b2cf5d2958
commit 108590d924
8 changed files with 98 additions and 18 deletions

1
Cargo.lock generated
View File

@ -1018,6 +1018,7 @@ name = "evmbin"
version = "0.1.0"
dependencies = [
"docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.12.0",
"ethcore-transaction 0.1.0",
"ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -30,7 +30,8 @@ pub use self::denominations::*;
use machine::EthereumMachine;
use super::spec::*;
fn load<'a, T: Into<Option<SpecParams<'a>>>>(params: T, b: &[u8]) -> Spec {
/// Load chain spec from `SpecParams` and JSON.
pub fn load<'a, T: Into<Option<SpecParams<'a>>>>(params: T, b: &[u8]) -> Spec {
match params.into() {
Some(params) => Spec::load(params, b),
None => Spec::load(&::std::env::temp_dir(), b)

View File

@ -770,6 +770,11 @@ impl Spec {
Ok(())
}
/// Return genesis state as Plain old data.
pub fn genesis_state(&self) -> &PodState {
&self.genesis_state
}
/// Returns `false` if the memoized state root is invalid. `true` otherwise.
pub fn is_state_root_valid(&self) -> bool {
// TODO: get rid of this function and ensure state root always is valid.

View File

@ -10,6 +10,7 @@ path = "./src/main.rs"
[dependencies]
docopt = "0.8"
env_logger = "0.5"
ethcore = { path = "../ethcore", features = ["test-helpers", "json-tests"] }
ethjson = { path = "../json" }
parity-bytes = { git = "https://github.com/paritytech/parity-common" }

38
evmbin/res/testchain.json Normal file
View File

@ -0,0 +1,38 @@
{
"name": "lab",
"engine": {
"Ethash": {
"params": {
"minimumDifficulty": "0x1",
"difficultyBoundDivisor": "0x800"
}
}
},
"accounts": {
"0000000000000000000000000000000000000020": {
"nonce": "0x0",
"balance": "0x64",
"code": "0x62aaaaaa60aa60aa5060aa60aa60aa60aa60aa60aa"
}
},
"params":{
"networkID": "0x42",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1",
"gasLimitBoundDivisor": "0x400"
},
"genesis": {
"gasLimit": "0x8000000",
"seal": {
"ethereum": {
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000042"
}
},
"difficulty": "0x400",
"extraData": "0x0",
"author": "0x3333333333333333333333333333333333333333",
"timestamp": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
}

View File

@ -167,13 +167,13 @@ impl<T: Writer> trace::VMTracer for Informant<T> {
}
#[cfg(test)]
mod tests {
pub mod tests {
use std::sync::{Arc, Mutex};
use super::*;
use info::tests::run_test;
#[derive(Debug, Clone, Default)]
struct TestWriter(pub Arc<Mutex<Vec<u8>>>);
pub struct TestWriter(pub Arc<Mutex<Vec<u8>>>);
impl Writer for TestWriter {
fn clone(&self) -> Self { Clone::clone(self) }
@ -189,7 +189,7 @@ mod tests {
}
}
fn informant() -> (Informant<TestWriter>, Arc<Mutex<Vec<u8>>>) {
pub fn informant() -> (Informant<TestWriter>, Arc<Mutex<Vec<u8>>>) {
let writer = TestWriter::default();
let res = writer.0.clone();
(Informant::new(writer), res)

View File

@ -68,11 +68,19 @@ pub type RunResult<T> = Result<Success<T>, Failure<T>>;
/// Execute given `ActionParams` and return the result.
pub fn run_action<T: Informant>(
spec: &spec::Spec,
params: ActionParams,
mut params: ActionParams,
mut informant: T,
) -> RunResult<T::Output> {
informant.set_gas(params.gas);
run(spec, params.gas, None, |mut client| {
// if the code is not overwritten from CLI, use code from spec file.
if params.code.is_none() {
if let Some(acc) = spec.genesis_state().get().get(&params.code_address) {
params.code = acc.code.clone().map(::std::sync::Arc::new);
params.code_hash = None;
}
}
run(spec, params.gas, spec.genesis_state(), |mut client| {
let result = client
.call(params, &mut trace::NoopTracer, &mut informant)
.map(|r| (0.into(), r.gas_left, r.return_data.to_vec()));
@ -130,24 +138,21 @@ pub fn run_transaction<T: Informant>(
}
/// Execute VM with given `ActionParams`
pub fn run<'a, F, T, X>(
pub fn run<'a, F, X>(
spec: &'a spec::Spec,
initial_gas: U256,
pre_state: T,
pre_state: &'a pod_state::PodState,
run: F,
) -> RunResult<X> where
F: FnOnce(EvmTestClient) -> (Result<(H256, U256, Vec<u8>), EvmTestError>, Option<X>),
T: Into<Option<&'a pod_state::PodState>>,
{
let test_client = match pre_state.into() {
Some(pre_state) => EvmTestClient::from_pod_state(spec, pre_state.clone()),
None => EvmTestClient::new(spec),
}.map_err(|error| Failure {
gas_used: 0.into(),
error,
time: Duration::from_secs(0),
traces: None,
})?;
let test_client = EvmTestClient::from_pod_state(spec, pre_state.clone())
.map_err(|error| Failure {
gas_used: 0.into(),
error,
time: Duration::from_secs(0),
traces: None,
})?;
let start = Instant::now();
let result = run(test_client);
@ -204,4 +209,31 @@ pub mod tests {
},
}
}
#[test]
fn should_call_account_from_spec() {
use display::std_json::tests::informant;
let (inf, res) = informant();
let mut params = ActionParams::default();
params.code_address = 0x20.into();
params.gas = 0xffff.into();
let spec = ::ethcore::ethereum::load(None, include_bytes!("../res/testchain.json"));
let _result = run_action(&spec, params, inf);
assert_eq!(
&String::from_utf8_lossy(&**res.lock().unwrap()),
r#"{"pc":0,"op":98,"opName":"PUSH3","gas":"0xffff","stack":[],"storage":{},"depth":1}
{"pc":4,"op":96,"opName":"PUSH1","gas":"0xfffc","stack":["0xaaaaaa"],"storage":{},"depth":1}
{"pc":6,"op":96,"opName":"PUSH1","gas":"0xfff9","stack":["0xaaaaaa","0xaa"],"storage":{},"depth":1}
{"pc":8,"op":80,"opName":"POP","gas":"0xfff6","stack":["0xaaaaaa","0xaa","0xaa"],"storage":{},"depth":1}
{"pc":9,"op":96,"opName":"PUSH1","gas":"0xfff4","stack":["0xaaaaaa","0xaa"],"storage":{},"depth":1}
{"pc":11,"op":96,"opName":"PUSH1","gas":"0xfff1","stack":["0xaaaaaa","0xaa","0xaa"],"storage":{},"depth":1}
{"pc":13,"op":96,"opName":"PUSH1","gas":"0xffee","stack":["0xaaaaaa","0xaa","0xaa","0xaa"],"storage":{},"depth":1}
{"pc":15,"op":96,"opName":"PUSH1","gas":"0xffeb","stack":["0xaaaaaa","0xaa","0xaa","0xaa","0xaa"],"storage":{},"depth":1}
{"pc":17,"op":96,"opName":"PUSH1","gas":"0xffe8","stack":["0xaaaaaa","0xaa","0xaa","0xaa","0xaa","0xaa"],"storage":{},"depth":1}
{"pc":19,"op":96,"opName":"PUSH1","gas":"0xffe5","stack":["0xaaaaaa","0xaa","0xaa","0xaa","0xaa","0xaa","0xaa"],"storage":{},"depth":1}
"#);
}
}

View File

@ -31,6 +31,7 @@ extern crate ethereum_types;
extern crate vm;
extern crate evm;
extern crate panic_hook;
extern crate env_logger;
#[cfg(test)]
#[macro_use]
@ -92,6 +93,7 @@ General options:
fn main() {
panic_hook::set_abort();
env_logger::init();
let args: Args = Docopt::new(USAGE).and_then(|d| d.deserialize()).unwrap_or_else(|e| e.exit());