fix: sanitize compilerinput based on version (#1111)

* fix: sanitize compilerinput based on version

* test: add compiler test

* chore: remove unused warnings

* style: make once lazy
This commit is contained in:
Matthias Seitz 2022-04-05 21:00:04 +02:00 committed by GitHub
parent ef1e715b86
commit 23e45e8531
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 6 deletions

View File

@ -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<VersionReq> =
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 <https://docs.soliditylang.org/en/v0.6.0/using-the-compiler.html#compiler-api>
// missing in <https://docs.soliditylang.org/en/v0.5.17/using-the-compiler.html#compiler-api>
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());
}
}

View File

@ -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))
}

View File

@ -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<HashMap<crate::SolcVersion, Vec<usize>>> {
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<std::collections::BTreeMap<Solc, (semver::Version, Sources)>> {
) -> Result<std::collections::BTreeMap<crate::Solc, (semver::Version, Sources)>> {
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();

View File

@ -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());
}