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