Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
feat: expand solc capabilities / chore: update ethabi (#445)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
gakonst authored Sep 13, 2021
1 parent 90df511 commit 77bc5aa
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 20 deletions.
11 changes: 5 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }

1 change: 1 addition & 0 deletions ethers-contract/ethers-contract-derive/src/abigen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ impl Parse for Method {
Ok(Param {
name: "".into(),
kind,
internal_type: None,
})
})
.collect::<ParseResult<Vec<_>>>()?;
Expand Down
3 changes: 2 additions & 1 deletion ethers-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down
1 change: 1 addition & 0 deletions ethers-core/src/abi/human_readable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ impl AbiParser {
Ok(Param {
name: name.to_string(),
kind: self.parse_type(type_str)?,
internal_type: None,
})
}
}
Expand Down
76 changes: 63 additions & 13 deletions ethers-core/src/utils/solc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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>,

Expand All @@ -72,17 +77,22 @@ 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
let paths = glob(path)
.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(),
Expand All @@ -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("--combined-json").arg("abi,bin,bin-runtime");

command
.arg("--evm-version")
.arg(self.evm_version.to_string())
.arg("--combined-json")
.arg("abi,bin");
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
Expand Down Expand Up @@ -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(),
Expand All @@ -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>>();

Expand All @@ -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));
Expand All @@ -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
Expand Down Expand Up @@ -257,7 +305,7 @@ impl Solc {
}
}

#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum EvmVersion {
Homestead,
TangerineWhistle,
Expand Down Expand Up @@ -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,
}

0 comments on commit 77bc5aa

Please sign in to comment.