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"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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 1.12.0",
|
||||||
"ethcore-transaction 0.1.0",
|
"ethcore-transaction 0.1.0",
|
||||||
"ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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 machine::EthereumMachine;
|
||||||
use super::spec::*;
|
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() {
|
match params.into() {
|
||||||
Some(params) => Spec::load(params, b),
|
Some(params) => Spec::load(params, b),
|
||||||
None => Spec::load(&::std::env::temp_dir(), b)
|
None => Spec::load(&::std::env::temp_dir(), b)
|
||||||
|
@ -770,6 +770,11 @@ impl Spec {
|
|||||||
Ok(())
|
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.
|
/// Returns `false` if the memoized state root is invalid. `true` otherwise.
|
||||||
pub fn is_state_root_valid(&self) -> bool {
|
pub fn is_state_root_valid(&self) -> bool {
|
||||||
// TODO: get rid of this function and ensure state root always is valid.
|
// TODO: get rid of this function and ensure state root always is valid.
|
||||||
|
@ -10,6 +10,7 @@ path = "./src/main.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
docopt = "0.8"
|
docopt = "0.8"
|
||||||
|
env_logger = "0.5"
|
||||||
ethcore = { path = "../ethcore", features = ["test-helpers", "json-tests"] }
|
ethcore = { path = "../ethcore", features = ["test-helpers", "json-tests"] }
|
||||||
ethjson = { path = "../json" }
|
ethjson = { path = "../json" }
|
||||||
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
pub mod tests {
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use super::*;
|
use super::*;
|
||||||
use info::tests::run_test;
|
use info::tests::run_test;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
struct TestWriter(pub Arc<Mutex<Vec<u8>>>);
|
pub struct TestWriter(pub Arc<Mutex<Vec<u8>>>);
|
||||||
|
|
||||||
impl Writer for TestWriter {
|
impl Writer for TestWriter {
|
||||||
fn clone(&self) -> Self { Clone::clone(self) }
|
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 writer = TestWriter::default();
|
||||||
let res = writer.0.clone();
|
let res = writer.0.clone();
|
||||||
(Informant::new(writer), res)
|
(Informant::new(writer), res)
|
||||||
|
@ -68,11 +68,19 @@ pub type RunResult<T> = Result<Success<T>, Failure<T>>;
|
|||||||
/// Execute given `ActionParams` and return the result.
|
/// Execute given `ActionParams` and return the result.
|
||||||
pub fn run_action<T: Informant>(
|
pub fn run_action<T: Informant>(
|
||||||
spec: &spec::Spec,
|
spec: &spec::Spec,
|
||||||
params: ActionParams,
|
mut params: ActionParams,
|
||||||
mut informant: T,
|
mut informant: T,
|
||||||
) -> RunResult<T::Output> {
|
) -> RunResult<T::Output> {
|
||||||
informant.set_gas(params.gas);
|
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
|
let result = client
|
||||||
.call(params, &mut trace::NoopTracer, &mut informant)
|
.call(params, &mut trace::NoopTracer, &mut informant)
|
||||||
.map(|r| (0.into(), r.gas_left, r.return_data.to_vec()));
|
.map(|r| (0.into(), r.gas_left, r.return_data.to_vec()));
|
||||||
@ -130,19 +138,16 @@ pub fn run_transaction<T: Informant>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Execute VM with given `ActionParams`
|
/// Execute VM with given `ActionParams`
|
||||||
pub fn run<'a, F, T, X>(
|
pub fn run<'a, F, X>(
|
||||||
spec: &'a spec::Spec,
|
spec: &'a spec::Spec,
|
||||||
initial_gas: U256,
|
initial_gas: U256,
|
||||||
pre_state: T,
|
pre_state: &'a pod_state::PodState,
|
||||||
run: F,
|
run: F,
|
||||||
) -> RunResult<X> where
|
) -> RunResult<X> where
|
||||||
F: FnOnce(EvmTestClient) -> (Result<(H256, U256, Vec<u8>), EvmTestError>, Option<X>),
|
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() {
|
let test_client = EvmTestClient::from_pod_state(spec, pre_state.clone())
|
||||||
Some(pre_state) => EvmTestClient::from_pod_state(spec, pre_state.clone()),
|
.map_err(|error| Failure {
|
||||||
None => EvmTestClient::new(spec),
|
|
||||||
}.map_err(|error| Failure {
|
|
||||||
gas_used: 0.into(),
|
gas_used: 0.into(),
|
||||||
error,
|
error,
|
||||||
time: Duration::from_secs(0),
|
time: Duration::from_secs(0),
|
||||||
@ -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 vm;
|
||||||
extern crate evm;
|
extern crate evm;
|
||||||
extern crate panic_hook;
|
extern crate panic_hook;
|
||||||
|
extern crate env_logger;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -92,6 +93,7 @@ General options:
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
panic_hook::set_abort();
|
panic_hook::set_abort();
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
let args: Args = Docopt::new(USAGE).and_then(|d| d.deserialize()).unwrap_or_else(|e| e.exit());
|
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