Allow calling contracts in genesis state. (#9375)
This commit is contained in:
parent
b2cf5d2958
commit
108590d924
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -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)",
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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
38
evmbin/res/testchain.json
Normal 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"
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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(¶ms.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}
|
||||
"#);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user