diff --git a/smart-contract-verifier/Cargo.lock b/smart-contract-verifier/Cargo.lock index b4c348451..597916528 100644 --- a/smart-contract-verifier/Cargo.lock +++ b/smart-contract-verifier/Cargo.lock @@ -5498,9 +5498,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..28da70230 --- /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\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":"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": {}, + + "expected_creation_match_type": "full", + "expected_creation_transformations": [ + { + "type": "insert", + "reason": "constructor", + "offset": 4512 + } + ], + "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/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..3d0d9315b 100644 --- a/smart-contract-verifier/smart-contract-verifier/src/zksync/implementation.rs +++ b/smart-contract-verifier/smart-contract-verifier/src/zksync/implementation.rs @@ -1,4 +1,4 @@ -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; @@ -99,10 +99,58 @@ 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) - .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 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?; + + (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 +158,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 +185,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 +379,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 +390,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 +408,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")?; @@ -411,35 +446,92 @@ 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, + evm_compiler: &FetchableEvmCompiler, ) -> Result<(PathBuf, PathBuf), Error> { 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(), + .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 (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 evm_path_future = cache.get(fetcher, &evm_compiler.version).map_err(|err| { + Error::Internal(anyhow::Error::new(err).context("fetching zk compiler")) + }); let (zk_path_result, evm_path_result) = futures::join!(zk_path_future, evm_path_future); + Ok((zk_path_result?, evm_path_result?)) } + + fn extract_compiler_versions_to_fetch( + &self, + zk_compiler: &CompactVersion, + evm_compiler: &DetailedVersion, + ) -> Result<(CompactVersion, NonEmpty), 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()); + + 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, + }) + } + + 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( + &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() + } } #[derive(Default)] 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, }