From 1e7cea791ab1d2780dab859ad020d384335e718b Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Mon, 10 Jun 2024 22:02:20 +0300 Subject: [PATCH 1/9] [do not merge] bump compilers --- Cargo.lock | 3 +- Cargo.toml | 1 + crates/common/src/compile.rs | 186 ++++++++++-------- crates/debugger/src/tui/draw.rs | 28 ++- crates/debugger/src/tui/mod.rs | 8 +- crates/evm/traces/src/identifier/etherscan.rs | 15 +- crates/forge/bin/cmd/test/mod.rs | 3 +- crates/forge/src/multi_runner.rs | 8 +- crates/script/src/build.rs | 3 +- crates/verify/src/etherscan/flatten.rs | 5 +- 10 files changed, 142 insertions(+), 118 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 05cf20bb599c..deafefdcc7ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3598,8 +3598,7 @@ dependencies = [ [[package]] name = "foundry-compilers" version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a92aa3e4d0aa91fda44c1840c68d634fc126bdd06099516eb2b81035e5e6d0" +source = "git+https://github.com/foundry-rs/compilers?rev=ad6ac98#ad6ac9868c994280f94b0ef236848728c61f1361" dependencies = [ "alloy-json-abi", "alloy-primitives", diff --git a/Cargo.toml b/Cargo.toml index 2418bdf081ca..02784c444c89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -244,6 +244,7 @@ tower-http = "0.5" soldeer = "0.2.15" [patch.crates-io] +foundry-compilers = { git = "https://github.com/foundry-rs/compilers", rev = "ad6ac98" } revm = { git = "https://github.com/bluealloy/revm.git", rev = "a28a543" } revm-interpreter = { git = "https://github.com/bluealloy/revm.git", rev = "a28a543" } revm-precompile = { git = "https://github.com/bluealloy/revm.git", rev = "a28a543" } diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index 4ab4b170d9d6..ec9e1019902b 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -6,11 +6,10 @@ use eyre::{Context, Result}; use foundry_block_explorers::contract::Metadata; use foundry_compilers::{ artifacts::{BytecodeObject, ContractBytecodeSome, Libraries, Source}, - compilers::{solc::SolcCompiler, CompilationError, Compiler}, + compilers::{multi::MultiCompilerLanguage, solc::SolcCompiler, Compiler}, remappings::Remapping, report::{BasicStdoutReporter, NoReporter, Report}, - Artifact, ArtifactId, Project, ProjectBuilder, ProjectCompileOutput, ProjectPathsConfig, Solc, - SolcConfig, + Artifact, Project, ProjectBuilder, ProjectCompileOutput, ProjectPathsConfig, Solc, SolcConfig, }; use foundry_linking::Linker; use num_format::{Locale, ToFormattedString}; @@ -20,6 +19,7 @@ use std::{ fmt::Display, io::IsTerminal, path::{Path, PathBuf}, + sync::Arc, time::Instant, }; @@ -122,10 +122,7 @@ impl ProjectCompiler { } /// Compiles the project. - pub fn compile( - mut self, - project: &Project, - ) -> Result> { + pub fn compile(mut self, project: &Project) -> Result> { // TODO: Avoid process::exit if !project.paths.has_input_files() && self.files.is_empty() { println!("Nothing to compile"); @@ -159,9 +156,9 @@ impl ProjectCompiler { /// ProjectCompiler::new().compile_with(|| Ok(prj.compile()?)).unwrap(); /// ``` #[instrument(target = "forge::compile", skip_all)] - fn compile_with(self, f: F) -> Result> + fn compile_with(self, f: F) -> Result> where - F: FnOnce() -> Result>, + F: FnOnce() -> Result>, { let quiet = self.quiet.unwrap_or(false); let bail = self.bail.unwrap_or(true); @@ -209,7 +206,7 @@ impl ProjectCompiler { } /// If configured, this will print sizes or names - fn handle_output(&self, output: &ProjectCompileOutput) { + fn handle_output(&self, output: &ProjectCompileOutput) { let print_names = self.print_names.unwrap_or(false); let print_sizes = self.print_sizes.unwrap_or(false); @@ -274,88 +271,125 @@ impl ProjectCompiler { } } -/// Contract source code and bytecode. +#[derive(Clone, Debug)] +pub struct SourceData { + pub source: Arc, + pub language: MultiCompilerLanguage, +} + +#[derive(Clone, Debug)] +pub struct ArtifactData { + pub bytecode: ContractBytecodeSome, + pub build_id: String, + pub file_id: u32, +} + +/// Contract source code and bytecode data used for debugger. #[derive(Clone, Debug, Default)] pub struct ContractSources { - /// Map over artifacts' contract names -> vector of file IDs - pub ids_by_name: HashMap>, - /// Map over file_id -> source code - pub sources_by_id: FxHashMap, - /// Map over file_id -> contract name -> bytecode - pub artifacts_by_id: FxHashMap>, + /// Map over build_id -> file_id -> (source code, language) + pub sources_by_id: HashMap>, + /// Map over contract name -> Vec<(bytecode, build_id, file_id)> + pub artifacts_by_name: HashMap>, } impl ContractSources { /// Collects the contract sources and artifacts from the project compile output. pub fn from_project_output( output: &ProjectCompileOutput, - root: &Path, - libraries: &Libraries, + link_data: Option<(&Path, &Libraries)>, ) -> Result { - let linker = Linker::new(root, output.artifact_ids().collect()); - let mut sources = Self::default(); + + sources.insert(output, link_data)?; + + Ok(sources) + } + + pub fn insert( + &mut self, + output: &ProjectCompileOutput, + link_data: Option<(&Path, &Libraries)>, + ) -> Result<()> + where + C::Language: Into, + { + let link_data = link_data.map(|(root, libraries)| { + let linker = Linker::new(root, output.artifact_ids().collect()); + (linker, libraries) + }); + for (id, artifact) in output.artifact_ids() { if let Some(file_id) = artifact.id { - let abs_path = root.join(&id.source); - let source_code = std::fs::read_to_string(abs_path).wrap_err_with(|| { - format!("failed to read artifact source file for `{}`", id.identifier()) - })?; - let linked = linker.link(&id, libraries)?; - let contract = compact_to_contract(linked.into_contract_bytecode())?; - sources.insert(&id, file_id, source_code, contract); + let artifact = if let Some((linker, libraries)) = link_data.as_ref() { + linker.link(&id, &libraries)?.into_contract_bytecode() + } else { + artifact.clone().into_contract_bytecode() + }; + let bytecode = compact_to_contract(artifact.clone().into_contract_bytecode())?; + + self.artifacts_by_name.entry(id.name.clone()).or_default().push(ArtifactData { + bytecode, + build_id: id.build_id.clone(), + file_id, + }); } else { warn!(id = id.identifier(), "source not found"); } } - Ok(sources) - } - /// Inserts a contract into the sources. - pub fn insert( - &mut self, - artifact_id: &ArtifactId, - file_id: u32, - source: String, - bytecode: ContractBytecodeSome, - ) { - self.ids_by_name.entry(artifact_id.name.clone()).or_default().push(file_id); - self.sources_by_id.insert(file_id, source); - self.artifacts_by_id.entry(file_id).or_default().insert(artifact_id.name.clone(), bytecode); - } + // Not all source files produce artifacts, so we are populating sources by using build + // infos. + let mut files: BTreeMap> = BTreeMap::new(); + for (build_id, build) in output.builds() { + for (source_id, source) in &build.source_id_to_path { + let source_code = if let Some(source) = files.get(source) { + source.clone() + } else { + let source_code = std::fs::read_to_string(source).wrap_err_with(|| { + format!("failed to read artifact source file for `{}`", source.display()) + })?; + let source_code = Arc::new(source_code); + files.insert(source.to_path_buf(), source_code.clone()); + source_code + }; + + self.sources_by_id.entry(build_id.clone()).or_default().insert( + *source_id, + SourceData { source: source_code, language: build.language.into() }, + ); + } + } - /// Returns the source for a contract by file ID. - pub fn get(&self, id: u32) -> Option<&String> { - self.sources_by_id.get(&id) + Ok(()) } /// Returns all sources for a contract by name. - pub fn get_sources<'a>( - &'a self, - name: &'a str, - ) -> Option> { - self.ids_by_name.get(name).map(|ids| { - ids.iter().filter_map(|id| { - Some(( - *id, - self.sources_by_id.get(id)?.as_ref(), - self.artifacts_by_id.get(id)?.get(name)?, - )) + pub fn get_sources( + &self, + name: &str, + ) -> Option> { + self.artifacts_by_name.get(name).map(|artifacts| { + artifacts.iter().filter_map(|artifact| { + let source = + self.sources_by_id.get(artifact.build_id.as_str())?.get(&artifact.file_id)?; + Some((artifact, source)) }) }) } - /// Returns all (name, source, bytecode) sets. - pub fn entries(&self) -> impl Iterator { - self.artifacts_by_id + /// Returns all (name, bytecode, source) sets. + pub fn entries(&self) -> impl Iterator { + self.artifacts_by_name .iter() - .filter_map(|(id, artifacts)| { - let source = self.sources_by_id.get(id)?; - Some( - artifacts - .iter() - .map(move |(name, bytecode)| (name.as_ref(), source.as_ref(), bytecode)), - ) + .map(|(name, artifacts)| { + artifacts.iter().filter_map(|artifact| { + let source = self + .sources_by_id + .get(artifact.build_id.as_str())? + .get(&artifact.file_id)?; + Some((name.as_str(), artifact, source)) + }) }) .flatten() } @@ -464,7 +498,7 @@ pub fn compile_target( target_path: &Path, project: &Project, quiet: bool, -) -> Result> { +) -> Result> { ProjectCompiler::new().quiet(quiet).files([target_path.into()]).compile(project) } @@ -472,7 +506,7 @@ pub fn compile_target( /// Returns the artifact_id, the file_id, and the bytecode pub async fn compile_from_source( metadata: &Metadata, -) -> Result<(ArtifactId, u32, ContractBytecodeSome)> { +) -> Result> { let root = tempfile::tempdir()?; let root_path = root.path(); let project = etherscan_project(metadata, root_path)?; @@ -483,23 +517,9 @@ pub async fn compile_from_source( eyre::bail!("{project_output}") } - let (artifact_id, file_id, contract) = project_output - .into_artifacts() - .find(|(artifact_id, _)| artifact_id.name == metadata.contract_name) - .map(|(aid, art)| { - (aid, art.source_file().expect("no source file").id, art.into_contract_bytecode()) - }) - .ok_or_else(|| { - eyre::eyre!( - "Unable to find bytecode in compiled output for contract: {}", - metadata.contract_name - ) - })?; - let bytecode = compact_to_contract(contract)?; - root.close()?; - Ok((artifact_id, file_id, bytecode)) + return Ok(project_output); } /// Creates a [Project] from an Etherscan source. diff --git a/crates/debugger/src/tui/draw.rs b/crates/debugger/src/tui/draw.rs index 8e55687a0aec..4585e8696af5 100644 --- a/crates/debugger/src/tui/draw.rs +++ b/crates/debugger/src/tui/draw.rs @@ -3,7 +3,7 @@ use super::context::{BufferKind, DebuggerContext}; use crate::op::OpcodeParam; use alloy_primitives::U256; -use foundry_compilers::sourcemap::SourceElement; +use foundry_compilers::{compilers::multi::MultiCompilerLanguage, sourcemap::SourceElement}; use ratatui::{ layout::{Alignment, Constraint, Direction, Layout, Rect}, style::{Color, Modifier, Style}, @@ -344,32 +344,40 @@ impl DebuggerContext<'_> { let is_create = matches!(self.call_kind(), CallKind::Create | CallKind::Create2); let pc = self.current_step().pc; let Some((source_element, source_code)) = - files_source_code.find_map(|(file_id, source_code, contract_source)| { + files_source_code.find_map(|(artifact, source)| { let bytecode = if is_create { - &contract_source.bytecode + &artifact.bytecode.bytecode } else { - contract_source.deployed_bytecode.bytecode.as_ref()? + artifact.bytecode.deployed_bytecode.bytecode.as_ref()? }; - let source_map = bytecode.source_map()?.ok()?; + let source_map = bytecode.source_map()?.expect("failed to parse"); let pc_ic_map = if is_create { create_map } else { rt_map }; let ic = pc_ic_map.get(pc)?; - let source_element = source_map.get(ic)?; + let source_element = if matches!(source.language, MultiCompilerLanguage::Solc(_)) { + source_map.get(ic)? + } else { + source_map.get(pc)? + }; // if the source element has an index, find the sourcemap for that index - source_element + let res = source_element .index() // if index matches current file_id, return current source code .and_then(|index| { - (index == file_id).then(|| (source_element.clone(), source_code)) + (index == artifact.file_id) + .then(|| (source_element.clone(), source.source.as_str())) }) .or_else(|| { // otherwise find the source code for the element's index self.debugger .contracts_sources .sources_by_id + .get(&artifact.build_id)? .get(&source_element.index()?) - .map(|source_code| (source_element.clone(), source_code.as_ref())) - }) + .map(|source| (source_element.clone(), source.source.as_str())) + }); + + res }) else { return Err(format!("No source map for contract {contract_name}")); diff --git a/crates/debugger/src/tui/mod.rs b/crates/debugger/src/tui/mod.rs index d57c6e7a26ee..c810440e5b13 100644 --- a/crates/debugger/src/tui/mod.rs +++ b/crates/debugger/src/tui/mod.rs @@ -66,12 +66,12 @@ impl Debugger { ) -> Self { let pc_ic_maps = contracts_sources .entries() - .filter_map(|(contract_name, _, contract)| { + .filter_map(|(name, artifact, _)| { Some(( - contract_name.to_owned(), + name.to_owned(), ( - PcIcMap::new(contract.bytecode.bytes()?), - PcIcMap::new(contract.deployed_bytecode.bytes()?), + PcIcMap::new(artifact.bytecode.bytecode.bytes()?), + PcIcMap::new(artifact.bytecode.deployed_bytecode.bytes()?), ), )) }) diff --git a/crates/evm/traces/src/identifier/etherscan.rs b/crates/evm/traces/src/identifier/etherscan.rs index 977b69a42340..794b3a9edd11 100644 --- a/crates/evm/traces/src/identifier/etherscan.rs +++ b/crates/evm/traces/src/identifier/etherscan.rs @@ -59,14 +59,11 @@ impl EtherscanIdentifier { /// Etherscan and compiles them locally, for usage in the debugger. pub async fn get_compiled_contracts(&self) -> eyre::Result { // TODO: Add caching so we dont double-fetch contracts. - let contracts_iter = self + let outputs_fut = self .contracts .iter() // filter out vyper files - .filter(|(_, metadata)| !metadata.is_vyper()); - - let outputs_fut = contracts_iter - .clone() + .filter(|(_, metadata)| !metadata.is_vyper()) .map(|(address, metadata)| { println!("Compiling: {} {address}", metadata.contract_name); let err_msg = @@ -76,15 +73,13 @@ impl EtherscanIdentifier { .collect::>(); // poll all the futures concurrently - let artifacts = join_all(outputs_fut).await; + let outputs = join_all(outputs_fut).await; let mut sources: ContractSources = Default::default(); // construct the map - for (results, (_, metadata)) in artifacts.into_iter().zip(contracts_iter) { - // get the inner type - let (artifact_id, file_id, bytecode) = results?; - sources.insert(&artifact_id, file_id, metadata.source_code(), bytecode); + for output in outputs { + sources.insert(&output?, None)?; } Ok(sources) diff --git a/crates/forge/bin/cmd/test/mod.rs b/crates/forge/bin/cmd/test/mod.rs index d2de7ef232b9..ee561e80baeb 100644 --- a/crates/forge/bin/cmd/test/mod.rs +++ b/crates/forge/bin/cmd/test/mod.rs @@ -337,8 +337,7 @@ impl TestArgs { let sources = ContractSources::from_project_output( output_clone.as_ref().unwrap(), - project.root(), - &libraries, + Some((&project.root(), &libraries)), )?; // Run the debugger. diff --git a/crates/forge/src/multi_runner.rs b/crates/forge/src/multi_runner.rs index 1e2be6c7cb84..1c1206fa06a4 100644 --- a/crates/forge/src/multi_runner.rs +++ b/crates/forge/src/multi_runner.rs @@ -8,7 +8,9 @@ use alloy_json_abi::{Function, JsonAbi}; use alloy_primitives::{Address, Bytes, U256}; use eyre::Result; use foundry_common::{get_contract_name, ContractsByArtifact, TestFunctionExt}; -use foundry_compilers::{artifacts::Libraries, Artifact, ArtifactId, ProjectCompileOutput}; +use foundry_compilers::{ + artifacts::Libraries, compilers::Compiler, Artifact, ArtifactId, ProjectCompileOutput, +}; use foundry_config::Config; use foundry_evm::{ backend::Backend, decode::RevertDecoder, executors::ExecutorBuilder, fork::CreateFork, @@ -356,10 +358,10 @@ impl MultiContractRunnerBuilder { /// Given an EVM, proceeds to return a runner which is able to execute all tests /// against that evm - pub fn build( + pub fn build( self, root: &Path, - output: ProjectCompileOutput, + output: ProjectCompileOutput, env: revm::primitives::Env, evm_opts: EvmOpts, ) -> Result { diff --git a/crates/script/src/build.rs b/crates/script/src/build.rs index 342096fda3d1..f1a18d45fa8b 100644 --- a/crates/script/src/build.rs +++ b/crates/script/src/build.rs @@ -136,8 +136,7 @@ impl LinkedBuildData { ) -> Result { let sources = ContractSources::from_project_output( &build_data.output, - &build_data.project_root, - &libraries, + Some((&build_data.project_root, &libraries)), )?; let known_contracts = diff --git a/crates/verify/src/etherscan/flatten.rs b/crates/verify/src/etherscan/flatten.rs index fa888f92295a..ac586b48cd13 100644 --- a/crates/verify/src/etherscan/flatten.rs +++ b/crates/verify/src/etherscan/flatten.rs @@ -4,6 +4,7 @@ use eyre::{Context, Result}; use foundry_block_explorers::verify::CodeFormat; use foundry_compilers::{ artifacts::{BytecodeHash, Source}, + buildinfo::RawBuildInfo, compilers::{ solc::{SolcCompiler, SolcLanguage, SolcVersionedInput}, Compiler, CompilerInput, @@ -87,8 +88,8 @@ impl EtherscanFlattenedSource { let out = SolcCompiler::Specific(solc).compile(&input)?; if out.errors.iter().any(|e| e.is_error()) { - let mut o = AggregatedCompilerOutput::default(); - o.extend(version, out); + let mut o = AggregatedCompilerOutput::::default(); + o.extend(version.clone(), RawBuildInfo::new(&input, &out, false)?, out); let diags = o.diagnostics(&[], &[], Default::default()); eyre::bail!( From 8e031500ef6589c25903d859246396a8104cfe2a Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Tue, 11 Jun 2024 01:42:12 +0300 Subject: [PATCH 2/9] update patch --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 02784c444c89..ec3b4bb6ea1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -244,7 +244,7 @@ tower-http = "0.5" soldeer = "0.2.15" [patch.crates-io] -foundry-compilers = { git = "https://github.com/foundry-rs/compilers", rev = "ad6ac98" } +foundry-compilers = { git = "https://github.com/foundry-rs/compilers", rev = "6010918" } revm = { git = "https://github.com/bluealloy/revm.git", rev = "a28a543" } revm-interpreter = { git = "https://github.com/bluealloy/revm.git", rev = "a28a543" } revm-precompile = { git = "https://github.com/bluealloy/revm.git", rev = "a28a543" } From ea7b279c074efb0fcae1e125fe0261cf7f97e9cb Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Tue, 11 Jun 2024 02:12:46 +0300 Subject: [PATCH 3/9] fix test --- Cargo.lock | 2 +- crates/forge/tests/cli/build.rs | 19 ++++++++++++++----- .../forge/tests/fixtures/compile_json.stdout | 9 ++++----- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index deafefdcc7ee..6d87841a0e3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3598,7 +3598,7 @@ dependencies = [ [[package]] name = "foundry-compilers" version = "0.6.2" -source = "git+https://github.com/foundry-rs/compilers?rev=ad6ac98#ad6ac9868c994280f94b0ef236848728c61f1361" +source = "git+https://github.com/foundry-rs/compilers?rev=6010918#60109185c77946175abf9c3935bbaef668f78346" dependencies = [ "alloy-json-abi", "alloy-primitives", diff --git a/crates/forge/tests/cli/build.rs b/crates/forge/tests/cli/build.rs index e2dca7e0aaa2..4222516fc0c8 100644 --- a/crates/forge/tests/cli/build.rs +++ b/crates/forge/tests/cli/build.rs @@ -1,7 +1,8 @@ +use foundry_common::fs::read_to_string; use foundry_config::Config; -use foundry_test_utils::{forgetest, util::OutputExt}; +use foundry_test_utils::forgetest; use globset::Glob; -use std::path::PathBuf; +use std::{collections::BTreeMap, path::PathBuf}; // tests that json is printed when --json is passed forgetest!(compile_json, |prj, cmd| { @@ -21,10 +22,18 @@ contract Dummy { // set up command cmd.args(["compile", "--format-json"]); - // run command and assert - cmd.unchecked_output().stdout_matches_path( + // Exclude build_infos from output as IDs depend on root dir and are not deterministic. + let mut output: BTreeMap = + serde_json::from_str(&cmd.stdout_lossy()).unwrap(); + output.remove("build_infos"); + + let output = serde_json::to_string_pretty(&output).unwrap(); + let expected = read_to_string( PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/compile_json.stdout"), - ); + ) + .unwrap(); + + similar_asserts::assert_eq!(output, expected); }); // tests build output is as expected diff --git a/crates/forge/tests/fixtures/compile_json.stdout b/crates/forge/tests/fixtures/compile_json.stdout index f3eb33ea0d8c..eff78e60c8d7 100644 --- a/crates/forge/tests/fixtures/compile_json.stdout +++ b/crates/forge/tests/fixtures/compile_json.stdout @@ -1,4 +1,5 @@ { + "contracts": {}, "errors": [ { "sourceLocation": { @@ -11,10 +12,8 @@ "severity": "error", "errorCode": "7576", "message": "Undeclared identifier. Did you mean \"newNumber\"?", - "formattedMessage": "DeclarationError: Undeclared identifier. Did you mean \"newNumber\"?\n --> src/dummy.sol:7:18:\n |\n7 | number = newnumber; // error here\n | ^^^^^^^^^\n\n" + "formattedMessage": "DeclarationError: Undeclared identifier. Did you mean \"newNumber\"?\n --> src/jsonError.sol:7:18:\n |\n7 | number = newnumber; // error here\n | ^^^^^^^^^\n\n" } ], - "sources": {}, - "contracts": {}, - "build_infos": {} -} + "sources": {} +} \ No newline at end of file From c2871ce913cdbf61f4124b37f0fed5e30622aaf5 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Tue, 11 Jun 2024 02:15:18 +0300 Subject: [PATCH 4/9] doc --- crates/debugger/src/tui/draw.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/debugger/src/tui/draw.rs b/crates/debugger/src/tui/draw.rs index 4585e8696af5..2909ef803ed6 100644 --- a/crates/debugger/src/tui/draw.rs +++ b/crates/debugger/src/tui/draw.rs @@ -354,6 +354,9 @@ impl DebuggerContext<'_> { let pc_ic_map = if is_create { create_map } else { rt_map }; let ic = pc_ic_map.get(pc)?; + + // Solc indexes source maps by instruction counter, but Vyper indexes by program + // counter. let source_element = if matches!(source.language, MultiCompilerLanguage::Solc(_)) { source_map.get(ic)? } else { From 0e4fd19f0fae8efcf7e9c38d0202d518bc257146 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Tue, 11 Jun 2024 02:36:33 +0300 Subject: [PATCH 5/9] fix tests --- crates/forge/bin/cmd/bind.rs | 2 +- crates/forge/tests/cli/build.rs | 9 ++++----- crates/test-utils/src/util.rs | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/crates/forge/bin/cmd/bind.rs b/crates/forge/bin/cmd/bind.rs index dcf76fc2f424..8283ca7d81cc 100644 --- a/crates/forge/bin/cmd/bind.rs +++ b/crates/forge/bin/cmd/bind.rs @@ -168,7 +168,7 @@ impl BindArgs { Ok(json_files(artifacts) .filter_map(|path| { // Ignore the build info JSON. - if path.to_str()?.contains("/build-info/") { + if path.to_str()?.contains("build-info") { return None; } diff --git a/crates/forge/tests/cli/build.rs b/crates/forge/tests/cli/build.rs index 4222516fc0c8..c4e725f7e9dd 100644 --- a/crates/forge/tests/cli/build.rs +++ b/crates/forge/tests/cli/build.rs @@ -1,6 +1,6 @@ -use foundry_common::fs::read_to_string; +use foundry_common::fs::{read_json_file, read_to_string}; use foundry_config::Config; -use foundry_test_utils::forgetest; +use foundry_test_utils::{forgetest, util::normalize_output}; use globset::Glob; use std::{collections::BTreeMap, path::PathBuf}; @@ -27,9 +27,8 @@ contract Dummy { serde_json::from_str(&cmd.stdout_lossy()).unwrap(); output.remove("build_infos"); - let output = serde_json::to_string_pretty(&output).unwrap(); - let expected = read_to_string( - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/compile_json.stdout"), + let expected: BTreeMap = read_json_file( + &PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/compile_json.stdout"), ) .unwrap(); diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index e1a681db62f8..6d2d5233a3c6 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -1083,7 +1083,7 @@ static IGNORE_IN_FIXTURES: Lazy = Lazy::new(|| { Regex::new(&format!("({})", re.join("|"))).unwrap() }); -fn normalize_output(s: &str) -> String { +pub fn normalize_output(s: &str) -> String { let s = s.replace("\r\n", "\n").replace('\\', "/"); IGNORE_IN_FIXTURES.replace_all(&s, "").into_owned() } From be7dbfcdba6b3e12eba8f9e3e57bf0b9d7eb4f82 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Tue, 11 Jun 2024 02:40:55 +0300 Subject: [PATCH 6/9] clippy --- crates/common/src/compile.rs | 21 ++++++++------------- crates/forge/bin/cmd/test/mod.rs | 2 +- crates/forge/tests/cli/build.rs | 4 ++-- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index ec9e1019902b..f6cefefc1ab9 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -322,7 +322,7 @@ impl ContractSources { for (id, artifact) in output.artifact_ids() { if let Some(file_id) = artifact.id { let artifact = if let Some((linker, libraries)) = link_data.as_ref() { - linker.link(&id, &libraries)?.into_contract_bytecode() + linker.link(&id, libraries)?.into_contract_bytecode() } else { artifact.clone().into_contract_bytecode() }; @@ -380,18 +380,13 @@ impl ContractSources { /// Returns all (name, bytecode, source) sets. pub fn entries(&self) -> impl Iterator { - self.artifacts_by_name - .iter() - .map(|(name, artifacts)| { - artifacts.iter().filter_map(|artifact| { - let source = self - .sources_by_id - .get(artifact.build_id.as_str())? - .get(&artifact.file_id)?; - Some((name.as_str(), artifact, source)) - }) + self.artifacts_by_name.iter().flat_map(|(name, artifacts)| { + artifacts.iter().filter_map(|artifact| { + let source = + self.sources_by_id.get(artifact.build_id.as_str())?.get(&artifact.file_id)?; + Some((name.as_str(), artifact, source)) }) - .flatten() + }) } } @@ -519,7 +514,7 @@ pub async fn compile_from_source( root.close()?; - return Ok(project_output); + Ok(project_output) } /// Creates a [Project] from an Etherscan source. diff --git a/crates/forge/bin/cmd/test/mod.rs b/crates/forge/bin/cmd/test/mod.rs index ee561e80baeb..c27e2053d6f1 100644 --- a/crates/forge/bin/cmd/test/mod.rs +++ b/crates/forge/bin/cmd/test/mod.rs @@ -337,7 +337,7 @@ impl TestArgs { let sources = ContractSources::from_project_output( output_clone.as_ref().unwrap(), - Some((&project.root(), &libraries)), + Some((project.root(), &libraries)), )?; // Run the debugger. diff --git a/crates/forge/tests/cli/build.rs b/crates/forge/tests/cli/build.rs index c4e725f7e9dd..93b313742678 100644 --- a/crates/forge/tests/cli/build.rs +++ b/crates/forge/tests/cli/build.rs @@ -1,6 +1,6 @@ -use foundry_common::fs::{read_json_file, read_to_string}; +use foundry_common::fs::read_json_file; use foundry_config::Config; -use foundry_test_utils::{forgetest, util::normalize_output}; +use foundry_test_utils::forgetest; use globset::Glob; use std::{collections::BTreeMap, path::PathBuf}; From 02cd64a496480a0c0769dbde605c5c69e519519c Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Tue, 11 Jun 2024 16:53:24 +0300 Subject: [PATCH 7/9] rm patch --- Cargo.lock | 9 +++++---- Cargo.toml | 5 ++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6d87841a0e3c..230e2ed58b90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3444,9 +3444,9 @@ dependencies = [ [[package]] name = "foundry-block-explorers" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673c42208fee48238ef6833cf55295c9e9b5546383caf426da72d849fb43dc24" +checksum = "35344cf275788b0450c4b36d452b812d1122d622bafb29887ce244b8099a86ad" dependencies = [ "alloy-chains", "alloy-json-abi", @@ -3597,8 +3597,9 @@ dependencies = [ [[package]] name = "foundry-compilers" -version = "0.6.2" -source = "git+https://github.com/foundry-rs/compilers?rev=6010918#60109185c77946175abf9c3935bbaef668f78346" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f9b10619d07d765a0336b1990ffcb1bb7b806a59b4d2e65cb78f5d77f373c5" dependencies = [ "alloy-json-abi", "alloy-primitives", diff --git a/Cargo.toml b/Cargo.toml index ec3b4bb6ea1f..65532c07434c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -152,8 +152,8 @@ foundry-wallets = { path = "crates/wallets" } foundry-linking = { path = "crates/linking" } # solc & compilation utilities -foundry-block-explorers = { version = "0.3.0", default-features = false } -foundry-compilers = { version = "0.6.2", default-features = false } +foundry-block-explorers = { version = "0.4.0", default-features = false } +foundry-compilers = { version = "0.7.0", default-features = false } ## revm # no default features to avoid c-kzg @@ -244,7 +244,6 @@ tower-http = "0.5" soldeer = "0.2.15" [patch.crates-io] -foundry-compilers = { git = "https://github.com/foundry-rs/compilers", rev = "6010918" } revm = { git = "https://github.com/bluealloy/revm.git", rev = "a28a543" } revm-interpreter = { git = "https://github.com/bluealloy/revm.git", rev = "a28a543" } revm-precompile = { git = "https://github.com/bluealloy/revm.git", rev = "a28a543" } From dfd2e3023d6cb73f92f91a925db9f9578f3efbe8 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Wed, 12 Jun 2024 07:00:59 +0300 Subject: [PATCH 8/9] use Source::read --- crates/common/src/compile.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index f6cefefc1ab9..fbdcd4cb4bfa 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -342,16 +342,15 @@ impl ContractSources { // infos. let mut files: BTreeMap> = BTreeMap::new(); for (build_id, build) in output.builds() { - for (source_id, source) in &build.source_id_to_path { - let source_code = if let Some(source) = files.get(source) { + for (source_id, path) in &build.source_id_to_path { + let source_code = if let Some(source) = files.get(path) { source.clone() } else { - let source_code = std::fs::read_to_string(source).wrap_err_with(|| { - format!("failed to read artifact source file for `{}`", source.display()) + let source = Source::read(&path).wrap_err_with(|| { + format!("failed to read artifact source file for `{}`", path.display()) })?; - let source_code = Arc::new(source_code); - files.insert(source.to_path_buf(), source_code.clone()); - source_code + files.insert(path.clone(), source.content.clone()); + source.content }; self.sources_by_id.entry(build_id.clone()).or_default().insert( From db849d21333edcb4dc152c46f2f47244fff292f9 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Wed, 12 Jun 2024 07:18:29 +0300 Subject: [PATCH 9/9] clippy --- crates/common/src/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index fbdcd4cb4bfa..d26b362a9adb 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -346,7 +346,7 @@ impl ContractSources { let source_code = if let Some(source) = files.get(path) { source.clone() } else { - let source = Source::read(&path).wrap_err_with(|| { + let source = Source::read(path).wrap_err_with(|| { format!("failed to read artifact source file for `{}`", path.display()) })?; files.insert(path.clone(), source.content.clone());