feat: expand solc capabilities / chore: update ethabi (#445)

* chore: use ethabi with bumped ethereum-types

* fix: do not use internal type in human readable abi

* fix: do not use internal type in abigen

* feat(solc): save the runtime bytecode

* feat: implement serde for CompiledContract

* feat: allow overriding solc binary path

* feat: expose providing raw file paths

* feat: do not set evm versions on old solc

* chore: use upstream ethabi
This commit is contained in:
Georgios Konstantopoulos 2021-09-13 15:35:50 +03:00 committed by GitHub
parent 90df511704
commit 77bc5aa30f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 73 additions and 20 deletions

11
Cargo.lock generated
View File

@ -805,8 +805,7 @@ dependencies = [
[[package]]
name = "ethabi"
version = "14.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a01317735d563b3bad2d5f90d2e1799f414165408251abb762510f40e790e69a"
source = "git+https://github.com/rust-ethereum/ethabi/?branch=master#506f6cc364cdb458ac09f2be4f300779da256b08"
dependencies = [
"anyhow",
"ethereum-types",
@ -833,9 +832,9 @@ dependencies = [
[[package]]
name = "ethereum-types"
version = "0.11.0"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f64b5df66a228d85e4b17e5d6c6aa43b0310898ffe8a85988c4c032357aaabfd"
checksum = "0dd6bde671199089e601e8d47e153368b893ef885f11f365a3261ec58153c211"
dependencies = [
"ethbloom",
"fixed-hash",
@ -1946,9 +1945,9 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "primitive-types"
version = "0.9.1"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06345ee39fbccfb06ab45f3a1a5798d9dafa04cb8921a76d227040003a234b0e"
checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373"
dependencies = [
"fixed-hash",
"impl-codec",

View File

@ -86,3 +86,4 @@ rand = "0.8.4"
serde = { version = "1.0.124", features = ["derive"] }
serde_json = "1.0.64"
tokio = { version = "1.5", features = ["macros", "rt-multi-thread"] }

View File

@ -169,6 +169,7 @@ impl Parse for Method {
Ok(Param {
name: "".into(),
kind,
internal_type: None,
})
})
.collect::<ParseResult<Vec<_>>>()?;

View File

@ -11,7 +11,8 @@ keywords = ["ethereum", "web3", "celo", "ethers"]
[dependencies]
rlp = { version = "0.5.0", default-features = false }
ethabi = { version = "14.1.0", default-features = false }
# ethabi = { version = "14.1.0", default-features = false }
ethabi = { git = "https://github.com/rust-ethereum/ethabi/", branch = "master" }
arrayvec = { version = "0.7.1", default-features = false }
rlp-derive = { version = "0.1.0", default-features = false }

View File

@ -364,6 +364,7 @@ impl AbiParser {
Ok(Param {
name: name.to_string(),
kind: self.parse_type(type_str)?,
internal_type: None,
})
}
}

View File

@ -21,13 +21,15 @@ pub enum SolcError {
SerdeJson(#[from] serde_json::Error),
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Serialize, Deserialize)]
/// The result of a solc compilation
pub struct CompiledContract {
/// The contract's ABI
pub abi: Abi,
/// The contract's bytecode
pub bytecode: Bytes,
/// The contract's runtime bytecode
pub runtime_bytecode: Bytes,
}
/// Solidity Compiler Bindings
@ -55,6 +57,9 @@ pub struct CompiledContract {
/// # }
/// ```
pub struct Solc {
/// The path to the Solc binary
pub solc_path: Option<PathBuf>,
/// The path where contracts will be read from
pub paths: Vec<String>,
@ -72,7 +77,7 @@ pub struct Solc {
}
impl Solc {
/// Instantiates the Solc builder for the provided paths
/// Instantiates The Solc builder with the provided glob of Solidity files
pub fn new(path: &str) -> Self {
// Convert the glob to a vector of string paths
// TODO: This might not be the most robust way to do this
@ -80,9 +85,14 @@ impl Solc {
.expect("could not get glob")
.map(|path| path.expect("path not found").to_string_lossy().to_string())
.collect::<Vec<String>>();
Self::new_with_paths(paths)
}
/// Instantiates the Solc builder for the provided paths
pub fn new_with_paths(paths: Vec<String>) -> Self {
Self {
paths,
solc_path: None,
optimizer: Some(200), // default optimizer runs = 200
evm_version: EvmVersion::Istanbul,
allowed_paths: Vec::new(),
@ -92,13 +102,19 @@ impl Solc {
/// Gets the ABI for the contracts
pub fn build_raw(self) -> Result<HashMap<String, CompiledContractStr>> {
let mut command = Command::new(SOLC);
let path = self.solc_path.unwrap_or_else(|| PathBuf::from(SOLC));
let mut command = Command::new(&path);
let version = Solc::version(Some(path));
command
.arg("--evm-version")
.arg(self.evm_version.to_string())
.arg("--combined-json")
.arg("abi,bin");
command.arg("--combined-json").arg("abi,bin,bin-runtime");
if (version.starts_with("0.5") && self.evm_version < EvmVersion::Istanbul)
|| !version.starts_with("0.4")
{
command
.arg("--evm-version")
.arg(self.evm_version.to_string());
}
if let Some(runs) = self.optimizer {
command
@ -148,7 +164,21 @@ impl Solc {
)))
}
};
contracts.insert(name, CompiledContractStr { abi, bin });
let runtime_bin =
if let serde_json::Value::String(bin) = contract["bin-runtime"].take() {
bin
} else {
panic!("no runtime bytecode found")
};
contracts.insert(
name,
CompiledContractStr {
abi,
bin,
runtime_bin,
},
);
} else {
return Err(SolcError::SolcError(
"could not find `bin` in solc output".to_string(),
@ -174,7 +204,19 @@ impl Solc {
let bytecode = hex::decode(contract.bin)
.expect("solc did not produce valid bytecode")
.into();
(name, CompiledContract { abi, bytecode })
// parse the runtime bytecode
let runtime_bytecode = hex::decode(contract.runtime_bin)
.expect("solc did not produce valid runtime-bytecode")
.into();
(
name,
CompiledContract {
abi,
bytecode,
runtime_bytecode,
},
)
})
.collect::<HashMap<String, CompiledContract>>();
@ -186,8 +228,8 @@ impl Solc {
/// # Panics
///
/// If `solc` is not in the user's $PATH
pub fn version() -> String {
let command_output = Command::new(SOLC)
pub fn version(solc_path: Option<PathBuf>) -> String {
let command_output = Command::new(solc_path.unwrap_or_else(|| PathBuf::from(SOLC)))
.arg("--version")
.output()
.unwrap_or_else(|_| panic!("`{}` not in user's $PATH", SOLC));
@ -209,6 +251,12 @@ impl Solc {
self
}
/// Sets the path to the solc binary
pub fn solc_path(mut self, path: PathBuf) -> Self {
self.solc_path = Some(std::fs::canonicalize(path).unwrap());
self
}
/// Sets the optimizer runs (default = 200). None indicates no optimization
///
/// ```rust,no_run
@ -257,7 +305,7 @@ impl Solc {
}
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum EvmVersion {
Homestead,
TangerineWhistle,
@ -297,4 +345,6 @@ pub struct CompiledContractStr {
pub abi: String,
/// The contract's bytecode in hex
pub bin: String,
/// The contract's runtime bytecode in hex
pub runtime_bin: String,
}