From fed50683fac2c7ea7c7dc7a30dddd8ff83140603 Mon Sep 17 00:00:00 2001 From: Rim Rakhimov Date: Thu, 24 Oct 2024 00:41:19 +0400 Subject: [PATCH 1/4] feat(verifier): add era-solidity compilers support for zksync solc verification --- smart-contract-verifier/Cargo.lock | 5 +- .../src/services/zksync_solidity_verifier.rs | 12 +- .../src/settings.rs | 6 +- .../era_solidity_0.8.28.json | 31 +++ .../zksync_integration/zksync_solidity.rs | 21 ++ .../smart-contract-verifier/Cargo.toml | 1 + .../src/compiler/mod.rs | 2 +- .../smart-contract-verifier/src/consts.rs | 7 + .../smart-contract-verifier/src/lib.rs | 4 +- .../src/zksync/implementation.rs | 210 ++++++++++++++---- 10 files changed, 245 insertions(+), 54 deletions(-) create mode 100644 smart-contract-verifier/smart-contract-verifier-server/tests/test_cases_zksync_solidity/era_solidity_0.8.28.json diff --git a/smart-contract-verifier/Cargo.lock b/smart-contract-verifier/Cargo.lock index b4c348451..13309983b 100644 --- a/smart-contract-verifier/Cargo.lock +++ b/smart-contract-verifier/Cargo.lock @@ -4929,6 +4929,7 @@ dependencies = [ "tempfile", "thiserror", "tokio", + "tokio-stream", "tracing", "url", "verification-common", @@ -5498,9 +5499,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", diff --git a/smart-contract-verifier/smart-contract-verifier-server/src/services/zksync_solidity_verifier.rs b/smart-contract-verifier/smart-contract-verifier-server/src/services/zksync_solidity_verifier.rs index 104e399c8..5e33cde33 100644 --- a/smart-contract-verifier/smart-contract-verifier-server/src/services/zksync_solidity_verifier.rs +++ b/smart-contract-verifier/smart-contract-verifier-server/src/services/zksync_solidity_verifier.rs @@ -36,12 +36,21 @@ impl Service { let evm_fetcher = common::initialize_fetcher( settings.evm_fetcher, settings.evm_compilers_dir.clone(), - settings.evm_refresh_versions_schedule, + settings.evm_refresh_versions_schedule.clone(), Some(solc_validator), ) .await .context("zksync solc fetcher initialization")?; + let era_evm_fetcher = common::initialize_fetcher( + settings.era_evm_fetcher, + settings.evm_compilers_dir.clone(), + settings.evm_refresh_versions_schedule, + None, + ) + .await + .context("zksync era solc fetcher initialization")?; + let zk_fetcher = common::initialize_fetcher( settings.zk_fetcher, settings.zk_compilers_dir.clone(), @@ -53,6 +62,7 @@ impl Service { let compilers = ZkSyncCompilers::new( evm_fetcher.clone(), + era_evm_fetcher.clone(), zk_fetcher.clone(), compilers_threads_semaphore, ); diff --git a/smart-contract-verifier/smart-contract-verifier-server/src/settings.rs b/smart-contract-verifier/smart-contract-verifier-server/src/settings.rs index d508835f9..852f3046a 100644 --- a/smart-contract-verifier/smart-contract-verifier-server/src/settings.rs +++ b/smart-contract-verifier/smart-contract-verifier-server/src/settings.rs @@ -7,8 +7,8 @@ use cron::Schedule; use serde::Deserialize; use serde_with::{serde_as, DisplayFromStr}; use smart_contract_verifier::{ - DEFAULT_SOLIDITY_COMPILER_LIST, DEFAULT_SOURCIFY_HOST, DEFAULT_VYPER_COMPILER_LIST, - DEFAULT_ZKSOLC_COMPILER_LIST, + DEFAULT_ERA_SOLIDITY_COMPILER_LIST, DEFAULT_SOLIDITY_COMPILER_LIST, DEFAULT_SOURCIFY_HOST, + DEFAULT_VYPER_COMPILER_LIST, DEFAULT_ZKSOLC_COMPILER_LIST, }; use std::{ num::{NonZeroU32, NonZeroUsize}, @@ -130,6 +130,7 @@ pub struct ZksyncSoliditySettings { #[serde_as(as = "DisplayFromStr")] pub evm_refresh_versions_schedule: Schedule, pub evm_fetcher: FetcherSettings, + pub era_evm_fetcher: FetcherSettings, pub zk_compilers_dir: PathBuf, #[serde_as(as = "DisplayFromStr")] pub zk_refresh_versions_schedule: Schedule, @@ -143,6 +144,7 @@ impl Default for ZksyncSoliditySettings { evm_compilers_dir: default_compilers_dir("zksync-solc-compilers"), evm_refresh_versions_schedule: schedule_every_hour(), evm_fetcher: default_list_fetcher(DEFAULT_SOLIDITY_COMPILER_LIST), + era_evm_fetcher: default_list_fetcher(DEFAULT_ERA_SOLIDITY_COMPILER_LIST), zk_compilers_dir: default_compilers_dir("zksync-zksolc-compilers"), zk_refresh_versions_schedule: schedule_every_hour(), zk_fetcher: default_list_fetcher(DEFAULT_ZKSOLC_COMPILER_LIST), diff --git a/smart-contract-verifier/smart-contract-verifier-server/tests/test_cases_zksync_solidity/era_solidity_0.8.28.json b/smart-contract-verifier/smart-contract-verifier-server/tests/test_cases_zksync_solidity/era_solidity_0.8.28.json new file mode 100644 index 000000000..b5191d8c6 --- /dev/null +++ b/smart-contract-verifier/smart-contract-verifier-server/tests/test_cases_zksync_solidity/era_solidity_0.8.28.json @@ -0,0 +1,31 @@ +{ + "_comment": "A contract compiled via era-solidity v0.8.28-1.0.1+commit.acc7d8f9", + "deployed_code": "0x00020000000000020000008004000039000000400040043f00000060031002700000007d0330019700000001002001900000000002000416000000200900008a000000660000c13d000000040030008c000000c10000413d000000000401043b000000e004400270000000850040009c0000009b0000613d000000860040009c000000c10000c13d000000240030008c000000c10000413d000000000002004b000000c10000c13d0000000402100370000000000402043b000000800040009c000000c10000213d0000002302400039000000000032004b000000c10000813d0000000405400039000000000251034f000000000202043b000000800020009c000000970000213d0000001f06200039000000000696016f0000003f06600039000000000696016f000000870060009c000000970000213d0000008006600039000000400060043f000000800020043f00000000042400190000002404400039000000000034004b000000c10000213d0000002003500039000000000331034f00000000049201700000001f0520018f000000a0014000390000003a0000613d000000a006000039000000000703034f000000007807043c0000000006860436000000000016004b000000360000c13d000000000005004b000000470000613d000000000343034f0000000304500210000000000501043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f0000000000310435000000a0012000390000000000010435000000800100043d000000800010009c000000970000213d000000000300041a000000010030019000000001023002700000007f0220618f0000001f0020008c00000000040000390000000104002039000000000343013f0000000100300190000000a70000c13d000000200020008c000001910000413d0000001f031000390000000503300270000000820330009a000000200010008c00000083030040410000001f022000390000000502200270000000820220009a000000000000043f000000000023004b000001910000813d000000000003041b0000000103300039000000610000013d000000000002004b000000c10000c13d0000001f023000390000007e022001970000008002200039000000400020043f0000001f0530018f0000007f063001980000008002600039000000750000613d000000000701034f000000007807043c0000000004840436000000000024004b000000710000c13d000000000005004b000000820000613d000000000161034f0000000304500210000000000502043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000120435000000200030008c000000c10000413d000000800400043d000000800040009c000000c10000213d0000001f01400039000000000031004b000000000200001900000081020080410000008101100197000000000001004b00000000050000190000008105004041000000810010009c000000000502c019000000000005004b000000c10000c13d00000080014000390000000002010433000000800020009c000000ad0000a13d0000008801000041000000000010043f0000004101000039000000aa0000013d000000000002004b000000c10000c13d000000000200041a000000010320019000000001012002700000007f0110618f0000001f0010008c00000000040000390000000104002039000000000442013f0000000100400190000000c30000613d0000008801000041000000000010043f0000002201000039000000040010043f0000008901000041000001f1000104300000001f01200039000000000191016f0000003f01100039000000000191016f000000400b00043d00000000011b00190000000000b1004b00000000050000390000000105004039000000800010009c000000970000213d0000000100500190000000970000c13d0000008005300039000000400010043f00000000012b0436000000a0034000390000000004320019000000000054004b000001140000a13d0000000001000019000001f100010430000000800010043f000000000003004b000000d10000613d0000008302000041000000000000043f0000000003000019000000000013004b000000d80000813d000000000402041a000000a005300039000000000045043500000020033000390000000102200039000000c90000013d000001000300008a000000000232016f000000a00020043f000000000001004b000000a0010000390000008001006039000000d90000013d0000008001300039000000600210008a000000800100003901ef01bc0000040f0000002002000039000000400100043d0000000003210436000000800200043d0000000000230435000000200a00008a0000000005a2016f0000001f0420018f0000004003100039000000a10030008c000000f70000413d000000000005004b000000f20000613d000000000743001900000080064001bf000000200770008a0000000008570019000000000956001900000000090904330000000000980435000000200550008c000000ec0000c13d000000000004004b0000010d0000613d000000a0050000390000000006030019000001030000013d0000000006530019000000000005004b000001000000613d000000a007000039000000000803001900000000790704340000000008980436000000000068004b000000fc0000c13d000000000004004b0000010d0000613d000000a0055000390000000304400210000000000706043300000000074701cf000000000747022f00000000050504330000010004400089000000000545022f00000000044501cf000000000474019f0000000000460435000000000332001900000000000304350000001f022000390000000002a2016f0000004002200039000000000300001901ef01cf0000040f000000000592016f0000001f0420018f000000000013004b000001280000813d000000000005004b000001240000613d00000000074300190000000006410019000000200660008a000000200770008a0000000008560019000000000957001900000000090904330000000000980435000000200550008c0000011e0000c13d000000000004004b0000013e0000613d0000000006010019000001340000013d0000000006510019000000000005004b000001310000613d0000000007030019000000000801001900000000790704340000000008980436000000000068004b0000012d0000c13d000000000004004b0000013e0000613d00000000035300190000000304400210000000000506043300000000054501cf000000000545022f00000000030304330000010004400089000000000343022f00000000034301cf000000000353019f00000000003604350000000002210019000000000002043500000000050b0433000000800050009c000000970000213d000000000200041a000000010420019000000001032002700000007f0330618f0000001f0030008c00000000020000390000000102002039000000000024004b000000a70000c13d000000200030008c0000015c0000413d0000001f025000390000000502200270000000820220009a000000200050008c00000083020040410000001f033000390000000503300270000000820330009a000000000000043f000000000032004b0000015c0000813d000000000002041b0000000102200039000001570000013d0000001f0050008c0000002008000039000001740000a13d000000000000043f000000000108001900020000000b001d000100000005001d01ef01d90000040f000000200800003900000001070000290000000206000029000000200200008a000000000227016f00000000030800190000000004000019000000000024004b00000000056300190000017f0000813d0000000005050433000000000051041b0000002004400039000000200330003900000001011000390000016b0000013d000000000005004b0000000002000019000001780000613d00000000020104330000000301500210000000010300008a000000000113022f000000000131013f000000000212016f00000001015002100000018b0000013d000000000072004b000001890000813d0000000302700210000000f80220018f000000010300008a000000000223022f000000000232013f0000000003050433000000000223016f000000000021041b00000001010000390000000102700210000000000112019f000000000010041b000001000080044300000120000004430000008401000041000001f00001042e0000001f0010008c000001ae0000a13d000000000391016f00000020040000390000008302000041000000000000043f0000000005000019000000000035004b0000008006400039000001a10000813d0000000006060433000000000062041b000000200550003900000020044000390000000102200039000001980000013d000000000013004b000001ab0000813d0000000303100210000000f80330018f000000010400008a000000000334022f000000000343013f0000000004060433000000000334016f000000000032041b00000001020000390000000103100210000001b80000013d000000000001004b0000000002000019000001b20000613d000000a00200043d0000000303100210000000010400008a000000000334022f000000000343013f000000000332016f0000000102100210000000000123019f000000000010041b0000000001000019000001f00001042e0000001f02200039000000200300008a000000000232016f0000000001120019000000000021004b00000000020000390000000102004039000000800010009c000001c90000213d0000000100200190000001c90000c13d000000400010043f000000000001042d0000008801000041000000000010043f0000004101000039000000040010043f0000008901000041000001f1000104300000007d0010009c0000007d0100804100000040011002100000007d0020009c0000007d020080410000006002200210000000000112019f000000e002300210000000000121019f000001f00001042e0000007d0010009c0000007d01008041000000600110021000000000020004140000007d0020009c0000007d02008041000000c002200210000000000112019f0000008a011001c7000080100200003901ef01ea0000040f0000000100200190000001e80000613d000000000101043b000000000001042d0000000001000019000001f100010430000001ed002104230000000102000039000000000001042d0000000002000019000000000001042d000001ef00000432000001f00001042e000001f1000104300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000000000000000000000000000ffffffffffffffff8000000000000000000000000000000000000000000000000000000000000000d6f21326ab749d5729fcba5677c79037b459436ab7bff709c9d06ce9f10c1a9d290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563000000020000000000000000000000000000004000000100000000000000000000000000000000000000000000000000000000000000000000000000cfae321700000000000000000000000000000000000000000000000000000000a4136862000000000000000000000000000000000000000000000000ffffffffffffff7f4e487b7100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002400000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a51d2e13c12093a421b91e8cc786a55312ca8850ffda3475747716ceca929ad8", + "constructor_arguments": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000094869207468657265210000000000000000000000000000000000000000000000", + "zk_compiler_version": "v1.5.6", + "evm_compiler_version": "v0.8.28+commit.7893614a", + "input": {"language":"Solidity","sources":{"src/Greeter.sol":{"content":"//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\ncontract Greeter {\n string private greeting;\n\n constructor(string memory _greeting) {\n greeting = _greeting;\n }\n\n function greet() public view returns (string memory) {\n return greeting;\n }\n\n function setGreeting(string memory _greeting) public {\n greeting = _greeting;\n }\n}\n\n"}},"settings":{"viaIR":false,"remappings":["forge-std/=lib/forge-std/src/","forge-zksync-std/=lib/forge-zksync-std/src/"],"evmVersion":"cancun","outputSelection":{"*":{"*":["abi"]}},"optimizer":{"enabled":true,"mode":"z","fallback_to_optimizing_for_size":false,"disable_system_request_memoization":true},"metadata":{},"libraries":{},"detectMissingLibraries":false,"enableEraVMExtensions":false,"forceEVMLA":false}}, + "file_name": "src/Greeter.sol", + "contract_name": "Greeter", + "expected_sources": { + "src/Greeter.sol": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\ncontract Greeter {\n string private greeting;\n\n constructor(string memory _greeting) {\n greeting = _greeting;\n }\n\n function greet() public view returns (string memory) {\n return greeting;\n }\n\n function setGreeting(string memory _greeting) public {\n greeting = _greeting;\n }\n}\n" + }, + "expected_compilation_artifacts": {"abi":[{"inputs":[{"internalType":"string","name":"_greeting","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"greet","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_greeting","type":"string"}],"name":"setGreeting","outputs":[],"stateMutability":"nonpayable","type":"function"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1},"storageLayout":{"storage":[{"astId":3,"contract":"contracts/Greeter.sol:Greeter","label":"greeting","offset":0,"slot":"0","type":"t_string_storage"}],"types":{"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"}}}}, + "expected_creation_code_artifacts": {}, + "expected_runtime_code_artifacts": {}, + + "expected_creation_match_type": "full", + "expected_creation_transformations": [ + { + "type": "insert", + "reason": "constructor", + "offset": 4192 + } + ], + "expected_creation_values": { + "constructorArguments": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000094869207468657265210000000000000000000000000000000000000000000000" + }, + "expected_runtime_match_type": "full", + "expected_runtime_transformations": [], + "expected_runtime_values": {} +} diff --git a/smart-contract-verifier/smart-contract-verifier-server/tests/zksync_integration/zksync_solidity.rs b/smart-contract-verifier/smart-contract-verifier-server/tests/zksync_integration/zksync_solidity.rs index 31848323f..4033c3a26 100644 --- a/smart-contract-verifier/smart-contract-verifier-server/tests/zksync_integration/zksync_solidity.rs +++ b/smart-contract-verifier/smart-contract-verifier-server/tests/zksync_integration/zksync_solidity.rs @@ -72,6 +72,27 @@ async fn zksolc_1_3_5() { test_case.check_verify_response(response); } +// Era Solidity compilers are forks of Solidity compilers created by zksync. +// They are used by foundry and hardhat tools and affect metadata hash of compiled contracts. +#[tokio::test] +async fn era_solidity_compiled_standard_json() { + const ROUTE: &str = "/api/v2/zksync-verifier/solidity/sources:verify-standard-json"; + + let test_case = types::from_file::("era_solidity_0.8.28"); + + let server = super::start().await; + + let request = test_case.to_request(); + let response: VerifyResponse = blockscout_service_launcher::test_server::send_post_request( + &server.base_url, + ROUTE, + &request, + ) + .await; + + test_case.check_verify_response(response); +} + #[tokio::test] async fn cannot_compile() { const ROUTE: &str = "/api/v2/zksync-verifier/solidity/sources:verify-standard-json"; diff --git a/smart-contract-verifier/smart-contract-verifier/Cargo.toml b/smart-contract-verifier/smart-contract-verifier/Cargo.toml index d6e43d41b..561c170bc 100644 --- a/smart-contract-verifier/smart-contract-verifier/Cargo.toml +++ b/smart-contract-verifier/smart-contract-verifier/Cargo.toml @@ -44,6 +44,7 @@ sscanf = "0.3" tempfile = "3.3" thiserror = "1.0" tokio = { version = "1", features = ["macros"] } +tokio-stream = { version = "0.1.16" } tracing = "0.1" url = { version = "2.4", features = ["serde"] } verification-common = { workspace = true } diff --git a/smart-contract-verifier/smart-contract-verifier/src/compiler/mod.rs b/smart-contract-verifier/smart-contract-verifier/src/compiler/mod.rs index 3f2c780bf..6fa7b7ba8 100644 --- a/smart-contract-verifier/smart-contract-verifier/src/compiler/mod.rs +++ b/smart-contract-verifier/smart-contract-verifier/src/compiler/mod.rs @@ -9,7 +9,7 @@ mod version_detailed; pub use compilers::{CompilerInput, Compilers, Error, EvmCompiler}; pub use download_cache::DownloadCache; -pub use fetcher::{FetchError, Fetcher, FileValidator, Version}; +pub use fetcher::{Fetcher, FileValidator, Version}; pub use fetcher_list::ListFetcher; pub use fetcher_s3::S3Fetcher; pub use version_compact::CompactVersion; diff --git a/smart-contract-verifier/smart-contract-verifier/src/consts.rs b/smart-contract-verifier/smart-contract-verifier/src/consts.rs index ffa5464eb..534b5c9ee 100644 --- a/smart-contract-verifier/smart-contract-verifier/src/consts.rs +++ b/smart-contract-verifier/smart-contract-verifier/src/consts.rs @@ -20,3 +20,10 @@ pub const DEFAULT_ZKSOLC_COMPILER_LIST: &str = #[cfg(target_os = "macos")] pub const DEFAULT_ZKSOLC_COMPILER_LIST: &str = "https://raw.githubusercontent.com/blockscout/solc-bin/main/zksolc.macosx-arm64.list.json"; + +#[cfg(target_os = "linux")] +pub const DEFAULT_ERA_SOLIDITY_COMPILER_LIST: &str = + "https://raw.githubusercontent.com/blockscout/solc-bin/main/era-solidity.linux-amd64.list.json"; +#[cfg(target_os = "macos")] +pub const DEFAULT_ERA_SOLIDITY_COMPILER_LIST: &str = + "https://raw.githubusercontent.com/blockscout/solc-bin/main/era-solidity.macosx-arm64.list.json"; diff --git a/smart-contract-verifier/smart-contract-verifier/src/lib.rs b/smart-contract-verifier/smart-contract-verifier/src/lib.rs index ebf602a1e..695f60eb0 100644 --- a/smart-contract-verifier/smart-contract-verifier/src/lib.rs +++ b/smart-contract-verifier/smart-contract-verifier/src/lib.rs @@ -20,8 +20,8 @@ pub mod zksync; pub(crate) use blockscout_display_bytes::Bytes as DisplayBytes; pub use consts::{ - DEFAULT_SOLIDITY_COMPILER_LIST, DEFAULT_SOURCIFY_HOST, DEFAULT_VYPER_COMPILER_LIST, - DEFAULT_ZKSOLC_COMPILER_LIST, + DEFAULT_ERA_SOLIDITY_COMPILER_LIST, DEFAULT_SOLIDITY_COMPILER_LIST, DEFAULT_SOURCIFY_HOST, + DEFAULT_VYPER_COMPILER_LIST, DEFAULT_ZKSOLC_COMPILER_LIST, }; pub use middleware::Middleware; diff --git a/smart-contract-verifier/smart-contract-verifier/src/zksync/implementation.rs b/smart-contract-verifier/smart-contract-verifier/src/zksync/implementation.rs index a9730acaa..01813b17d 100644 --- a/smart-contract-verifier/smart-contract-verifier/src/zksync/implementation.rs +++ b/smart-contract-verifier/smart-contract-verifier/src/zksync/implementation.rs @@ -1,9 +1,9 @@ -use crate::{compiler::{CompactVersion, DetailedVersion, DownloadCache, FetchError, Fetcher}, decode_hex, Version, zksync::zksolc_standard_json::{input, input::Input, output, output::contract::Contract}}; +use crate::{compiler::{CompactVersion, DetailedVersion, DownloadCache, Fetcher}, decode_hex, Version, zksync::zksolc_standard_json::{input, input::Input, output, output::contract::Contract}}; use anyhow::Context; use async_trait::async_trait; use bytes::Bytes; use foundry_compilers::error::SolcError; -use futures::TryFutureExt; +use futures::{StreamExt, TryFutureExt, TryStreamExt}; use nonempty::NonEmpty; use serde::{de::DeserializeOwned, Deserialize}; use serde_json::Value; @@ -99,10 +99,52 @@ pub async fn verify( compiler_input.normalize_output_selection(&zk_compiler_version); - let (compiler_output, _raw_compiler_output) = compilers - .compile(&zk_compiler_version, &evm_compiler_version, &compiler_input) + let (zk_compiler_path, evm_compiler_paths) = compilers + .fetch_compilers(&zk_compiler_version, &evm_compiler_version) .await?; + let mut successes = vec![]; + let mut failures = vec![]; + for evm_compiler_path in evm_compiler_paths { + let (compiler_output, _raw_compiler_output) = compilers + .compile(&zk_compiler_path, &evm_compiler_path, &compiler_input) + .await?; + + (successes, failures) = verify_compiler_output( + request.code.clone(), + request.constructor_arguments.clone(), + compiler_output, + )?; + + if !successes.is_empty() { + break; + } + } + + let sources = compiler_input + .sources + .into_iter() + .map(|(file, source)| (file, source.content.to_string())) + .collect(); + Ok(VerificationResult { + zk_compiler: "zksolc".to_string(), + zk_compiler_version, + evm_compiler: "solc".to_string(), + evm_compiler_version, + language: Language::Solidity, + compiler_settings: serde_json::to_value(compiler_input.settings) + .context("compiler settings serialization")?, + sources, + successes, + failures, + }) +} + +fn verify_compiler_output( + code: Bytes, + constructor_arguments: Option, + compiler_output: output::Output, +) -> Result<(Vec, Vec), Error> { let mut successes = Vec::new(); let mut failures = Vec::new(); for (file, contracts) in compiler_output.contracts.unwrap_or_default() { @@ -110,8 +152,8 @@ pub async fn verify( match check_contract( file.clone(), name, - request.code.clone(), - request.constructor_arguments.clone(), + code.clone(), + constructor_arguments.clone(), contract, )? { Ok(success) => { @@ -137,23 +179,7 @@ pub async fn verify( } } - let sources = compiler_input - .sources - .into_iter() - .map(|(file, source)| (file, source.content.to_string())) - .collect(); - Ok(VerificationResult { - zk_compiler: "zksolc".to_string(), - zk_compiler_version, - evm_compiler: "solc".to_string(), - evm_compiler_version, - language: Language::Solidity, - compiler_settings: serde_json::to_value(compiler_input.settings) - .context("compiler settings serialization")?, - sources, - successes, - failures, - }) + Ok((successes, failures)) } fn check_contract( @@ -347,6 +373,8 @@ pub trait ZkSyncCompiler { pub struct ZkSyncCompilers { evm_cache: DownloadCache, evm_fetcher: Arc>, + era_evm_cache: DownloadCache, + era_evm_fetcher: Arc>, zk_cache: DownloadCache, zk_fetcher: Arc>, threads_semaphore: Arc, @@ -356,12 +384,15 @@ pub struct ZkSyncCompilers { impl ZkSyncCompilers { pub fn new( evm_fetcher: Arc>, + era_evm_fetcher: Arc>, zk_fetcher: Arc>, threads_semaphore: Arc, ) -> Self { Self { evm_cache: DownloadCache::default(), evm_fetcher, + era_evm_cache: DownloadCache::default(), + era_evm_fetcher, zk_cache: DownloadCache::default(), zk_fetcher, threads_semaphore, @@ -371,19 +402,17 @@ impl ZkSyncCompilers { pub async fn compile( &self, - zk_compiler: &CompactVersion, - evm_compiler: &DetailedVersion, + zk_compiler_path: &Path, + evm_compiler_path: &Path, input: &ZkC::CompilerInput, ) -> Result<(ZkC::CompilerOutput, Value), Error> { - let (zk_path, evm_path) = self.fetch_compilers(zk_compiler, evm_compiler).await?; - let _permit = self .threads_semaphore .acquire() .await .context("acquiring lock")?; - let raw_compiler_output = ZkC::compile(&zk_path, &evm_path, input) + let raw_compiler_output = ZkC::compile(zk_compiler_path, evm_compiler_path, input) .await .context("compilation")?; @@ -416,29 +445,118 @@ impl ZkSyncCompilers { &self, zk_compiler: &CompactVersion, evm_compiler: &DetailedVersion, - ) -> Result<(PathBuf, PathBuf), Error> { + ) -> Result<(PathBuf, NonEmpty), Error> { + let (zk_compiler, maybe_evm_compiler, era_evm_compilers) = + self.choose_compiler_versions_to_fetch(zk_compiler, evm_compiler)?; + + assert!( + maybe_evm_compiler.is_some() || !era_evm_compilers.is_empty(), + "there must be at least one valid evm compiler after choosing" + ); + let zk_path_future = self .zk_cache - .get(self.zk_fetcher.as_ref(), zk_compiler) - .map_err(|err| match err { - FetchError::NotFound(version) => Error::ZkCompilerNotFound(version), - err => anyhow::Error::new(err) - .context("fetching zk compiler") - .into(), + .get(self.zk_fetcher.as_ref(), &zk_compiler) + .map_err(|err| { + Error::Internal(anyhow::Error::new(err).context("fetching zk compiler")) }); - let evm_path_future = self - .evm_cache - .get(self.evm_fetcher.as_ref(), evm_compiler) - .map_err(|err| match err { - FetchError::NotFound(version) => Error::EvmCompilerNotFound(version), - err => anyhow::Error::new(err) - .context("fetching evm compiler") - .into(), - }); + let mut evm_compilers = vec![]; + if let Some(evm_compiler) = maybe_evm_compiler { + evm_compilers.push(evm_compiler) + } + let evm_paths_future = tokio_stream::iter(evm_compilers) + .map(|version| async move { + self.evm_cache + .get(self.evm_fetcher.as_ref(), &version) + .await + .map_err(|err| { + Error::Internal( + anyhow::Error::new(err) + .context(format!("fetching evm compiler: {version}")), + ) + }) + }) + .buffered(3) + .try_collect::>(); + + let era_evm_paths_future = tokio_stream::iter(era_evm_compilers) + .map(|version| async move { + self.era_evm_cache + .get(self.era_evm_fetcher.as_ref(), &version) + .await + .map_err(|err| { + Error::Internal( + anyhow::Error::new(err) + .context(format!("fetching evm compiler: {version}")), + ) + }) + }) + .buffered(3) + .try_collect::>(); + + let (zk_path_result, evm_paths_result, era_evm_paths_result) = + futures::join!(zk_path_future, evm_paths_future, era_evm_paths_future); + let (zk_path_result, evm_paths_result, era_evm_paths_result) = + (zk_path_result?, evm_paths_result?, era_evm_paths_result?); + + let mut all_evm_paths_result = era_evm_paths_result; + all_evm_paths_result.extend(evm_paths_result); + let all_evm_paths_result = + NonEmpty::from_vec(all_evm_paths_result).expect("at least 1 valid evm_version exists"); + + Ok((zk_path_result, all_evm_paths_result)) + } + + fn choose_compiler_versions_to_fetch( + &self, + zk_compiler: &CompactVersion, + evm_compiler: &DetailedVersion, + ) -> Result< + ( + CompactVersion, + Option, + Vec, + ), + Error, + > { + let all_zk_compilers = self.zk_fetcher.all_versions(); + let zk_compiler = match all_zk_compilers + .into_iter() + .find(|value| zk_compiler == value) + { + None => return Err(Error::ZkCompilerNotFound(zk_compiler.to_string())), + Some(zk_compiler) => zk_compiler, + }; + + let all_evm_compilers = self.evm_fetcher.all_versions(); + let maybe_requested_evm_compiler = all_evm_compilers + .contains(evm_compiler) + .then(|| evm_compiler.clone()); + + let matching_era_evm_compilers = + self.lookup_era_evm_compilers_by_semver_version(evm_compiler.version()); + + if maybe_requested_evm_compiler.is_none() && matching_era_evm_compilers.is_empty() { + return Err(Error::EvmCompilerNotFound(evm_compiler.to_string())); + } + + Ok(( + zk_compiler, + maybe_requested_evm_compiler, + matching_era_evm_compilers, + )) + } - let (zk_path_result, evm_path_result) = futures::join!(zk_path_future, evm_path_future); - Ok((zk_path_result?, evm_path_result?)) + fn lookup_era_evm_compilers_by_semver_version( + &self, + version: &semver::Version, + ) -> Vec { + let era_evm_compilers = self.era_evm_fetcher.all_versions(); + era_evm_compilers + .into_iter() + .filter(|compiler| compiler.version() == version) + .collect() } } From d2c66eec48daff95893ade880973a215f5633cb6 Mon Sep 17 00:00:00 2001 From: Rim Rakhimov Date: Thu, 24 Oct 2024 01:35:09 +0400 Subject: [PATCH 2/4] fix(verifier): update zksync input related structs to correspond to the latest zksync compiler version --- .../era_solidity_0.8.28.json | 6 +-- .../eravm_metadata_hash.rs | 31 ++++++++++-- .../era_compiler_llvm_context/mod.rs | 2 +- .../input/settings/metadata.rs | 4 +- .../input/settings/mod.rs | 47 ++++++++----------- .../input/settings/optimizer/mod.rs | 24 ++++++++++ .../input/settings/selection/file/flag.rs | 28 ++++------- 7 files changed, 85 insertions(+), 57 deletions(-) diff --git a/smart-contract-verifier/smart-contract-verifier-server/tests/test_cases_zksync_solidity/era_solidity_0.8.28.json b/smart-contract-verifier/smart-contract-verifier-server/tests/test_cases_zksync_solidity/era_solidity_0.8.28.json index b5191d8c6..28da70230 100644 --- a/smart-contract-verifier/smart-contract-verifier-server/tests/test_cases_zksync_solidity/era_solidity_0.8.28.json +++ b/smart-contract-verifier/smart-contract-verifier-server/tests/test_cases_zksync_solidity/era_solidity_0.8.28.json @@ -8,9 +8,9 @@ "file_name": "src/Greeter.sol", "contract_name": "Greeter", "expected_sources": { - "src/Greeter.sol": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\ncontract Greeter {\n string private greeting;\n\n constructor(string memory _greeting) {\n greeting = _greeting;\n }\n\n function greet() public view returns (string memory) {\n return greeting;\n }\n\n function setGreeting(string memory _greeting) public {\n greeting = _greeting;\n }\n}\n" + "src/Greeter.sol": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\ncontract Greeter {\n string private greeting;\n\n constructor(string memory _greeting) {\n greeting = _greeting;\n }\n\n function greet() public view returns (string memory) {\n return greeting;\n }\n\n function setGreeting(string memory _greeting) public {\n greeting = _greeting;\n }\n}\n\n" }, - "expected_compilation_artifacts": {"abi":[{"inputs":[{"internalType":"string","name":"_greeting","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"greet","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_greeting","type":"string"}],"name":"setGreeting","outputs":[],"stateMutability":"nonpayable","type":"function"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1},"storageLayout":{"storage":[{"astId":3,"contract":"contracts/Greeter.sol:Greeter","label":"greeting","offset":0,"slot":"0","type":"t_string_storage"}],"types":{"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"}}}}, + "expected_compilation_artifacts": {"abi":[{"inputs":[{"internalType":"string","name":"_greeting","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"greet","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_greeting","type":"string"}],"name":"setGreeting","outputs":[],"stateMutability":"nonpayable","type":"function"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1},"storageLayout":{"storage":[{"astId":3,"contract":"src/Greeter.sol:Greeter","label":"greeting","offset":0,"slot":"0","type":"t_string_storage"}],"types":{"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"}}}}, "expected_creation_code_artifacts": {}, "expected_runtime_code_artifacts": {}, @@ -19,7 +19,7 @@ { "type": "insert", "reason": "constructor", - "offset": 4192 + "offset": 4512 } ], "expected_creation_values": { diff --git a/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/era_compiler_llvm_context/eravm_metadata_hash.rs b/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/era_compiler_llvm_context/eravm_metadata_hash.rs index 378891484..c1eef2f7a 100644 --- a/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/era_compiler_llvm_context/eravm_metadata_hash.rs +++ b/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/era_compiler_llvm_context/eravm_metadata_hash.rs @@ -1,11 +1,34 @@ -use serde::{Deserialize, Serialize}; +//! +//! The hash type. +//! -#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)] -pub enum MetadataHash { +use std::str::FromStr; + +/// +/// The hash type. +/// +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] +pub enum Type { /// Do not include bytecode hash. #[serde(rename = "none")] None, - /// The default keccak256 hash. + /// The `keccak256`` hash type. #[serde(rename = "keccak256")] Keccak256, + /// The `ipfs` hash. + #[serde(rename = "ipfs")] + Ipfs, +} + +impl FromStr for Type { + type Err = anyhow::Error; + + fn from_str(string: &str) -> Result { + match string { + "none" => Ok(Self::None), + "keccak256" => Ok(Self::Keccak256), + "ipfs" => Ok(Self::Ipfs), + string => anyhow::bail!("unknown bytecode hash mode: `{string}`"), + } + } } diff --git a/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/era_compiler_llvm_context/mod.rs b/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/era_compiler_llvm_context/mod.rs index 026016455..2b4f8cd65 100644 --- a/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/era_compiler_llvm_context/mod.rs +++ b/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/era_compiler_llvm_context/mod.rs @@ -1,3 +1,3 @@ mod eravm_metadata_hash; -pub use eravm_metadata_hash::MetadataHash as EraVMMetadataHash; +pub use eravm_metadata_hash::Type as HashType; diff --git a/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/metadata.rs b/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/metadata.rs index 02bf0b8f7..51ed0972d 100644 --- a/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/metadata.rs +++ b/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/metadata.rs @@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize}; pub struct Metadata { /// The bytecode hash mode. #[serde(skip_serializing_if = "Option::is_none")] - pub bytecode_hash: Option, + pub bytecode_hash: Option, /// Whether to use literal content. #[serde(skip_serializing_if = "Option::is_none")] pub use_literal_content: Option, @@ -24,7 +24,7 @@ impl Metadata { /// A shortcut constructor. /// pub fn new( - bytecode_hash: era_compiler_llvm_context::EraVMMetadataHash, + bytecode_hash: era_compiler_llvm_context::HashType, use_literal_content: bool, ) -> Self { Self { diff --git a/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/mod.rs b/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/mod.rs index 44d41c133..3dc980eb0 100644 --- a/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/mod.rs +++ b/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/mod.rs @@ -30,44 +30,35 @@ pub struct Settings { /// The output selection filters. #[serde(skip_serializing_if = "Option::is_none")] pub output_selection: Option, - /// Whether to compile via IR. Only for testing with solc >=0.8.13. + /// Whether to compile via EVM assembly. + #[serde(rename = "forceEVMLA", skip_serializing_if = "Option::is_none")] + pub force_evmla: Option, + /// Whether to add the Yul step to compilation via EVM assembly. + #[serde(rename = "viaIR", skip_serializing_if = "Option::is_none")] + pub via_ir: Option, + /// Whether to enable EraVM extensions. #[serde( - rename = "viaIR", - skip_serializing_if = "Option::is_none", - skip_deserializing + rename = "enableEraVMExtensions", + skip_serializing_if = "Option::is_none" )] - pub via_ir: Option, + pub enable_eravm_extensions: Option, + /// Whether to enable the missing libraries detection mode. + #[serde( + rename = "detectMissingLibraries", + skip_serializing_if = "Option::is_none" + )] + pub detect_missing_libraries: Option, /// The optimizer settings. pub optimizer: Optimizer, + /// The extra LLVM options. + #[serde(rename = "LLVMOptions", skip_serializing_if = "Option::is_none")] + pub llvm_options: Option>, /// The metadata settings. #[serde(skip_serializing_if = "Option::is_none")] pub metadata: Option, } impl Settings { - /// - /// A shortcut constructor. - /// - pub fn new( - evm_version: Option, - libraries: BTreeMap>, - remappings: Option>, - output_selection: Selection, - via_ir: bool, - optimizer: Optimizer, - metadata: Option, - ) -> Self { - Self { - evm_version, - libraries: Some(libraries), - remappings, - output_selection: Some(output_selection), - via_ir: if via_ir { Some(true) } else { None }, - optimizer, - metadata, - } - } - /// /// Sets the necessary defaults. /// diff --git a/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/optimizer/mod.rs b/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/optimizer/mod.rs index 820e05f15..4395a4149 100644 --- a/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/optimizer/mod.rs +++ b/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/optimizer/mod.rs @@ -31,6 +31,27 @@ pub struct Optimizer { /// Set the jump table density threshold. #[serde(skip_serializing_if = "Option::is_none")] pub jump_table_density_threshold: Option, + // The original structure contained `camelCase` modifier for all optimizer fields. + // But sometimes those parameters are supplied in a snake case. + // To support such cases, we also add explicit snake case variations. + /// Whether to try to recompile with -Oz if the bytecode is too large. + #[serde( + rename = "fallback_to_optimizing_for_size", + skip_serializing_if = "Option::is_none" + )] + pub fallback_to_optimizing_for_size_snake: Option, + /// Whether to disable the system request memoization. + #[serde( + rename = "disable_system_request_memoization", + skip_serializing_if = "Option::is_none" + )] + pub disable_system_request_memoization_snake: Option, + /// Set the jump table density threshold. + #[serde( + rename = "jump_table_density_threshold", + skip_serializing_if = "Option::is_none" + )] + pub jump_table_density_threshold_snake: Option, } impl Optimizer { @@ -52,6 +73,9 @@ impl Optimizer { fallback_to_optimizing_for_size: Some(fallback_to_optimizing_for_size), disable_system_request_memoization: Some(disable_system_request_memoization), jump_table_density_threshold, + fallback_to_optimizing_for_size_snake: Some(fallback_to_optimizing_for_size), + disable_system_request_memoization_snake: Some(disable_system_request_memoization), + jump_table_density_threshold_snake: jump_table_density_threshold, } } diff --git a/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/selection/file/flag.rs b/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/selection/file/flag.rs index 1c7e8ec53..f2446050f 100644 --- a/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/selection/file/flag.rs +++ b/smart-contract-verifier/smart-contract-verifier/src/zksync/zksolc_standard_json/input/settings/selection/file/flag.rs @@ -21,9 +21,6 @@ pub enum Flag { /// The user documentation. #[serde(rename = "userdoc")] Userdoc, - /// The function signature hashes JSON. - #[serde(rename = "evm.methodIdentifiers")] - MethodIdentifiers, /// The storage layout. #[serde(rename = "storageLayout")] StorageLayout, @@ -33,23 +30,16 @@ pub enum Flag { /// The Yul IR. #[serde(rename = "irOptimized")] Yul, + /// The EVM bytecode. + #[serde(rename = "evm")] + EVM, /// The EVM legacy assembly JSON. #[serde(rename = "evm.legacyAssembly")] EVMLA, -} - -impl std::fmt::Display for Flag { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::ABI => write!(f, "abi"), - Self::Metadata => write!(f, "metadata"), - Self::Devdoc => write!(f, "devdoc"), - Self::Userdoc => write!(f, "userdoc"), - Self::MethodIdentifiers => write!(f, "evm.methodIdentifiers"), - Self::StorageLayout => write!(f, "storageLayout"), - Self::AST => write!(f, "ast"), - Self::Yul => write!(f, "irOptimized"), - Self::EVMLA => write!(f, "evm.legacyAssembly"), - } - } + /// The function signature hashes JSON. + #[serde(rename = "evm.methodIdentifiers")] + MethodIdentifiers, + /// The EraVM assembly. + #[serde(rename = "eravm.assembly")] + EraVMAssembly, } From 2c3a040ee58180c86ead70d5afbe40c680aed3ed Mon Sep 17 00:00:00 2001 From: Rim Rakhimov Date: Thu, 24 Oct 2024 12:15:53 +0400 Subject: [PATCH 3/4] refactor(verifier): extract if compilers exists checks into verification function --- .../src/zksync/implementation.rs | 122 +++++++----------- 1 file changed, 48 insertions(+), 74 deletions(-) diff --git a/smart-contract-verifier/smart-contract-verifier/src/zksync/implementation.rs b/smart-contract-verifier/smart-contract-verifier/src/zksync/implementation.rs index 01813b17d..fd0864c99 100644 --- a/smart-contract-verifier/smart-contract-verifier/src/zksync/implementation.rs +++ b/smart-contract-verifier/smart-contract-verifier/src/zksync/implementation.rs @@ -3,7 +3,7 @@ use anyhow::Context; use async_trait::async_trait; use bytes::Bytes; use foundry_compilers::error::SolcError; -use futures::{StreamExt, TryFutureExt, TryStreamExt}; +use futures::{TryFutureExt}; use nonempty::NonEmpty; use serde::{de::DeserializeOwned, Deserialize}; use serde_json::Value; @@ -99,13 +99,19 @@ pub async fn verify( compiler_input.normalize_output_selection(&zk_compiler_version); - let (zk_compiler_path, evm_compiler_paths) = compilers - .fetch_compilers(&zk_compiler_version, &evm_compiler_version) - .await?; + // retrieves both usual solidity and zksync era solidity evm compiler versions + // matching to the requested evm compiler version. + // zk_compiler version is checked to exist, so also returned in the response. + let (zk_compiler, evm_compilers) = compilers + .extract_compiler_versions_to_fetch(&zk_compiler_version, &evm_compiler_version)?; let mut successes = vec![]; let mut failures = vec![]; - for evm_compiler_path in evm_compiler_paths { + for evm_compiler in evm_compilers { + let (zk_compiler_path, evm_compiler_path) = compilers + .fetch_compilers(&zk_compiler, &evm_compiler) + .await?; + let (compiler_output, _raw_compiler_output) = compilers .compile(&zk_compiler_path, &evm_compiler_path, &compiler_input) .await?; @@ -440,86 +446,44 @@ impl ZkSyncCompilers { } } +pub struct FetchableEvmCompiler { + version: DetailedVersion, + is_era_evm_compiler: bool, +} + impl ZkSyncCompilers { pub async fn fetch_compilers( &self, zk_compiler: &CompactVersion, - evm_compiler: &DetailedVersion, - ) -> Result<(PathBuf, NonEmpty), Error> { - let (zk_compiler, maybe_evm_compiler, era_evm_compilers) = - self.choose_compiler_versions_to_fetch(zk_compiler, evm_compiler)?; - - assert!( - maybe_evm_compiler.is_some() || !era_evm_compilers.is_empty(), - "there must be at least one valid evm compiler after choosing" - ); - + evm_compiler: &FetchableEvmCompiler, + ) -> Result<(PathBuf, PathBuf), Error> { let zk_path_future = self .zk_cache - .get(self.zk_fetcher.as_ref(), &zk_compiler) + .get(self.zk_fetcher.as_ref(), zk_compiler) .map_err(|err| { Error::Internal(anyhow::Error::new(err).context("fetching zk compiler")) }); - let mut evm_compilers = vec![]; - if let Some(evm_compiler) = maybe_evm_compiler { - evm_compilers.push(evm_compiler) - } - let evm_paths_future = tokio_stream::iter(evm_compilers) - .map(|version| async move { - self.evm_cache - .get(self.evm_fetcher.as_ref(), &version) - .await - .map_err(|err| { - Error::Internal( - anyhow::Error::new(err) - .context(format!("fetching evm compiler: {version}")), - ) - }) - }) - .buffered(3) - .try_collect::>(); - - let era_evm_paths_future = tokio_stream::iter(era_evm_compilers) - .map(|version| async move { - self.era_evm_cache - .get(self.era_evm_fetcher.as_ref(), &version) - .await - .map_err(|err| { - Error::Internal( - anyhow::Error::new(err) - .context(format!("fetching evm compiler: {version}")), - ) - }) - }) - .buffered(3) - .try_collect::>(); + let (cache, fetcher) = if evm_compiler.is_era_evm_compiler { + (&self.era_evm_cache, self.era_evm_fetcher.as_ref()) + } else { + (&self.evm_cache, self.evm_fetcher.as_ref()) + }; - let (zk_path_result, evm_paths_result, era_evm_paths_result) = - futures::join!(zk_path_future, evm_paths_future, era_evm_paths_future); - let (zk_path_result, evm_paths_result, era_evm_paths_result) = - (zk_path_result?, evm_paths_result?, era_evm_paths_result?); + let evm_path_future = cache.get(fetcher, &evm_compiler.version).map_err(|err| { + Error::Internal(anyhow::Error::new(err).context("fetching zk compiler")) + }); - let mut all_evm_paths_result = era_evm_paths_result; - all_evm_paths_result.extend(evm_paths_result); - let all_evm_paths_result = - NonEmpty::from_vec(all_evm_paths_result).expect("at least 1 valid evm_version exists"); + let (zk_path_result, evm_path_result) = futures::join!(zk_path_future, evm_path_future); - Ok((zk_path_result, all_evm_paths_result)) + Ok((zk_path_result?, evm_path_result?)) } - fn choose_compiler_versions_to_fetch( + fn extract_compiler_versions_to_fetch( &self, zk_compiler: &CompactVersion, evm_compiler: &DetailedVersion, - ) -> Result< - ( - CompactVersion, - Option, - Vec, - ), - Error, - > { + ) -> Result<(CompactVersion, NonEmpty), Error> { let all_zk_compilers = self.zk_fetcher.all_versions(); let zk_compiler = match all_zk_compilers .into_iter() @@ -537,15 +501,25 @@ impl ZkSyncCompilers { let matching_era_evm_compilers = self.lookup_era_evm_compilers_by_semver_version(evm_compiler.version()); - if maybe_requested_evm_compiler.is_none() && matching_era_evm_compilers.is_empty() { - return Err(Error::EvmCompilerNotFound(evm_compiler.to_string())); + let mut fetchable_evm_compilers: Vec<_> = matching_era_evm_compilers + .into_iter() + .map(|version| FetchableEvmCompiler { + version, + is_era_evm_compiler: true, + }) + .collect(); + + if let Some(requested_evm_compiler) = maybe_requested_evm_compiler { + fetchable_evm_compilers.push(FetchableEvmCompiler { + version: requested_evm_compiler, + is_era_evm_compiler: false, + }) } - Ok(( - zk_compiler, - maybe_requested_evm_compiler, - matching_era_evm_compilers, - )) + match NonEmpty::from_vec(fetchable_evm_compilers) { + None => Err(Error::EvmCompilerNotFound(evm_compiler.to_string())), + Some(fetchable_evm_compilers) => Ok((zk_compiler, fetchable_evm_compilers)), + } } fn lookup_era_evm_compilers_by_semver_version( From 777080e93f156ebeaebb5cc7a69c6ae95bb42d42 Mon Sep 17 00:00:00 2001 From: Rim Rakhimov Date: Thu, 24 Oct 2024 12:26:49 +0400 Subject: [PATCH 4/4] refactor(verifier): remove unused tokio-stream dependency --- smart-contract-verifier/Cargo.lock | 1 - smart-contract-verifier/smart-contract-verifier/Cargo.toml | 1 - .../smart-contract-verifier/src/zksync/implementation.rs | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/smart-contract-verifier/Cargo.lock b/smart-contract-verifier/Cargo.lock index 13309983b..597916528 100644 --- a/smart-contract-verifier/Cargo.lock +++ b/smart-contract-verifier/Cargo.lock @@ -4929,7 +4929,6 @@ dependencies = [ "tempfile", "thiserror", "tokio", - "tokio-stream", "tracing", "url", "verification-common", diff --git a/smart-contract-verifier/smart-contract-verifier/Cargo.toml b/smart-contract-verifier/smart-contract-verifier/Cargo.toml index 561c170bc..d6e43d41b 100644 --- a/smart-contract-verifier/smart-contract-verifier/Cargo.toml +++ b/smart-contract-verifier/smart-contract-verifier/Cargo.toml @@ -44,7 +44,6 @@ sscanf = "0.3" tempfile = "3.3" thiserror = "1.0" tokio = { version = "1", features = ["macros"] } -tokio-stream = { version = "0.1.16" } tracing = "0.1" url = { version = "2.4", features = ["serde"] } verification-common = { workspace = true } diff --git a/smart-contract-verifier/smart-contract-verifier/src/zksync/implementation.rs b/smart-contract-verifier/smart-contract-verifier/src/zksync/implementation.rs index fd0864c99..3d0d9315b 100644 --- a/smart-contract-verifier/smart-contract-verifier/src/zksync/implementation.rs +++ b/smart-contract-verifier/smart-contract-verifier/src/zksync/implementation.rs @@ -3,7 +3,7 @@ use anyhow::Context; use async_trait::async_trait; use bytes::Bytes; use foundry_compilers::error::SolcError; -use futures::{TryFutureExt}; +use futures::TryFutureExt; use nonempty::NonEmpty; use serde::{de::DeserializeOwned, Deserialize}; use serde_json::Value;