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:
parent
90df511704
commit
77bc5aa30f
|
@ -805,8 +805,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethabi"
|
name = "ethabi"
|
||||||
version = "14.1.0"
|
version = "14.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/rust-ethereum/ethabi/?branch=master#506f6cc364cdb458ac09f2be4f300779da256b08"
|
||||||
checksum = "a01317735d563b3bad2d5f90d2e1799f414165408251abb762510f40e790e69a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ethereum-types",
|
"ethereum-types",
|
||||||
|
@ -833,9 +832,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethereum-types"
|
name = "ethereum-types"
|
||||||
version = "0.11.0"
|
version = "0.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f64b5df66a228d85e4b17e5d6c6aa43b0310898ffe8a85988c4c032357aaabfd"
|
checksum = "0dd6bde671199089e601e8d47e153368b893ef885f11f365a3261ec58153c211"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethbloom",
|
"ethbloom",
|
||||||
"fixed-hash",
|
"fixed-hash",
|
||||||
|
@ -1946,9 +1945,9 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "primitive-types"
|
name = "primitive-types"
|
||||||
version = "0.9.1"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06345ee39fbccfb06ab45f3a1a5798d9dafa04cb8921a76d227040003a234b0e"
|
checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fixed-hash",
|
"fixed-hash",
|
||||||
"impl-codec",
|
"impl-codec",
|
||||||
|
|
|
@ -86,3 +86,4 @@ rand = "0.8.4"
|
||||||
serde = { version = "1.0.124", features = ["derive"] }
|
serde = { version = "1.0.124", features = ["derive"] }
|
||||||
serde_json = "1.0.64"
|
serde_json = "1.0.64"
|
||||||
tokio = { version = "1.5", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.5", features = ["macros", "rt-multi-thread"] }
|
||||||
|
|
||||||
|
|
|
@ -169,6 +169,7 @@ impl Parse for Method {
|
||||||
Ok(Param {
|
Ok(Param {
|
||||||
name: "".into(),
|
name: "".into(),
|
||||||
kind,
|
kind,
|
||||||
|
internal_type: None,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<ParseResult<Vec<_>>>()?;
|
.collect::<ParseResult<Vec<_>>>()?;
|
||||||
|
|
|
@ -11,7 +11,8 @@ keywords = ["ethereum", "web3", "celo", "ethers"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rlp = { version = "0.5.0", default-features = false }
|
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 }
|
arrayvec = { version = "0.7.1", default-features = false }
|
||||||
rlp-derive = { version = "0.1.0", default-features = false }
|
rlp-derive = { version = "0.1.0", default-features = false }
|
||||||
|
|
||||||
|
|
|
@ -364,6 +364,7 @@ impl AbiParser {
|
||||||
Ok(Param {
|
Ok(Param {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
kind: self.parse_type(type_str)?,
|
kind: self.parse_type(type_str)?,
|
||||||
|
internal_type: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,13 +21,15 @@ pub enum SolcError {
|
||||||
SerdeJson(#[from] serde_json::Error),
|
SerdeJson(#[from] serde_json::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
/// The result of a solc compilation
|
/// The result of a solc compilation
|
||||||
pub struct CompiledContract {
|
pub struct CompiledContract {
|
||||||
/// The contract's ABI
|
/// The contract's ABI
|
||||||
pub abi: Abi,
|
pub abi: Abi,
|
||||||
/// The contract's bytecode
|
/// The contract's bytecode
|
||||||
pub bytecode: Bytes,
|
pub bytecode: Bytes,
|
||||||
|
/// The contract's runtime bytecode
|
||||||
|
pub runtime_bytecode: Bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Solidity Compiler Bindings
|
/// Solidity Compiler Bindings
|
||||||
|
@ -55,6 +57,9 @@ pub struct CompiledContract {
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Solc {
|
pub struct Solc {
|
||||||
|
/// The path to the Solc binary
|
||||||
|
pub solc_path: Option<PathBuf>,
|
||||||
|
|
||||||
/// The path where contracts will be read from
|
/// The path where contracts will be read from
|
||||||
pub paths: Vec<String>,
|
pub paths: Vec<String>,
|
||||||
|
|
||||||
|
@ -72,7 +77,7 @@ pub struct Solc {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
pub fn new(path: &str) -> Self {
|
||||||
// Convert the glob to a vector of string paths
|
// Convert the glob to a vector of string paths
|
||||||
// TODO: This might not be the most robust way to do this
|
// TODO: This might not be the most robust way to do this
|
||||||
|
@ -80,9 +85,14 @@ impl Solc {
|
||||||
.expect("could not get glob")
|
.expect("could not get glob")
|
||||||
.map(|path| path.expect("path not found").to_string_lossy().to_string())
|
.map(|path| path.expect("path not found").to_string_lossy().to_string())
|
||||||
.collect::<Vec<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 {
|
Self {
|
||||||
paths,
|
paths,
|
||||||
|
solc_path: None,
|
||||||
optimizer: Some(200), // default optimizer runs = 200
|
optimizer: Some(200), // default optimizer runs = 200
|
||||||
evm_version: EvmVersion::Istanbul,
|
evm_version: EvmVersion::Istanbul,
|
||||||
allowed_paths: Vec::new(),
|
allowed_paths: Vec::new(),
|
||||||
|
@ -92,13 +102,19 @@ impl Solc {
|
||||||
|
|
||||||
/// Gets the ABI for the contracts
|
/// Gets the ABI for the contracts
|
||||||
pub fn build_raw(self) -> Result<HashMap<String, CompiledContractStr>> {
|
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("--combined-json").arg("abi,bin,bin-runtime");
|
||||||
|
|
||||||
|
if (version.starts_with("0.5") && self.evm_version < EvmVersion::Istanbul)
|
||||||
|
|| !version.starts_with("0.4")
|
||||||
|
{
|
||||||
command
|
command
|
||||||
.arg("--evm-version")
|
.arg("--evm-version")
|
||||||
.arg(self.evm_version.to_string())
|
.arg(self.evm_version.to_string());
|
||||||
.arg("--combined-json")
|
}
|
||||||
.arg("abi,bin");
|
|
||||||
|
|
||||||
if let Some(runs) = self.optimizer {
|
if let Some(runs) = self.optimizer {
|
||||||
command
|
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 {
|
} else {
|
||||||
return Err(SolcError::SolcError(
|
return Err(SolcError::SolcError(
|
||||||
"could not find `bin` in solc output".to_string(),
|
"could not find `bin` in solc output".to_string(),
|
||||||
|
@ -174,7 +204,19 @@ impl Solc {
|
||||||
let bytecode = hex::decode(contract.bin)
|
let bytecode = hex::decode(contract.bin)
|
||||||
.expect("solc did not produce valid bytecode")
|
.expect("solc did not produce valid bytecode")
|
||||||
.into();
|
.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>>();
|
.collect::<HashMap<String, CompiledContract>>();
|
||||||
|
|
||||||
|
@ -186,8 +228,8 @@ impl Solc {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// If `solc` is not in the user's $PATH
|
/// If `solc` is not in the user's $PATH
|
||||||
pub fn version() -> String {
|
pub fn version(solc_path: Option<PathBuf>) -> String {
|
||||||
let command_output = Command::new(SOLC)
|
let command_output = Command::new(solc_path.unwrap_or_else(|| PathBuf::from(SOLC)))
|
||||||
.arg("--version")
|
.arg("--version")
|
||||||
.output()
|
.output()
|
||||||
.unwrap_or_else(|_| panic!("`{}` not in user's $PATH", SOLC));
|
.unwrap_or_else(|_| panic!("`{}` not in user's $PATH", SOLC));
|
||||||
|
@ -209,6 +251,12 @@ impl Solc {
|
||||||
self
|
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
|
/// Sets the optimizer runs (default = 200). None indicates no optimization
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
|
@ -257,7 +305,7 @@ impl Solc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum EvmVersion {
|
pub enum EvmVersion {
|
||||||
Homestead,
|
Homestead,
|
||||||
TangerineWhistle,
|
TangerineWhistle,
|
||||||
|
@ -297,4 +345,6 @@ pub struct CompiledContractStr {
|
||||||
pub abi: String,
|
pub abi: String,
|
||||||
/// The contract's bytecode in hex
|
/// The contract's bytecode in hex
|
||||||
pub bin: String,
|
pub bin: String,
|
||||||
|
/// The contract's runtime bytecode in hex
|
||||||
|
pub runtime_bin: String,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue