diff --git a/ethers-solc/src/artifacts/mod.rs b/ethers-solc/src/artifacts/mod.rs index 85f21b4b..9ded58dc 100644 --- a/ethers-solc/src/artifacts/mod.rs +++ b/ethers-solc/src/artifacts/mod.rs @@ -3,7 +3,7 @@ use ethers_core::abi::Abi; use colored::Colorize; use md5::Digest; -use semver::Version; +use semver::{Version, VersionReq}; use std::{ collections::{BTreeMap, HashSet}, fmt, fs, @@ -92,6 +92,22 @@ impl CompilerInput { res } + /// This will remove/adjust values in the `CompilerInput` that are not compatible with this + /// version + pub fn sanitized(mut self, version: &Version) -> Self { + static PRE_V0_6_0: once_cell::sync::Lazy = + once_cell::sync::Lazy::new(|| VersionReq::parse("<0.6.0").unwrap()); + + if PRE_V0_6_0.matches(version) { + if let Some(ref mut meta) = self.settings.metadata { + // introduced in + // missing in + meta.bytecode_hash.take(); + } + } + self + } + /// Sets the settings for compilation #[must_use] pub fn settings(mut self, settings: Settings) -> Self { @@ -1400,4 +1416,24 @@ mod tests { ) } } + + #[test] + fn can_sanitize_byte_code_hash() { + let version: Version = "0.6.0".parse().unwrap(); + + let settings = Settings { metadata: Some(BytecodeHash::Ipfs.into()), ..Default::default() }; + + let input = CompilerInput { + language: "Solidity".to_string(), + sources: Default::default(), + settings, + }; + + let i = input.clone().sanitized(&version); + assert_eq!(i.settings.metadata.unwrap().bytecode_hash, Some(BytecodeHash::Ipfs)); + + let version: Version = "0.5.17".parse().unwrap(); + let i = input.sanitized(&version); + assert!(i.settings.metadata.unwrap().bytecode_hash.is_none()); + } } diff --git a/ethers-solc/src/compile/project.rs b/ethers-solc/src/compile/project.rs index b3716b6d..c831afd3 100644 --- a/ethers-solc/src/compile/project.rs +++ b/ethers-solc/src/compile/project.rs @@ -451,7 +451,8 @@ fn compile_sequential( let input = input .settings(opt_settings.clone()) .normalize_evm_version(&version) - .with_remappings(paths.remappings.clone()); + .with_remappings(paths.remappings.clone()) + .sanitized(&version); tracing::trace!( "calling solc `{}` with {} sources {:?}", @@ -529,7 +530,8 @@ fn compile_parallel( let job = input .settings(settings.clone()) .normalize_evm_version(&version) - .with_remappings(paths.remappings.clone()); + .with_remappings(paths.remappings.clone()) + .sanitized(&version); jobs.push((solc.clone(), version.clone(), job, actually_dirty)) } diff --git a/ethers-solc/src/resolver/mod.rs b/ethers-solc/src/resolver/mod.rs index 621533ef..bb947ae2 100644 --- a/ethers-solc/src/resolver/mod.rs +++ b/ethers-solc/src/resolver/mod.rs @@ -57,7 +57,7 @@ use rayon::prelude::*; use semver::VersionReq; -use crate::{error::Result, utils, ProjectPathsConfig, Solc, SolcError, Source, Sources}; +use crate::{error::Result, utils, ProjectPathsConfig, SolcError, Source, Sources}; mod parse; mod tree; @@ -482,6 +482,8 @@ impl Graph { &self, offline: bool, ) -> Result>> { + use crate::Solc; + tracing::trace!("resolving input node versions"); // this is likely called by an application and will be eventually printed so we don't exit // on first error, instead gather all the errors and return a bundled error message instead @@ -683,7 +685,9 @@ impl VersionedSources { pub fn get( self, allowed_lib_paths: &crate::AllowedLibPaths, - ) -> Result> { + ) -> Result> { + use crate::Solc; + // we take the installer lock here to ensure installation checking is done in sync #[cfg(any(test, feature = "tests"))] let _lock = crate::compile::take_solc_installer_lock(); diff --git a/ethers-solc/tests/project.rs b/ethers-solc/tests/project.rs index 5c7bf890..463758c3 100644 --- a/ethers-solc/tests/project.rs +++ b/ethers-solc/tests/project.rs @@ -8,6 +8,7 @@ use std::{ }; use ethers_solc::{ + artifacts::BytecodeHash, cache::{SolFilesCache, SOLIDITY_FILES_CACHE_FILENAME}, project_util::*, remappings::Remapping, @@ -875,9 +876,27 @@ fn can_compile_sparse_with_link_references() { let mut compiled = tmp.compile_sparse(TestFileFilter::default()).unwrap(); assert!(!compiled.has_compiler_errors()); - println!("{}", compiled); assert!(compiled.find("ATest").is_some()); assert!(compiled.find("MyLib").is_some()); let lib = compiled.remove("MyLib").unwrap(); assert!(lib.bytecode.is_some()); } + +#[test] +fn can_sanitize_bytecode_hash() { + let mut tmp = TempProject::dapptools().unwrap(); + tmp.project_mut().solc_config.settings.metadata = Some(BytecodeHash::Ipfs.into()); + + tmp.add_source( + "A", + r#" + pragma solidity =0.5.17; + contract A {} + "#, + ) + .unwrap(); + + let compiled = tmp.compile().unwrap(); + assert!(!compiled.has_compiler_errors()); + assert!(compiled.find("A").is_some()); +}