From 2b193f00d49edadcc749007829f1aeb7eb014db6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 14 Jul 2016 14:25:44 +0200 Subject: [PATCH] Allow RPC to use solc to compile solidity (#1607) * Allow use to use solc to compile solidity. * Remove unneeded commemt. [si:skip] * Address grumble and disable incorrect tests. --- rpc/src/v1/impls/eth.rs | 42 ++++++++++++++++++++++++++++++---- rpc/src/v1/tests/mocked/eth.rs | 7 ++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 9133393e9..14b3e1192 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -18,6 +18,8 @@ extern crate ethash; +use std::io::{Write}; +use std::process::{Command, Stdio}; use std::thread; use std::time::{Instant, Duration}; use std::sync::{Arc, Weak}; @@ -28,7 +30,7 @@ use jsonrpc_core::*; use util::numbers::*; use util::sha3::*; use util::rlp::{encode, decode, UntrustedRlp, View}; -use util::Mutex; +use util::{FromHex, Mutex}; use ethcore::account_provider::AccountProvider; use ethcore::client::{MiningBlockChainClient, BlockID, TransactionID, UncleID}; use ethcore::header::Header as BlockHeader; @@ -255,6 +257,12 @@ impl EthClient where } } +#[cfg(windows)] +static SOLC: &'static str = "solc.exe"; + +#[cfg(not(windows))] +static SOLC: &'static str = "solc"; + impl Eth for EthClient where C: MiningBlockChainClient + 'static, S: SyncProvider + 'static, @@ -508,7 +516,13 @@ impl Eth for EthClient where fn compilers(&self, params: Params) -> Result { try!(self.active()); match params { - Params::None => to_value(&(&[] as &[String])), + Params::None => { + let mut compilers = vec![]; + if Command::new(SOLC).output().is_ok() { + compilers.push("solidity".to_owned()) + } + to_value(&compilers) + } _ => Err(Error::invalid_params()) } } @@ -647,8 +661,28 @@ impl Eth for EthClient where rpc_unimplemented!() } - fn compile_solidity(&self, _: Params) -> Result { + fn compile_solidity(&self, params: Params) -> Result { try!(self.active()); - rpc_unimplemented!() + from_params::<(String, )>(params) + .and_then(|(code, )| { + let maybe_child = Command::new(SOLC) + .arg("--bin") + .arg("--optimize") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::null()) + .spawn(); + if let Ok(mut child) = maybe_child { + if let Ok(_) = child.stdin.as_mut().expect("we called child.stdin(Stdio::piped()) before spawn; qed").write_all(code.as_bytes()) { + if let Ok(output) = child.wait_with_output() { + let s = String::from_utf8_lossy(&output.stdout); + if let Some(hex) = s.lines().skip_while(|ref l| !l.contains("Binary")).skip(1).next() { + return to_value(&Bytes::new(hex.from_hex().unwrap_or(vec![]))); + } + } + } + } + Err(Error::invalid_params()) + }) } } diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 92ff3ec8c..39e22ebac 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -707,6 +707,11 @@ fn rpc_eth_compilers() { assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } +// These tests are incorrect: their output is undefined as long as eth_getCompilers is []. +// Will ignore for now, but should probably be replaced by more substantial tests which check +// the output of eth_getCompilers to determine whether to test. CI systems can then be preinstalled +// with solc/serpent/lllc and they'll be proper again. +#[ignore] #[test] fn rpc_eth_compile_lll() { let request = r#"{"jsonrpc": "2.0", "method": "eth_compileLLL", "params": [], "id": 1}"#; @@ -715,6 +720,7 @@ fn rpc_eth_compile_lll() { assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } +#[ignore] #[test] fn rpc_eth_compile_solidity() { let request = r#"{"jsonrpc": "2.0", "method": "eth_compileSolidity", "params": [], "id": 1}"#; @@ -723,6 +729,7 @@ fn rpc_eth_compile_solidity() { assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } +#[ignore] #[test] fn rpc_eth_compile_serpent() { let request = r#"{"jsonrpc": "2.0", "method": "eth_compileSerpent", "params": [], "id": 1}"#;