diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/sanitizers.yml index c34670e9..82496c7e 100644 --- a/.github/workflows/sanitizers.yml +++ b/.github/workflows/sanitizers.yml @@ -30,8 +30,13 @@ on: mode: required: false type: string - default: 'Y+M3B3 0.8.26' - description: 'Mode filter for the era-compiler-tester. For example: Y+M3B3 0.8.26' + default: 'Y+M3B3 0.8.28' + description: 'Mode filter for the era-compiler-tester. For example: Y+M3B3 0.8.28' + target: + required: false + type: string + default: 'eravm' + description: 'Target filter for the era-compiler-tester. Possible values are: `eravm` or `evm`' jobs: run-with-sanitizers: @@ -88,6 +93,7 @@ jobs: run: | set -x ./target/${TARGET}/debug/compiler-tester \ + --target "${{ inputs.target }}" \ --zksolc "./target-zksolc/${TARGET}/debug/zksolc" \ --zkvyper "./target-zkvyper/${TARGET}/debug/zkvyper" \ --path '${{ inputs.path }}' \ diff --git a/.github/workflows/secrets-scanner.yaml b/.github/workflows/secrets-scanner.yaml new file mode 100644 index 00000000..205477f5 --- /dev/null +++ b/.github/workflows/secrets-scanner.yaml @@ -0,0 +1,19 @@ +name: Leaked Secrets Scan +on: + pull_request: + merge_group: +jobs: + TruffleHog: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + with: + fetch-depth: 0 + - name: TruffleHog OSS + uses: trufflesecurity/trufflehog@7e78ca385fb82c19568c7a4b341c97d57d9aa5e1 # v3.82.2 + with: + path: ./ + base: ${{ github.event.repository.default_branch }} + head: HEAD + extra_args: --debug --only-verified diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 4095cd04..310bd15d 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -36,11 +36,6 @@ concurrency: jobs: - # Check for secrets leak in the repository - secrets-scanner: - uses: matter-labs/era-compiler-ci/.github/workflows/secrets-scanner.yaml@v1 - secrets: inherit - # Check for cargo issues cargo-check: runs-on: matterlabs-ci-runner-high-performance @@ -133,7 +128,6 @@ jobs: runs-on: ubuntu-latest if: always() needs: - - secrets-scanner - cargo-check - integration-tests - benchmarks diff --git a/.gitignore b/.gitignore index b79c463a..12dcfdf4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,29 +1,28 @@ +# IDE +/.idea/ +/.vscode/ + +# MacOS +/**/.DS_Store + +# Backup files generated by rustfmt +/**/*.rs.bk + # Compiled files and executables /target*/ -# These are backup files generated by rustfmt -**/*.rs.bk +# Dependency locks +# /Cargo.lock +# /LLVM.lock -# The LLVM framework source +# LLVM framework source /llvm/ # External compilers -/solc-bin*/* -/vyper-bin/* +/solc-bin*/ +/vyper-bin*/ -# The debug, trace, benchmark artifacts +# Debug and benchmark artifacts /debug/ -/trace/ -/**/*.json -/**/*.txt - -# The dependency locks -# /Cargo.lock -# /LLVM.lock - -# IDE -/.idea/ -/.vscode/ - -# MacOS -/**/.DS_Store +/*.json +/*.txt \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index dc4a4a44..72622394 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,12 @@ [submodule "tests"] - path = tests - url = https://github.com/matter-labs/era-compiler-tests - branch = main + path = tests + url = https://github.com/matter-labs/era-compiler-tests + branch = main [submodule "solidity"] - path = solidity - url = https://github.com/ethereum/solidity - branch = develop + path = solidity + url = https://github.com/ethereum/solidity + branch = develop [submodule "era-contracts"] - path = era-contracts - url = https://github.com/lambdaclass/era-contracts - branch = evm-equivalence-yul-new + path = era-contracts + url = https://github.com/matter-labs/era-contracts + branch = stable/evm-emulator diff --git a/Cargo.lock b/Cargo.lock index aa2695a1..e2781d99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] @@ -40,9 +40,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-eip2930" @@ -56,9 +56,9 @@ dependencies = [ [[package]] name = "alloy-eip7702" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d319bb544ca6caeab58c39cea8921c55d924d4f68f2c60f24f914673f9a74a" +checksum = "ea59dc42102bc9a1905dc57901edc6dd48b9f38115df86c7d252acba70d71d04" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "0.3.3" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c35df7b972b06f1b2f4e8b7a53328522fa788054a9d3e556faf2411c5a51d5a" +checksum = "f923dd5fca5f67a43d81ed3ebad0880bd41f6dd0ada930030353ac356c54cd0f" dependencies = [ "alloy-eip2930", "alloy-eip7702", @@ -83,31 +83,35 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.3" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "411aff151f2a73124ee473708e82ed51b2535f68928b6a1caa8bc1246ae6f7cd" +checksum = "788bb18e8f61d5d9340b52143f27771daf7e1dccbaf2741621d2493f9debf52e" dependencies = [ "alloy-rlp", "bytes", "cfg-if", "const-hex", "derive_more 1.0.0", - "hex-literal", + "foldhash", + "indexmap", "itoa", "k256", "keccak-asm", + "paste", "proptest", "rand", "ruint", + "rustc-hash", "serde", + "sha3 0.10.8", "tiny-keccak", ] [[package]] name = "alloy-rlp" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" +checksum = "f542548a609dca89fcd72b3b9f355928cf844d4363c5eed9c5273a3dd225e097" dependencies = [ "alloy-rlp-derive", "arrayvec 0.7.6", @@ -116,26 +120,84 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c" +checksum = "5a833d97bf8a5f0f878daf2c8451fff7de7f9de38baa5a45d936ec718d81255a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", ] [[package]] -name = "anyhow" -version = "1.0.88" +name = "android-tzdata" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] -name = "arbitrary" -version = "1.3.2" +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + +[[package]] +name = "anyhow" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "ark-ff" @@ -263,9 +325,9 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" @@ -297,14 +359,14 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" @@ -345,6 +407,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "base64ct" version = "1.6.0" @@ -356,10 +424,13 @@ name = "benchmark-analyzer" version = "1.5.0" dependencies = [ "anyhow", + "chrono", + "clap", "colored", + "era-compiler-common", + "regex", "serde", "serde_json", - "structopt", ] [[package]] @@ -481,6 +552,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "boolinator" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" + [[package]] name = "bumpalo" version = "3.16.0" @@ -501,9 +578,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "c-kzg" @@ -522,12 +599,10 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.18" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" +checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7" dependencies = [ - "jobserver", - "libc", "shlex", ] @@ -537,6 +612,27 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.6", +] + [[package]] name = "cid" version = "0.5.1" @@ -550,15 +646,50 @@ dependencies = [ [[package]] name = "clap" -version = "2.34.0" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ - "bitflags 1.3.2", - "textwrap", - "unicode-width", + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.95", ] +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + [[package]] name = "colored" version = "2.1.0" @@ -576,12 +707,15 @@ dependencies = [ "anyhow", "benchmark-analyzer", "bincode", + "chrono", + "clap", "colored", "era-compiler-common", "era-compiler-downloader", "era-compiler-llvm-context", "era-compiler-solidity", "era-compiler-vyper", + "era-solc", "evm", "glob", "hex", @@ -592,7 +726,7 @@ dependencies = [ "once_cell", "rayon", "regex", - "reqwest", + "reqwest 0.11.27", "revm", "rlp", "ron", @@ -602,34 +736,18 @@ dependencies = [ "serde_yaml", "sha3 0.10.8", "solidity-adapter", - "structopt", "web3", "which", - "zkevm_opcode_defs 0.150.0 (git+https://github.com/matter-labs/era-zkevm_opcode_defs?branch=v1.5.0)", + "zkevm_opcode_defs", "zkevm_tester", "zksync_vm2", ] -[[package]] -name = "compiler-tester-fuzz" -version = "1.5.0" -dependencies = [ - "anyhow", - "compiler-tester", - "era-compiler-common", - "era-compiler-llvm-context", - "era-compiler-solidity", - "libfuzzer-sys", - "semver 1.0.23", - "solidity-adapter", - "zkevm_tester", -] - [[package]] name = "const-hex" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +checksum = "4b0485bab839b018a8f1723fc5391819fea5f8f0f32288ef8a735fd096b6160c" dependencies = [ "cfg-if", "cpufeatures", @@ -677,35 +795,35 @@ name = "coverage-watcher" version = "1.5.0" dependencies = [ "anyhow", + "clap", "era-compiler-common", "serde", "serde_yaml", - "structopt", ] [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -722,9 +840,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" @@ -812,7 +930,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.77", + "syn 2.0.95", ] [[package]] @@ -832,7 +950,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", "unicode-xid", ] @@ -857,6 +975,17 @@ dependencies = [ "subtle", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", +] + [[package]] name = "dyn-clone" version = "1.0.17" @@ -905,9 +1034,9 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] @@ -921,7 +1050,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", ] [[package]] @@ -932,7 +1061,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", ] [[package]] @@ -944,7 +1073,7 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "era-compiler-common" version = "1.5.0" -source = "git+https://github.com/matter-labs/era-compiler-common?branch=main#666de17f795f20530423bb88c912efe45d5a092e" +source = "git+https://github.com/matter-labs/era-compiler-common?branch=main#10ea52ee6a27ae3392c25647f5f70fb60e3ce2a6" dependencies = [ "anyhow", "base58", @@ -959,13 +1088,13 @@ dependencies = [ [[package]] name = "era-compiler-downloader" -version = "0.1.0" -source = "git+https://github.com/matter-labs/era-compiler-common?branch=main#666de17f795f20530423bb88c912efe45d5a092e" +version = "1.5.0" +source = "git+https://github.com/matter-labs/era-compiler-common?branch=main#10ea52ee6a27ae3392c25647f5f70fb60e3ce2a6" dependencies = [ "anyhow", "colored", "openssl", - "reqwest", + "reqwest 0.11.27", "serde", "serde_json", ] @@ -973,7 +1102,7 @@ dependencies = [ [[package]] name = "era-compiler-llvm-context" version = "1.5.0" -source = "git+https://github.com/matter-labs/era-compiler-llvm-context?branch=main#7c1ba758b7f68c9391c16db766f69df47834f4ea" +source = "git+https://github.com/matter-labs/era-compiler-llvm-context?branch=main#564e41b4d9e0b6a3a0d2f875c6dd891477cef70c" dependencies = [ "anyhow", "era-compiler-common", @@ -982,17 +1111,19 @@ dependencies = [ "num", "semver 1.0.23", "serde", - "zkevm_opcode_defs 0.150.0 (git+https://github.com/matter-labs/era-zkevm_opcode_defs?branch=v1.5.0)", + "zkevm_opcode_defs", ] [[package]] name = "era-compiler-solidity" -version = "1.5.4" -source = "git+https://github.com/matter-labs/era-compiler-solidity?branch=main#62830743e1dbdeea99798e35d700f6a792c151f1" +version = "1.5.9" +source = "git+https://github.com/matter-labs/era-compiler-solidity?branch=main#2333c0e275e4a83f494990ae3ce7484c643a908d" dependencies = [ "anyhow", + "clap", "era-compiler-common", "era-compiler-llvm-context", + "era-solc", "era-yul", "hex", "inkwell", @@ -1001,25 +1132,23 @@ dependencies = [ "num", "num_cpus", "path-slash", - "rand", "rayon", - "regex", "rusty_pool", "semver 1.0.23", "serde", "serde_json", - "sha3 0.10.8", - "structopt", - "thiserror", - "which", + "thiserror 1.0.64", + "zkevm_opcode_defs", ] [[package]] name = "era-compiler-vyper" -version = "1.5.5" -source = "git+https://github.com/matter-labs/era-compiler-vyper?branch=main#f353939d6b056a5f456af7ed5ec6e6d785031d15" +version = "1.5.9" +source = "git+https://github.com/matter-labs/era-compiler-vyper?branch=main#51f8baf7514e2482145d1b2f1e37615fb50bb2ca" dependencies = [ "anyhow", + "boolinator", + "clap", "era-compiler-common", "era-compiler-llvm-context", "hex", @@ -1032,30 +1161,46 @@ dependencies = [ "semver 1.0.23", "serde", "serde_json", - "structopt", "which", - "zkevm_opcode_defs 0.150.0 (git+https://github.com/matter-labs/era-zkevm_opcode_defs?branch=v1.5.0)", + "zkevm_opcode_defs", +] + +[[package]] +name = "era-solc" +version = "1.5.9" +source = "git+https://github.com/matter-labs/era-compiler-solidity?branch=main#2333c0e275e4a83f494990ae3ce7484c643a908d" +dependencies = [ + "anyhow", + "boolinator", + "era-compiler-common", + "hex", + "num", + "rayon", + "semver 1.0.23", + "serde", + "serde_json", + "which", ] [[package]] name = "era-yul" -version = "1.5.4" -source = "git+https://github.com/matter-labs/era-compiler-solidity?branch=main#62830743e1dbdeea99798e35d700f6a792c151f1" +version = "1.5.9" +source = "git+https://github.com/matter-labs/era-compiler-solidity?branch=main#2333c0e275e4a83f494990ae3ce7484c643a908d" dependencies = [ "anyhow", "regex", "serde", - "thiserror", + "thiserror 1.0.64", ] [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1071,7 +1216,7 @@ dependencies = [ "serde", "serde_json", "sha3 0.10.8", - "thiserror", + "thiserror 1.0.64", "uint", ] @@ -1128,9 +1273,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fastrlp" @@ -1143,6 +1288,17 @@ dependencies = [ "bytes", ] +[[package]] +name = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec 0.7.6", + "auto_impl", + "bytes", +] + [[package]] name = "ff" version = "0.13.0" @@ -1183,6 +1339,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" + [[package]] name = "foreign-types" version = "0.3.2" @@ -1215,9 +1377,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1230,9 +1392,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1240,15 +1402,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1257,32 +1419,32 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" @@ -1292,9 +1454,9 @@ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -1326,15 +1488,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] name = "gimli" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" @@ -1364,7 +1528,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", "indexmap", "slab", "tokio", @@ -1383,37 +1547,16 @@ dependencies = [ ] [[package]] -name = "headers" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" -dependencies = [ - "base64", - "bytes", - "headers-core", - "http", - "httpdate", - "mime", - "sha1", -] - -[[package]] -name = "headers-core" -version = "0.2.0" +name = "hashbrown" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http", -] +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" -version = "0.3.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -1427,12 +1570,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hex-literal" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" - [[package]] name = "hmac" version = "0.12.1" @@ -1444,11 +1581,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1462,6 +1599,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -1469,15 +1617,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.2.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -1487,17 +1658,17 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.30" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -1509,18 +1680,41 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-rustls" -version = "0.24.2" +version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", - "http", - "hyper", + "http 1.2.0", + "hyper 1.5.2", + "hyper-util", "rustls", + "rustls-pki-types", "tokio", "tokio-rustls", + "tower-service", + "webpki-roots", ] [[package]] @@ -1530,84 +1724,245 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper", + "hyper 0.14.32", "native-tls", "tokio", "tokio-native-tls", ] [[package]] -name = "idna" -version = "0.4.0" +name = "hyper-util" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "bytes", + "futures-channel", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "hyper 1.5.2", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", ] [[package]] -name = "idna" -version = "0.5.0" +name = "iana-time-zone" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", ] [[package]] -name = "impl-codec" -version = "0.6.0" +name = "iana-time-zone-haiku" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "parity-scale-codec", + "cc", ] [[package]] -name = "impl-rlp" -version = "0.3.0" +name = "icu_collections" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ - "rlp", + "displaydoc", + "yoke", + "zerofrom", + "zerovec", ] [[package]] -name = "impl-serde" -version = "0.4.0" +name = "icu_locid" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ - "serde", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", ] [[package]] name = "impl-trait-for-tuples" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.95", ] [[package]] name = "indexmap" -version = "2.5.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", ] [[package]] name = "inkwell" version = "0.4.0" -source = "git+https://github.com/matter-labs-forks/inkwell?branch=llvm-17#fd415e819f185f5a4b5ed60cff4e67814b9c9b53" +source = "git+https://github.com/matter-labs-forks/inkwell?branch=llvm-17#c5d783f52b755f5382e99e3f1179039b9435e3cc" dependencies = [ "either", "inkwell_internals", @@ -1616,17 +1971,17 @@ dependencies = [ "once_cell", "parking_lot", "serde", - "thiserror", + "thiserror 1.0.64", ] [[package]] name = "inkwell_internals" version = "0.9.0" -source = "git+https://github.com/matter-labs-forks/inkwell?branch=llvm-17#fd415e819f185f5a4b5ed60cff4e67814b9c9b53" +source = "git+https://github.com/matter-labs-forks/inkwell?branch=llvm-17#c5d783f52b755f5382e99e3f1179039b9435e3cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", ] [[package]] @@ -1654,9 +2009,15 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.0" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -1678,25 +2039,17 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "jobserver" -version = "0.1.32" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1717,9 +2070,9 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if", "ecdsa", @@ -1759,26 +2112,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.158" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" - -[[package]] -name = "libfuzzer-sys" -version = "0.4.7" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" -dependencies = [ - "arbitrary", - "cc", - "once_cell", -] +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libmimalloc-sys" @@ -1803,14 +2145,20 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "litemap" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "llvm-sys" version = "170.0.1" -source = "git+https://github.com/matter-labs-forks/llvm-sys.rs?branch=llvm-17.0#a0eca916803d6123b22d9a67d1e7d2cd07227d26" +source = "git+https://github.com/matter-labs-forks/llvm-sys.rs?branch=llvm-17.0#b65826dfdb19676637dbddb9f01bcc52ae2c4308" dependencies = [ "anyhow", "cc", @@ -1865,20 +2213,19 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi", "libc", "wasi", "windows-sys 0.52.0", @@ -2038,23 +2385,23 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", ] [[package]] name = "object" -version = "0.36.4" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "opaque-debug" @@ -2064,9 +2411,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.66" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -2085,7 +2432,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", ] [[package]] @@ -2096,18 +2443,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.3.2+3.3.2" +version = "300.4.1+3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a211a18d945ef7e648cc6e0058f4c548ee46aab922ea203e0d30e966ea23647b" +checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.103" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -2206,40 +2553,40 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.12" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c73c26c01b8c87956cea613c907c9d6ecffd8d18a2a5908e5de0adfaa185cea" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror", + "thiserror 2.0.10", "ucd-trie", ] [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -2259,9 +2606,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "ppv-lite86" @@ -2310,38 +2657,14 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.22.20", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", + "toml_edit 0.22.22", ] [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -2368,9 +2691,9 @@ dependencies = [ [[package]] name = "psm" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205" +checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" dependencies = [ "cc", ] @@ -2390,11 +2713,63 @@ dependencies = [ "byteorder", ] +[[package]] +name = "quinn" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.10", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +dependencies = [ + "bytes", + "getrandom", + "rand", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.10", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -2466,18 +2841,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.4" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", @@ -2487,9 +2862,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -2504,9 +2879,9 @@ checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" @@ -2514,16 +2889,15 @@ version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", - "hyper-rustls", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", "hyper-tls", "ipnet", "js-sys", @@ -2533,23 +2907,63 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "reqwest" +version = "0.12.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.5.2", + "hyper-rustls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "tokio", "tokio-rustls", + "tower", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", "webpki-roots", - "winreg", + "windows-registry", ] [[package]] @@ -2607,7 +3021,7 @@ dependencies = [ "cfg-if", "dyn-clone", "enumn", - "hashbrown", + "hashbrown 0.14.5", "hex", "serde", ] @@ -2662,7 +3076,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ - "base64", + "base64 0.21.7", "bitflags 2.6.0", "serde", "serde_derive", @@ -2670,16 +3084,18 @@ dependencies = [ [[package]] name = "ruint" -version = "1.12.3" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +checksum = "f5ef8fb1dd8de3870cb8400d51b4c2023854bbafd5431a3ac7e7317243e22d2f" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", "ark-ff 0.4.2", "bytes", - "fastrlp", + "fastrlp 0.3.1", + "fastrlp 0.4.0", "num-bigint", + "num-integer", "num-traits", "parity-scale-codec", "primitive-types", @@ -2704,6 +3120,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -2730,27 +3152,29 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.21.12" +version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ - "log", + "once_cell", "ring", + "rustls-pki-types", "rustls-webpki", - "sct", + "subtle", + "zeroize", ] [[package]] @@ -2759,16 +3183,35 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64", + "base64 0.21.7", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +dependencies = [ + "web-time", ] [[package]] name = "rustls-webpki" -version = "0.101.7" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", + "rustls-pki-types", "untrusted", ] @@ -2804,34 +3247,34 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "scale-info" -version = "2.11.3" +version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b" dependencies = [ "bitvec", "cfg-if", - "derive_more 0.99.18", + "derive_more 1.0.0", "parity-scale-codec", "scale-info-derive", ] [[package]] name = "scale-info-derive" -version = "2.11.3" +version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.95", ] [[package]] name = "schannel" -version = "0.1.24" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -2842,16 +3285,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "sec1" version = "0.7.3" @@ -2868,11 +3301,11 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.27.0" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" dependencies = [ - "secp256k1-sys 0.8.1", + "secp256k1-sys 0.9.2", ] [[package]] @@ -2887,9 +3320,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.8.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" dependencies = [ "cc", ] @@ -2918,9 +3351,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -2946,9 +3379,9 @@ dependencies = [ [[package]] name = "semver-parser" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" dependencies = [ "pest", ] @@ -2979,7 +3412,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", ] [[package]] @@ -3043,17 +3476,6 @@ dependencies = [ "opaque-debug", ] -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - [[package]] name = "sha2" version = "0.9.9" @@ -3143,9 +3565,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -3156,6 +3578,7 @@ name = "solidity-adapter" version = "1.5.0" dependencies = [ "anyhow", + "clap", "colored", "era-compiler-common", "md5", @@ -3163,7 +3586,6 @@ dependencies = [ "semver 1.0.23", "serde", "serde_yaml", - "structopt", "web3", ] @@ -3183,6 +3605,12 @@ dependencies = [ "der", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "stacker" version = "0.1.17" @@ -3203,28 +3631,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] -name = "structopt" -version = "0.3.26" +name = "strsim" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" -dependencies = [ - "clap", - "lazy_static", - "structopt-derive", -] - -[[package]] -name = "structopt-derive" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "substrate-bn" @@ -3258,9 +3668,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a" dependencies = [ "proc-macro2", "quote", @@ -3273,6 +3683,26 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -3302,44 +3732,56 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.12.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", + "getrandom", "once_cell", "rustix", "windows-sys 0.59.0", ] [[package]] -name = "textwrap" -version = "0.11.0" +name = "thiserror" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ - "unicode-width", + "thiserror-impl 1.0.64", ] [[package]] name = "thiserror" -version = "1.0.63" +version = "2.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "a3ac7f54ca534db81081ef1c1e7f6ea8a3ef428d2fc069097c079443d24124d3" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.10", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e9465d30713b56a37ede7185763c3492a91be2f5fa68d958c44e41ab9248beb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", ] [[package]] @@ -3360,11 +3802,21 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] @@ -3377,9 +3829,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.40.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "bytes", @@ -3402,9 +3854,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.24.1" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ "rustls", "tokio", @@ -3412,9 +3864,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -3442,15 +3894,36 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "toml_datetime", - "winnow 0.6.18", + "winnow 0.6.22", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tokio", + "tower-layer", + "tower-service", ] +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + [[package]] name = "tower-service" version = "0.3.3" @@ -3459,9 +3932,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -3470,20 +3943,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", ] @@ -3502,9 +3975,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "uint" @@ -3524,44 +3997,17 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" - -[[package]] -name = "unicode-width" -version = "0.1.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-xid" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unsafe-libyaml" @@ -3589,15 +4035,33 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna", "percent-encoding", ] +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "valuable" version = "0.1.0" @@ -3648,9 +4112,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", @@ -3659,36 +4123,36 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3696,58 +4160,66 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "web3" -version = "0.19.0" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5388522c899d1e1c96a4c307e3797e0f697ba7c77dd8e0e625ecba9dd0342937" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web3" +version = "0.20.0" +source = "git+https://github.com/jacques-kigo/rust-web3?branch=master#61c8dd5c23f89cc5f7cc365c894b69500fba8993" dependencies = [ "arrayvec 0.7.6", - "base64", + "base64 0.22.1", "bytes", "derive_more 0.99.18", "ethabi", "ethereum-types", "futures", "futures-timer", - "headers", "hex", - "idna 0.4.0", + "idna", "jsonrpc-core", "log", "once_cell", "parking_lot", "pin-project", - "reqwest", + "reqwest 0.12.12", "rlp", - "secp256k1 0.27.0", + "secp256k1 0.28.2", "serde", "serde_json", "tiny-keccak", @@ -3756,9 +4228,12 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.4" +version = "0.26.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +dependencies = [ + "rustls-pki-types", +] [[package]] name = "which" @@ -3772,6 +4247,45 @@ dependencies = [ "winsafe", ] +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -3931,9 +4445,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980" dependencies = [ "memchr", ] @@ -3954,6 +4468,18 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "wyz" version = "0.5.1" @@ -3963,6 +4489,30 @@ dependencies = [ "tap", ] +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -3981,7 +4531,28 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", + "synstructure", ] [[package]] @@ -4001,13 +4572,36 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.95", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", ] [[package]] name = "zk_evm" -version = "0.150.0" -source = "git+https://github.com/matter-labs/era-zk_evm?branch=v1.5.0#9ddd65ce2910049bae402aff0230e6e1bfed578a" +version = "0.150.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c14bda6c101389145cd01fac900f1392876bc0284d98faf7f376237baa2cb19d" dependencies = [ "anyhow", "lazy_static", @@ -4020,38 +4614,22 @@ dependencies = [ [[package]] name = "zk_evm_abstractions" -version = "0.150.0" +version = "0.150.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc313cea4ac9ef6b855264b1425cbe9de30dd8f009559dabcb6b2896122da5db" +checksum = "a008f2442fc6a508bdd1f902380242cb6ff11b8b27acdac2677c6d9f75cbb004" dependencies = [ "anyhow", "num_enum", "serde", "static_assertions", - "zkevm_opcode_defs 0.150.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zkevm_opcode_defs", ] [[package]] name = "zkevm_opcode_defs" -version = "0.150.0" +version = "0.150.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3328c012d444bdbfadb754a72c01a56879eb66584efc71eac457e89e7843608" -dependencies = [ - "bitflags 2.6.0", - "blake2", - "ethereum-types", - "k256", - "lazy_static", - "p256", - "serde", - "sha2 0.10.8", - "sha3 0.10.8", -] - -[[package]] -name = "zkevm_opcode_defs" -version = "0.150.0" -source = "git+https://github.com/matter-labs/era-zkevm_opcode_defs?branch=v1.5.0#cf5f9c18c580f845b32fc2a4d565a77380fd15bc" +checksum = "762b5f1c1b283c5388995a85d40a05aef1c14f50eb904998b7e9364739f5b899" dependencies = [ "bitflags 2.6.0", "blake2", @@ -4067,7 +4645,7 @@ dependencies = [ [[package]] name = "zkevm_tester" version = "1.5.0" -source = "git+https://github.com/matter-labs/era-zkevm_tester?branch=v1.5.0#5e79ef0c9d3a47c826c388b49245baf68264c946" +source = "git+https://github.com/matter-labs/era-zkevm_tester?branch=v1.5.0#393e31814c6838378d84e9932f1b378c1da5b5fe" dependencies = [ "anyhow", "ethabi", @@ -4085,20 +4663,20 @@ dependencies = [ [[package]] name = "zksync_vm2" -version = "0.1.0" -source = "git+https://github.com/matter-labs/vm2#cd6136c42ec56856e0abcf2a98d1a9e120161482" +version = "0.2.1" +source = "git+https://github.com/matter-labs/vm2#457d8a7eea9093af9440662e33e598c13ba41633" dependencies = [ "enum_dispatch", "primitive-types", "zk_evm_abstractions", - "zkevm_opcode_defs 0.150.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zkevm_opcode_defs", "zksync_vm2_interface", ] [[package]] name = "zksync_vm2_interface" -version = "0.1.0" -source = "git+https://github.com/matter-labs/vm2#cd6136c42ec56856e0abcf2a98d1a9e120161482" +version = "0.2.1" +source = "git+https://github.com/matter-labs/vm2#457d8a7eea9093af9440662e33e598c13ba41633" dependencies = [ "primitive-types", ] diff --git a/Cargo.toml b/Cargo.toml index 7a574496..02fe53d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,6 @@ members = [ "solidity_adapter", "coverage_watcher", "benchmark_analyzer", - "fuzzer" + # "fuzzer" ] resolver = "2" diff --git a/README.md b/README.md index 4e8c1a05..2eabfa22 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ By default, the Tester SHOULD run the entire Collection in all possible combinat but it MAY omit some subset of the combinations for the sake of saving time, e.g. when only front-end changes have been made, and there is no point in running tests in all LLVM optimization modes. + + ## Building
@@ -105,16 +107,16 @@ made, and there is no point in running tests in all LLVM optimization modes.
-5. Build zksolc and zkvyper compilers. +5. Build compiler executables. * Build [zksolc](https://github.com/matter-labs/era-compiler-solidity) and [zkvyper](https://github.com/matter-labs/era-compiler-vyper) compilers and add the binaries to `$PATH`, or use the `--zksolc` or `--zkvyper` options to specify their paths.
-6. Build era-compiler-tester. +6. Build the main application. - * Build the Tester with `cargo`: + * Build era-compiler-tester with `cargo`: ```shell cargo build --release ``` @@ -123,6 +125,8 @@ made, and there is no point in running tests in all LLVM optimization modes. When the build succeeds, you can run the tests using [the examples below](#usage). + + ## GitHub Actions The `era-compiler-tester` is integrated into the GitHub Actions workflows of the following projects: @@ -130,14 +134,16 @@ The `era-compiler-tester` is integrated into the GitHub Actions workflows of the * [era-compiler-llvm](https://github.com/matter-labs/era-compiler-llvm) * [era-solidity](https://github.com/matter-labs/era-solidity/) -To allow testing custom FE and VM changes in the Pull Requests (PRs) of these repositories, two additional tags are supported: -* `era-solidity-test` +To allow testing custom FE and VM changes in Pull Requests (PRs) of these repositories, two additional tags are supported: * `era-compiler-llvm-test` +* `era-solidity-test` If these tags exist, the tester from these tags will be used by the workflows instead of the default `main` branch. When testing is done, these tags should be removed. + + ## What is supported ### Languages @@ -169,7 +175,7 @@ When testing is done, these tags should be removed. - [0.4.10; latest] for compiling Solidity via EVM assembly - [0.3.3, 0.3.9] for compiling Vyper via LLL IR -### Compiler pipelines +### Compiler codegens Currently only relevant for the Solidity compiler, where you can choose the IR: @@ -181,6 +187,7 @@ Currently only relevant for the Solidity compiler, where you can choose the IR: Most of the specifiers support wildcards `*` (any), `^` ('3' and 'z'). With no mode argument, iterates over all option combinations (approximately 800). + ## Usage Each command assumes you are at the root of the `compiler-tester` repository. @@ -220,6 +227,8 @@ cargo run --release --bin compiler-tester -- -DT \ --zksolc '../era-compiler-solidity/target/release/zksolc' ``` +Modes are insensitive to spaces, therefore options such as `'Y+M3B3 0.8.26'` and `'Y + M3B3 0.8.26'` are equivalent. + ### Example 2 Run all simple Yul tests. This currently runs about three hundred tests and takes about eight minutes. @@ -251,10 +260,7 @@ cargo run --release --bin compiler-tester -- \ --zkvyper '../era-compiler-vyper/target/release/zkvyper' ``` -## Tracing -If you run the tester with `-T` flag, JSON trace files will be written to the `./trace/` directory. -The trace files can be used with our [custom ZKsync EraVM assembly tracer](https://staging-scan-v2.zksync.dev/tools/debugger) for debugging and research purposes. ## Benchmarking @@ -291,10 +297,44 @@ cargo run --release --bin benchmark-analyzer -- --reference reference.json --can After you make any changes in LLVM, you only need to repeat steps 2-3 to update the working branch benchmark data. +### Comparing results + +By default, benchmark analyzer compares tests from groups with the same name, which means that every test should be compiled with the same codegen and optimizations. +To compare two groups with different names, use the options `--query-reference` and `--query-candidate`. Then, use benchmark analyzer: + +```shell +cargo run --release --bin benchmark-analyzer -- --reference reference.json --candidate candidate.json --query-reference "M0B0" --query-candidate "M3B3" +``` + +The queries are regular expressions, and the group name, codegen, and +optimization options are matched against it. + + + +### Report formats + +Use the parameter `--benchmark-format` of compiler tester to select the output format: `json` (default), `csv`, or `json-lnt`. + +If `json-lnt` format is selected: + +1. The benchmark report will consist of multiple files. They will be placed in the directory provided via the `--output` argument. +2. It is mandatory to pass a JSON file with additional information using `--benchmark-context`. Here is a minimal example: + +```json +{ + "machine": "some_machine", + "target": "some_target", + "toolchain": "some_solc_type" +} +``` + + ## Troubleshooting - Unset any LLVM-related environment variables you may have set, especially `LLVM_SYS__PREFIX` (see e.g. [https://crates.io/crates/llvm-sys](https://crates.io/crates/llvm-sys) and [https://llvm.org/docs/GettingStarted.html#local-llvm-configuration](https://llvm.org/docs/GettingStarted.html#local-llvm-configuration)). To make sure: `set | grep LLVM`. + + ## License The Era Compiler Tester is distributed under the terms of either @@ -304,10 +344,14 @@ The Era Compiler Tester is distributed under the terms of either at your option. + + ## Resources [ZKsync Era compiler toolchain documentation](https://docs.zksync.io/zk-stack/components/compiler/toolchain) + + ## Official Links - [Website](https://zksync.io/) @@ -316,6 +360,8 @@ at your option. - [Twitter for Devs](https://twitter.com/ZKsyncDevs) - [Discord](https://join.zksync.dev/) + + ## Disclaimer ZKsync Era has been through extensive testing and audits, and although it is live, it is still in alpha state and diff --git a/benchmark_analyzer/Cargo.toml b/benchmark_analyzer/Cargo.toml index c10c048e..1ee1078b 100644 --- a/benchmark_analyzer/Cargo.toml +++ b/benchmark_analyzer/Cargo.toml @@ -3,6 +3,7 @@ name = "benchmark-analyzer" version = "1.5.0" authors = [ "Oleksandr Zarudnyi ", + "Igor Zhirkov ", ] license = "MIT OR Apache-2.0" edition = "2021" @@ -13,9 +14,13 @@ name = "benchmark-analyzer" path = "src/benchmark_analyzer/main.rs" [dependencies] -structopt = { version = "0.3", default-features = false } -anyhow = "1.0" -colored = "2.1" +clap = { version = "=4.5.21", features = ["derive"] } +anyhow = "=1.0.89" +colored = "=2.1.0" +regex = "=1.11.0" -serde = { version = "1.0", features = [ "derive" ] } -serde_json = "1.0" +serde = { version = "=1.0.210", features = [ "derive" ] } +serde_json = "=1.0.128" +chrono = { version = "=0.4.38", features = [ "serde", "clock" ] } + +era-compiler-common = { git = "https://github.com/matter-labs/era-compiler-common", branch = "main" } diff --git a/benchmark_analyzer/src/analysis/evm_interpreter/mod.rs b/benchmark_analyzer/src/analysis/evm_interpreter/mod.rs new file mode 100644 index 00000000..83e39a43 --- /dev/null +++ b/benchmark_analyzer/src/analysis/evm_interpreter/mod.rs @@ -0,0 +1,59 @@ +//! +//! Collects definitions related to the analysis of EVM interpreter tests. +//! + +use std::collections::BTreeMap; + +use crate::model::benchmark::test::codegen::versioned::executable::run::Run; +use crate::model::benchmark::test::metadata::Metadata as TestMetadata; +use crate::model::evm_interpreter::OPCODES; +use crate::results::group::Group; + +const OPTIMIZE_FOR_CYCLES: &str = "+M3B3"; + +/// +/// Returns `true` if the group collects measurements of EVM Interpreter tests +/// compiled for maximum performance. +/// +pub fn is_evm_interpreter_cycles_tests_group(group: &Group<'_>) -> bool { + matches!( + group, + Group::EVMInterpreter { + optimizations: OPTIMIZE_FOR_CYCLES, + .. + } + ) +} + +/// +/// Returns the EVM interpreter ergs/gas ratio for every EVM bytecode. +/// +pub fn opcode_cost_ratios<'a>( + group: &BTreeMap<&'a str, (&'a TestMetadata, &'a Run)>, +) -> Vec<(String, f64)> { + let mut results = Vec::new(); + + for evm_opcode in OPCODES.into_iter() { + // Case name corresponds to the EVM bytecode + // Collect three last #fallback's to get the gas and ergs measurements + let runs = group + .values() + .filter_map(|(metadata, run)| match &metadata.selector.case { + Some(case) if case == evm_opcode => match &metadata.selector.input { + Some(input) if input.is_fallback() => Some(*run), + _ => None, + }, + _ => None, + }) + .collect::>(); + let [_skip, full, template]: [&'a Run; 3] = runs + .try_into() + .unwrap_or_else(|_| panic!("Failed to extract three #fallback tests from the EVM interpreter tests attributed to the opcode {evm_opcode}")); + + let ergs_difference = full.ergs as i64 - template.ergs as i64; + let gas_difference = full.gas as i64 - template.gas as i64; + let ergs_gas_ratio = (ergs_difference as f64) / (gas_difference as f64); + results.push((evm_opcode.to_owned(), ergs_gas_ratio)); + } + results +} diff --git a/benchmark_analyzer/src/analysis/mod.rs b/benchmark_analyzer/src/analysis/mod.rs new file mode 100644 index 00000000..0dc7024b --- /dev/null +++ b/benchmark_analyzer/src/analysis/mod.rs @@ -0,0 +1,277 @@ +//! +//! Provides tools for collecting and comparing benchmark results. +//! + +pub mod evm_interpreter; + +use std::collections::BTreeMap; + +use evm_interpreter::is_evm_interpreter_cycles_tests_group; +use evm_interpreter::opcode_cost_ratios; + +use crate::model::benchmark::test::codegen::versioned::executable::run::Run; +use crate::model::benchmark::test::metadata::Metadata as TestMetadata; +use crate::model::benchmark::Benchmark; +use crate::results::group::Group; +use crate::results::Results; +use crate::util::btreemap::cross_join_filter_map; +use crate::util::btreemap::intersect_keys; +use crate::util::btreemap::intersect_map; + +type GroupRuns<'a> = BTreeMap<&'a str, (&'a TestMetadata, &'a Run)>; + +/// +/// Collects measurements from a benchmark into groups. +/// Groups may intersect. +/// +fn collect_runs(benchmark: &Benchmark) -> BTreeMap, GroupRuns> { + let mut result: BTreeMap, GroupRuns> = BTreeMap::new(); + + for (test_identifier, test) in &benchmark.tests { + for (codegen, codegen_group) in &test.codegen_groups { + for versioned_group in codegen_group.versioned_groups.values() { + for (mode, executable) in &versioned_group.executables { + for tag in test + .metadata + .tags + .iter() + .map(Some) + .chain(std::iter::once(None)) + { + let tag = tag.map(|t| t.as_str()); + result + .entry(Group::from_tag(tag, Some(codegen), Some(mode))) + .or_default() + .insert(test_identifier.as_str(), (&test.metadata, &executable.run)); + } + } + } + } + } + + result +} + +/// +/// Compare two benchmark runs [reference] and [candidate] by groups. +/// Every resulting group is either: +/// - a result of comparison of a group from [reference] with a group from [candidate] sharing the same name +/// - or a result of comparing two distinct groups from [reference] and +/// [candidate] for which [custom_group_comparisons] returned `true`. +/// +pub fn compare<'a>( + reference: &'a Benchmark, + candidate: &'a Benchmark, + custom_group_comparisons: impl Fn(&Group, &Group) -> bool, +) -> Vec<(Group<'a>, Results<'a>)> { + let groups = { + let reference_runs: BTreeMap, GroupRuns<'a>> = collect_runs(reference); + let candidate_runs: BTreeMap, GroupRuns<'a>> = collect_runs(candidate); + + let comparisons: Vec<(Group<'a>, GroupRuns<'a>, GroupRuns<'a>)> = + cross_join_filter_map(&reference_runs, &candidate_runs, |g1, g2| { + if custom_group_comparisons(g1, g2) { + Some(Group::new_comparison(g1, g2)) + } else { + None + } + }); + + intersect_keys(reference_runs, candidate_runs).chain(comparisons) + }; + + let results: Vec<(Group<'_>, Results<'_>)> = groups + .map(|(group_name, reference_tests, candidate_tests)| { + let ratios = if is_evm_interpreter_cycles_tests_group(&group_name) { + Some(( + opcode_cost_ratios(&reference_tests), + opcode_cost_ratios(&candidate_tests), + )) + } else { + None + }; + + let runs: Vec<(&TestMetadata, &Run, &Run)> = intersect_map( + reference_tests, + candidate_tests, + |_id, (metadata, run_reference), (_, run_candidate)| { + (metadata, run_reference, run_candidate) + }, + ) + .collect(); + let results = { + let mut runs = compare_runs(runs); + + if let Some((reference_ratios, candidate_ratios)) = ratios { + runs.set_evm_interpreter_ratios(reference_ratios, candidate_ratios); + } + runs + }; + (group_name, results) + }) + .collect(); + + results +} + +/// +/// Compare two sets of measurements. +/// The parameter `[run]` is a vector of triples where each element contains: +/// - metadata for a test, +/// - measurement in the first set, +/// - measurement in the second set. +/// +fn compare_runs<'a>(runs: Vec<(&'a TestMetadata, &'a Run, &'a Run)>) -> Results<'a> { + let elements_number = runs.len(); + + let mut size_factors = Vec::with_capacity(elements_number); + let mut size_min = 1.0; + let mut size_max = 1.0; + let mut size_negatives: Vec<(f64, &TestMetadata)> = Vec::with_capacity(elements_number); + let mut size_positives: Vec<(f64, &TestMetadata)> = Vec::with_capacity(elements_number); + let mut size_total_reference: u64 = 0; + let mut size_total_candidate: u64 = 0; + + let mut cycles_factors = Vec::with_capacity(elements_number); + let mut cycles_min = 1.0; + let mut cycles_max = 1.0; + let mut cycles_negatives: Vec<(f64, &TestMetadata)> = Vec::with_capacity(elements_number); + let mut cycles_positives: Vec<(f64, &TestMetadata)> = Vec::with_capacity(elements_number); + let mut cycles_total_reference: u64 = 0; + let mut cycles_total_candidate: u64 = 0; + + let mut ergs_factors = Vec::with_capacity(elements_number); + let mut ergs_min = 1.0; + let mut ergs_max = 1.0; + let mut ergs_negatives: Vec<(f64, &TestMetadata)> = Vec::with_capacity(elements_number); + let mut ergs_positives: Vec<(f64, &TestMetadata)> = Vec::with_capacity(elements_number); + let mut ergs_total_reference: u64 = 0; + let mut ergs_total_candidate: u64 = 0; + + let mut gas_factors = Vec::with_capacity(elements_number); + let mut gas_min = 1.0; + let mut gas_max = 1.0; + let mut gas_negatives = Vec::with_capacity(elements_number); + let mut gas_positives = Vec::with_capacity(elements_number); + let mut gas_total_reference: u64 = 0; + let mut gas_total_candidate: u64 = 0; + + for (metadata, reference, candidate) in runs { + let file_path = &metadata.selector.path; + // FIXME: ad-hoc patch + if file_path.contains(crate::model::evm_interpreter::TEST_PATH) { + if let Some(input) = &metadata.selector.input { + if input.is_deployer() { + continue; + } + } + } + + cycles_total_reference += reference.cycles as u64; + cycles_total_candidate += candidate.cycles as u64; + let cycles_factor = (candidate.cycles as f64) / (reference.cycles as f64); + if cycles_factor > 1.0 { + cycles_negatives.push((cycles_factor, metadata)); + } + if cycles_factor < 1.0 { + cycles_positives.push((cycles_factor, metadata)); + } + if cycles_factor < cycles_min { + cycles_min = cycles_factor; + } + if cycles_factor > cycles_max { + cycles_max = cycles_factor; + } + cycles_factors.push(cycles_factor); + + ergs_total_reference += reference.ergs; + ergs_total_candidate += candidate.ergs; + let ergs_factor = (candidate.ergs as f64) / (reference.ergs as f64); + if ergs_factor > 1.0 { + ergs_negatives.push((ergs_factor, metadata)); + } + if ergs_factor < 1.0 { + ergs_positives.push((ergs_factor, metadata)); + } + if ergs_factor < ergs_min { + ergs_min = ergs_factor; + } + if ergs_factor > ergs_max { + ergs_max = ergs_factor; + } + ergs_factors.push(ergs_factor); + + gas_total_reference += reference.gas; + gas_total_candidate += candidate.gas; + let gas_factor = (candidate.gas as f64) / (reference.gas as f64); + if gas_factor > 1.0 { + gas_negatives.push((gas_factor, metadata)); + } + if gas_factor < 1.0 { + gas_positives.push((gas_factor, metadata)); + } + if gas_factor < gas_min { + gas_min = gas_factor; + } + if gas_factor > gas_max { + gas_max = gas_factor; + } + gas_factors.push(gas_factor); + + let reference_size = match reference.size { + Some(size) => size, + None => continue, + }; + let candidate_size = match candidate.size { + Some(size) => size, + None => continue, + }; + size_total_reference += reference_size as u64; + size_total_candidate += candidate_size as u64; + let size_factor = (candidate_size as f64) / (reference_size as f64); + if size_factor > 1.0 { + size_negatives.push((size_factor, metadata)); + } + if size_factor < 1.0 { + size_positives.push((size_factor, metadata)); + } + if size_factor < size_min { + size_min = size_factor; + } + if size_factor > size_max { + size_max = size_factor; + } + size_factors.push(size_factor); + } + + let size_total = (size_total_candidate as f64) / (size_total_reference as f64); + + let cycles_total = (cycles_total_candidate as f64) / (cycles_total_reference as f64); + + let ergs_total = (ergs_total_candidate as f64) / (ergs_total_reference as f64); + + let gas_total = (gas_total_candidate as f64) / (gas_total_reference as f64); + + Results::new( + size_min, + size_max, + size_total, + size_negatives, + size_positives, + cycles_min, + cycles_max, + cycles_total, + cycles_negatives, + cycles_positives, + ergs_min, + ergs_max, + ergs_total, + ergs_negatives, + ergs_positives, + gas_min, + gas_max, + gas_total, + gas_negatives, + gas_positives, + ) +} diff --git a/benchmark_analyzer/src/benchmark/group/mod.rs b/benchmark_analyzer/src/benchmark/group/mod.rs deleted file mode 100644 index 78dca30d..00000000 --- a/benchmark_analyzer/src/benchmark/group/mod.rs +++ /dev/null @@ -1,179 +0,0 @@ -//! -//! The benchmark group representation. -//! - -pub mod element; -pub mod results; - -use std::collections::BTreeMap; - -use serde::Deserialize; -use serde::Serialize; - -use crate::benchmark::Benchmark; - -use self::element::Element; -use self::results::Results; - -/// -/// The benchmark group representation. -/// -#[derive(Debug, Default, Serialize, Deserialize, Clone)] -pub struct Group { - /// The group elements. - pub elements: BTreeMap, -} - -impl Group { - /// - /// Compares two benchmark groups. - /// - pub fn compare<'a>(reference: &'a Self, candidate: &'a Self) -> Results<'a> { - let elements_number = reference.elements.len(); - - let mut size_factors = Vec::with_capacity(elements_number); - let mut size_min = 1.0; - let mut size_max = 1.0; - let mut size_negatives = Vec::with_capacity(elements_number); - let mut size_positives = Vec::with_capacity(elements_number); - let mut size_total_reference: u64 = 0; - let mut size_total_candidate: u64 = 0; - - let mut cycles_factors = Vec::with_capacity(elements_number); - let mut cycles_min = 1.0; - let mut cycles_max = 1.0; - let mut cycles_negatives = Vec::with_capacity(elements_number); - let mut cycles_positives = Vec::with_capacity(elements_number); - let mut cycles_total_reference: u64 = 0; - let mut cycles_total_candidate: u64 = 0; - - let mut ergs_factors = Vec::with_capacity(elements_number); - let mut ergs_min = 1.0; - let mut ergs_max = 1.0; - let mut ergs_negatives = Vec::with_capacity(elements_number); - let mut ergs_positives = Vec::with_capacity(elements_number); - let mut ergs_total_reference: u64 = 0; - let mut ergs_total_candidate: u64 = 0; - - for (path, reference) in reference.elements.iter() { - if path.contains("tests/solidity/complex/interpreter/test.json") - && path.contains("#deployer") - { - continue; - } - let candidate = match candidate.elements.get(path.as_str()) { - Some(candidate) => candidate, - None => continue, - }; - - cycles_total_reference += reference.cycles as u64; - cycles_total_candidate += candidate.cycles as u64; - let cycles_factor = (candidate.cycles as f64) / (reference.cycles as f64); - if cycles_factor > 1.0 { - cycles_negatives.push((cycles_factor, path.as_str())); - } - if cycles_factor < 1.0 { - cycles_positives.push((cycles_factor, path.as_str())); - } - if cycles_factor < cycles_min { - cycles_min = cycles_factor; - } - if cycles_factor > cycles_max { - cycles_max = cycles_factor; - } - cycles_factors.push(cycles_factor); - - ergs_total_reference += reference.ergs; - ergs_total_candidate += candidate.ergs; - let ergs_factor = (candidate.ergs as f64) / (reference.ergs as f64); - if ergs_factor > 1.0 { - ergs_negatives.push((ergs_factor, path.as_str())); - } - if ergs_factor < 1.0 { - ergs_positives.push((ergs_factor, path.as_str())); - } - if ergs_factor < ergs_min { - ergs_min = ergs_factor; - } - if ergs_factor > ergs_max { - ergs_max = ergs_factor; - } - ergs_factors.push(ergs_factor); - - let reference_size = match reference.size { - Some(size) => size, - None => continue, - }; - let candidate_size = match candidate.size { - Some(size) => size, - None => continue, - }; - size_total_reference += reference_size as u64; - size_total_candidate += candidate_size as u64; - let size_factor = (candidate_size as f64) / (reference_size as f64); - if size_factor > 1.0 { - size_negatives.push((size_factor, path.as_str())); - } - if size_factor < 1.0 { - size_positives.push((size_factor, path.as_str())); - } - if size_factor < size_min { - size_min = size_factor; - } - if size_factor > size_max { - size_max = size_factor; - } - size_factors.push(size_factor); - } - - let size_total = (size_total_candidate as f64) / (size_total_reference as f64); - - let cycles_total = (cycles_total_candidate as f64) / (cycles_total_reference as f64); - - let ergs_total = (ergs_total_candidate as f64) / (ergs_total_reference as f64); - - Results::new( - size_min, - size_max, - size_total, - size_negatives, - size_positives, - cycles_min, - cycles_max, - cycles_total, - cycles_negatives, - cycles_positives, - ergs_min, - ergs_max, - ergs_total, - ergs_negatives, - ergs_positives, - ) - } - - /// - /// Returns the EVM interpreter ergs/gas ratio. - /// - pub fn evm_interpreter_ratios(&self) -> Vec<(String, f64)> { - let mut results = Vec::with_capacity(Benchmark::EVM_OPCODES.len()); - for evm_opcode in Benchmark::EVM_OPCODES.into_iter() { - let name_substring = format!("test.json::{evm_opcode}["); - let [full, template]: [Element; 2] = self - .elements - .iter() - .filter(|element| element.0.contains(name_substring.as_str())) - .rev() - .take(2) - .map(|element| (element.1.to_owned())) - .collect::>() - .try_into() - .expect("Always valid"); - - let ergs_difference = full.ergs - template.ergs; - let gas_difference = full.gas - template.gas; - let ergs_gas_ratio = (ergs_difference as f64) / (gas_difference as f64); - results.push((evm_opcode.to_owned(), ergs_gas_ratio)); - } - results - } -} diff --git a/benchmark_analyzer/src/benchmark/mod.rs b/benchmark_analyzer/src/benchmark/mod.rs deleted file mode 100644 index ad724502..00000000 --- a/benchmark_analyzer/src/benchmark/mod.rs +++ /dev/null @@ -1,225 +0,0 @@ -//! -//! The benchmark representation. -//! - -pub mod group; - -use std::collections::BTreeMap; -use std::path::PathBuf; - -use serde::Deserialize; -use serde::Serialize; - -use self::group::results::Results; -use self::group::Group; - -/// -/// The benchmark representation. -/// -#[derive(Debug, Default, Serialize, Deserialize)] -pub struct Benchmark { - /// The benchmark groups. - pub groups: BTreeMap, -} - -impl Benchmark { - /// The EVM interpreter group identifier. - pub const EVM_INTERPRETER_GROUP_NAME: &'static str = "EVMInterpreter"; - - /// The EVM interpreter cycles group identifier. - pub const EVM_INTERPRETER_GROUP_NAME_CYCLES: &'static str = "EVMInterpreter M3B3"; - - /// The EVM opcodes to test. - pub const EVM_OPCODES: [&'static str; 135] = [ - "ADD", - "MUL", - "SUB", - "DIV", - "SDIV", - "MOD", - "SMOD", - "ADDMOD", - "MULMOD", - "EXP", - "SIGNEXTEND", - "LT", - "GT", - "SLT", - "SGT", - "EQ", - "ISZERO", - "AND", - "OR", - "XOR", - "NOT", - "BYTE", - "SHL", - "SHR", - "SAR", - "SGT", - "SHA3", - "ADDRESS", - "BALANCE", - "ORIGIN", - "CALLER", - "CALLVALUE", - "CALLDATALOAD", - "CALLDATASIZE", - "CALLDATACOPY", - "CODESIZE", - "CODECOPY", - "GASPRICE", - "EXTCODESIZE", - "EXTCODECOPY", - "RETURNDATASIZE", - "RETURNDATACOPY", - "EXTCODEHASH", - "BLOCKHASH", - "COINBASE", - "TIMESTAMP", - "NUMBER", - "PREVRANDAO", - "GASLIMIT", - "CHAINID", - "SELFBALANCE", - "BASEFEE", - "POP", - "MLOAD", - "MSTORE", - "MSTORE8", - "SLOAD", - "SSTORE", - "JUMP", - "JUMPI", - "PC", - "MSIZE", - "GAS", - "JUMPDEST", - "PUSH0", - "PUSH1", - "PUSH2", - "PUSH4", - "PUSH5", - "PUSH6", - "PUSH7", - "PUSH8", - "PUSH9", - "PUSH10", - "PUSH11", - "PUSH12", - "PUSH13", - "PUSH14", - "PUSH15", - "PUSH16", - "PUSH17", - "PUSH18", - "PUSH19", - "PUSH20", - "PUSH21", - "PUSH22", - "PUSH23", - "PUSH24", - "PUSH25", - "PUSH26", - "PUSH27", - "PUSH28", - "PUSH29", - "PUSH30", - "PUSH31", - "PUSH32", - "DUP1", - "DUP2", - "DUP3", - "DUP4", - "DUP5", - "DUP6", - "DUP7", - "DUP8", - "DUP9", - "DUP10", - "DUP11", - "DUP12", - "DUP13", - "DUP14", - "DUP15", - "DUP16", - "SWAP1", - "SWAP2", - "SWAP3", - "SWAP4", - "SWAP5", - "SWAP6", - "SWAP7", - "SWAP8", - "SWAP9", - "SWAP10", - "SWAP11", - "SWAP12", - "SWAP13", - "SWAP14", - "SWAP15", - "SWAP16", - "CALL", - "STATICCALL", - "DELEGATECALL", - "CREATE", - "CREATE2", - "RETURN", - "REVERT", - ]; - - /// - /// Compares two benchmarks. - /// - pub fn compare<'a>(reference: &'a Self, candidate: &'a Self) -> BTreeMap<&'a str, Results<'a>> { - let mut results = BTreeMap::new(); - - for (group_name, reference_group) in reference.groups.iter() { - let candidate_group = match candidate.groups.get(group_name) { - Some(candidate_group) => candidate_group, - None => continue, - }; - - let mut group_results = Group::compare(reference_group, candidate_group); - if group_name.starts_with(Self::EVM_INTERPRETER_GROUP_NAME_CYCLES) { - if let (Some(reference_ratios), Some(candidate_ratios)) = ( - reference - .groups - .get(group_name.as_str()) - .map(|group| group.evm_interpreter_ratios()), - candidate - .groups - .get(group_name.as_str()) - .map(|group| group.evm_interpreter_ratios()), - ) { - group_results.set_evm_interpreter_ratios(reference_ratios, candidate_ratios); - } - } - results.insert(group_name.as_str(), group_results); - } - - results - } - - /// - /// Writes the benchmark to a file. - /// - pub fn write_to_file(self, path: PathBuf) -> anyhow::Result<()> { - let contents = serde_json::to_string(&self).expect("Always valid"); - std::fs::write(path.as_path(), contents) - .map_err(|error| anyhow::anyhow!("Benchmark file {:?} reading: {}", path, error))?; - Ok(()) - } -} - -impl TryFrom for Benchmark { - type Error = anyhow::Error; - - fn try_from(path: PathBuf) -> Result { - let text = std::fs::read_to_string(path.as_path()) - .map_err(|error| anyhow::anyhow!("Benchmark file {:?} reading: {}", path, error))?; - let json: Self = serde_json::from_str(text.as_str()) - .map_err(|error| anyhow::anyhow!("Benchmark file {:?} parsing: {}", path, error))?; - Ok(json) - } -} diff --git a/benchmark_analyzer/src/benchmark_analyzer/arguments.rs b/benchmark_analyzer/src/benchmark_analyzer/arguments.rs index ffc96623..3fffc116 100644 --- a/benchmark_analyzer/src/benchmark_analyzer/arguments.rs +++ b/benchmark_analyzer/src/benchmark_analyzer/arguments.rs @@ -4,39 +4,35 @@ use std::path::PathBuf; -use structopt::StructOpt; +use clap::Parser; /// /// The benchmark analyzer arguments. /// -#[derive(Debug, StructOpt)] -#[structopt( - name = "benchmark-analyzer", - about = "ZKsync toolchain benchmark analyzer" -)] +#[derive(Debug, Parser)] +#[command(about, long_about = None)] pub struct Arguments { /// The reference build benchmark. - #[structopt(long = "reference", default_value = "reference.json")] + #[structopt(long, default_value = "reference.json")] pub reference: PathBuf, /// The candidate build benchmark. - #[structopt(long = "candidate", default_value = "candidate.json")] + #[structopt(long, default_value = "candidate.json")] pub candidate: PathBuf, /// The output file. If unset, the result is printed to `stdout`. - #[structopt(short = "o", long = "output-file")] - pub output_path: Option, + #[structopt(short = 'o', long)] + pub output_file: Option, /// Maximum number of results displayed in a group. - #[structopt(long = "group-max", default_value = "100")] + #[structopt(long, default_value_t = 100)] pub group_max: usize, -} -impl Arguments { - /// - /// A shortcut constructor. - /// - pub fn new() -> Self { - Self::from_args() - } + /// Regular expression to select reference group for the comparison. + #[structopt(long)] + pub query_reference: Option, + + /// Regular expression to select candidate group for the comparison. + #[structopt(long)] + pub query_candidate: Option, } diff --git a/benchmark_analyzer/src/benchmark_analyzer/main.rs b/benchmark_analyzer/src/benchmark_analyzer/main.rs index e0a0d8a6..572f9a3e 100644 --- a/benchmark_analyzer/src/benchmark_analyzer/main.rs +++ b/benchmark_analyzer/src/benchmark_analyzer/main.rs @@ -6,26 +6,58 @@ pub(crate) mod arguments; use std::io::Write; +use clap::Parser; + use self::arguments::Arguments; +use benchmark_analyzer::ResultsGroup; /// /// The application entry point. /// fn main() -> anyhow::Result<()> { - let arguments = Arguments::new(); + let arguments = Arguments::try_parse()?; + + let reference_benchmark = benchmark_analyzer::Benchmark::try_from(arguments.reference)?; + let candidate_benchmark = benchmark_analyzer::Benchmark::try_from(arguments.candidate)?; + + let groups_results = if let (Some(reference_query), Some(candidate_query)) = + (arguments.query_reference, arguments.query_candidate) + { + // If the user provides regular expressions to select groups for + // comparison, the analyzer will compare all groups with the same names, + // plus all pairs of groups matching regular expressions + // [regex_reference] and [regex_candidate]. - let reference = benchmark_analyzer::Benchmark::try_from(arguments.reference)?; - let candidate = benchmark_analyzer::Benchmark::try_from(arguments.candidate)?; + let regex_reference = + regex::Regex::new(&reference_query).expect("Invalid reference query regexp"); + let regex_candidate = + regex::Regex::new(&candidate_query).expect("Invalid candidate query regexp"); - let groups_results = benchmark_analyzer::Benchmark::compare(&reference, &candidate); + benchmark_analyzer::analysis::compare( + &reference_benchmark, + &candidate_benchmark, + |g1: &ResultsGroup<'_>, g2: &ResultsGroup<'_>| { + g1.regex_matches(®ex_reference) && g2.regex_matches(®ex_candidate) + }, + ) + } else { + // If the user did not provide regular expressions to select groups for + // comparison, the analyzer will compare only the groups with the same + // names. + benchmark_analyzer::analysis::compare( + &reference_benchmark, + &candidate_benchmark, + |_: &ResultsGroup<'_>, _: &ResultsGroup<'_>| false, + ) + }; - match arguments.output_path { + match arguments.output_file { Some(output_path) => { let mut file = std::fs::File::create(output_path)?; for (group_name, mut results) in groups_results.into_iter() { results.sort_worst(); - results.print_worst_results(arguments.group_max, group_name); - results.write_all(&mut file, group_name)?; + results.print_worst_results(arguments.group_max, &group_name.to_string()); + results.write_all(&mut file, &group_name.to_string())?; writeln!(file)?; println!(); println!(); @@ -35,8 +67,8 @@ fn main() -> anyhow::Result<()> { let mut stdout = std::io::stdout(); for (group_name, mut results) in groups_results.into_iter() { results.sort_worst(); - results.print_worst_results(arguments.group_max, group_name); - results.write_all(&mut stdout, group_name)?; + results.print_worst_results(arguments.group_max, &group_name.to_string()); + results.write_all(&mut stdout, &group_name.to_string())?; writeln!(stdout)?; println!(); println!(); diff --git a/benchmark_analyzer/src/lib.rs b/benchmark_analyzer/src/lib.rs index f01677a8..622f4eb5 100644 --- a/benchmark_analyzer/src/lib.rs +++ b/benchmark_analyzer/src/lib.rs @@ -2,13 +2,34 @@ //! The benchmark analyzer library. //! -pub(crate) mod benchmark; +pub mod analysis; +pub mod model; +pub mod output; +pub mod results; +pub mod util; -pub use self::benchmark::group::element::Element as BenchmarkElement; -pub use self::benchmark::group::Group as BenchmarkGroup; -pub use self::benchmark::Benchmark; +pub use crate::output::format::csv::Csv as CsvSerializer; +pub use crate::output::format::json::lnt::JsonLNT as JsonLNTSerializer; +pub use crate::output::format::json::native::Json as JsonNativeSerializer; -/// -/// The all elements group name. -/// -pub const BENCHMARK_ALL_GROUP_NAME: &str = "All"; +pub use crate::model::benchmark::test::codegen::versioned::executable::run::Run; +pub use crate::model::benchmark::test::codegen::versioned::executable::Executable; +pub use crate::model::benchmark::test::codegen::versioned::VersionedGroup; +pub use crate::model::benchmark::test::codegen::CodegenGroup; +pub use crate::model::benchmark::test::input::Input; +pub use crate::model::benchmark::test::selector::Selector as TestSelector; +pub use crate::model::benchmark::test::Test; +pub use crate::model::benchmark::write_to_file; +pub use crate::model::benchmark::Benchmark; +pub use crate::model::context::validate_context; +pub use crate::model::context::Context as BenchmarkContext; + +// Metadata for various parts of the model +pub use crate::model::benchmark::metadata::BenchmarkVersion; +pub use crate::model::benchmark::metadata::Metadata as BenchmarkMetadata; +pub use crate::model::benchmark::test::codegen::versioned::executable::metadata::Metadata as ExecutableMetadata; +pub use crate::model::benchmark::test::metadata::Metadata as TestMetadata; + +pub use crate::results::group::Group as ResultsGroup; + +pub use crate::model::evm_interpreter::GROUP_NAME as TEST_GROUP_EVM_INTERPRETER; diff --git a/benchmark_analyzer/src/model/benchmark/metadata.rs b/benchmark_analyzer/src/model/benchmark/metadata.rs new file mode 100644 index 00000000..93695e63 --- /dev/null +++ b/benchmark_analyzer/src/model/benchmark/metadata.rs @@ -0,0 +1,36 @@ +//! +//! Information associated with the benchmark run. +//! + +use chrono::DateTime; +use chrono::Utc; +use serde::Deserialize; +use serde::Serialize; + +use crate::model::context::Context; + +/// Version of the benchmark format. +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub enum BenchmarkVersion { + #[default] + /// Flat format, a map from key (Identifier + mode) to measurements. + V1, + /// New format with metadata. + V2, +} + +/// +/// Information associated with the benchmark run. +/// +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct Metadata { + /// Version for the benchmark report. + pub version: BenchmarkVersion, + /// Start of the benchmark run. + pub start: DateTime, + /// End of the benchmark run. + pub end: DateTime, + /// Context of benchmarking, passed from compiler tester. + #[serde(skip)] + pub context: Option, +} diff --git a/benchmark_analyzer/src/model/benchmark/mod.rs b/benchmark_analyzer/src/model/benchmark/mod.rs new file mode 100644 index 00000000..0e82ceb5 --- /dev/null +++ b/benchmark_analyzer/src/model/benchmark/mod.rs @@ -0,0 +1,78 @@ +//! +//! The benchmark representation. +//! + +pub mod metadata; +pub mod test; + +use std::collections::BTreeMap; +use std::path::PathBuf; + +use serde::Deserialize; +use serde::Serialize; + +use crate::output::comparison_result::Output; +use crate::output::file::File; +use crate::output::IBenchmarkSerializer; + +use metadata::Metadata; + +use self::test::Test; + +/// +/// The benchmark representation. +/// +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct Benchmark { + /// Metadata related to the whole benchmark. + pub metadata: Metadata, + /// The tests. + pub tests: BTreeMap, +} + +/// +/// Writes the benchmark results to a file using a provided serializer. +/// +pub fn write_to_file( + benchmark: &Benchmark, + path: PathBuf, + serializer: impl IBenchmarkSerializer, +) -> anyhow::Result<()> { + match serializer + .serialize_to_string(benchmark) + .expect("Always valid") + { + Output::SingleFile(contents) => { + std::fs::write(path.as_path(), contents) + .map_err(|error| anyhow::anyhow!("Benchmark file {path:?} writing: {error}"))?; + } + Output::MultipleFiles(files) => { + if !files.is_empty() { + std::fs::create_dir_all(&path)?; + } + for File { + path: relative_path, + contents, + } in files + { + let file_path = path.join(relative_path); + std::fs::write(file_path.as_path(), contents).map_err(|error| { + anyhow::anyhow!("Benchmark file {file_path:?} writing: {error}") + })?; + } + } + } + Ok(()) +} + +impl TryFrom for Benchmark { + type Error = anyhow::Error; + + fn try_from(path: PathBuf) -> Result { + let text = std::fs::read_to_string(path.as_path()) + .map_err(|error| anyhow::anyhow!("Benchmark file {path:?} reading: {error}"))?; + let json: Self = serde_json::from_str(text.as_str()) + .map_err(|error| anyhow::anyhow!("Benchmark file {path:?} parsing: {error}"))?; + Ok(json) + } +} diff --git a/benchmark_analyzer/src/model/benchmark/test/codegen/mod.rs b/benchmark_analyzer/src/model/benchmark/test/codegen/mod.rs new file mode 100644 index 00000000..1cde5971 --- /dev/null +++ b/benchmark_analyzer/src/model/benchmark/test/codegen/mod.rs @@ -0,0 +1,26 @@ +//! +//! Groups test instances by the code generator version. +//! + +pub mod versioned; + +use std::collections::BTreeMap; + +use serde::Deserialize; +use serde::Serialize; +use versioned::VersionedGroup; + +/// +/// The language version associated with a test. +/// +pub type Version = String; + +/// +/// Groups test instances by the code generator version. +/// +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +pub struct CodegenGroup { + #[serde(flatten)] + /// Inner groups that differ by the associated language version. + pub versioned_groups: BTreeMap, +} diff --git a/benchmark_analyzer/src/model/benchmark/test/codegen/versioned/executable/metadata.rs b/benchmark_analyzer/src/model/benchmark/test/codegen/versioned/executable/metadata.rs new file mode 100644 index 00000000..bc9776de --- /dev/null +++ b/benchmark_analyzer/src/model/benchmark/test/codegen/versioned/executable/metadata.rs @@ -0,0 +1,12 @@ +//! +//! Information associated with an executable in a benchmark. +//! + +use serde::Deserialize; +use serde::Serialize; + +/// +/// Information associated with an executable in a benchmark. +/// +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct Metadata {} diff --git a/benchmark_analyzer/src/model/benchmark/test/codegen/versioned/executable/mod.rs b/benchmark_analyzer/src/model/benchmark/test/codegen/versioned/executable/mod.rs new file mode 100644 index 00000000..65353f30 --- /dev/null +++ b/benchmark_analyzer/src/model/benchmark/test/codegen/versioned/executable/mod.rs @@ -0,0 +1,26 @@ +//! +//! Executable is the compiled artifact corresponding to the test. +//! Executables differ by compilation flags. +//! + +pub mod metadata; +pub mod run; + +use metadata::Metadata; +use run::Run; +use serde::Deserialize; +use serde::Serialize; + +/// +/// Executable is the compiled artifact corresponding to the test. +/// Executables differ by compilation flags. +/// +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Executable { + #[serde(default, skip)] + /// Metadata associated with the compiled executable. + pub metadata: Metadata, + #[serde(flatten)] + /// Measurements. + pub run: Run, +} diff --git a/benchmark_analyzer/src/benchmark/group/element.rs b/benchmark_analyzer/src/model/benchmark/test/codegen/versioned/executable/run/mod.rs similarity index 72% rename from benchmark_analyzer/src/benchmark/group/element.rs rename to benchmark_analyzer/src/model/benchmark/test/codegen/versioned/executable/run/mod.rs index 550cae70..48652f60 100644 --- a/benchmark_analyzer/src/benchmark/group/element.rs +++ b/benchmark_analyzer/src/model/benchmark/test/codegen/versioned/executable/run/mod.rs @@ -1,26 +1,26 @@ //! -//! The benchmark element. +//! A run of a test with fixed compiler options (mode). //! use serde::Deserialize; use serde::Serialize; /// -/// The benchmark element. +/// A run of a test with fixed compiler options (mode). /// #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Element { +pub struct Run { /// The contract size, `Some` for contracts deploys. pub size: Option, /// The number of cycles. pub cycles: usize, - /// The number of ergs. + /// The amount of ergs. pub ergs: u64, - /// The number of EVM gas. + /// The amount of EVM gas. pub gas: u64, } -impl Element { +impl Run { /// /// A shortcut constructor. /// diff --git a/benchmark_analyzer/src/model/benchmark/test/codegen/versioned/mod.rs b/benchmark_analyzer/src/model/benchmark/test/codegen/versioned/mod.rs new file mode 100644 index 00000000..ce3ced25 --- /dev/null +++ b/benchmark_analyzer/src/model/benchmark/test/codegen/versioned/mod.rs @@ -0,0 +1,27 @@ +//! +//! Groups test runs by the language version associated with them. +//! + +pub mod executable; + +use std::collections::BTreeMap; + +use executable::Executable; +use serde::Deserialize; +use serde::Serialize; + +/// +/// Encoded compiler mode. In future, it can be replaced with a structured type +/// shared between crates `benchmark_analyzer` and `compiler_tester`. +/// +pub type Mode = String; + +/// +/// Groups test runs by the language version associated with them. +/// +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +pub struct VersionedGroup { + #[serde(flatten)] + /// Compiled executables associated with test runs. + pub executables: BTreeMap, +} diff --git a/benchmark_analyzer/src/model/benchmark/test/input.rs b/benchmark_analyzer/src/model/benchmark/test/input.rs new file mode 100644 index 00000000..0190968e --- /dev/null +++ b/benchmark_analyzer/src/model/benchmark/test/input.rs @@ -0,0 +1,78 @@ +//! +//! Identifier for the test input. Describes the input type and position but not the actual contents. +//! + +use serde::Deserialize; +use serde::Serialize; + +/// +/// Identifier for the test input. Describes the input type and position but not the actual contents. +/// +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub enum Input { + /// The contract deploy, regardless of target. + Deployer { + /// Contract identifier, usually file name and contract name separated by a colon. + contract_identifier: String, + }, + /// The fallback method. + Fallback { + /// Index in the array of inputs. + input_index: usize, + }, + /// The contract call. + Runtime { + /// Index in the array of inputs. + input_index: usize, + /// Input name, provided in the test description. + name: String, + }, + /// The storage empty check. + StorageEmpty { + /// Index in the array of inputs. + input_index: usize, + }, + /// Check account balance. + Balance { + /// Index in the array of inputs. + input_index: usize, + }, +} + +impl Input { + /// Returns `true` if the input is [`Deployer`]. + /// + /// [`Deployer`]: Input::Deployer + #[must_use] + pub fn is_deployer(&self) -> bool { + matches!(self, Self::Deployer { .. }) + } + + /// Returns `true` if the input is [`Fallback`]. + /// + /// [`Fallback`]: Input::Fallback + #[must_use] + pub fn is_fallback(&self) -> bool { + matches!(self, Self::Fallback { .. }) + } +} + +impl std::fmt::Display for Input { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Input::Deployer { + contract_identifier, + } => f.write_fmt(format_args!("#deployer:{contract_identifier}")), + Input::Runtime { input_index, name } => { + f.write_fmt(format_args!("{name}:{input_index}")) + } + Input::StorageEmpty { input_index } => { + f.write_fmt(format_args!("#storage_empty_check:{input_index}")) + } + Input::Balance { input_index } => { + f.write_fmt(format_args!("#balance_check:{input_index}")) + } + Input::Fallback { input_index } => f.write_fmt(format_args!("#fallback:{input_index}")), + } + } +} diff --git a/benchmark_analyzer/src/model/benchmark/test/metadata.rs b/benchmark_analyzer/src/model/benchmark/test/metadata.rs new file mode 100644 index 00000000..ebd565c9 --- /dev/null +++ b/benchmark_analyzer/src/model/benchmark/test/metadata.rs @@ -0,0 +1,29 @@ +//! +//! Information associated with a specific test in benchmark. +//! + +use serde::Deserialize; +use serde::Serialize; + +use crate::model::benchmark::test::selector::Selector; + +/// +/// Information associated with a specific test in benchmark. +/// +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct Metadata { + #[serde(default)] + /// Tests may be tagged with one or many groups. + pub tags: Vec, + /// Test selector. + pub selector: Selector, +} + +impl Metadata { + /// + /// Creates a new instance of test metadata provided with the test selector and tags. + /// + pub fn new(selector: Selector, tags: Vec) -> Self { + Self { selector, tags } + } +} diff --git a/benchmark_analyzer/src/model/benchmark/test/mod.rs b/benchmark_analyzer/src/model/benchmark/test/mod.rs new file mode 100644 index 00000000..ebd82fd1 --- /dev/null +++ b/benchmark_analyzer/src/model/benchmark/test/mod.rs @@ -0,0 +1,44 @@ +//! +//! The benchmark group representation. +//! + +pub mod codegen; +pub mod input; +pub mod metadata; +pub mod selector; + +use std::collections::BTreeMap; + +use codegen::CodegenGroup; +use metadata::Metadata; +use serde::Deserialize; +use serde::Serialize; + +/// +/// The codegen associated with a test definition. +/// +pub type Codegen = String; + +/// +/// The benchmark group representation. +/// +#[derive(Debug, Default, Serialize, Deserialize, Clone)] +pub struct Test { + /// Metadata for this test. + #[serde(default)] + pub metadata: Metadata, + /// Versions. + pub codegen_groups: BTreeMap, +} + +impl Test { + /// + /// Creates a new test with provided metadata. + /// + pub fn new(metadata: Metadata) -> Self { + Self { + codegen_groups: Default::default(), + metadata, + } + } +} diff --git a/benchmark_analyzer/src/model/benchmark/test/selector.rs b/benchmark_analyzer/src/model/benchmark/test/selector.rs new file mode 100644 index 00000000..00abf174 --- /dev/null +++ b/benchmark_analyzer/src/model/benchmark/test/selector.rs @@ -0,0 +1,39 @@ +//! +//! Test selector, unambiously locating a test suite, or a specific input. +//! + +use serde::Deserialize; +use serde::Serialize; + +use crate::model::benchmark::test::input::Input; + +/// +/// Test selector, unambiously locating a test suite, case, or input. +/// +#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)] +pub struct Selector { + /// Path to the file containing test. + pub path: String, + /// Name of the case, if any. `None` means nameless case. + pub case: Option, + /// Identifier of the specific input. + pub input: Option, +} + +impl std::fmt::Display for Selector { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { + path: filename, + case: case_name, + input, + } = self; + f.write_fmt(format_args!("{filename}"))?; + if let Some(case_name) = case_name { + f.write_fmt(format_args!("::{case_name}"))?; + } + if let Some(input) = input { + f.write_fmt(format_args!("[{input}]"))?; + } + Ok(()) + } +} diff --git a/benchmark_analyzer/src/model/context/mod.rs b/benchmark_analyzer/src/model/context/mod.rs new file mode 100644 index 00000000..9bd9ca65 --- /dev/null +++ b/benchmark_analyzer/src/model/context/mod.rs @@ -0,0 +1,35 @@ +//! +//! A context for benchmarking, passed by compiler-tester. +//! + +/// +/// A context for benchmarking, passed by compiler-tester. +/// +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct Context { + /// Unique identifier of the machine. + pub machine: String, + /// Target, for example "eravm" or "evm". + pub target: era_compiler_common::Target, + /// Type of `solc`, for example `zksync` + pub toolchain: String, +} + +/// +/// Checks that the context is well-formed. +/// +pub fn validate_context(context: &Context) -> anyhow::Result<()> { + let Context { + machine, + toolchain, + target: _, + } = context; + + if machine.is_empty() { + anyhow::bail!("The `machine` field in the benchmark context is empty") + } + if toolchain.is_empty() { + anyhow::bail!("The `toolchain` field in the benchmark context is empty") + } + Ok(()) +} diff --git a/benchmark_analyzer/src/model/evm_interpreter.rs b/benchmark_analyzer/src/model/evm_interpreter.rs new file mode 100644 index 00000000..91e09836 --- /dev/null +++ b/benchmark_analyzer/src/model/evm_interpreter.rs @@ -0,0 +1,148 @@ +//! +//! Collects the benchmark model's definitions related to EVM Interpreter test suite. +//! + +/// Path to EVM interpreter test. +pub const TEST_PATH: &str = "tests/solidity/complex/interpreter/test.json"; + +/// Component of a name of the results group where tests for EVM opcodes reside. +pub const GROUP_NAME: &str = "EVMInterpreter"; + +/// The EVM opcodes to test. +pub const OPCODES: [&str; 135] = [ + "ADD", + "MUL", + "SUB", + "DIV", + "SDIV", + "MOD", + "SMOD", + "ADDMOD", + "MULMOD", + "EXP", + "SIGNEXTEND", + "LT", + "GT", + "SLT", + "SGT", + "EQ", + "ISZERO", + "AND", + "OR", + "XOR", + "NOT", + "BYTE", + "SHL", + "SHR", + "SAR", + "SGT", + "SHA3", + "ADDRESS", + "BALANCE", + "ORIGIN", + "CALLER", + "CALLVALUE", + "CALLDATALOAD", + "CALLDATASIZE", + "CALLDATACOPY", + "CODESIZE", + "CODECOPY", + "GASPRICE", + "EXTCODESIZE", + "EXTCODECOPY", + "RETURNDATASIZE", + "RETURNDATACOPY", + "EXTCODEHASH", + "BLOCKHASH", + "COINBASE", + "TIMESTAMP", + "NUMBER", + "PREVRANDAO", + "GASLIMIT", + "CHAINID", + "SELFBALANCE", + "BASEFEE", + "POP", + "MLOAD", + "MSTORE", + "MSTORE8", + "SLOAD", + "SSTORE", + "JUMP", + "JUMPI", + "PC", + "MSIZE", + "GAS", + "JUMPDEST", + "PUSH0", + "PUSH1", + "PUSH2", + "PUSH4", + "PUSH5", + "PUSH6", + "PUSH7", + "PUSH8", + "PUSH9", + "PUSH10", + "PUSH11", + "PUSH12", + "PUSH13", + "PUSH14", + "PUSH15", + "PUSH16", + "PUSH17", + "PUSH18", + "PUSH19", + "PUSH20", + "PUSH21", + "PUSH22", + "PUSH23", + "PUSH24", + "PUSH25", + "PUSH26", + "PUSH27", + "PUSH28", + "PUSH29", + "PUSH30", + "PUSH31", + "PUSH32", + "DUP1", + "DUP2", + "DUP3", + "DUP4", + "DUP5", + "DUP6", + "DUP7", + "DUP8", + "DUP9", + "DUP10", + "DUP11", + "DUP12", + "DUP13", + "DUP14", + "DUP15", + "DUP16", + "SWAP1", + "SWAP2", + "SWAP3", + "SWAP4", + "SWAP5", + "SWAP6", + "SWAP7", + "SWAP8", + "SWAP9", + "SWAP10", + "SWAP11", + "SWAP12", + "SWAP13", + "SWAP14", + "SWAP15", + "SWAP16", + "CALL", + "STATICCALL", + "DELEGATECALL", + "CREATE", + "CREATE2", + "RETURN", + "REVERT", +]; diff --git a/benchmark_analyzer/src/model/mod.rs b/benchmark_analyzer/src/model/mod.rs new file mode 100644 index 00000000..1c6ad9a0 --- /dev/null +++ b/benchmark_analyzer/src/model/mod.rs @@ -0,0 +1,7 @@ +//! +//! Defines a model of benchmark data. +//! + +pub mod benchmark; +pub mod context; +pub mod evm_interpreter; diff --git a/benchmark_analyzer/src/output/comparison_result.rs b/benchmark_analyzer/src/output/comparison_result.rs new file mode 100644 index 00000000..7f25f048 --- /dev/null +++ b/benchmark_analyzer/src/output/comparison_result.rs @@ -0,0 +1,16 @@ +//! +//! Result of comparing two benchmarks. +//! + +use super::file::File; + +/// +/// Result of comparing two benchmarks. +/// +pub enum Output { + /// Benchmark output is a single unnamed file. + SingleFile(String), + /// Benchmark output is structured as a file tree, relative to some + /// user-provided output directory. + MultipleFiles(Vec), +} diff --git a/benchmark_analyzer/src/output/file.rs b/benchmark_analyzer/src/output/file.rs new file mode 100644 index 00000000..8813c0aa --- /dev/null +++ b/benchmark_analyzer/src/output/file.rs @@ -0,0 +1,15 @@ +//! +//! Represents a single benchmark output file in a set of many. +//! + +use std::path::PathBuf; + +/// +/// Represents a single benchmark output file in a set of many. +/// +pub struct File { + /// Path to this file relative to user-provided root. + pub path: PathBuf, + /// File contents. + pub contents: String, +} diff --git a/benchmark_analyzer/src/output/format/csv.rs b/benchmark_analyzer/src/output/format/csv.rs new file mode 100644 index 00000000..52c3fa12 --- /dev/null +++ b/benchmark_analyzer/src/output/format/csv.rs @@ -0,0 +1,88 @@ +//! +//! Serializing benchmark data to CSV. +//! + +use std::fmt::Write as _; + +use crate::model::benchmark::test::metadata::Metadata as TestMetadata; +use crate::model::benchmark::test::selector::Selector; +use crate::model::benchmark::test::Test; +use crate::model::benchmark::Benchmark; +use crate::output::IBenchmarkSerializer; +use crate::output::Output; + +/// +/// Serialize the benchmark to CSV in the following format: +/// "group", "codegen", "version", "optimizations", "path", "case", "input", "size", "cycles", "ergs", "gas"" +/// +#[derive(Default)] +pub struct Csv; + +impl IBenchmarkSerializer for Csv { + type Err = std::fmt::Error; + + fn serialize_to_string(&self, benchmark: &Benchmark) -> Result { + let mut result = String::with_capacity(estimate_csv_size(benchmark)); + result.push_str( + r#""group", "codegen", "version", "optimizations", "path", "case", "input", "size", "cycles", "ergs", "gas""#, + ); + + result.push('\n'); + for Test { + metadata: + TestMetadata { + tags, + selector: Selector { path, case, input }, + }, + codegen_groups, + } in benchmark.tests.values() + { + for (codegen, codegen_group) in codegen_groups { + for (version, versioned_group) in &codegen_group.versioned_groups { + for ( + optimizations, + crate::Executable { + run: + crate::Run { + size, + cycles, + ergs, + gas, + }, + .. + }, + ) in &versioned_group.executables + { + let tags = { + let mut tags = tags.clone(); + tags.sort(); + tags.join(" ") + }; + let size_str = size.map(|s| s.to_string()).unwrap_or_default(); + let input = input.clone().map(|s| s.to_string()).unwrap_or_default(); + let case = case.as_deref().unwrap_or_default(); + writeln!( + &mut result, + r#""{tags}", "{codegen}", "{version}", "{optimizations}", "{path}", "{case}", "{input}", {size_str}, {cycles}, {ergs}, {gas}"#, + )?; + } + } + } + } + Ok(Output::SingleFile(result)) + } +} + +fn estimate_csv_line_length() -> usize { + let number_fields = 4; + let number_field_estimated_max_length = 15; + let group_name_estimated_max = 10; + let test_name_estimated_max = 300; + group_name_estimated_max + + test_name_estimated_max + + number_fields * number_field_estimated_max_length +} + +fn estimate_csv_size(benchmark: &Benchmark) -> usize { + (benchmark.tests.len() + 1) * estimate_csv_line_length() +} diff --git a/benchmark_analyzer/src/output/format/json/lnt/benchmark/machine.rs b/benchmark_analyzer/src/output/format/json/lnt/benchmark/machine.rs new file mode 100644 index 00000000..8536b686 --- /dev/null +++ b/benchmark_analyzer/src/output/format/json/lnt/benchmark/machine.rs @@ -0,0 +1,20 @@ +//! +//! Description of the `machine` section in the JSON file generated for LNT. +//! See https://llvm.org/docs/lnt/importing_data.html +//! + +/// +/// Description of the `machine` section in the JSON file generated for LNT. +/// See https://llvm.org/docs/lnt/importing_data.html +/// +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +pub struct Machine { + /// Machine name, for example "LNT-AArch64-A53-O3__clang_DEV__aarch64". + pub name: String, + /// Target name, for example "eravm" or "solc". + pub target: era_compiler_common::Target, + /// Optimizations level, for example "+M3B3". + pub optimizations: String, + /// Type of solc, for example, "zksync". + pub toolchain: String, +} diff --git a/benchmark_analyzer/src/output/format/json/lnt/benchmark/mod.rs b/benchmark_analyzer/src/output/format/json/lnt/benchmark/mod.rs new file mode 100644 index 00000000..2e8fda40 --- /dev/null +++ b/benchmark_analyzer/src/output/format/json/lnt/benchmark/mod.rs @@ -0,0 +1,30 @@ +//! Root benchmark structure describing a single JSON file passed to LNT. +//! One such file is generated for every machine configuration. +//! See https://llvm.org/docs/lnt/importing_data.html + +pub mod machine; +pub mod run_description; +pub mod test_description; + +use machine::Machine; +use run_description::RunDescription; +use test_description::TestDescription; + +use crate::BenchmarkVersion; + +/// +/// Root benchmark structure describing a single JSON file passed to LNT. +/// One such file is generated for every machine configuration. +/// See https://llvm.org/docs/lnt/importing_data.html +/// +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +pub struct LntBenchmark { + /// Benchmark format version + pub format_version: BenchmarkVersion, + /// Machine description is used as a group identifier + pub machine: Machine, + /// Describes the runtime benchmark characteristics, for example, when it has started and when it has ended + pub run: RunDescription, + /// Tests grouped in this benchmark. + pub tests: Vec, +} diff --git a/benchmark_analyzer/src/output/format/json/lnt/benchmark/run_description.rs b/benchmark_analyzer/src/output/format/json/lnt/benchmark/run_description.rs new file mode 100644 index 00000000..bb0ae38d --- /dev/null +++ b/benchmark_analyzer/src/output/format/json/lnt/benchmark/run_description.rs @@ -0,0 +1,17 @@ +//! +//! Description of the benchmark run in a JSON file passed to LNT. +//! + +use chrono::DateTime; +use chrono::Utc; + +/// +/// Description of the benchmark run in a JSON file passed to LNT. +/// +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +pub struct RunDescription { + /// Time when benchmark run was started. + pub start_time: DateTime, + /// Time when benchmark run was finished. + pub end_time: DateTime, +} diff --git a/benchmark_analyzer/src/output/format/json/lnt/benchmark/test_description.rs b/benchmark_analyzer/src/output/format/json/lnt/benchmark/test_description.rs new file mode 100644 index 00000000..17eb3371 --- /dev/null +++ b/benchmark_analyzer/src/output/format/json/lnt/benchmark/test_description.rs @@ -0,0 +1,18 @@ +//! +//! Description of a single measurement in a JSON file passed to LNT. +//! + +use crate::model::benchmark::test::codegen::versioned::executable::run::Run; + +/// +/// Description of a single measurement in a JSON file passed to LNT. +/// +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +pub struct TestDescription { + /// A unique identifier of the test, incorporating language version, optimization levels and so on. + /// See [crate::output::format::json::lnt::test_name]. + pub name: String, + /// Measurements: gas, ergs, cycles, and size for contract deploys. + #[serde(flatten)] + pub measurements: Run, +} diff --git a/benchmark_analyzer/src/output/format/json/lnt/error.rs b/benchmark_analyzer/src/output/format/json/lnt/error.rs new file mode 100644 index 00000000..1b9e73ac --- /dev/null +++ b/benchmark_analyzer/src/output/format/json/lnt/error.rs @@ -0,0 +1,25 @@ +//! +//! Errors occuring during generation of LNT-compatible JSON files. +//! + +/// +/// Errors occuring during generation of LNT-compatible JSON files. +/// +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum LntSerializationError { + /// + /// No instance of [crate::model::context::Context] is provided. + /// + NoContext, +} + +impl std::fmt::Display for LntSerializationError { + #[allow(unreachable_patterns)] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + LntSerializationError::NoContext => f.write_str("LNT backend requires explicitly passed benchmark context, but no context was provided."), + _ => f.write_fmt(format_args!("{self:?}")), + } + } +} +impl std::error::Error for LntSerializationError {} diff --git a/benchmark_analyzer/src/output/format/json/lnt/mod.rs b/benchmark_analyzer/src/output/format/json/lnt/mod.rs new file mode 100644 index 00000000..be2d1c1e --- /dev/null +++ b/benchmark_analyzer/src/output/format/json/lnt/mod.rs @@ -0,0 +1,127 @@ +//! +//! JSON format compatible with LNT. +//! + +pub mod benchmark; +pub mod error; + +use std::collections::BTreeMap; +use std::path::PathBuf; + +use benchmark::machine::Machine; +use benchmark::run_description::RunDescription; +use benchmark::test_description::TestDescription; +use benchmark::LntBenchmark; +use error::LntSerializationError; + +use crate::model::benchmark::test::metadata::Metadata as TestMetadata; +use crate::model::benchmark::test::selector::Selector; +use crate::model::benchmark::test::Test; +use crate::model::benchmark::Benchmark; +use crate::output::format::json::make_json_file; +use crate::output::IBenchmarkSerializer; +use crate::output::Output; + +/// +/// Serialize the benchmark to a set of JSON files compatible with LNT format. +/// +#[derive(Default)] +pub struct JsonLNT; + +/// +/// Generate the test name for a measurement, containing a unique test identifier. +/// +fn test_name(selector: &Selector, version: impl std::fmt::Display) -> String { + fn shorten_file_name(name: &str) -> String { + let path_buf = PathBuf::from(name); + path_buf + .file_name() + .expect("Always valid") + .to_str() + .expect("Always valid") + .to_string() + } + let Selector { path, case, input } = selector; + let short_path = shorten_file_name(path); + let short_input = match input { + Some(crate::Input::Deployer { + contract_identifier, + }) => Some(crate::Input::Deployer { + contract_identifier: shorten_file_name(contract_identifier), + }), + _ => input.clone(), + }; + format!( + "{} {version}", + Selector { + path: short_path.to_string(), + case: case.clone(), + input: short_input, + } + ) +} + +impl IBenchmarkSerializer for JsonLNT { + type Err = LntSerializationError; + + fn serialize_to_string(&self, benchmark: &Benchmark) -> anyhow::Result { + let mut files: BTreeMap = Default::default(); + + let context = if let Some(context) = &benchmark.metadata.context { + context + } else { + return Err(LntSerializationError::NoContext); + }; + + for Test { + metadata: TestMetadata { selector, .. }, + codegen_groups, + } in benchmark.tests.values() + { + for (codegen, codegen_group) in codegen_groups { + for (version, versioned_group) in &codegen_group.versioned_groups { + for ( + optimizations, + crate::Executable { + run: measurements, .. + }, + ) in &versioned_group.executables + { + let machine_name = format!("{}-{codegen}-{optimizations}", context.machine); + + let machine = Machine { + name: context.machine.clone(), + target: context.target, + optimizations: optimizations.to_owned(), + toolchain: context.toolchain.clone(), + }; + let run = RunDescription { + start_time: benchmark.metadata.start, + end_time: benchmark.metadata.end, + }; + files + .entry(machine_name) + .or_insert(LntBenchmark { + format_version: benchmark.metadata.version.clone(), + machine, + run, + tests: vec![], + }) + .tests + .push(TestDescription { + name: test_name(selector, version), + measurements: measurements.clone(), + }); + } + } + } + } + + Ok(Output::MultipleFiles( + files + .iter() + .map(|(key, value)| make_json_file(key, value)) + .collect(), + )) + } +} diff --git a/benchmark_analyzer/src/output/format/json/mod.rs b/benchmark_analyzer/src/output/format/json/mod.rs new file mode 100644 index 00000000..3aac068d --- /dev/null +++ b/benchmark_analyzer/src/output/format/json/mod.rs @@ -0,0 +1,20 @@ +//! +//! Defines JSON-based output formats. +//! + +pub mod lnt; +pub mod native; + +use crate::output::file::File; + +/// +/// Create a new [`crate::output::File`] instance with an object serialized to JSON. +/// +pub(crate) fn make_json_file(filename: impl std::fmt::Display, object: T) -> File +where + T: Sized + serde::Serialize, +{ + let path = format!("{filename}.json").into(); + let contents = serde_json::to_string_pretty(&object).expect("Always valid"); + File { path, contents } +} diff --git a/benchmark_analyzer/src/output/format/json/native/mod.rs b/benchmark_analyzer/src/output/format/json/native/mod.rs new file mode 100644 index 00000000..42cf7f82 --- /dev/null +++ b/benchmark_analyzer/src/output/format/json/native/mod.rs @@ -0,0 +1,21 @@ +//! +//! Native JSON format that corresponds to the inner benchmark analyzer data model. +//! + +use crate::model::benchmark::Benchmark; +use crate::output::comparison_result::Output; +use crate::output::IBenchmarkSerializer; + +/// +/// Serialize the benchmark internal model to JSON using `serde` library. +/// +#[derive(Default)] +pub struct Json; + +impl IBenchmarkSerializer for Json { + type Err = serde_json::error::Error; + + fn serialize_to_string(&self, benchmark: &Benchmark) -> Result { + serde_json::to_string_pretty(benchmark).map(Output::SingleFile) + } +} diff --git a/benchmark_analyzer/src/output/format/mod.rs b/benchmark_analyzer/src/output/format/mod.rs new file mode 100644 index 00000000..4c33cf82 --- /dev/null +++ b/benchmark_analyzer/src/output/format/mod.rs @@ -0,0 +1,6 @@ +//! +//! Serialization of benchmark data in different output formats. +//! + +pub mod csv; +pub mod json; diff --git a/benchmark_analyzer/src/output/mod.rs b/benchmark_analyzer/src/output/mod.rs new file mode 100644 index 00000000..01903740 --- /dev/null +++ b/benchmark_analyzer/src/output/mod.rs @@ -0,0 +1,26 @@ +//! +//! Benchmark-analyzer output. +//! + +pub mod comparison_result; +pub mod file; +pub mod format; + +use comparison_result::Output; + +use crate::model::benchmark::Benchmark; + +/// +/// Serialization format for benchmark data. +/// +pub trait IBenchmarkSerializer { + /// + /// Type of serialization error. + /// + type Err: std::error::Error; + + /// + /// Serialize benchmark data in the selected format. + /// + fn serialize_to_string(&self, benchmark: &Benchmark) -> anyhow::Result; +} diff --git a/benchmark_analyzer/src/results/group.rs b/benchmark_analyzer/src/results/group.rs new file mode 100644 index 00000000..08b03131 --- /dev/null +++ b/benchmark_analyzer/src/results/group.rs @@ -0,0 +1,175 @@ +//! +//! A group of results +//! + +use crate::model::evm_interpreter; +use regex::Regex; +use std::fmt::Display; + +/// +/// Group of results. +/// +#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] +pub enum Group<'a> { + /// A group with EVM interpreter tests. + EVMInterpreter { + /// Codegen used to produce executables for all tests in this group. + codegen: &'a str, + /// Optimization level used to produce executables for all tests in this group. + optimizations: &'a str, + }, + /// A default group containing all tests. + Default { + /// Codegen used to produce executables for all tests in this group. + codegen: &'a str, + /// Optimization level used to produce executables for all tests in this group. + optimizations: &'a str, + }, + /// A user-named group. + Named { + /// Group name, provided by the user in the test definition file. + name: &'a str, + /// Codegen used to produce executables for all tests in this group. + codegen: &'a str, + /// Optimization level used to produce executables for all tests in this group. + optimizations: &'a str, + }, + /// A group comparing two groups with distinct names: + /// - one belonging to a reference run, + /// - another belonging to a candidate run. + Comparison { + /// Group belonging to the reference run. + reference: Box>, + /// Group belonging to the candidate run. + candidate: Box>, + }, +} + +impl Group<'_> { + fn comparison_name(reference: &Group<'_>, candidate: &Group<'_>) -> String { + if reference.name() == candidate.name() { + format!( + "{}: {}{} vs {}{}", + reference.name(), + reference.codegen().unwrap_or_default(), + reference.optimizations().unwrap_or_default(), + candidate.codegen().unwrap_or_default(), + candidate.optimizations().unwrap_or_default(), + ) + } else { + format!("{} vs {}", reference.name(), candidate.name()) + } + } + + /// + /// Returns true if the provided regular expression matches the string representation of the group. + /// + pub fn regex_matches(&self, regex: &Regex) -> bool { + !self.is_comparison() && (regex.is_match(&self.to_string())) + } + + /// + /// Codegen used in this group. + /// + pub fn codegen(&self) -> Option { + match self { + Group::EVMInterpreter { codegen, .. } => Some(codegen.to_string()), + Group::Default { codegen, .. } => Some(codegen.to_string()), + Group::Named { codegen, .. } => Some(codegen.to_string()), + Group::Comparison { .. } => None, + } + } + + /// + /// Optimizations used in this group. + /// + pub fn optimizations(&self) -> Option { + match self { + Group::EVMInterpreter { optimizations, .. } => Some(optimizations.to_string()), + Group::Default { optimizations, .. } => Some(optimizations.to_string()), + Group::Named { optimizations, .. } => Some(optimizations.to_string()), + Group::Comparison { .. } => None, + } + } + + /// + /// Name of the group. + /// + pub fn name(&self) -> String { + match self { + Group::EVMInterpreter { .. } => "EVMInterpreter".into(), + Group::Default { .. } => "All".into(), + Group::Named { name, .. } => name.to_string(), + Group::Comparison { .. } => "Comparison".into(), + } + } + + /// Returns `true` if the group is [`Comparison`]. + /// + /// [`Comparison`]: Group::Comparison + #[must_use] + pub fn is_comparison(&self) -> bool { + matches!(self, Self::Comparison { .. }) + } +} + +impl<'a> Group<'a> { + /// + /// Create a new group provided an optional tag, codegen and optimization level. + /// + pub fn from_tag(tag: Option<&'a str>, codegen: Option<&'a str>, opt: Option<&'a str>) -> Self { + let codegen = codegen.unwrap_or_default(); + let optimizations = opt.unwrap_or_default(); + match tag { + None => Self::Default { + optimizations, + codegen, + }, + Some(group_name) if group_name == evm_interpreter::GROUP_NAME => Self::EVMInterpreter { + optimizations, + codegen, + }, + Some(name) => Self::Named { + name, + codegen, + optimizations, + }, + } + } + + /// + /// Create a new group that compares two groups with distinct names: + /// - one belonging to a reference run, + /// - another belonging to a candidate run. + /// + pub fn new_comparison(reference: &Self, candidate: &Self) -> Self { + Self::Comparison { + reference: Box::new(reference.clone()), + candidate: Box::new(candidate.clone()), + } + } +} + +impl Display for Group<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Group::EVMInterpreter { + codegen, + optimizations, + } => f.write_fmt(format_args!("{} {codegen} {optimizations}", self.name())), + Group::Default { + codegen, + optimizations, + } => f.write_fmt(format_args!("{} {codegen} {optimizations}", self.name())), + Group::Named { + name, + codegen, + optimizations, + } => f.write_fmt(format_args!("{name} {codegen} {optimizations}")), + Group::Comparison { + reference, + candidate, + } => f.write_str(&Self::comparison_name(reference, candidate)), + } + } +} diff --git a/benchmark_analyzer/src/benchmark/group/results.rs b/benchmark_analyzer/src/results/mod.rs similarity index 73% rename from benchmark_analyzer/src/benchmark/group/results.rs rename to benchmark_analyzer/src/results/mod.rs index e59efd1a..e5970591 100644 --- a/benchmark_analyzer/src/benchmark/group/results.rs +++ b/benchmark_analyzer/src/results/mod.rs @@ -2,6 +2,9 @@ //! The benchmark group results. //! +pub mod group; + +use crate::model::benchmark::test::metadata::Metadata as TestMetadata; use colored::Colorize; use std::cmp; @@ -17,9 +20,9 @@ pub struct Results<'a> { /// The size total decrease result. pub size_total: f64, /// The size negative result test names. - pub size_negatives: Vec<(f64, &'a str)>, + pub size_negatives: Vec<(f64, &'a TestMetadata)>, /// The size positive result test names. - pub size_positives: Vec<(f64, &'a str)>, + pub size_positives: Vec<(f64, &'a TestMetadata)>, /// The cycles best result. pub cycles_best: f64, @@ -28,9 +31,9 @@ pub struct Results<'a> { /// The cycles total decrease result. pub cycles_total: f64, /// The cycles negative result test names. - pub cycles_negatives: Vec<(f64, &'a str)>, + pub cycles_negatives: Vec<(f64, &'a TestMetadata)>, /// The cycles positive result test names. - pub cycles_positives: Vec<(f64, &'a str)>, + pub cycles_positives: Vec<(f64, &'a TestMetadata)>, /// The ergs best result. pub ergs_best: f64, @@ -39,9 +42,20 @@ pub struct Results<'a> { /// The ergs total decrease result. pub ergs_total: f64, /// The ergs negative result test names. - pub ergs_negatives: Vec<(f64, &'a str)>, + pub ergs_negatives: Vec<(f64, &'a TestMetadata)>, /// The ergs positive result test names. - pub ergs_positives: Vec<(f64, &'a str)>, + pub ergs_positives: Vec<(f64, &'a TestMetadata)>, + + /// The gas best result. + pub gas_best: f64, + /// The gas worst result. + pub gas_worst: f64, + /// The gas total decrease result. + pub gas_total: f64, + /// The gas negative result test names. + pub gas_negatives: Vec<(f64, &'a TestMetadata)>, + /// The gas positive result test names. + pub gas_positives: Vec<(f64, &'a TestMetadata)>, /// The EVM interpreter reference ratios. pub evm_interpreter_reference_ratios: Option>, @@ -58,20 +72,26 @@ impl<'a> Results<'a> { size_best: f64, size_worst: f64, size_total: f64, - size_negatives: Vec<(f64, &'a str)>, - size_positives: Vec<(f64, &'a str)>, + size_negatives: Vec<(f64, &'a TestMetadata)>, + size_positives: Vec<(f64, &'a TestMetadata)>, cycles_best: f64, cycles_worst: f64, cycles_total: f64, - cycles_negatives: Vec<(f64, &'a str)>, - cycles_positives: Vec<(f64, &'a str)>, + cycles_negatives: Vec<(f64, &'a TestMetadata)>, + cycles_positives: Vec<(f64, &'a TestMetadata)>, ergs_best: f64, ergs_worst: f64, ergs_total: f64, - ergs_negatives: Vec<(f64, &'a str)>, - ergs_positives: Vec<(f64, &'a str)>, + ergs_negatives: Vec<(f64, &'a TestMetadata)>, + ergs_positives: Vec<(f64, &'a TestMetadata)>, + + gas_best: f64, + gas_worst: f64, + gas_total: f64, + gas_negatives: Vec<(f64, &'a TestMetadata)>, + gas_positives: Vec<(f64, &'a TestMetadata)>, ) -> Self { Self { size_best, @@ -92,6 +112,12 @@ impl<'a> Results<'a> { ergs_negatives, ergs_positives, + gas_best, + gas_worst, + gas_total, + gas_negatives, + gas_positives, + evm_interpreter_reference_ratios: None, evm_interpreter_candidate_ratios: None, } @@ -134,6 +160,14 @@ impl<'a> Results<'a> { std::cmp::Ordering::Equal } }); + self.gas_negatives.sort_by(|a, b| { + if a.0 > b.0 { + std::cmp::Ordering::Less + } else { + std::cmp::Ordering::Equal + } + }); + self.size_positives.sort_by(|a, b| { if a.0 < b.0 { std::cmp::Ordering::Less @@ -155,6 +189,13 @@ impl<'a> Results<'a> { std::cmp::Ordering::Equal } }); + self.gas_positives.sort_by(|a, b| { + if a.0 < b.0 { + std::cmp::Ordering::Less + } else { + std::cmp::Ordering::Equal + } + }); } /// @@ -168,7 +209,7 @@ impl<'a> Results<'a> { self.size_negatives.len() ); for (value, path) in self.size_negatives.iter().take(count) { - println!("{:010}: {}", Self::format_f64(*value), path); + println!("{:010}: {}", Self::format_f64(*value), path.selector); } println!(); println!( @@ -178,7 +219,7 @@ impl<'a> Results<'a> { self.cycles_negatives.len() ); for (value, path) in self.cycles_negatives.iter().take(count) { - println!("{:010}: {}", Self::format_f64(*value), path); + println!("{:010}: {}", Self::format_f64(*value), path.selector); } println!(); println!( @@ -188,9 +229,20 @@ impl<'a> Results<'a> { self.ergs_negatives.len() ); for (value, path) in self.ergs_negatives.iter().take(count) { - println!("{:010}: {}", Self::format_f64(*value), path); + println!("{:010}: {}", Self::format_f64(*value), path.selector); } println!(); + println!( + "Group '{}' gas (-%) worst {} out of {}:", + group_name, + count, + self.gas_negatives.len() + ); + for (value, path) in self.gas_negatives.iter().take(count) { + println!("{:010}: {}", Self::format_f64(*value), path.selector); + } + println!(); + println!( "Group '{}' size (-%) best {} out of {}:", group_name, @@ -198,7 +250,7 @@ impl<'a> Results<'a> { self.size_positives.len() ); for (value, path) in self.size_positives.iter().take(count) { - println!("{:010}: {}", Self::format_f64(*value), path); + println!("{:010}: {}", Self::format_f64(*value), path.selector); } println!(); println!( @@ -208,7 +260,7 @@ impl<'a> Results<'a> { self.cycles_positives.len() ); for (value, path) in self.cycles_positives.iter().take(count) { - println!("{:010}: {}", Self::format_f64(*value), path); + println!("{:010}: {}", Self::format_f64(*value), path.selector); } println!(); println!( @@ -218,7 +270,17 @@ impl<'a> Results<'a> { self.ergs_positives.len() ); for (value, path) in self.ergs_positives.iter().take(count) { - println!("{:010}: {}", Self::format_f64(*value), path); + println!("{:010}: {}", Self::format_f64(*value), path.selector); + } + println!(); + println!( + "Group '{}' gas (-%) best {} out of {}:", + group_name, + count, + self.gas_positives.len() + ); + for (value, path) in self.gas_positives.iter().take(count) { + println!("{:010}: {}", Self::format_f64(*value), path.selector); } println!(); } @@ -234,77 +296,106 @@ impl<'a> Results<'a> { w, "╔═╡ {} ╞{}╡ {} ╞═╗", "Size (-%)".bright_white(), - "═".repeat(cmp::max(24 - group_name.len(), 0)), + "═".repeat(cmp::max(44 - group_name.len(), 0)), group_name.bright_white() )?; writeln!( w, - "║ {:33} {:07} ║", + "║ {:53} {:07} ║", "Best".bright_white(), Self::format_f64(self.size_best) )?; writeln!( w, - "║ {:33} {:07} ║", + "║ {:53} {:07} ║", "Worst".bright_white(), Self::format_f64(self.size_worst) )?; writeln!( w, - "║ {:33} {:07} ║", + "║ {:53} {:07} ║", "Total".bright_white(), Self::format_f64(self.size_total) )?; + writeln!( w, "╠═╡ {} ╞{}╡ {} ╞═╣", "Cycles (-%)".bright_white(), - "═".repeat(cmp::max(22 - group_name.len(), 0)), + "═".repeat(cmp::max(42 - group_name.len(), 0)), group_name.bright_white() )?; writeln!( w, - "║ {:33} {:07} ║", + "║ {:53} {:07} ║", "Best".bright_white(), Self::format_f64(self.cycles_best) )?; writeln!( w, - "║ {:33} {:07} ║", + "║ {:53} {:07} ║", "Worst".bright_white(), Self::format_f64(self.cycles_worst) )?; writeln!( w, - "║ {:33} {:07} ║", + "║ {:53} {:07} ║", "Total".bright_white(), Self::format_f64(self.cycles_total) )?; + writeln!( w, "╠═╡ {} ╞{}╡ {} ╞═╣", "Ergs (-%)".bright_white(), - "═".repeat(cmp::max(24 - group_name.len(), 0)), + "═".repeat(cmp::max(44 - group_name.len(), 0)), group_name.bright_white() )?; writeln!( w, - "║ {:33} {:07} ║", + "║ {:53} {:07} ║", "Best".bright_white(), Self::format_f64(self.ergs_best) )?; writeln!( w, - "║ {:33} {:07} ║", + "║ {:53} {:07} ║", "Worst".bright_white(), Self::format_f64(self.ergs_worst) )?; writeln!( w, - "║ {:33} {:07} ║", + "║ {:53} {:07} ║", "Total".bright_white(), Self::format_f64(self.ergs_total) )?; + + writeln!( + w, + "╠══╡ {} ╞{}╡ {} ╞═╣", + "Gas (-%)".bright_white(), + "═".repeat(cmp::max(44 - group_name.len(), 0)), + group_name.bright_white() + )?; + writeln!( + w, + "║ {:53} {:07} ║", + "Best".bright_white(), + Self::format_f64(self.gas_best) + )?; + writeln!( + w, + "║ {:53} {:07} ║", + "Worst".bright_white(), + Self::format_f64(self.gas_worst) + )?; + writeln!( + w, + "║ {:53} {:07} ║", + "Total".bright_white(), + Self::format_f64(self.gas_total) + )?; + if let (Some(gas_reference_ratios), Some(gas_candidate_ratios)) = ( self.evm_interpreter_reference_ratios.as_deref(), self.evm_interpreter_candidate_ratios.as_deref(), @@ -313,7 +404,7 @@ impl<'a> Results<'a> { w, "╠═╡ {} ╞{}╡ {} ╞═╣", "Ergs/gas".bright_white(), - "═".repeat(cmp::max(25 - group_name.len(), 0)), + "═".repeat(cmp::max(45 - group_name.len(), 0)), group_name.bright_white() )?; for (opcode, reference_ratio) in gas_reference_ratios.iter() { @@ -333,7 +424,7 @@ impl<'a> Results<'a> { writeln!( w, - "║ {:32} {} ║", + "║ {:52} {} ║", if is_positive { opcode.green() } else if is_negative { @@ -355,7 +446,7 @@ impl<'a> Results<'a> { w, "╠═╡ {} ╞{}╡ {} ╞═╣", "Ergs/gas (-%)".bright_white(), - "═".repeat(cmp::max(20 - group_name.len(), 0)), + "═".repeat(cmp::max(40 - group_name.len(), 0)), group_name.bright_white() )?; for (opcode, reference_ratio) in gas_reference_ratios.iter() { @@ -378,7 +469,7 @@ impl<'a> Results<'a> { writeln!( w, - "║ {:32} {} ║", + "║ {:52} {} ║", if is_positive { opcode.green() } else if is_negative { @@ -397,7 +488,10 @@ impl<'a> Results<'a> { } } } - writeln!(w, "╚═══════════════════════════════════════════╝")?; + writeln!( + w, + "╚═══════════════════════════════════════════════════════════════╝" + )?; Ok(()) } diff --git a/benchmark_analyzer/src/util/btreemap.rs b/benchmark_analyzer/src/util/btreemap.rs new file mode 100644 index 00000000..cdf1c816 --- /dev/null +++ b/benchmark_analyzer/src/util/btreemap.rs @@ -0,0 +1,164 @@ +//! +//! Utility functions +//! + +use std::collections::BTreeMap; + +/// Intersects two `BTreeMap` instances and merges their entries using a +/// specified merger function. +/// +/// # Arguments +/// +/// * `map1` - The first `BTreeMap` containing keys of type `K` and values of +/// type `V1`. +/// * `map2` - The second `BTreeMap` containing keys of type `K` and values of +/// type `V2`. This map is modified during the intersection. +/// * `merger` - A closure that takes a key of type `K`, and a value from each +/// map (`V1` and `V2`), and returns a merged result of type `R`. +/// +/// # Returns +/// +/// An iterator that yields merged results of type `R` for each intersecting key +/// from the maps. +/// +/// # Example +/// +/// ```rust +/// use benchmark_analyzer::util::btreemap::intersect_map; +/// +/// let first = [(1, 1), (2, 2), (3, 3)]; +/// let second = [(1, 10), (3, 30)]; +/// let expected: Vec<_> = [111, 333].into(); +/// assert_eq!( +/// intersect_map(first.into(), second.into(), |k, v1, v2| 100 * k + v1 + v2) +/// .collect::>(), +/// expected +/// ) +/// ``` + +pub fn intersect_map( + map1: BTreeMap, + mut map2: BTreeMap, + merger: impl Fn(K, V1, V2) -> R + 'static, +) -> impl Iterator +where + K: Ord, +{ + map1.into_iter().filter_map(move |(key, value1)| { + map2.remove(&key).map(|value2| merger(key, value1, value2)) + }) +} + +/// Perform a cross join on two `BTreeMap` instances, applying a +/// selector function to each pair of keys. If the selector function returns an +/// `Option::Some`, it includes the transformed key along with cloned values +/// from both maps into the result vector. +/// +/// # Arguments +/// +/// * `map1` - A reference to the first `BTreeMap` with key type `K` and value +/// type `V1`. +/// * `map2` - A reference to the second `BTreeMap` with key type `K` and value +/// type `V2`. +/// * `selector` - A closure or function that takes two keys (one from each map) +/// and returns an `Option`, where `N` is the type of the transformed key +/// to be included in the result if the option is `Some`. +/// +/// # Returns +/// +/// A vector containing tuples of the transformed key type `N`, and values from +/// both maps (`V1` and `V2`), corresponding to each pair of matched keys for +/// which the selector function has returned `Some`. +/// +/// # Type Parameters +/// +/// * `K` - The type of key used in both input maps, which must implement `Ord`. +/// * `N` - The type for transformed key pairs. +/// * `V1` - The type of value in the first map, which must implement `Clone`. +/// * `V2` - The type of value in the second map, which must implement `Clone`. +/// +/// # Example +/// +/// ```rust +/// use std::collections::BTreeMap; +/// +/// use benchmark_analyzer::util::btreemap::cross_join_filter_map; +/// +/// // Assume we have two BTreeMaps. +/// let map1: BTreeMap<_, _> = [(1, "a"), (2, "b")].iter().cloned().collect(); +/// let map2: BTreeMap<_, _> = [(1, "x"), (2, "y")].iter().cloned().collect(); +/// +/// // Define a selector function that combines the keys. +/// let selector = |k1: &i32, k2: &i32| if k1 == k2 { Some(k1 + k2) } else { None }; +/// +/// // Execute the cross join with filtering using the selector. +/// let result = cross_join_filter_map(&map1, &map2, selector); +/// +/// // Result now contains: [(2, "a", "x"), (4, "b", "y")] +/// assert_eq!(result, vec![(2, "a", "x"), (4, "b", "y")]); +/// ``` + +pub fn cross_join_filter_map( + map1: &BTreeMap, + map2: &BTreeMap, + selector: impl Fn(&K, &K) -> Option, +) -> Vec<(N, V1, V2)> +where + K: Ord, + V1: Clone, + V2: Clone, +{ + let mut result: Vec<(N, V1, V2)> = Vec::new(); + + for (key1, value1) in map1 { + for (key2, value2) in map2 { + if let Some(new_key) = selector(key1, key2) { + result.push((new_key, value1.clone(), value2.clone())); + } + } + } + + result +} + +/// Returns an iterator over +/// the elements that are common to both `map1` and `map2`. +/// +/// # Arguments +/// +/// * `map1` - A BTreeMap where the keys are compared. +/// * `map2` - A mutable BTreeMap from which matching keys are removed and their values paired with those from `map1`. +/// +/// # Returns +/// +/// An iterator over tuples `(K, V1, V2)` where: +/// * `K` is the common key. +/// * `V1` is the associated value from `map1`. +/// * `V2` is the associated value from `map2`. +/// +/// The iterator only includes keys that are present in both maps. +/// +/// # Example +/// +/// ```rust +/// use benchmark_analyzer::util::btreemap::intersect_keys; +/// +/// let first = [(1, "1"), (2, "2"), (3, "3")]; +/// let second = [(1, "11"), (3, "33")]; +/// let expected: Vec<_> = [(1, "1", "11"), (3, "3", "33")].into(); +/// assert_eq!( +/// intersect_keys(first.into(), second.into()).collect::>(), +/// expected +/// ) +/// ``` +/// +pub fn intersect_keys( + map1: BTreeMap, + mut map2: BTreeMap, +) -> impl Iterator +where + K: Ord, +{ + map1.into_iter() + .filter_map(move |(key, value1)| map2.remove(&key).map(|value2| (key, value1, value2))) +} diff --git a/benchmark_analyzer/src/util/mod.rs b/benchmark_analyzer/src/util/mod.rs new file mode 100644 index 00000000..e0e4bfb0 --- /dev/null +++ b/benchmark_analyzer/src/util/mod.rs @@ -0,0 +1,5 @@ +//! +//! Utility functions. +//! + +pub mod btreemap; diff --git a/compiler_tester/Cargo.toml b/compiler_tester/Cargo.toml index 51851d13..092d386e 100644 --- a/compiler_tester/Cargo.toml +++ b/compiler_tester/Cargo.toml @@ -17,56 +17,54 @@ path = "src/compiler_tester/main.rs" doctest = false [dependencies] -structopt = { version = "0.3", default-features = false } -anyhow = "1.0" -which = "6.0" -colored = "2.1" +clap = { version = "=4.5.21", features = ["derive"] } +anyhow = "=1.0.89" +which = "=6.0.3" +colored = "=2.1.0" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -serde_yaml = "0.9" -md5 = "0.7" -hex = "0.4" -sha3 = "0.10" -ron = "0.8" -rlp = "0.5" -regex = "1.10" -glob = "0.3" -semver = { version = "1.0", features = ["serde"] } -itertools = "0.13" -once_cell = "1.19" -rayon = "1.10" -lazy_static = "1.4" -bincode = "1.3" +serde = { version = "=1.0.210", features = ["derive"] } +serde_json = "=1.0.128" +serde_yaml = "=0.9.34" +md5 = "=0.7.0" +hex = "=0.4.3" +sha3 = "=0.10.8" +ron = "=0.8.1" +rlp = "=0.5.2" +regex = "=1.11.0" +glob = "=0.3.1" +semver = { version = "=1.0.23", features = ["serde"] } +itertools = "=0.13.0" +once_cell = "=1.20.2" +rayon = "=1.10.0" +lazy_static = "=1.5.0" +bincode = "=1.3.3" +chrono = "=0.4.38" evm = { git = "https://github.com/rust-ethereum/evm", rev = "f7a23df6c478ca6a151af5f60e62944800529a61" } revm = { git = "https://github.com/bluealloy/revm", rev = "fa5650ee8a4d802f4f3557014dd157adfb074460" } -vm2 = { git = "https://github.com/matter-labs/vm2", optional = true, package = "zksync_vm2" } -zkevm_opcode_defs = { git = "https://github.com/matter-labs/era-zkevm_opcode_defs", branch = "v1.5.0" } +zkevm_opcode_defs = "=0.150.6" zkevm_tester = { git = "https://github.com/matter-labs/era-zkevm_tester", branch = "v1.5.0" } +vm2 = { git = "https://github.com/matter-labs/vm2", optional = true, package = "zksync_vm2" } era-compiler-common = { git = "https://github.com/matter-labs/era-compiler-common", branch = "main" } era-compiler-downloader = { git = "https://github.com/matter-labs/era-compiler-common", branch = "main" } era-compiler-llvm-context = { git = "https://github.com/matter-labs/era-compiler-llvm-context", branch = "main" } era-compiler-solidity = { git = "https://github.com/matter-labs/era-compiler-solidity", branch = "main" } +era-solc = { git = "https://github.com/matter-labs/era-compiler-solidity", branch = "main" } era-compiler-vyper = { git = "https://github.com/matter-labs/era-compiler-vyper", branch = "main" } -# era-compiler-common = { path = "../../era-compiler-common" } -# era-compiler-llvm-context = { path = "../../era-compiler-llvm-context" } -# era-compiler-solidity = { path = "../../era-compiler-solidity" } -# era-compiler-vyper = { path = "../../era-compiler-vyper" } - solidity-adapter = { path = "../solidity_adapter" } benchmark-analyzer = { path = "../benchmark_analyzer" } [dependencies.web3] -version = "0.19" +git = "https://github.com/jacques-kigo/rust-web3" +branch = "master" default-features = false features = ["http-rustls-tls", "test", "signing"] [dependencies.reqwest] -version = "0.11" +version = "=0.11.27" default-features = false features = ["blocking"] diff --git a/compiler_tester/src/compiler_tester/arguments/benchmark_format.rs b/compiler_tester/src/compiler_tester/arguments/benchmark_format.rs new file mode 100644 index 00000000..4bbc89e5 --- /dev/null +++ b/compiler_tester/src/compiler_tester/arguments/benchmark_format.rs @@ -0,0 +1,48 @@ +//! +//! Output format for benchmark data. +//! + +/// +/// Output format for benchmark data. +/// +#[derive(Debug, Default, Clone, PartialEq, Eq)] +pub enum BenchmarkFormat { + #[default] + /// Unstable JSON format, corresponds to the inner data model of benchmark analyzer. + Json, + /// CSV format. + Csv, + /// JSON format compatible with LNT. + JsonLNT, +} + +impl std::str::FromStr for BenchmarkFormat { + type Err = anyhow::Error; + + fn from_str(string: &str) -> Result { + match string.to_lowercase().as_str() { + "json" => Ok(Self::Json), + "json-lnt" => Ok(Self::JsonLNT), + "csv" => Ok(Self::Csv), + string => anyhow::bail!( + "Unknown benchmark format `{string}`. Supported formats: {}", + vec![Self::Json, Self::Csv] + .into_iter() + .map(|element| element.to_string().to_lowercase()) + .collect::>() + .join(", ") + ), + } + } +} + +impl std::fmt::Display for BenchmarkFormat { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let repr = match self { + BenchmarkFormat::Json => "json", + BenchmarkFormat::JsonLNT => "json-lnt", + BenchmarkFormat::Csv => "csv", + }; + f.write_str(repr) + } +} diff --git a/compiler_tester/src/compiler_tester/arguments.rs b/compiler_tester/src/compiler_tester/arguments/mod.rs similarity index 56% rename from compiler_tester/src/compiler_tester/arguments.rs rename to compiler_tester/src/compiler_tester/arguments/mod.rs index 93c77ebd..951b091b 100644 --- a/compiler_tester/src/compiler_tester/arguments.rs +++ b/compiler_tester/src/compiler_tester/arguments/mod.rs @@ -2,127 +2,130 @@ //! The compiler tester arguments. //! +pub mod benchmark_format; +pub mod validation; + use std::path::PathBuf; -use structopt::StructOpt; +use benchmark_format::BenchmarkFormat; +use clap::Parser; + +pub const ARGUMENT_BENCHMARK_CONTEXT: &str = "benchmark-context"; /// /// The compiler tester arguments. /// -#[derive(Debug, StructOpt)] -#[structopt( - name = "compiler-tester", - about = "EraVM Compiler Integration Testing Framework" -)] +#[derive(Debug, Parser)] +#[command(about, long_about = None)] pub struct Arguments { /// The logging level. - #[structopt(short = "v", long = "verbose")] - pub verbosity: bool, + #[arg(short, long)] + pub verbose: bool, /// Suppresses the output completely. - #[structopt(short = "q", long = "quiet")] + #[arg(short, long)] pub quiet: bool, /// Saves all IRs produced by compilers to `./debug/` directory. - #[structopt(short = "D", long = "debug")] + #[arg(short = 'D', long)] pub debug: bool, /// Runs tests only in modes that contain any string from the specified ones. - #[structopt(short = "m", long = "mode")] - pub modes: Vec, + #[arg(short, long)] + pub mode: Vec, /// Runs only tests whose name contains any string from the specified ones. - #[structopt(short = "p", long = "path")] - pub paths: Vec, + #[arg(short, long)] + pub path: Vec, /// Runs only tests from the specified groups. - #[structopt(short = "g", long = "group")] - pub groups: Vec, + #[structopt(short, long)] + pub group: Vec, /// The benchmark output path, if requested. - #[structopt(short = "b", long = "benchmark")] + #[structopt(short, long)] pub benchmark: Option, + /// The benchmark output format: `json`, `csv`, or `json-lnt`. + /// Using `json-lnt` requires providing the path to a JSON file describing the + /// benchmarking context via `--benchmark-context`. + #[structopt(long = "benchmark-format", default_value_t = BenchmarkFormat::Json)] + pub benchmark_format: BenchmarkFormat, + + /// The benchmark context to pass additional data to backends. + #[structopt(long = ARGUMENT_BENCHMARK_CONTEXT )] + pub benchmark_context: Option, + /// Sets the number of threads, which execute the tests concurrently. - #[structopt(short = "t", long = "threads")] + #[structopt(short, long)] pub threads: Option, /// Whether to dump the debug data for system contracts. - #[structopt(long = "dump-system")] + #[structopt(long)] pub dump_system: bool, /// Whether the deployer should be disabled. - #[structopt(long = "disable-deployer")] + #[structopt(long)] pub disable_deployer: bool, /// Whether the msg.value simulator should be disabled. - #[structopt(long = "disable-value-simulator")] + #[structopt(long)] pub disable_value_simulator: bool, - /// Path to the `zksolc` binary. + /// Path to the `zksolc` executable. /// Is set to `zksolc` by default. - #[structopt(long = "zksolc")] + #[structopt(long)] pub zksolc: Option, - /// Path to the `zkvyper` binary. + /// Path to the `zkvyper` executable. /// Is set to `zkvyper` by default. - #[structopt(long = "zkvyper")] + #[structopt(long)] pub zkvyper: Option, /// Specify the compiler toolchain. /// Available arguments: `ir-llvm`, `solc`, `solc-llvm`. /// The default for `EraVM` target is `ir-llvm`. /// The default for `EVM` target is `solc`. - #[structopt(long = "toolchain")] + #[structopt(long)] pub toolchain: Option, /// Specify the target architecture. /// Available arguments: `eravm`, `evm`. - /// The default is `eravm`. - #[structopt(long = "target", default_value = "eravm")] + #[structopt(long)] pub target: era_compiler_common::Target, /// Specify the environment to run tests on. /// Available arguments: `zk_evm`, `FastVM`, `EVMInterpreter`, `REVM`. /// The default for `EraVM` target is `zk_evm`. /// The default for `EVM` target is `EVMInterpreter`. - #[structopt(long = "environment")] + #[structopt(long)] pub environment: Option, /// Choose between `build` to compile tests only without running, and `run` to compile and run. - #[structopt(long = "workflow", default_value = "run")] + #[structopt(long, default_value_t = compiler_tester::Workflow::BuildAndRun)] pub workflow: compiler_tester::Workflow, - /// Path to the default `solc` binaries download configuration file. - #[structopt(long = "solc-bin-config-path")] + /// Path to the default `solc` executables download configuration file. + #[structopt(long)] pub solc_bin_config_path: Option, - /// Path to the default `vyper` binaries download configuration file. - #[structopt(long = "vyper-bin-config-path")] + /// Path to the default `vyper` executables download configuration file. + #[structopt(long)] pub vyper_bin_config_path: Option, /// Whether to load the system contracts builds from the specified file. - #[structopt(long = "load-system-contracts")] - pub system_contracts_load_path: Option, + #[structopt(long)] + pub load_system_contracts: Option, /// Whether to save the system contracts builds to the specified file. - #[structopt(long = "save-system-contracts")] - pub system_contracts_save_path: Option, + #[structopt(long)] + pub save_system_contracts: Option, /// Sets the `verify each` option in LLVM. - #[structopt(long = "llvm-verify-each")] + #[structopt(long)] pub llvm_verify_each: bool, /// Sets the `debug logging` option in LLVM. - #[structopt(long = "llvm-debug-logging")] + #[structopt(long)] pub llvm_debug_logging: bool, } - -impl Arguments { - /// - /// A shortcut constructor. - /// - pub fn new() -> Self { - Self::from_args() - } -} diff --git a/compiler_tester/src/compiler_tester/arguments/validation.rs b/compiler_tester/src/compiler_tester/arguments/validation.rs new file mode 100644 index 00000000..2c1eb263 --- /dev/null +++ b/compiler_tester/src/compiler_tester/arguments/validation.rs @@ -0,0 +1,28 @@ +//! +//! Validate the arguments passed from user, checking invariants that are not +//! expressed in the type system. +//! + +use super::benchmark_format::BenchmarkFormat; +use super::Arguments; + +use super::ARGUMENT_BENCHMARK_CONTEXT; + +/// +/// Validate the arguments passed from user, checking invariants that are not +/// expressed in the type system. +/// +pub fn validate_arguments(arguments: Arguments) -> anyhow::Result { + match (&arguments.benchmark_format, &arguments.benchmark_context) { + (BenchmarkFormat::JsonLNT, None) => + anyhow::bail!("Generation of LNT-compatible benchmark results in JSON format requires passing a valid context in the argument `--{ARGUMENT_BENCHMARK_CONTEXT}` to compiler tester.") + , + (BenchmarkFormat::JsonLNT, Some(_)) => (), + (_, Some(_)) => + anyhow::bail!("Only LNT backend in JSON format supports passing a valid context in the argument `--{ARGUMENT_BENCHMARK_CONTEXT}` to compiler tester.") + , + _ => (), + } + + Ok(arguments) +} diff --git a/compiler_tester/src/compiler_tester/main.rs b/compiler_tester/src/compiler_tester/main.rs index 3a540880..36e7faec 100644 --- a/compiler_tester/src/compiler_tester/main.rs +++ b/compiler_tester/src/compiler_tester/main.rs @@ -1,5 +1,5 @@ //! -//! The compiler tester binary. +//! The compiler tester executable. //! pub(crate) mod arguments; @@ -8,6 +8,9 @@ use std::path::PathBuf; use std::str::FromStr; use std::time::Instant; +use arguments::benchmark_format::BenchmarkFormat; +use arguments::validation::validate_arguments; +use clap::Parser; use colored::Colorize; use self::arguments::Arguments; @@ -19,7 +22,10 @@ const RAYON_WORKER_STACK_SIZE: usize = 16 * 1024 * 1024; /// The application entry point. /// fn main() { - let exit_code = match main_inner(Arguments::new()) { + let exit_code = match Arguments::try_parse() + .map_err(|error| anyhow::anyhow!(error)) + .and_then(main_inner) + { Ok(()) => era_compiler_common::EXIT_CODE_SUCCESS, Err(error) => { eprintln!("{error:?}"); @@ -34,6 +40,7 @@ fn main() { /// The entry point wrapper used for proper error handling. /// fn main_inner(arguments: Arguments) -> anyhow::Result<()> { + let arguments = validate_arguments(arguments)?; println!( " {} {} v{} (LLVM build {})", "Starting".bright_green().bold(), @@ -89,29 +96,18 @@ fn main_inner(arguments: Arguments) -> anyhow::Result<()> { .build_global() .expect("Thread pool configuration failure"); - let summary = compiler_tester::Summary::new(arguments.verbosity, arguments.quiet).wrap(); - - let filters = compiler_tester::Filters::new(arguments.paths, arguments.modes, arguments.groups); - - let compiler_tester = compiler_tester::CompilerTester::new( - summary.clone(), - filters, - debug_config.clone(), - arguments.workflow, - )?; - let toolchain = match (arguments.target, arguments.toolchain) { (era_compiler_common::Target::EraVM, Some(toolchain)) => toolchain, (era_compiler_common::Target::EraVM, None) => compiler_tester::Toolchain::IrLLVM, (era_compiler_common::Target::EVM, Some(toolchain)) => toolchain, (era_compiler_common::Target::EVM, None) => compiler_tester::Toolchain::Solc, }; - let binary_download_config_paths = vec![ + let executable_download_config_paths = vec![ arguments.solc_bin_config_path.unwrap_or_else(|| { PathBuf::from(match toolchain { compiler_tester::Toolchain::IrLLVM => "./configs/solc-bin-default.json", compiler_tester::Toolchain::Solc => "./configs/solc-bin-upstream.json", - compiler_tester::Toolchain::SolcLLVM => todo!(), + compiler_tester::Toolchain::SolcLLVM => "./configs/solc-bin-llvm.json", }) }), arguments @@ -141,6 +137,19 @@ fn main_inner(arguments: Arguments) -> anyhow::Result<()> { ), }; + let summary = compiler_tester::Summary::new(arguments.verbose, arguments.quiet) + .start_timer()? + .wrap(); + + let filters = compiler_tester::Filters::new(arguments.path, arguments.mode, arguments.group); + + let compiler_tester = compiler_tester::CompilerTester::new( + summary.clone(), + filters, + debug_config.clone(), + arguments.workflow, + )?; + let run_time_start = Instant::now(); println!( " {} tests with {} worker threads", @@ -156,11 +165,11 @@ fn main_inner(arguments: Arguments) -> anyhow::Result<()> { None }; let vm = compiler_tester::EraVM::new( - binary_download_config_paths, + executable_download_config_paths, PathBuf::from("./configs/solc-bin-system-contracts.json"), system_contracts_debug_config, - arguments.system_contracts_load_path, - arguments.system_contracts_save_path, + arguments.load_system_contracts, + arguments.save_system_contracts, arguments.target, )?; @@ -168,16 +177,16 @@ fn main_inner(arguments: Arguments) -> anyhow::Result<()> { arguments.disable_deployer, arguments.disable_value_simulator, ) { - (true, true) => { - compiler_tester.run_eravm::(vm) - } - (true, false) => { - compiler_tester.run_eravm::(vm) - } + (true, true) => compiler_tester + .run_eravm::(vm, toolchain), + (true, false) => compiler_tester + .run_eravm::(vm, toolchain), (false, true) => compiler_tester - .run_eravm::(vm), + .run_eravm::( + vm, toolchain, + ), (false, false) => compiler_tester - .run_eravm::(vm), + .run_eravm::(vm, toolchain), } } compiler_tester::Environment::FastVM => todo!(), @@ -188,11 +197,11 @@ fn main_inner(arguments: Arguments) -> anyhow::Result<()> { None }; let vm = compiler_tester::EraVM::new( - binary_download_config_paths, + executable_download_config_paths, PathBuf::from("./configs/solc-bin-system-contracts.json"), system_contract_debug_config, - arguments.system_contracts_load_path, - arguments.system_contracts_save_path, + arguments.load_system_contracts, + arguments.save_system_contracts, arguments.target, )?; @@ -202,12 +211,12 @@ fn main_inner(arguments: Arguments) -> anyhow::Result<()> { ) } compiler_tester::Environment::REVM => { - compiler_tester::EVM::download(binary_download_config_paths)?; + compiler_tester::EVM::download(executable_download_config_paths)?; compiler_tester.run_revm(toolchain) } }?; - let summary = compiler_tester::Summary::unwrap_arc(summary); + let summary = compiler_tester::Summary::unwrap_arc(summary).stop_timer()?; print!("{summary}"); println!( " {} running tests in {}m{:02}s", @@ -217,8 +226,29 @@ fn main_inner(arguments: Arguments) -> anyhow::Result<()> { ); if let Some(path) = arguments.benchmark { - let benchmark = summary.benchmark()?; - benchmark.write_to_file(path)?; + let context = if let Some(context_path) = arguments.benchmark_context { + Some(read_context(context_path)?) + } else { + None + }; + let benchmark = summary.benchmark(toolchain, context)?; + match arguments.benchmark_format { + BenchmarkFormat::Json => benchmark_analyzer::write_to_file( + &benchmark, + path, + benchmark_analyzer::JsonNativeSerializer, + )?, + BenchmarkFormat::Csv => benchmark_analyzer::write_to_file( + &benchmark, + path, + benchmark_analyzer::CsvSerializer, + )?, + BenchmarkFormat::JsonLNT => benchmark_analyzer::write_to_file( + &benchmark, + path, + benchmark_analyzer::JsonLNTSerializer, + )?, + } } if !summary.is_successful() { @@ -228,6 +258,24 @@ fn main_inner(arguments: Arguments) -> anyhow::Result<()> { Ok(()) } +/// +/// Reads the benchmarking context from a JSON file and validates its correctness. +/// Benchmarking context provides additional information about benchmarking that +/// will be used to generate a report. +/// +/// # Errors +/// +/// This function will return an error if +/// - file can't be read, +/// - deserialization from JSON file failed, +/// - the context validation failed. +fn read_context(path: PathBuf) -> anyhow::Result { + let contents = std::fs::read_to_string(path)?; + let context: benchmark_analyzer::BenchmarkContext = serde_json::de::from_str(&contents)?; + benchmark_analyzer::validate_context(&context)?; + Ok(context) +} + #[cfg(test)] mod tests { use std::path::PathBuf; @@ -239,13 +287,15 @@ mod tests { std::env::set_current_dir("..").expect("Change directory failed"); let arguments = Arguments { - verbosity: false, + verbose: false, quiet: false, debug: false, - modes: vec!["Y+M3B3 0.8.26".to_owned()], - paths: vec!["tests/solidity/simple/default.sol".to_owned()], - groups: vec![], + mode: vec!["Y+M3B3 0.8.28".to_owned()], + path: vec!["tests/solidity/simple/default.sol".to_owned()], + group: vec![], benchmark: None, + benchmark_format: crate::BenchmarkFormat::Json, + benchmark_context: None, threads: Some(1), dump_system: false, disable_deployer: false, @@ -260,8 +310,8 @@ mod tests { workflow: compiler_tester::Workflow::BuildAndRun, solc_bin_config_path: Some(PathBuf::from("./configs/solc-bin-default.json")), vyper_bin_config_path: Some(PathBuf::from("./configs/vyper-bin-default.json")), - system_contracts_load_path: Some(PathBuf::from("system-contracts-stable-build")), - system_contracts_save_path: None, + load_system_contracts: Some(PathBuf::from("system-contracts-stable-build")), + save_system_contracts: None, llvm_verify_each: false, llvm_debug_logging: false, }; diff --git a/compiler_tester/src/compilers/eravm/mod.rs b/compiler_tester/src/compilers/eravm/mod.rs index e47a77e3..39745912 100644 --- a/compiler_tester/src/compilers/eravm/mod.rs +++ b/compiler_tester/src/compilers/eravm/mod.rs @@ -4,10 +4,9 @@ pub mod mode; -use std::collections::BTreeMap; use std::collections::HashMap; -use era_compiler_solidity::CollectableError; +use era_solc::CollectableError; use crate::compilers::mode::Mode; use crate::compilers::Compiler; @@ -27,7 +26,7 @@ impl Compiler for EraVMCompiler { &self, _test_path: String, sources: Vec<(String, String)>, - _libraries: BTreeMap>, + libraries: era_solc::StandardJsonInputLibraries, _mode: &Mode, llvm_options: Vec, debug_config: Option, @@ -41,12 +40,7 @@ impl Compiler for EraVMCompiler { let project = era_compiler_solidity::Project::try_from_eravm_assembly_sources( sources .into_iter() - .map(|(path, source)| { - ( - path, - era_compiler_solidity::SolcStandardJsonInputSource::from(source), - ) - }) + .map(|(path, source)| (path, era_solc::StandardJsonInputSource::from(source))) .collect(), None, )?; @@ -58,12 +52,13 @@ impl Compiler for EraVMCompiler { era_compiler_llvm_context::OptimizerSettings::none(), llvm_options, true, - None, debug_config.clone(), )?; - build.collect_errors()?; + build.check_errors()?; + let build = build.link(libraries.as_linker_symbols()?); + build.check_errors()?; let builds = build - .contracts + .results .into_iter() .map(|(path, result)| Ok((path, result.expect("Always valid").build))) .collect::>>()?; @@ -75,7 +70,7 @@ impl Compiler for EraVMCompiler { &self, _test_path: String, _sources: Vec<(String, String)>, - _libraries: BTreeMap>, + _libraries: era_solc::StandardJsonInputLibraries, _mode: &Mode, _test_params: Option<&solidity_adapter::Params>, _llvm_options: Vec, diff --git a/compiler_tester/src/compilers/eravm/mode.rs b/compiler_tester/src/compilers/eravm/mode.rs index 050c1f41..98dfbac6 100644 --- a/compiler_tester/src/compilers/eravm/mode.rs +++ b/compiler_tester/src/compilers/eravm/mode.rs @@ -2,10 +2,12 @@ //! The compiler tester EraVM mode. //! +use crate::compilers::mode::imode::IMode; + /// /// The compiler tester EraVM mode. /// -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, Eq, PartialEq)] pub struct Mode {} impl std::fmt::Display for Mode { @@ -13,3 +15,16 @@ impl std::fmt::Display for Mode { write!(f, "") } } +impl IMode for Mode { + fn optimizations(&self) -> Option { + None + } + + fn codegen(&self) -> Option { + None + } + + fn version(&self) -> Option { + None + } +} diff --git a/compiler_tester/src/compilers/llvm/mod.rs b/compiler_tester/src/compilers/llvm/mod.rs index e635d0c3..55d24a2f 100644 --- a/compiler_tester/src/compilers/llvm/mod.rs +++ b/compiler_tester/src/compilers/llvm/mod.rs @@ -4,10 +4,9 @@ pub mod mode; -use std::collections::BTreeMap; use std::collections::HashMap; -use era_compiler_solidity::CollectableError; +use era_solc::CollectableError; use crate::compilers::mode::Mode; use crate::compilers::Compiler; @@ -40,7 +39,7 @@ impl Compiler for LLVMCompiler { &self, _test_path: String, sources: Vec<(String, String)>, - _libraries: BTreeMap>, + libraries: era_solc::StandardJsonInputLibraries, mode: &Mode, llvm_options: Vec, debug_config: Option, @@ -53,16 +52,14 @@ impl Compiler for LLVMCompiler { .0 .clone(); + let linker_symbols = libraries.as_linker_symbols()?; + let project = era_compiler_solidity::Project::try_from_llvm_ir_sources( sources .into_iter() - .map(|(path, source)| { - ( - path, - era_compiler_solidity::SolcStandardJsonInputSource::from(source), - ) - }) + .map(|(path, source)| (path, era_solc::StandardJsonInputSource::from(source))) .collect(), + libraries, None, )?; @@ -73,12 +70,13 @@ impl Compiler for LLVMCompiler { mode.llvm_optimizer_settings.to_owned(), llvm_options, true, - None, debug_config.clone(), )?; - build.collect_errors()?; + build.check_errors()?; + let build = build.link(linker_symbols); + build.check_errors()?; let builds = build - .contracts + .results .into_iter() .map(|(path, result)| Ok((path, result.expect("Always valid").build))) .collect::>>()?; @@ -90,7 +88,7 @@ impl Compiler for LLVMCompiler { &self, _test_path: String, sources: Vec<(String, String)>, - _libraries: BTreeMap>, + _libraries: era_solc::StandardJsonInputLibraries, mode: &Mode, _test_params: Option<&solidity_adapter::Params>, llvm_options: Vec, @@ -107,34 +105,27 @@ impl Compiler for LLVMCompiler { let project = era_compiler_solidity::Project::try_from_llvm_ir_sources( sources .into_iter() - .map(|(path, source)| { - ( - path, - era_compiler_solidity::SolcStandardJsonInputSource::from(source), - ) - }) + .map(|(path, source)| (path, era_solc::StandardJsonInputSource::from(source))) .collect(), + era_solc::StandardJsonInputLibraries::default(), None, )?; let build = project.compile_to_evm( &mut vec![], + era_compiler_common::HashType::Ipfs, mode.llvm_optimizer_settings.to_owned(), llvm_options, - era_compiler_common::HashType::Ipfs, None, debug_config.clone(), )?; - build.collect_errors()?; + build.check_errors()?; let builds: HashMap = build - .contracts + .results .into_iter() .map(|(path, build)| { let build = build.expect("Always valid"); - let build = EVMBuild::new( - era_compiler_llvm_context::EVMBuild::default(), - build.runtime_build, - ); + let build = EVMBuild::new(vec![], build.runtime_build); (path, build) }) .collect(); diff --git a/compiler_tester/src/compilers/llvm/mode.rs b/compiler_tester/src/compilers/llvm/mode.rs index 0b7cea09..54ec79a5 100644 --- a/compiler_tester/src/compilers/llvm/mode.rs +++ b/compiler_tester/src/compilers/llvm/mode.rs @@ -2,6 +2,7 @@ //! The compiler tester LLVM mode. //! +use crate::compilers::mode::imode::IMode; use crate::compilers::mode::llvm_options::LLVMOptions; use crate::compilers::mode::Mode as ModeWrapper; @@ -9,7 +10,7 @@ use crate::compilers::mode::Mode as ModeWrapper; /// /// The compiler tester LLVM mode. /// -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Mode { /// The optimizer settings. pub llvm_optimizer_settings: era_compiler_llvm_context::OptimizerSettings, @@ -45,8 +46,22 @@ impl Mode { } } +impl IMode for Mode { + fn optimizations(&self) -> Option { + Some(format!("{}", self.llvm_optimizer_settings)) + } + + fn codegen(&self) -> Option { + None + } + + fn version(&self) -> Option { + None + } +} + impl std::fmt::Display for Mode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.llvm_optimizer_settings,) + write!(f, "{}", self.optimizations().unwrap_or_default(),) } } diff --git a/compiler_tester/src/compilers/mod.rs b/compiler_tester/src/compilers/mod.rs index c29d7ee9..08566f4f 100644 --- a/compiler_tester/src/compilers/mod.rs +++ b/compiler_tester/src/compilers/mod.rs @@ -10,8 +10,6 @@ pub mod solidity; pub mod vyper; pub mod yul; -use std::collections::BTreeMap; - use crate::vm::eravm::input::Input as EraVMInput; use crate::vm::evm::input::Input as EVMInput; @@ -28,7 +26,7 @@ pub trait Compiler: Send + Sync + 'static { &self, test_path: String, sources: Vec<(String, String)>, - libraries: BTreeMap>, + libraries: era_solc::StandardJsonInputLibraries, mode: &Mode, llvm_options: Vec, debug_config: Option, @@ -41,7 +39,7 @@ pub trait Compiler: Send + Sync + 'static { &self, test_path: String, sources: Vec<(String, String)>, - libraries: BTreeMap>, + libraries: era_solc::StandardJsonInputLibraries, mode: &Mode, test_params: Option<&solidity_adapter::Params>, llvm_options: Vec, diff --git a/compiler_tester/src/compilers/mode/imode.rs b/compiler_tester/src/compilers/mode/imode.rs new file mode 100644 index 00000000..e479d05a --- /dev/null +++ b/compiler_tester/src/compilers/mode/imode.rs @@ -0,0 +1,31 @@ +//! +//! Common interface for different compiler modes. +//! + +/// +/// Common interface for different compiler modes. +/// +pub trait IMode { + /// Optimization level, if applicable. + fn optimizations(&self) -> Option; + + /// Codegen version, if applicable. + fn codegen(&self) -> Option; + + /// Language version, if applicable. + fn version(&self) -> Option; +} + +pub fn mode_to_string_aux(mode: &impl IMode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for (i, element) in [mode.codegen(), mode.optimizations(), mode.version()] + .iter() + .flatten() + .enumerate() + { + if i > 0 { + write!(f, " ")?; + } + write!(f, "{}", element)?; + } + Ok(()) +} diff --git a/compiler_tester/src/compilers/mode/mod.rs b/compiler_tester/src/compilers/mode/mod.rs index 2a1b945a..7072f1d5 100644 --- a/compiler_tester/src/compilers/mode/mod.rs +++ b/compiler_tester/src/compilers/mode/mod.rs @@ -2,9 +2,13 @@ //! The compiler mode. //! +pub mod imode; pub mod llvm_options; use std::collections::HashSet; +use std::fmt::Display; + +use imode::{mode_to_string_aux, IMode}; use crate::compilers::eravm::mode::Mode as EraVMMode; use crate::compilers::llvm::mode::Mode as LLVMMode; @@ -17,7 +21,7 @@ use crate::compilers::yul::mode_upstream::Mode as YulUpstreamMode; /// /// The compiler mode. /// -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] #[allow(clippy::upper_case_acronyms)] pub enum Mode { /// The `Solidity` mode. @@ -207,6 +211,7 @@ impl Mode { } } + current = current.replace(' ', ""); current } } @@ -253,16 +258,46 @@ impl From for Mode { } } -impl std::fmt::Display for Mode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl IMode for Mode { + fn optimizations(&self) -> Option { + match self { + Mode::Solidity(mode) => mode.optimizations(), + Mode::SolidityUpstream(mode) => mode.optimizations(), + Mode::Yul(mode) => mode.optimizations(), + Mode::YulUpstream(mode) => mode.optimizations(), + Mode::Vyper(mode) => mode.optimizations(), + Mode::LLVM(mode) => mode.optimizations(), + Mode::EraVM(mode) => mode.optimizations(), + } + } + + fn codegen(&self) -> Option { + match self { + Mode::Solidity(mode) => mode.codegen(), + Mode::SolidityUpstream(mode) => mode.codegen(), + Mode::Yul(mode) => mode.codegen(), + Mode::YulUpstream(mode) => mode.codegen(), + Mode::Vyper(mode) => mode.codegen(), + Mode::LLVM(mode) => mode.codegen(), + Mode::EraVM(mode) => mode.codegen(), + } + } + + fn version(&self) -> Option { match self { - Self::Solidity(inner) => write!(f, "{inner}"), - Self::SolidityUpstream(inner) => write!(f, "{inner}"), - Self::Yul(inner) => write!(f, "{inner}"), - Self::YulUpstream(inner) => write!(f, "{inner}"), - Self::Vyper(inner) => write!(f, "{inner}"), - Self::LLVM(inner) => write!(f, "{inner}"), - Self::EraVM(inner) => write!(f, "{inner}"), + Mode::Solidity(mode) => mode.version(), + Mode::SolidityUpstream(mode) => mode.version(), + Mode::Yul(mode) => mode.version(), + Mode::YulUpstream(mode) => mode.version(), + Mode::Vyper(mode) => mode.version(), + Mode::LLVM(mode) => mode.version(), + Mode::EraVM(mode) => mode.version(), } } } + +impl Display for Mode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + mode_to_string_aux(self, f) + } +} diff --git a/compiler_tester/src/compilers/solidity/cache_key.rs b/compiler_tester/src/compilers/solidity/cache_key.rs index 2bb9e654..7145b414 100644 --- a/compiler_tester/src/compilers/solidity/cache_key.rs +++ b/compiler_tester/src/compilers/solidity/cache_key.rs @@ -12,7 +12,7 @@ pub struct CacheKey { /// The Solidity compiler version. pub version: semver::Version, /// The Solidity compiler output type. - pub pipeline: era_compiler_solidity::SolcPipeline, + pub codegen: era_solc::StandardJsonInputCodegen, /// Whether to enable the EVMLA codegen via Yul IR. pub via_ir: bool, /// Whether to run the Solidity compiler optimizer. @@ -26,14 +26,14 @@ impl CacheKey { pub fn new( test_path: String, version: semver::Version, - pipeline: era_compiler_solidity::SolcPipeline, + codegen: era_solc::StandardJsonInputCodegen, via_ir: bool, optimize: bool, ) -> Self { Self { test_path, version, - pipeline, + codegen, via_ir, optimize, } diff --git a/compiler_tester/src/compilers/solidity/mod.rs b/compiler_tester/src/compilers/solidity/mod.rs index 3fe13f15..38a5af88 100644 --- a/compiler_tester/src/compilers/solidity/mod.rs +++ b/compiler_tester/src/compilers/solidity/mod.rs @@ -7,12 +7,13 @@ pub mod mode; pub mod upstream; use std::collections::BTreeMap; +use std::collections::BTreeSet; use std::collections::HashMap; use std::path::Path; use itertools::Itertools; -use era_compiler_solidity::CollectableError; +use era_solc::CollectableError; use crate::compilers::cache::Cache; use crate::compilers::mode::Mode; @@ -29,7 +30,7 @@ use self::mode::Mode as SolidityMode; /// pub struct SolidityCompiler { /// The `solc` process output cache. - cache: Cache, + cache: Cache, } lazy_static::lazy_static! { @@ -39,28 +40,26 @@ lazy_static::lazy_static! { /// All compilers must be downloaded before initialization. /// static ref MODES: Vec = { - let mut solc_pipeline_versions = Vec::new(); - for (pipeline, optimize, via_ir) in [ - (era_compiler_solidity::SolcPipeline::EVMLA, false, false), - (era_compiler_solidity::SolcPipeline::EVMLA, true, false), - (era_compiler_solidity::SolcPipeline::EVMLA, true, true), - (era_compiler_solidity::SolcPipeline::Yul, false, true), - (era_compiler_solidity::SolcPipeline::Yul, true, true), + let mut solc_codegen_versions = Vec::new(); + for (codegen, optimize, via_ir) in [ + (era_solc::StandardJsonInputCodegen::EVMLA, true, false), + (era_solc::StandardJsonInputCodegen::EVMLA, true, true), + (era_solc::StandardJsonInputCodegen::Yul, true, true), ] { - for version in SolidityCompiler::all_versions(pipeline, via_ir).expect("`solc` versions analysis error") { - solc_pipeline_versions.push((pipeline, optimize, via_ir, version)); + for version in SolidityCompiler::all_versions(codegen, via_ir).expect("`solc` versions analysis error") { + solc_codegen_versions.push((codegen, optimize, via_ir, version)); } } era_compiler_llvm_context::OptimizerSettings::combinations() .into_iter() - .cartesian_product(solc_pipeline_versions) + .cartesian_product(solc_codegen_versions) .map( - |(mut llvm_optimizer_settings, (pipeline, optimize, via_ir, version))| { + |(mut llvm_optimizer_settings, (codegen, optimize, via_ir, version))| { llvm_optimizer_settings.enable_fallback_to_size(); SolidityMode::new( version, - pipeline, + codegen, via_ir, optimize, llvm_optimizer_settings, @@ -81,7 +80,10 @@ impl Default for SolidityCompiler { } impl SolidityCompiler { - /// The compiler binaries directory. + /// The last ZKsync `solc` revision. + pub const LAST_ZKSYNC_SOLC_REVISION: semver::Version = semver::Version::new(1, 0, 1); + + /// The compiler executables directory. const DIRECTORY: &'static str = "solc-bin/"; /// The solc allow paths argument value. @@ -99,28 +101,24 @@ impl SolidityCompiler { /// /// Returns the `solc` executable by its version. /// - pub fn executable( - version: &semver::Version, - ) -> anyhow::Result { - era_compiler_solidity::SolcCompiler::new( - format!("{}/solc-{}", Self::DIRECTORY, version).as_str(), - ) + pub fn executable(version: &semver::Version) -> anyhow::Result { + era_solc::Compiler::try_from_path(format!("{}/solc-{}", Self::DIRECTORY, version).as_str()) } /// /// Returns the `solc` executable used to compile system contracts. /// - pub fn system_contract_executable() -> anyhow::Result { - era_compiler_solidity::SolcCompiler::new( + pub fn system_contract_executable() -> anyhow::Result { + era_solc::Compiler::try_from_path( format!("{}/solc-system-contracts", Self::DIRECTORY).as_str(), ) } /// - /// Returns the compiler versions downloaded for the specified compilation pipeline. + /// Returns the compiler versions downloaded for the specified compilation codegen. /// pub fn all_versions( - pipeline: era_compiler_solidity::SolcPipeline, + codegen: era_solc::StandardJsonInputCodegen, via_ir: bool, ) -> anyhow::Result> { let mut versions = Vec::new(); @@ -136,7 +134,7 @@ impl SolidityCompiler { })?; if !entry_type.is_file() { anyhow::bail!( - "Invalid `solc` binary file type: {}", + "Invalid `solc` executable file type: {}", path.to_string_lossy() ); } @@ -150,14 +148,14 @@ impl SolidityCompiler { Ok(version) => version, Err(_) => continue, }; - if era_compiler_solidity::SolcPipeline::Yul == pipeline - && version < era_compiler_solidity::SolcCompiler::FIRST_YUL_VERSION + if era_solc::StandardJsonInputCodegen::Yul == codegen + && version < era_solc::Compiler::FIRST_YUL_VERSION { continue; } - if era_compiler_solidity::SolcPipeline::EVMLA == pipeline + if era_solc::StandardJsonInputCodegen::EVMLA == codegen && via_ir - && version < era_compiler_solidity::SolcCompiler::FIRST_VIA_IR_VERSION + && version < era_solc::Compiler::FIRST_VIA_IR_VERSION { continue; } @@ -172,9 +170,9 @@ impl SolidityCompiler { /// fn standard_json_output( sources: &[(String, String)], - libraries: &BTreeMap>, + libraries: &era_solc::StandardJsonInputLibraries, mode: &SolidityMode, - ) -> anyhow::Result { + ) -> anyhow::Result { let solc_compiler = if mode.is_system_contracts_mode { Self::system_contract_executable() } else { @@ -182,44 +180,47 @@ impl SolidityCompiler { }?; let mut output_selection = - era_compiler_solidity::SolcStandardJsonInputSettingsSelection::new_required(Some( - mode.solc_pipeline, - )); - output_selection.extend_with_eravm_assembly(); - - let optimizer = era_compiler_solidity::SolcStandardJsonInputSettingsOptimizer::new( - mode.solc_optimize, - None, - &mode.solc_version, - false, - ); + era_solc::StandardJsonInputSelection::new_required(mode.solc_codegen); + output_selection.extend(era_solc::StandardJsonInputSelection::new(vec![ + era_solc::StandardJsonInputSelector::EraVMAssembly, + ])); - let evm_version = if mode.solc_version >= semver::Version::new(0, 8, 24) - /* TODO */ - { + let evm_version = if mode.solc_version >= era_solc::Compiler::FIRST_CANCUN_VERSION { Some(era_compiler_common::EVMVersion::Cancun) } else { None }; - let mut solc_input = - era_compiler_solidity::SolcStandardJsonInput::try_from_solidity_sources( - evm_version, - sources.iter().cloned().collect(), - libraries.clone(), - None, - output_selection, - optimizer, - None, - mode.solc_pipeline == era_compiler_solidity::SolcPipeline::EVMLA, - mode.via_ir, - mode.enable_eravm_extensions, - false, - vec![], - vec![era_compiler_solidity::MessageType::SendTransfer], - vec![], - ) - .map_err(|error| anyhow::anyhow!("Solidity standard JSON I/O error: {}", error))?; + let sources: BTreeMap = sources + .iter() + .map(|(path, source)| { + ( + path.to_owned(), + era_solc::StandardJsonInputSource::from(source.to_owned()), + ) + }) + .collect(); + + let mut solc_input = era_solc::StandardJsonInput::try_from_solidity_sources( + sources, + libraries.to_owned(), + BTreeSet::new(), + era_solc::StandardJsonInputOptimizer::default(), + Some(mode.solc_codegen), + evm_version, + mode.enable_eravm_extensions, + output_selection, + era_solc::StandardJsonInputMetadata::default(), + vec![], + vec![ + era_solc::StandardJsonInputErrorType::SendTransfer, + era_solc::StandardJsonInputErrorType::AssemblyCreate, + ], + vec![], + false, + mode.via_ir, + ) + .map_err(|error| anyhow::anyhow!("Solidity standard JSON I/O error: {}", error))?; let allow_paths = Path::new(Self::SOLC_ALLOW_PATHS) .canonicalize() @@ -229,7 +230,6 @@ impl SolidityCompiler { solc_compiler.standard_json( &mut solc_input, - Some(mode.solc_pipeline), &mut vec![], None, vec![], @@ -244,13 +244,13 @@ impl SolidityCompiler { &self, test_path: String, sources: &[(String, String)], - libraries: &BTreeMap>, + libraries: &era_solc::StandardJsonInputLibraries, mode: &SolidityMode, - ) -> anyhow::Result { + ) -> anyhow::Result { let cache_key = CacheKey::new( test_path, mode.solc_version.clone(), - mode.solc_pipeline, + mode.solc_codegen, mode.via_ir, mode.solc_optimize, ); @@ -268,16 +268,11 @@ impl SolidityCompiler { /// Get the method identifiers from the solc output. /// fn get_method_identifiers( - solc_output: &era_compiler_solidity::SolcStandardJsonOutput, + solc_output: &era_solc::StandardJsonOutput, ) -> anyhow::Result>> { - let files = solc_output - .contracts - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Solidity contracts not found in the output"))?; - let mut method_identifiers = BTreeMap::new(); - for (path, contracts) in files.iter() { - for (name, contract) in contracts.iter() { + for (path, file) in solc_output.contracts.iter() { + for (name, contract) in file.iter() { let mut contract_identifiers = BTreeMap::new(); for (entry, selector) in contract .evm @@ -286,14 +281,6 @@ impl SolidityCompiler { anyhow::anyhow!("EVM object of the contract `{}:{}` not found", path, name) })? .method_identifiers - .as_ref() - .ok_or_else(|| { - anyhow::anyhow!( - "Method identifiers of the contract `{}:{}` not found", - path, - name - ) - })? .iter() { let selector = @@ -317,31 +304,21 @@ impl SolidityCompiler { /// Get the last contract from the solc output. /// fn get_last_contract( - solc_output: &era_compiler_solidity::SolcStandardJsonOutput, + solc_output: &era_solc::StandardJsonOutput, sources: &[(String, String)], ) -> anyhow::Result { - solc_output - .sources - .as_ref() - .ok_or_else(|| { - anyhow::anyhow!( - "The Solidity sources are empty. Found errors: {:?}", - solc_output.errors - ) - }) - .and_then(|output_sources| { - for (path, _source) in sources.iter().rev() { - match output_sources - .get(path) - .ok_or_else(|| anyhow::anyhow!("The last source not found in the output"))? - .last_contract_name() - { - Ok(name) => return Ok(format!("{path}:{name}")), - Err(_error) => continue, - } - } - anyhow::bail!("The last source not found in the output") - }) + for (path, _source) in sources.iter().rev() { + match solc_output + .sources + .get(path) + .ok_or_else(|| anyhow::anyhow!("The last source not found in the output"))? + .last_contract_name() + { + Ok(name) => return Ok(format!("{path}:{name}")), + Err(_error) => continue, + } + } + anyhow::bail!("The last source not found in the output") } } @@ -350,7 +327,7 @@ impl Compiler for SolidityCompiler { &self, test_path: String, sources: Vec<(String, String)>, - libraries: BTreeMap>, + libraries: era_solc::StandardJsonInputLibraries, mode: &Mode, llvm_options: Vec, debug_config: Option, @@ -360,7 +337,7 @@ impl Compiler for SolidityCompiler { let mut solc_output = self .standard_json_output_cached(test_path, &sources, &libraries, mode) .map_err(|error| anyhow::anyhow!("Solidity standard JSON I/O error: {}", error))?; - solc_output.collect_errors()?; + solc_output.check_errors()?; let method_identifiers = Self::get_method_identifiers(&solc_output) .map_err(|error| anyhow::anyhow!("Failed to get method identifiers: {}", error))?; @@ -374,9 +351,11 @@ impl Compiler for SolidityCompiler { SolidityCompiler::executable(&mode.solc_version) }?; + let linker_symbols = libraries.as_linker_symbols()?; + let project = era_compiler_solidity::Project::try_from_solc_output( libraries, - mode.solc_pipeline, + mode.solc_codegen, &mut solc_output, &solc_compiler, debug_config.as_ref(), @@ -389,35 +368,37 @@ impl Compiler for SolidityCompiler { mode.llvm_optimizer_settings.to_owned(), llvm_options, true, - None, debug_config, )?; - build.collect_errors()?; + build.check_errors()?; + let build = build.link(linker_symbols); + build.check_errors()?; let builds = build - .contracts + .results .iter() .map(|(path, build)| { let build = build.to_owned().expect("Always valid"); - let build = era_compiler_llvm_context::EraVMBuild::new( + let build = era_compiler_llvm_context::EraVMBuild::new_with_bytecode_hash( build.build.bytecode, - build.build.bytecode_hash, + build.build.bytecode_hash.ok_or_else(|| { + anyhow::anyhow!("Bytecode hash not found in the build artifacts") + })?, None, build.build.assembly, ); - (path.to_owned(), build) + Ok((path.to_owned(), build)) }) - .collect(); + .collect::>>()?; build.write_to_standard_json( &mut solc_output, - Some(&era_compiler_solidity::SolcVersion::new( + Some(&era_solc::Version::new( mode.solc_version.to_string(), mode.solc_version.to_owned(), - None, + Self::LAST_ZKSYNC_SOLC_REVISION, )), - &semver::Version::new(0, 0, 0), )?; - solc_output.collect_errors()?; + solc_output.check_errors()?; Ok(EraVMInput::new( builds, @@ -430,7 +411,7 @@ impl Compiler for SolidityCompiler { &self, test_path: String, sources: Vec<(String, String)>, - libraries: BTreeMap>, + libraries: era_solc::StandardJsonInputLibraries, mode: &Mode, _test_params: Option<&solidity_adapter::Params>, llvm_options: Vec, @@ -440,7 +421,7 @@ impl Compiler for SolidityCompiler { let mut solc_output = self.standard_json_output_cached(test_path, &sources, &libraries, mode)?; - solc_output.collect_errors()?; + solc_output.check_errors()?; let method_identifiers = Self::get_method_identifiers(&solc_output)?; @@ -450,7 +431,7 @@ impl Compiler for SolidityCompiler { let project = era_compiler_solidity::Project::try_from_solc_output( libraries, - mode.solc_pipeline, + mode.solc_codegen, &mut solc_output, &solc_compiler, debug_config.as_ref(), @@ -458,15 +439,15 @@ impl Compiler for SolidityCompiler { let build = project.compile_to_evm( &mut vec![], + era_compiler_common::HashType::Ipfs, mode.llvm_optimizer_settings.to_owned(), llvm_options, - era_compiler_common::HashType::Ipfs, None, debug_config, )?; - build.collect_errors()?; + build.check_errors()?; let builds: HashMap = build - .contracts + .results .into_iter() .map(|(path, result)| { let contract = result.expect("Always valid"); diff --git a/compiler_tester/src/compilers/solidity/mode.rs b/compiler_tester/src/compilers/solidity/mode.rs index 296abf7f..f89463c6 100644 --- a/compiler_tester/src/compilers/solidity/mode.rs +++ b/compiler_tester/src/compilers/solidity/mode.rs @@ -6,17 +6,18 @@ use itertools::Itertools; use crate::compilers::mode::llvm_options::LLVMOptions; +use crate::compilers::mode::imode::IMode; use crate::compilers::mode::Mode as ModeWrapper; /// /// The compiler tester Solidity mode. /// -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Mode { /// The Solidity compiler version. pub solc_version: semver::Version, /// The Solidity compiler output type. - pub solc_pipeline: era_compiler_solidity::SolcPipeline, + pub solc_codegen: era_solc::StandardJsonInputCodegen, /// Whether to enable the EVMLA codegen via Yul IR. pub via_ir: bool, /// Whether to run the Solidity compiler optimizer. @@ -35,7 +36,7 @@ impl Mode { /// pub fn new( solc_version: semver::Version, - solc_pipeline: era_compiler_solidity::SolcPipeline, + solc_codegen: era_solc::StandardJsonInputCodegen, via_ir: bool, solc_optimize: bool, mut llvm_optimizer_settings: era_compiler_llvm_context::OptimizerSettings, @@ -49,7 +50,7 @@ impl Mode { Self { solc_version, - solc_pipeline, + solc_codegen, via_ir, solc_optimize, llvm_optimizer_settings, @@ -112,35 +113,43 @@ impl Mode { return false; } - match self.solc_pipeline { - era_compiler_solidity::SolcPipeline::Yul => { + match self.solc_codegen { + era_solc::StandardJsonInputCodegen::Yul => { params.compile_via_yul != solidity_adapter::CompileViaYul::False && params.abi_encoder_v1_only != solidity_adapter::ABIEncoderV1Only::True } - era_compiler_solidity::SolcPipeline::EVMLA if self.via_ir => { + era_solc::StandardJsonInputCodegen::EVMLA if self.via_ir => { params.compile_via_yul != solidity_adapter::CompileViaYul::False && params.abi_encoder_v1_only != solidity_adapter::ABIEncoderV1Only::True } - era_compiler_solidity::SolcPipeline::EVMLA => { + era_solc::StandardJsonInputCodegen::EVMLA => { params.compile_via_yul != solidity_adapter::CompileViaYul::True } } } } -impl std::fmt::Display for Mode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}{}{} {}", - match self.solc_pipeline { - era_compiler_solidity::SolcPipeline::Yul => "Y", - era_compiler_solidity::SolcPipeline::EVMLA if self.via_ir => "I", - era_compiler_solidity::SolcPipeline::EVMLA => "E", - }, +impl IMode for Mode { + fn optimizations(&self) -> Option { + Some(format!( + "{}{}", if self.solc_optimize { '+' } else { '-' }, self.llvm_optimizer_settings, - self.solc_version, + )) + } + + fn codegen(&self) -> Option { + Some( + (match self.solc_codegen { + era_solc::StandardJsonInputCodegen::Yul => "Y", + era_solc::StandardJsonInputCodegen::EVMLA if self.via_ir => "I", + era_solc::StandardJsonInputCodegen::EVMLA => "E", + }) + .to_string(), ) } + + fn version(&self) -> Option { + Some(self.solc_version.to_string()) + } } diff --git a/compiler_tester/src/compilers/solidity/upstream/mod.rs b/compiler_tester/src/compilers/solidity/upstream/mod.rs index b86c9c7d..cf1ae610 100644 --- a/compiler_tester/src/compilers/solidity/upstream/mod.rs +++ b/compiler_tester/src/compilers/solidity/upstream/mod.rs @@ -14,15 +14,16 @@ use crate::compilers::mode::Mode; use crate::compilers::solidity::cache_key::CacheKey; use crate::compilers::yul::mode_upstream::Mode as YulUpstreamMode; use crate::compilers::Compiler; +use crate::toolchain::Toolchain; use crate::vm::eravm::input::Input as EraVMInput; use crate::vm::evm::input::build::Build as EVMBuild; use crate::vm::evm::input::Input as EVMInput; use self::mode::Mode as SolidityUpstreamMode; use self::solc::standard_json::input::language::Language as SolcStandardJsonInputLanguage; -use self::solc::standard_json::input::settings::debug::Debug as SolcStandardJsonInputSettingsDebug; -use self::solc::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer; -use self::solc::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection; +use self::solc::standard_json::input::settings::debug::Debug as SolcStandardJsonInputDebug; +use self::solc::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputOptimizer; +use self::solc::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSelection; use self::solc::standard_json::input::Input as SolcStandardJsonInput; use self::solc::standard_json::output::Output as SolcStandardJsonOutput; use self::solc::Compiler as SolcUpstreamCompiler; @@ -33,6 +34,9 @@ use self::solc::Compiler as SolcUpstreamCompiler; pub struct SolidityCompiler { /// The language the compiler will compile. language: SolcStandardJsonInputLanguage, + /// The toolchain identifier. + /// Only `solc` and `solc-llvm` are supported. + toolchain: Toolchain, /// The `solc` process output cache. cache: Cache, } @@ -45,16 +49,16 @@ lazy_static::lazy_static! { /// static ref SOLIDITY_MODES: Vec = { let mut modes = Vec::new(); - for (pipeline, optimize, via_ir) in [ - (era_compiler_solidity::SolcPipeline::EVMLA, false, false), - (era_compiler_solidity::SolcPipeline::EVMLA, false, true), - (era_compiler_solidity::SolcPipeline::EVMLA, true, false), - (era_compiler_solidity::SolcPipeline::EVMLA, true, true), - (era_compiler_solidity::SolcPipeline::Yul, false, true), - (era_compiler_solidity::SolcPipeline::Yul, true, true), + for (codegen, optimize, via_ir) in [ + (era_solc::StandardJsonInputCodegen::EVMLA, false, false), + (era_solc::StandardJsonInputCodegen::EVMLA, false, true), + (era_solc::StandardJsonInputCodegen::EVMLA, true, false), + (era_solc::StandardJsonInputCodegen::EVMLA, true, true), + (era_solc::StandardJsonInputCodegen::Yul, false, true), + (era_solc::StandardJsonInputCodegen::Yul, true, true), ] { - for version in SolidityCompiler::all_versions(pipeline, via_ir).expect("`solc` versions analysis error") { - modes.push(SolidityUpstreamMode::new(version, pipeline, via_ir, optimize).into()); + for version in SolidityCompiler::all_versions(codegen, via_ir).expect("`solc` versions analysis error") { + modes.push(SolidityUpstreamMode::new(version, codegen, via_ir, false, optimize).into()); } } modes @@ -70,17 +74,38 @@ lazy_static::lazy_static! { for optimize in [ false, true ] { - for version in SolidityCompiler::all_versions(era_compiler_solidity::SolcPipeline::Yul, true).expect("`solc` versions analysis error") { - modes.push(YulUpstreamMode::new(version, optimize).into()); + for version in SolidityCompiler::all_versions(era_solc::StandardJsonInputCodegen::Yul, true).expect("`solc` versions analysis error") { + modes.push(YulUpstreamMode::new(version, false, optimize).into()); } } modes }; + + /// + /// The supported Solidity modes for MLIR codegen. + /// + /// All compilers must be downloaded before initialization. + /// + static ref SOLIDITY_MLIR_MODES: Vec = { + vec![SolidityUpstreamMode::new(semver::Version::new(0, 8, 26), era_solc::StandardJsonInputCodegen::Yul, false, true, false).into()] + }; + + /// + /// The supported Yul modes for MLIR codegen. + /// + /// All compilers must be downloaded before initialization. + /// + static ref YUL_MLIR_MODES: Vec = { + vec![YulUpstreamMode::new(semver::Version::new(0, 8, 26), true, false).into()] + }; } impl SolidityCompiler { - /// The compiler binaries directory. - const DIRECTORY: &'static str = "solc-bin-upstream/"; + /// The upstream compiler executables directory. + const DIRECTORY_UPSTREAM: &'static str = "solc-bin-upstream/"; + + /// The LLVM-fork compiler executables directory. + const DIRECTORY_LLVM: &'static str = "solc-bin-llvm/"; /// The solc allow paths argument value. const SOLC_ALLOW_PATHS: &'static str = "tests"; @@ -88,9 +113,10 @@ impl SolidityCompiler { /// /// A shortcut constructor. /// - pub fn new(language: SolcStandardJsonInputLanguage) -> Self { + pub fn new(language: SolcStandardJsonInputLanguage, toolchain: Toolchain) -> Self { Self { language, + toolchain, cache: Cache::new(), } } @@ -98,19 +124,27 @@ impl SolidityCompiler { /// /// Returns the `solc` executable by its version. /// - pub fn executable(version: &semver::Version) -> anyhow::Result { - SolcUpstreamCompiler::new(format!("{}/solc-{}", Self::DIRECTORY, version)) + pub fn executable( + toolchain: Toolchain, + version: &semver::Version, + ) -> anyhow::Result { + let directory = match toolchain { + Toolchain::Solc => Self::DIRECTORY_UPSTREAM, + Toolchain::SolcLLVM => Self::DIRECTORY_LLVM, + toolchain => panic!("Unsupported toolchain: {toolchain}"), + }; + SolcUpstreamCompiler::new(format!("{}/solc-{}", directory, version)) } /// - /// Returns the compiler versions downloaded for the specified compilation pipeline. + /// Returns the compiler versions downloaded for the specified compilation codegen. /// pub fn all_versions( - pipeline: era_compiler_solidity::SolcPipeline, + codegen: era_solc::StandardJsonInputCodegen, via_ir: bool, ) -> anyhow::Result> { let mut versions = Vec::new(); - for entry in std::fs::read_dir(Self::DIRECTORY)? { + for entry in std::fs::read_dir(Self::DIRECTORY_UPSTREAM)? { let entry = entry?; let path = entry.path(); let entry_type = entry.file_type().map_err(|error| { @@ -122,7 +156,7 @@ impl SolidityCompiler { })?; if !entry_type.is_file() { anyhow::bail!( - "Invalid `solc` binary file type: {}", + "Invalid `solc` executable file type: {}", path.to_string_lossy() ); } @@ -136,12 +170,12 @@ impl SolidityCompiler { Ok(version) => version, Err(_) => continue, }; - if era_compiler_solidity::SolcPipeline::Yul == pipeline + if era_solc::StandardJsonInputCodegen::Yul == codegen && version < SolcUpstreamCompiler::FIRST_YUL_VERSION { continue; } - if era_compiler_solidity::SolcPipeline::EVMLA == pipeline + if era_solc::StandardJsonInputCodegen::EVMLA == codegen && via_ir && version < SolcUpstreamCompiler::FIRST_VIA_IR_VERSION { @@ -158,8 +192,9 @@ impl SolidityCompiler { /// pub fn standard_json_output( language: SolcStandardJsonInputLanguage, + toolchain: Toolchain, sources: &[(String, String)], - libraries: &BTreeMap>, + libraries: &era_solc::StandardJsonInputLibraries, mode: &Mode, test_params: Option<&solidity_adapter::Params>, ) -> anyhow::Result { @@ -168,15 +203,15 @@ impl SolidityCompiler { Mode::YulUpstream(mode) => &mode.solc_version, mode => anyhow::bail!("Unsupported mode: {mode}"), }; - let mut solc = Self::executable(solc_version)?; + let mut solc = Self::executable(toolchain, solc_version)?; - let output_selection = SolcStandardJsonInputSettingsSelection::new_required(match mode { - Mode::SolidityUpstream(mode) => mode.solc_pipeline, - Mode::YulUpstream(_mode) => era_compiler_solidity::SolcPipeline::Yul, + let output_selection = SolcStandardJsonInputSelection::new_required(match mode { + Mode::SolidityUpstream(mode) => mode.solc_codegen, + Mode::YulUpstream(_mode) => era_solc::StandardJsonInputCodegen::Yul, mode => anyhow::bail!("Unsupported mode: {mode}"), }); - let optimizer = SolcStandardJsonInputSettingsOptimizer::new(match mode { + let optimizer = SolcStandardJsonInputOptimizer::new(match mode { Mode::SolidityUpstream(mode) => mode.solc_optimize, Mode::YulUpstream(mode) => mode.solc_optimize, mode => anyhow::bail!("Unsupported mode: {mode}"), @@ -199,11 +234,15 @@ impl SolidityCompiler { mode => anyhow::bail!("Unsupported mode: {mode}"), }; + let via_mlir = match mode { + Mode::SolidityUpstream(mode) => mode.via_mlir, + Mode::YulUpstream(mode) => mode.via_mlir, + mode => anyhow::bail!("Unsupported mode: {mode}"), + }; + let debug = if solc_version >= &semver::Version::new(0, 6, 3) { test_params.map(|test_params| { - SolcStandardJsonInputSettingsDebug::new(Some( - test_params.revert_strings.to_string(), - )) + SolcStandardJsonInputDebug::new(Some(test_params.revert_strings.to_string())) }) } else { None @@ -217,6 +256,7 @@ impl SolidityCompiler { None, output_selection, via_ir, + via_mlir, optimizer, debug, ) @@ -239,7 +279,7 @@ impl SolidityCompiler { test_path: String, language: SolcStandardJsonInputLanguage, sources: &[(String, String)], - libraries: &BTreeMap>, + libraries: &era_solc::StandardJsonInputLibraries, mode: &Mode, test_params: Option<&solidity_adapter::Params>, ) -> anyhow::Result { @@ -247,14 +287,14 @@ impl SolidityCompiler { Mode::SolidityUpstream(mode) => CacheKey::new( test_path, mode.solc_version.to_owned(), - mode.solc_pipeline, + mode.solc_codegen, mode.via_ir, mode.solc_optimize, ), Mode::YulUpstream(mode) => CacheKey::new( test_path, mode.solc_version.to_owned(), - era_compiler_solidity::SolcPipeline::Yul, + era_solc::StandardJsonInputCodegen::Yul, true, mode.solc_optimize, ), @@ -263,7 +303,14 @@ impl SolidityCompiler { if !self.cache.contains(&cache_key) { self.cache.evaluate(cache_key.clone(), || { - Self::standard_json_output(language, sources, libraries, mode, test_params) + Self::standard_json_output( + language, + self.toolchain, + sources, + libraries, + mode, + test_params, + ) }); } @@ -374,21 +421,101 @@ impl SolidityCompiler { impl Compiler for SolidityCompiler { fn compile_for_eravm( &self, - _test_path: String, - _sources: Vec<(String, String)>, - _libraries: BTreeMap>, - _mode: &Mode, + test_path: String, + sources: Vec<(String, String)>, + libraries: era_solc::StandardJsonInputLibraries, + mode: &Mode, _llvm_options: Vec, _debug_config: Option, ) -> anyhow::Result { - anyhow::bail!("The upstream Solidity compiler cannot compile for EraVM"); + let solc_output = self.standard_json_output_cached( + test_path, + self.language, + &sources, + &libraries, + mode, + None, + )?; + + if let Some(errors) = solc_output.errors.as_deref() { + let mut has_errors = false; + let mut error_messages = Vec::with_capacity(errors.len()); + + for error in errors.iter() { + if error.severity.as_str() == "error" { + has_errors = true; + error_messages.push(error.formatted_message.to_owned()); + } + } + + if has_errors { + anyhow::bail!("`solc` errors found: {:?}", error_messages); + } + } + + let method_identifiers = match self.language { + SolcStandardJsonInputLanguage::Solidity => { + Some(Self::get_method_identifiers(&solc_output)?) + } + SolcStandardJsonInputLanguage::Yul => None, + }; + + let last_contract = Self::get_last_contract(self.language, &solc_output, &sources)?; + + let contracts = solc_output + .contracts + .ok_or_else(|| anyhow::anyhow!("Solidity contracts not found in the output"))?; + + let mut builds = HashMap::with_capacity(contracts.len()); + for (file, contracts) in contracts.into_iter() { + for (name, contract) in contracts.into_iter() { + let path = format!("{file}:{name}"); + let bytecode_string = contract + .evm + .as_ref() + .ok_or_else(|| { + anyhow::anyhow!("EraVM object of the contract `{path}` not found") + })? + .bytecode + .as_ref() + .ok_or_else(|| { + anyhow::anyhow!("EraVM bytecode of the contract `{path}` not found") + })? + .object + .as_str(); + let bytecode = hex::decode(bytecode_string).map_err(|error| { + anyhow::anyhow!("EraVM bytecode of the contract `{path}` is invalid: {error}") + })?; + let bytecode_words: Vec<[u8; era_compiler_common::BYTE_LENGTH_FIELD]> = bytecode + .as_slice() + .chunks(era_compiler_common::BYTE_LENGTH_FIELD) + .map(|word| word.try_into().expect("Always valid")) + .collect(); + let bytecode_hash = zkevm_opcode_defs::utils::bytecode_to_code_hash_for_mode::< + { era_compiler_common::BYTE_LENGTH_X64 }, + zkevm_opcode_defs::decoding::EncodingModeProduction, + >(bytecode_words.as_slice()) + .map_err(|_| { + anyhow::anyhow!("EraVM bytecode of the contract `{path}` hashing error") + })?; + let build = era_compiler_llvm_context::EraVMBuild::new_with_bytecode_hash( + bytecode, + bytecode_hash, + None, + None, + ); + builds.insert(path, build); + } + } + + Ok(EraVMInput::new(builds, method_identifiers, last_contract)) } fn compile_for_evm( &self, test_path: String, sources: Vec<(String, String)>, - libraries: BTreeMap>, + libraries: era_solc::StandardJsonInputLibraries, mode: &Mode, test_params: Option<&solidity_adapter::Params>, _llvm_options: Vec, @@ -450,15 +577,10 @@ impl Compiler for SolidityCompiler { .object .as_str(); let build = EVMBuild::new( - era_compiler_llvm_context::EVMBuild::new( - hex::decode(bytecode_string).map_err(|error| { - anyhow::anyhow!( - "EVM bytecode of the contract `{path}` is invalid: {error}" - ) - })?, - None, - ), - era_compiler_llvm_context::EVMBuild::default(), + hex::decode(bytecode_string).map_err(|error| { + anyhow::anyhow!("EVM bytecode of the contract `{path}` is invalid: {error}") + })?, + vec![], ); builds.insert(path, build); } @@ -468,9 +590,13 @@ impl Compiler for SolidityCompiler { } fn all_modes(&self) -> Vec { - match self.language { - SolcStandardJsonInputLanguage::Solidity => SOLIDITY_MODES.clone(), - SolcStandardJsonInputLanguage::Yul => YUL_MODES.clone(), + match (self.language, self.toolchain) { + (SolcStandardJsonInputLanguage::Solidity, Toolchain::SolcLLVM) => { + SOLIDITY_MLIR_MODES.clone() + } + (SolcStandardJsonInputLanguage::Solidity, _) => SOLIDITY_MODES.clone(), + (SolcStandardJsonInputLanguage::Yul, Toolchain::SolcLLVM) => YUL_MLIR_MODES.clone(), + (SolcStandardJsonInputLanguage::Yul, _) => YUL_MODES.clone(), } } diff --git a/compiler_tester/src/compilers/solidity/upstream/mode.rs b/compiler_tester/src/compilers/solidity/upstream/mode.rs index 16734c00..4d4d9616 100644 --- a/compiler_tester/src/compilers/solidity/upstream/mode.rs +++ b/compiler_tester/src/compilers/solidity/upstream/mode.rs @@ -4,19 +4,21 @@ use itertools::Itertools; -use crate::compilers::mode::Mode as ModeWrapper; +use crate::compilers::mode::{imode::IMode, Mode as ModeWrapper}; /// /// The compiler tester Solidity mode. /// -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Mode { /// The Solidity compiler version. pub solc_version: semver::Version, /// The Solidity compiler output type. - pub solc_pipeline: era_compiler_solidity::SolcPipeline, + pub solc_codegen: era_solc::StandardJsonInputCodegen, /// Whether to enable the EVMLA codegen via Yul IR. pub via_ir: bool, + /// Whether to enable the MLIR codegen. + pub via_mlir: bool, /// Whether to run the Solidity compiler optimizer. pub solc_optimize: bool, } @@ -27,14 +29,16 @@ impl Mode { /// pub fn new( solc_version: semver::Version, - solc_pipeline: era_compiler_solidity::SolcPipeline, + solc_codegen: era_solc::StandardJsonInputCodegen, via_ir: bool, + via_mlir: bool, solc_optimize: bool, ) -> Self { Self { solc_version, - solc_pipeline, + solc_codegen, via_ir, + via_mlir, solc_optimize, } } @@ -93,34 +97,43 @@ impl Mode { return false; } - match self.solc_pipeline { - era_compiler_solidity::SolcPipeline::Yul => { + match self.solc_codegen { + era_solc::StandardJsonInputCodegen::Yul => { params.compile_via_yul != solidity_adapter::CompileViaYul::False && params.abi_encoder_v1_only != solidity_adapter::ABIEncoderV1Only::True } - era_compiler_solidity::SolcPipeline::EVMLA if self.via_ir => { + era_solc::StandardJsonInputCodegen::EVMLA if self.via_ir => { params.compile_via_yul != solidity_adapter::CompileViaYul::False && params.abi_encoder_v1_only != solidity_adapter::ABIEncoderV1Only::True } - era_compiler_solidity::SolcPipeline::EVMLA => { + era_solc::StandardJsonInputCodegen::EVMLA => { params.compile_via_yul != solidity_adapter::CompileViaYul::True } } } } -impl std::fmt::Display for Mode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}{} {}", - match self.solc_pipeline { - era_compiler_solidity::SolcPipeline::Yul => "Y", - era_compiler_solidity::SolcPipeline::EVMLA if self.via_ir => "I", - era_compiler_solidity::SolcPipeline::EVMLA => "E", - }, - if self.solc_optimize { '+' } else { '-' }, - self.solc_version, +impl IMode for Mode { + fn optimizations(&self) -> Option { + Some((if self.solc_optimize { "+" } else { "-" }).to_string()) + } + + fn codegen(&self) -> Option { + Some( + (if self.via_mlir { + "L" + } else { + match self.solc_codegen { + era_solc::StandardJsonInputCodegen::Yul => "Y", + era_solc::StandardJsonInputCodegen::EVMLA if self.via_ir => "I", + era_solc::StandardJsonInputCodegen::EVMLA => "E", + } + }) + .to_string(), ) } + + fn version(&self) -> Option { + Some(self.solc_version.to_string()) + } } diff --git a/compiler_tester/src/compilers/solidity/upstream/solc/mod.rs b/compiler_tester/src/compilers/solidity/upstream/solc/mod.rs index 7f4f0e23..1b4ab09f 100644 --- a/compiler_tester/src/compilers/solidity/upstream/solc/mod.rs +++ b/compiler_tester/src/compilers/solidity/upstream/solc/mod.rs @@ -13,7 +13,7 @@ use self::standard_json::output::Output as StandardJsonOutput; /// The Solidity compiler. /// pub struct Compiler { - /// The binary executable name. + /// The executable name. pub executable: String, } diff --git a/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/mod.rs b/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/mod.rs index 7a9c3533..b051e233 100644 --- a/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/mod.rs +++ b/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/mod.rs @@ -13,9 +13,9 @@ use rayon::iter::IntoParallelIterator; use rayon::iter::ParallelIterator; use serde::Serialize; -use self::settings::debug::Debug as SolcStandardJsonInputSettingsDebug; -use self::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer; -use self::settings::selection::Selection as SolcStandardJsonInputSettingsSelection; +use self::settings::debug::Debug as SolcStandardJsonInputDebug; +use self::settings::optimizer::Optimizer as SolcStandardJsonInputOptimizer; +use self::settings::selection::Selection as SolcStandardJsonInputSelection; use self::language::Language; use self::settings::Settings; @@ -45,12 +45,13 @@ impl Input { language: Language, evm_version: Option, sources: BTreeMap, - libraries: BTreeMap>, + libraries: era_solc::StandardJsonInputLibraries, remappings: Option>, - output_selection: SolcStandardJsonInputSettingsSelection, + output_selection: SolcStandardJsonInputSelection, via_ir: bool, - optimizer: SolcStandardJsonInputSettingsOptimizer, - debug: Option, + via_mlir: bool, + optimizer: SolcStandardJsonInputOptimizer, + debug: Option, ) -> anyhow::Result { let sources = sources .into_par_iter() @@ -66,6 +67,7 @@ impl Input { remappings, output_selection, via_ir, + via_mlir, optimizer, debug, ), diff --git a/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/mod.rs b/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/mod.rs index e97c4c6b..8daf0889 100644 --- a/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/mod.rs +++ b/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/mod.rs @@ -6,7 +6,6 @@ pub mod debug; pub mod optimizer; pub mod selection; -use std::collections::BTreeMap; use std::collections::BTreeSet; use serde::Serialize; @@ -25,8 +24,11 @@ pub struct Settings { #[serde(skip_serializing_if = "Option::is_none")] pub evm_version: Option, /// The linker library addresses. - #[serde(default, skip_serializing_if = "Option::is_none")] - pub libraries: Option>>, + #[serde( + default, + skip_serializing_if = "era_solc::StandardJsonInputLibraries::is_empty" + )] + pub libraries: era_solc::StandardJsonInputLibraries, /// The sorted list of remappings. #[serde(skip_serializing_if = "Option::is_none")] pub remappings: Option>, @@ -40,6 +42,13 @@ pub struct Settings { skip_deserializing )] pub via_ir: Option, + /// Whether to compile via MLIR. + #[serde( + rename = "viaMLIR", + skip_serializing_if = "Option::is_none", + skip_deserializing + )] + pub via_mlir: Option, /// The optimizer settings. pub optimizer: Optimizer, /// The debug settings. @@ -53,19 +62,21 @@ impl Settings { /// pub fn new( evm_version: Option, - libraries: BTreeMap>, + libraries: era_solc::StandardJsonInputLibraries, remappings: Option>, output_selection: Selection, via_ir: bool, + via_mlir: bool, optimizer: Optimizer, debug: Option, ) -> Self { Self { evm_version, - libraries: Some(libraries), + libraries, remappings, output_selection: Some(output_selection), via_ir: if via_ir { Some(true) } else { None }, + via_mlir: if via_mlir { Some(true) } else { None }, optimizer, debug, } diff --git a/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/selection/file/flag.rs b/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/selection/file/flag.rs index dc86bc50..20ef485b 100644 --- a/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/selection/file/flag.rs +++ b/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/selection/file/flag.rs @@ -28,11 +28,11 @@ pub enum Flag { EVMLA, } -impl From for Flag { - fn from(pipeline: era_compiler_solidity::SolcPipeline) -> Self { - match pipeline { - era_compiler_solidity::SolcPipeline::Yul => Self::Yul, - era_compiler_solidity::SolcPipeline::EVMLA => Self::EVMLA, +impl From for Flag { + fn from(codegen: era_solc::StandardJsonInputCodegen) -> Self { + match codegen { + era_solc::StandardJsonInputCodegen::Yul => Self::Yul, + era_solc::StandardJsonInputCodegen::EVMLA => Self::EVMLA, } } } diff --git a/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/selection/file/mod.rs b/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/selection/file/mod.rs index 70b82559..263a60a0 100644 --- a/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/selection/file/mod.rs +++ b/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/selection/file/mod.rs @@ -27,13 +27,13 @@ impl File { /// /// Creates the selection required by EVM compilation process. /// - pub fn new_required(pipeline: era_compiler_solidity::SolcPipeline) -> Self { + pub fn new_required(codegen: era_solc::StandardJsonInputCodegen) -> Self { Self { per_file: Some(HashSet::from_iter([SelectionFlag::AST])), per_contract: Some(HashSet::from_iter([ SelectionFlag::Bytecode, SelectionFlag::MethodIdentifiers, - SelectionFlag::from(pipeline), + SelectionFlag::from(codegen), ])), } } diff --git a/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/selection/mod.rs b/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/selection/mod.rs index c8f84ecd..db6cb4ee 100644 --- a/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/selection/mod.rs +++ b/compiler_tester/src/compilers/solidity/upstream/solc/standard_json/input/settings/selection/mod.rs @@ -22,9 +22,9 @@ impl Selection { /// /// Creates the selection required by EVM compilation process. /// - pub fn new_required(pipeline: era_compiler_solidity::SolcPipeline) -> Self { + pub fn new_required(codegen: era_solc::StandardJsonInputCodegen) -> Self { Self { - all: Some(FileSelection::new_required(pipeline)), + all: Some(FileSelection::new_required(codegen)), } } } diff --git a/compiler_tester/src/compilers/vyper/mod.rs b/compiler_tester/src/compilers/vyper/mod.rs index 678d1565..907d6505 100644 --- a/compiler_tester/src/compilers/vyper/mod.rs +++ b/compiler_tester/src/compilers/vyper/mod.rs @@ -55,7 +55,7 @@ impl Default for VyperCompiler { } impl VyperCompiler { - /// The compiler binaries directory. + /// The compiler executables directory. pub const DIRECTORY: &'static str = "vyper-bin/"; /// @@ -88,7 +88,7 @@ impl VyperCompiler { .file_type() .map_err(|error| anyhow::anyhow!("File {path:?} type getting error: {error}"))?; if !entry_type.is_file() { - anyhow::bail!("Invalid `vyper` binary file type: {path:?}"); + anyhow::bail!("Invalid `vyper` executable file type: {path:?}"); } let file_name = entry.file_name().to_string_lossy().to_string(); @@ -132,11 +132,12 @@ impl VyperCompiler { &mode.vyper_version, paths, &[ - era_compiler_vyper::VyperSelection::IRJson, - era_compiler_vyper::VyperSelection::EraVMAssembly, + era_compiler_vyper::VyperSelector::IRJson, + era_compiler_vyper::VyperSelector::EraVMAssembly, ], evm_version, true, + None, mode.vyper_optimize, ) } @@ -195,7 +196,7 @@ impl Compiler for VyperCompiler { &self, test_path: String, sources: Vec<(String, String)>, - _libraries: BTreeMap>, + libraries: era_solc::StandardJsonInputLibraries, mode: &Mode, llvm_options: Vec, debug_config: Option, @@ -225,7 +226,7 @@ impl Compiler for VyperCompiler { let method_identifiers = Self::get_method_identifiers(&project) .map_err(|error| anyhow::anyhow!("Failed to get method identifiers: {error}"))?; - let build = project.compile( + let mut build = project.compile( None, era_compiler_common::HashType::Ipfs, mode.llvm_optimizer_settings.to_owned(), @@ -233,19 +234,22 @@ impl Compiler for VyperCompiler { vec![], debug_config, )?; + build.link(libraries.as_linker_symbols()?)?; let builds = build .contracts .into_iter() .map(|(path, contract)| { - let build = era_compiler_llvm_context::EraVMBuild::new( + let build = era_compiler_llvm_context::EraVMBuild::new_with_bytecode_hash( contract.build.bytecode, - contract.build.bytecode_hash, + contract.build.bytecode_hash.ok_or_else(|| { + anyhow::anyhow!("Bytecode hash not found in the build artifacts") + })?, None, contract.build.assembly, ); - (path, build) + Ok((path, build)) }) - .collect::>(); + .collect::>>()?; Ok(EraVMInput::new( builds, @@ -258,7 +262,7 @@ impl Compiler for VyperCompiler { &self, _test_path: String, _sources: Vec<(String, String)>, - _libraries: BTreeMap>, + _libraries: era_solc::StandardJsonInputLibraries, _mode: &Mode, _test_params: Option<&solidity_adapter::Params>, _llvm_options: Vec, diff --git a/compiler_tester/src/compilers/vyper/mode.rs b/compiler_tester/src/compilers/vyper/mode.rs index bae8363c..03a80fbf 100644 --- a/compiler_tester/src/compilers/vyper/mode.rs +++ b/compiler_tester/src/compilers/vyper/mode.rs @@ -2,6 +2,7 @@ //! The compiler tester Vyper mode. //! +use crate::compilers::mode::imode::IMode; use crate::compilers::mode::llvm_options::LLVMOptions; use crate::compilers::mode::Mode as ModeWrapper; @@ -9,7 +10,7 @@ use crate::compilers::mode::Mode as ModeWrapper; /// /// The compiler tester Vyper mode. /// -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Mode { /// The Vyper compiler version. pub vyper_version: semver::Version, @@ -75,15 +76,20 @@ impl Mode { }) } } - -impl std::fmt::Display for Mode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "V{}{} {}", +impl IMode for Mode { + fn optimizations(&self) -> Option { + Some(format!( + "{}{}", if self.vyper_optimize { '+' } else { '-' }, self.llvm_optimizer_settings, - self.vyper_version, - ) + )) + } + + fn codegen(&self) -> Option { + Some("V".into()) + } + + fn version(&self) -> Option { + Some(format!("{}", self.vyper_version)) } } diff --git a/compiler_tester/src/compilers/yul/mod.rs b/compiler_tester/src/compilers/yul/mod.rs index 015553bb..133f710a 100644 --- a/compiler_tester/src/compilers/yul/mod.rs +++ b/compiler_tester/src/compilers/yul/mod.rs @@ -5,14 +5,14 @@ pub mod mode; pub mod mode_upstream; -use std::collections::BTreeMap; use std::collections::HashMap; -use era_compiler_solidity::CollectableError; +use era_solc::CollectableError; use crate::compilers::mode::Mode; use crate::compilers::solidity::upstream::solc::standard_json::input::language::Language as SolcStandardJsonInputLanguage; use crate::compilers::solidity::upstream::SolidityCompiler as SolidityUpstreamCompiler; +use crate::compilers::solidity::SolidityCompiler; use crate::compilers::Compiler; use crate::toolchain::Toolchain; use crate::vm::eravm::input::Input as EraVMInput; @@ -26,7 +26,6 @@ use self::mode::Mode as YulMode; /// pub struct YulCompiler { /// The compiler toolchain to use. - #[allow(dead_code)] toolchain: Toolchain, } @@ -56,7 +55,7 @@ impl Compiler for YulCompiler { &self, _test_path: String, sources: Vec<(String, String)>, - _libraries: BTreeMap>, + libraries: era_solc::StandardJsonInputLibraries, mode: &Mode, llvm_options: Vec, debug_config: Option, @@ -66,8 +65,10 @@ impl Compiler for YulCompiler { let solc_version = if mode.enable_eravm_extensions { None } else { - Some(era_compiler_solidity::SolcVersion::new_simple( - era_compiler_solidity::SolcCompiler::LAST_SUPPORTED_VERSION, + Some(era_solc::Version::new( + era_solc::Compiler::LAST_SUPPORTED_VERSION.to_string(), + era_solc::Compiler::LAST_SUPPORTED_VERSION, + SolidityCompiler::LAST_ZKSYNC_SOLC_REVISION, )) }; @@ -77,17 +78,16 @@ impl Compiler for YulCompiler { .0 .clone(); + let linker_symbols = libraries.as_linker_symbols()?; + + let sources = sources + .into_iter() + .map(|(path, source)| (path, era_solc::StandardJsonInputSource::from(source))) + .collect(); + let project = era_compiler_solidity::Project::try_from_yul_sources( - sources - .into_iter() - .map(|(path, source)| { - ( - path, - era_compiler_solidity::SolcStandardJsonInputSource::from(source), - ) - }) - .collect(), - BTreeMap::new(), + sources, + libraries, None, solc_version.as_ref(), debug_config.as_ref(), @@ -100,22 +100,25 @@ impl Compiler for YulCompiler { mode.llvm_optimizer_settings.to_owned(), llvm_options, true, - None, debug_config.clone(), )?; - build.collect_errors()?; + build.check_errors()?; + let build = build.link(linker_symbols); + build.check_errors()?; let builds = build - .contracts - .into_iter() - .map(|(path, result)| { + .results + .into_values() + .map(|result| { let contract = result.expect("Always valid"); - let build = era_compiler_llvm_context::EraVMBuild::new( + let build = era_compiler_llvm_context::EraVMBuild::new_with_bytecode_hash( contract.build.bytecode, - contract.build.bytecode_hash, + contract.build.bytecode_hash.ok_or_else(|| { + anyhow::anyhow!("Bytecode hash not found in the build artifacts") + })?, None, contract.build.assembly, ); - Ok((path, build)) + Ok((contract.name.path, build)) }) .collect::>>()?; @@ -126,7 +129,7 @@ impl Compiler for YulCompiler { &self, test_path: String, sources: Vec<(String, String)>, - libraries: BTreeMap>, + libraries: era_solc::StandardJsonInputLibraries, mode: &Mode, test_params: Option<&solidity_adapter::Params>, _llvm_options: Vec, @@ -134,7 +137,7 @@ impl Compiler for YulCompiler { ) -> anyhow::Result { let language = SolcStandardJsonInputLanguage::Yul; - let solc_compiler = SolidityUpstreamCompiler::new(language); + let solc_compiler = SolidityUpstreamCompiler::new(language, self.toolchain); let solc_output = solc_compiler.standard_json_output_cached( test_path, @@ -188,13 +191,8 @@ impl Compiler for YulCompiler { })? .object .as_str(); - let build = EVMBuild::new( - era_compiler_llvm_context::EVMBuild::new( - hex::decode(bytecode_string).expect("Always valid"), - None, - ), - era_compiler_llvm_context::EVMBuild::default(), - ); + let build = + EVMBuild::new(hex::decode(bytecode_string).expect("Always valid"), vec![]); builds.insert(path, build); } } diff --git a/compiler_tester/src/compilers/yul/mode.rs b/compiler_tester/src/compilers/yul/mode.rs index 8f334a75..2044eb07 100644 --- a/compiler_tester/src/compilers/yul/mode.rs +++ b/compiler_tester/src/compilers/yul/mode.rs @@ -2,6 +2,7 @@ //! The compiler tester Yul mode. //! +use crate::compilers::mode::imode::IMode; use crate::compilers::mode::llvm_options::LLVMOptions; use crate::compilers::mode::Mode as ModeWrapper; @@ -9,7 +10,7 @@ use crate::compilers::mode::Mode as ModeWrapper; /// /// The compiler tester Yul mode. /// -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Mode { /// The optimizer settings. pub llvm_optimizer_settings: era_compiler_llvm_context::OptimizerSettings, @@ -51,8 +52,16 @@ impl Mode { } } -impl std::fmt::Display for Mode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.llvm_optimizer_settings) +impl IMode for Mode { + fn optimizations(&self) -> Option { + Some(format!("{}", self.llvm_optimizer_settings)) + } + + fn codegen(&self) -> Option { + None + } + + fn version(&self) -> Option { + None } } diff --git a/compiler_tester/src/compilers/yul/mode_upstream.rs b/compiler_tester/src/compilers/yul/mode_upstream.rs index 46b58c01..9f6faffa 100644 --- a/compiler_tester/src/compilers/yul/mode_upstream.rs +++ b/compiler_tester/src/compilers/yul/mode_upstream.rs @@ -2,15 +2,17 @@ //! The compiler tester upstream Yul mode. //! -use crate::compilers::mode::Mode as ModeWrapper; +use crate::compilers::mode::{imode::IMode, Mode as ModeWrapper}; /// /// The compiler tester upstream Yul mode. /// -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Mode { /// The Solidity compiler version. pub solc_version: semver::Version, + /// Whether to enable the MLIR codegen. + pub via_mlir: bool, /// Whether to run the Solidity compiler optimizer. pub solc_optimize: bool, } @@ -19,9 +21,10 @@ impl Mode { /// /// A shortcut constructor. /// - pub fn new(solc_version: semver::Version, solc_optimize: bool) -> Self { + pub fn new(solc_version: semver::Version, via_mlir: bool, solc_optimize: bool) -> Self { Self { solc_version, + via_mlir, solc_optimize, } } @@ -41,13 +44,16 @@ impl Mode { } } -impl std::fmt::Display for Mode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "Y{} {}", - if self.solc_optimize { '+' } else { '-' }, - self.solc_version, - ) +impl IMode for Mode { + fn optimizations(&self) -> Option { + Some((if self.solc_optimize { "+" } else { "-" }).to_string()) + } + + fn codegen(&self) -> Option { + Some((if self.via_mlir { "L" } else { "Y" }).to_string()) + } + + fn version(&self) -> Option { + Some(format!("{}", self.solc_version)) } } diff --git a/compiler_tester/src/directories/ethereum/test.rs b/compiler_tester/src/directories/ethereum/test.rs index 04d8fa40..1f2f7742 100644 --- a/compiler_tester/src/directories/ethereum/test.rs +++ b/compiler_tester/src/directories/ethereum/test.rs @@ -14,6 +14,8 @@ use crate::environment::Environment; use crate::filters::Filters; use crate::summary::Summary; use crate::test::case::Case; +use crate::test::description::TestDescription; +use crate::test::selector::TestSelector; use crate::test::Test; use crate::vm::address_iterator::AddressIterator; use crate::vm::eravm::address_iterator::EraVMAddressIterator; @@ -24,8 +26,8 @@ use crate::vm::evm::address_iterator::EVMAddressIterator; /// #[derive(Debug)] pub struct EthereumTest { - /// The test identifier. - pub identifier: String, + /// The test selector. + pub selector: TestSelector, /// The index test entity. pub index_entity: solidity_adapter::EnabledTest, /// The test data. @@ -41,9 +43,9 @@ impl EthereumTest { summary: Arc>, filters: &Filters, ) -> Option { - let identifier = index_entity.path.to_string_lossy().to_string(); + let path = index_entity.path.to_string_lossy().to_string(); - if !filters.check_case_path(&identifier) { + if !filters.check_case_path(&path) { return None; } @@ -51,16 +53,21 @@ impl EthereumTest { return None; } + let selector = TestSelector { + path, + case: None, + input: None, + }; let test = match solidity_adapter::Test::try_from(index_entity.path.as_path()) { Ok(test) => test, Err(error) => { - Summary::invalid(summary, None, identifier, error); + Summary::invalid(summary, TestDescription::default_for(selector), error); return None; } }; Some(Self { - identifier, + selector, index_entity, test, }) @@ -124,7 +131,7 @@ impl EthereumTest { ) -> anyhow::Result<( web3::types::Address, BTreeMap, - BTreeMap>, + era_solc::StandardJsonInputLibraries, )> { let mut caller = solidity_adapter::account_address(solidity_adapter::DEFAULT_ACCOUNT_INDEX); @@ -163,7 +170,7 @@ impl EthereumTest { } let contract_address = contract_address.expect("Always valid"); - Ok((contract_address, libraries_addresses, libraries)) + Ok((contract_address, libraries_addresses, libraries.into())) } /// @@ -177,9 +184,12 @@ impl EthereumTest { None => { Summary::invalid( summary, - Some(mode.to_owned()), - self.identifier.to_owned(), - anyhow::anyhow!("The Ethereum test `{}` sources are empty", self.identifier), + TestDescription { + group: None, + mode: Some(mode.clone()), + selector: self.selector.clone(), + }, + anyhow::anyhow!("The Ethereum test `{}` sources are empty", &self.selector), ); None } @@ -204,6 +214,12 @@ impl Buildable for EthereumTest { let last_source = self.last_source(summary.clone(), &mode)?; + let test_description = TestDescription { + group: None, + mode: Some(mode.clone()), + selector: self.selector.clone(), + }; + let (contract_address, libraries_addresses, libraries) = match self.get_addresses( EraVMAddressIterator::new(), calls.as_slice(), @@ -213,7 +229,7 @@ impl Buildable for EthereumTest { (contract_address, libraries_addresses, libraries) } Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -221,7 +237,7 @@ impl Buildable for EthereumTest { let evm_version = self.test.params.evm_version; let eravm_input = match compiler .compile_for_eravm( - self.identifier.to_owned(), + self.selector.to_string(), self.test.sources.clone(), libraries, &mode, @@ -232,7 +248,7 @@ impl Buildable for EthereumTest { { Ok(output) => output, Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -244,7 +260,7 @@ impl Buildable for EthereumTest { ) { Ok(instance) => instance, Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -257,12 +273,7 @@ impl Buildable for EthereumTest { ) { Ok(case) => case, Err(error) => { - Summary::invalid( - summary.clone(), - Some(mode), - self.identifier.to_owned(), - error, - ); + Summary::invalid(summary.clone(), test_description, error); return None; } }; @@ -272,14 +283,16 @@ impl Buildable for EthereumTest { .into_values() .map(|build| { ( - web3::types::U256::from_big_endian(build.bytecode_hash.as_slice()), + web3::types::U256::from_big_endian( + build.bytecode_hash.expect("Always exists").as_slice(), + ), build.bytecode, ) }) .collect(); Some(Test::new( - self.identifier.to_owned(), + self.selector.to_string(), vec![case], mode, self.index_entity.group.clone(), @@ -303,6 +316,11 @@ impl Buildable for EthereumTest { let mut calls = self.test.calls.clone(); self.insert_deploy_calls(&mut calls); + let test_description = TestDescription { + group: None, + mode: Some(mode.clone()), + selector: self.selector.clone(), + }; let last_source = self.last_source(summary.clone(), &mode)?; let (contract_address, libraries_addresses, libraries) = match self.get_addresses( @@ -314,7 +332,7 @@ impl Buildable for EthereumTest { (contract_address, libraries_addresses, libraries) } Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -322,7 +340,7 @@ impl Buildable for EthereumTest { let evm_version = self.test.params.evm_version; let evm_input = match compiler .compile_for_evm( - self.identifier.to_owned(), + self.selector.to_string(), self.test.sources.clone(), libraries, &mode, @@ -334,7 +352,7 @@ impl Buildable for EthereumTest { { Ok(output) => output, Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -346,7 +364,7 @@ impl Buildable for EthereumTest { ) { Ok(instance) => instance, Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -359,18 +377,13 @@ impl Buildable for EthereumTest { ) { Ok(case) => case, Err(error) => { - Summary::invalid( - summary.clone(), - Some(mode), - self.identifier.to_owned(), - error, - ); + Summary::invalid(summary.clone(), test_description, error); return None; } }; Some(Test::new( - self.identifier.to_owned(), + self.selector.path.to_string(), vec![case], mode, self.index_entity.group.clone(), diff --git a/compiler_tester/src/directories/matter_labs/test/metadata/evm_contract.rs b/compiler_tester/src/directories/matter_labs/test/metadata/evm_contract.rs index 0bcf1005..1bef195e 100644 --- a/compiler_tester/src/directories/matter_labs/test/metadata/evm_contract.rs +++ b/compiler_tester/src/directories/matter_labs/test/metadata/evm_contract.rs @@ -18,9 +18,9 @@ impl EVMContract { pub const RUNTIME_CODE_REPEATS: usize = 32; /// - /// Returns the init code. + /// Returns the deploy code. /// - pub fn init_code(&self, size: usize) -> String { + pub fn deploy_code(&self, size: usize) -> String { if size > 0xffff { panic!("The bytecode is too large"); } diff --git a/compiler_tester/src/directories/matter_labs/test/metadata/mod.rs b/compiler_tester/src/directories/matter_labs/test/metadata/mod.rs index 44c7a198..940a4d23 100644 --- a/compiler_tester/src/directories/matter_labs/test/metadata/mod.rs +++ b/compiler_tester/src/directories/matter_labs/test/metadata/mod.rs @@ -27,7 +27,7 @@ pub struct Metadata { /// The test contracts as `instance -> path`. #[serde(default)] pub contracts: BTreeMap, - /// The EVM auxiliary contracts as `instance -> init code`. + /// The EVM auxiliary contracts as `instance -> deploy code`. #[serde(default)] pub evm_contracts: BTreeMap, /// The test libraries for linking. diff --git a/compiler_tester/src/directories/matter_labs/test/mod.rs b/compiler_tester/src/directories/matter_labs/test/mod.rs index b9154bac..184d2fca 100644 --- a/compiler_tester/src/directories/matter_labs/test/mod.rs +++ b/compiler_tester/src/directories/matter_labs/test/mod.rs @@ -19,7 +19,9 @@ use crate::environment::Environment; use crate::filters::Filters; use crate::summary::Summary; use crate::test::case::Case; +use crate::test::description::TestDescription; use crate::test::instance::Instance; +use crate::test::selector::TestSelector; use crate::test::Test; use crate::vm::address_iterator::AddressIterator; use crate::vm::eravm::address_iterator::EraVMAddressIterator; @@ -61,8 +63,8 @@ pub fn default_caller_address() -> String { pub struct MatterLabsTest { /// The test path. path: PathBuf, - /// The test identifier. - identifier: String, + /// The test selector. + selector: TestSelector, /// The test metadata. metadata: Metadata, /// The test sources. @@ -74,16 +76,22 @@ impl MatterLabsTest { /// Try to create new test. /// pub fn new(path: PathBuf, summary: Arc>, filters: &Filters) -> Option { - let identifier = path.to_string_lossy().to_string(); + let selector = TestSelector { + path: path.to_string_lossy().to_string(), + case: None, + input: None, + }; - if !filters.check_test_path(identifier.as_str()) { + if !filters.check_test_path(selector.path.to_string().as_str()) { return None; } + let test_description = TestDescription::default_for(selector.clone()); + let main_file_string = match std::fs::read_to_string(path.as_path()) { Ok(data) => data, Err(error) => { - Summary::invalid(summary, None, identifier.clone(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -93,13 +101,13 @@ impl MatterLabsTest { { Ok(metadata) => metadata, Err(error) => { - Summary::invalid(summary, None, identifier.clone(), error); + Summary::invalid(summary, test_description, error); return None; } }; if metadata.ignore { - Summary::ignored(summary, identifier.clone()); + Summary::ignored(summary, test_description); return None; } @@ -147,7 +155,7 @@ impl MatterLabsTest { { Ok(source) => source, Err(error) => { - Summary::invalid(summary, None, identifier.clone(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -157,12 +165,19 @@ impl MatterLabsTest { }; metadata.cases.retain(|case| { - let case_name = format!("{}::{}", identifier, case.name); + let selector_with_case = TestSelector { + path: selector.path.clone(), + case: Some(case.name.clone()), + input: selector.input.clone(), + }; if case.ignore { - Summary::ignored(summary.clone(), case_name); + Summary::ignored( + summary.clone(), + TestDescription::default_for(selector_with_case), + ); return false; } - + let case_name = selector_with_case.to_string(); if !filters.check_case_path(&case_name) { return false; } @@ -171,7 +186,7 @@ impl MatterLabsTest { Some(Self { path, - identifier, + selector, metadata, sources, }) @@ -215,9 +230,9 @@ impl MatterLabsTest { ) { if contracts.is_empty() { let contract_name = if is_multi_contract { - format!("{}:{}", self.identifier, SIMPLE_TESTS_CONTRACT_NAME) + format!("{}:{}", self.selector.path, SIMPLE_TESTS_CONTRACT_NAME) } else { - self.identifier.to_owned() + self.selector.path.to_string() }; contracts.insert(SIMPLE_TESTS_INSTANCE.to_owned(), contract_name); } @@ -230,7 +245,7 @@ impl MatterLabsTest { &self, address_iterator: &mut API, ) -> ( - BTreeMap>, + era_solc::StandardJsonInputLibraries, BTreeMap, ) where @@ -262,7 +277,7 @@ impl MatterLabsTest { libraries.insert(file_path.to_string_lossy().to_string(), file_libraries); } - (libraries, library_addresses) + (libraries.into(), library_addresses) } /// @@ -274,7 +289,7 @@ impl MatterLabsTest { for (instance, evm_contract) in self.metadata.evm_contracts.iter() { let instruction_name = instance.split('_').next().expect("Always exists"); let runtime_code = evm_contract.runtime_code(instruction_name); - let mut bytecode = evm_contract.init_code(runtime_code.len()); + let mut bytecode = evm_contract.deploy_code(runtime_code.len()); bytecode.push_str(runtime_code.as_str()); let bytecode = hex::decode(bytecode.as_str()).map_err(|error| { @@ -289,14 +304,18 @@ impl MatterLabsTest { Ok(instances) } + fn is_evm_interpreter_test(&self) -> bool { + matches!( + self.metadata.group.as_deref(), + Some(benchmark_analyzer::TEST_GROUP_EVM_INTERPRETER) + ) + } /// /// Returns cases needed for running benchmarks on the EVM interpreter. /// - fn evm_interpreter_benchmark_cases(&self) -> Vec { - if self.metadata.group.as_deref() - != Some(benchmark_analyzer::Benchmark::EVM_INTERPRETER_GROUP_NAME) - { - return vec![]; + fn evm_interpreter_benchmark_cases(&self) -> Option> { + if !self.is_evm_interpreter_test() { + return None; } let mut evm_contracts: Vec = self @@ -383,7 +402,7 @@ impl MatterLabsTest { expected_evm: None, }) } - metadata_cases + Some(metadata_cases) } } @@ -398,7 +417,6 @@ impl Buildable for MatterLabsTest { debug_config: Option, ) -> Option { mode.enable_eravm_extensions(self.metadata.enable_eravm_extensions); - self.check_filters(filters, &mode, era_compiler_common::Target::EraVM)?; let mut contracts = self.metadata.contracts.clone(); @@ -407,11 +425,16 @@ impl Buildable for MatterLabsTest { let mut eravm_address_iterator = EraVMAddressIterator::new(); let evm_address_iterator = EVMAddressIterator::default(); - let (libraries, library_addresses) = self.get_libraries(&mut eravm_address_iterator); + let test_description = TestDescription { + group: None, + mode: Some(mode.clone()), + selector: self.selector.clone(), + }; + let (libraries, library_addresses) = self.get_libraries(&mut eravm_address_iterator); let eravm_input = match compiler .compile_for_eravm( - self.identifier.to_owned(), + self.selector.path.to_string(), self.sources.clone(), libraries, &mode, @@ -422,7 +445,7 @@ impl Buildable for MatterLabsTest { { Ok(vm_input) => vm_input, Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -434,7 +457,7 @@ impl Buildable for MatterLabsTest { ) { Ok(instances) => instances, Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -442,14 +465,19 @@ impl Buildable for MatterLabsTest { let evm_instances = match self.get_evm_instances() { Ok(evm_instances) => evm_instances, Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } }; instances.extend(evm_instances); - let mut metadata_cases = self.metadata.cases.to_owned(); - metadata_cases.extend(self.evm_interpreter_benchmark_cases()); + let metadata_cases = { + let mut base_cases = self.metadata.cases.to_owned(); + if let Some(opcode_test_cases) = self.evm_interpreter_benchmark_cases() { + base_cases.extend(opcode_test_cases); + } + base_cases + }; let mut cases = Vec::with_capacity(metadata_cases.len()); for case in metadata_cases.into_iter() { @@ -462,7 +490,7 @@ impl Buildable for MatterLabsTest { let case = match case.normalize(&contracts, &instances, environment) { Ok(case) => case, Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -475,7 +503,7 @@ impl Buildable for MatterLabsTest { ) { Ok(_) => {} Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } } @@ -492,7 +520,7 @@ impl Buildable for MatterLabsTest { { Ok(case) => case, Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -505,14 +533,16 @@ impl Buildable for MatterLabsTest { .into_values() .map(|build| { ( - web3::types::U256::from_big_endian(build.bytecode_hash.as_slice()), + web3::types::U256::from_big_endian( + build.bytecode_hash.expect("Always exists").as_slice(), + ), build.bytecode, ) }) .collect(); Some(Test::new( - self.identifier.to_owned(), + self.selector.to_string(), cases, mode, self.metadata.group.clone(), @@ -540,9 +570,15 @@ impl Buildable for MatterLabsTest { let (libraries, library_addresses) = self.get_libraries(&mut evm_address_iterator); + let test_description = TestDescription { + group: None, + mode: Some(mode.clone()), + selector: self.selector.clone(), + }; + let evm_input = match compiler .compile_for_evm( - self.identifier.to_owned(), + self.selector.path.to_string(), sources, libraries, &mode, @@ -554,7 +590,7 @@ impl Buildable for MatterLabsTest { { Ok(output) => output, Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -562,7 +598,7 @@ impl Buildable for MatterLabsTest { let mut instances = match evm_input.get_instances(&contracts, library_addresses, None) { Ok(instances) => instances, Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -581,7 +617,7 @@ impl Buildable for MatterLabsTest { { Ok(case) => case, Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -594,7 +630,7 @@ impl Buildable for MatterLabsTest { ) { Ok(_) => {} Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } } @@ -611,7 +647,7 @@ impl Buildable for MatterLabsTest { { Ok(case) => case, Err(error) => { - Summary::invalid(summary, Some(mode), self.identifier.to_owned(), error); + Summary::invalid(summary, test_description, error); return None; } }; @@ -620,7 +656,7 @@ impl Buildable for MatterLabsTest { } Some(Test::new( - self.identifier.to_owned(), + self.selector.to_string(), cases, mode, self.metadata.group.clone(), diff --git a/compiler_tester/src/filters.rs b/compiler_tester/src/filters.rs index 7e09992c..8a0ed2e7 100644 --- a/compiler_tester/src/filters.rs +++ b/compiler_tester/src/filters.rs @@ -30,7 +30,12 @@ impl Filters { ) -> Self { Self { path_filters: path_filters.into_iter().collect(), - mode_filters: mode_filters.into_iter().collect(), + // Mode filters are stripped of spaces so filters like "Y+M3B3 + // 0.2.1 " and "Y +M3B3 0.2.1" become equivalent + mode_filters: mode_filters + .into_iter() + .map(|f| f.replace(' ', "")) + .collect(), group_filters: group_filters.into_iter().collect(), } } diff --git a/compiler_tester/src/lib.rs b/compiler_tester/src/lib.rs index 4793eacc..ff5c2a57 100644 --- a/compiler_tester/src/lib.rs +++ b/compiler_tester/src/lib.rs @@ -123,11 +123,11 @@ impl CompilerTester { /// /// Runs all tests on EraVM. /// - pub fn run_eravm(self, vm: EraVM) -> anyhow::Result<()> + pub fn run_eravm(self, vm: EraVM, toolchain: Toolchain) -> anyhow::Result<()> where D: EraVMDeployer, { - let tests = self.all_tests(era_compiler_common::Target::EraVM, Toolchain::IrLLVM)?; + let tests = self.all_tests(era_compiler_common::Target::EraVM, toolchain)?; let vm = Arc::new(vm); let _: Vec<()> = tests @@ -266,12 +266,14 @@ impl CompilerTester { let solidity_compiler = Arc::new(SolidityCompiler::new()); let solidity_upstream_compiler = Arc::new(SolidityUpstreamCompiler::new( SolcStandardJsonInputLanguage::Solidity, + toolchain, )); let solidity_upstream_yul_compiler = Arc::new(SolidityUpstreamCompiler::new( SolcStandardJsonInputLanguage::Yul, + toolchain, )); - let vyper_compiler = Arc::new(VyperCompiler::new()); let yul_compiler = Arc::new(YulCompiler::new(toolchain)); + let vyper_compiler = Arc::new(VyperCompiler::new()); let llvm_compiler = Arc::new(LLVMCompiler); let eravm_compiler = Arc::new(EraVMCompiler); @@ -283,8 +285,7 @@ impl CompilerTester { era_compiler_common::EXTENSION_SOLIDITY, match toolchain { Toolchain::IrLLVM => solidity_compiler.clone(), - Toolchain::Solc => solidity_upstream_compiler.clone(), - Toolchain::SolcLLVM => todo!(), + Toolchain::Solc | Toolchain::SolcLLVM => solidity_upstream_compiler.clone(), }, )?); if let era_compiler_common::Target::EraVM = target { @@ -301,8 +302,7 @@ impl CompilerTester { era_compiler_common::EXTENSION_YUL, match toolchain { Toolchain::IrLLVM => yul_compiler.clone(), - Toolchain::Solc => solidity_upstream_yul_compiler.clone(), - Toolchain::SolcLLVM => todo!(), + Toolchain::Solc | Toolchain::SolcLLVM => solidity_upstream_yul_compiler.clone(), }, )?); tests.extend(self.directory::( @@ -324,8 +324,7 @@ impl CompilerTester { era_compiler_common::EXTENSION_JSON, match toolchain { Toolchain::IrLLVM => solidity_compiler.clone(), - Toolchain::Solc => solidity_upstream_compiler.clone(), - Toolchain::SolcLLVM => todo!(), + Toolchain::Solc | Toolchain::SolcLLVM => solidity_upstream_compiler.clone(), }, )?); if let era_compiler_common::Target::EraVM = target { @@ -346,8 +345,7 @@ impl CompilerTester { era_compiler_common::EXTENSION_SOLIDITY, match toolchain { Toolchain::IrLLVM => solidity_compiler.clone(), - Toolchain::Solc => solidity_upstream_compiler.clone(), - Toolchain::SolcLLVM => todo!(), + Toolchain::Solc | Toolchain::SolcLLVM => solidity_upstream_compiler.clone(), }, )?); if let era_compiler_common::Target::EraVM = target { diff --git a/compiler_tester/src/summary/benchmark_adapters/input.rs b/compiler_tester/src/summary/benchmark_adapters/input.rs new file mode 100644 index 00000000..85b59b97 --- /dev/null +++ b/compiler_tester/src/summary/benchmark_adapters/input.rs @@ -0,0 +1,32 @@ +//! +//! Converts `[InputIdentifier]` to the representation used by the benchmark. +//! + +use crate::test::case::input::identifier::InputIdentifier; + +impl From for benchmark_analyzer::Input { + /// + /// Converts `[InputIdentifier]` to the representation used by the benchmark. + /// + fn from(val: InputIdentifier) -> Self { + match val { + InputIdentifier::Deployer { + contract_identifier, + } => benchmark_analyzer::Input::Deployer { + contract_identifier, + }, + InputIdentifier::Runtime { input_index, name } => { + benchmark_analyzer::Input::Runtime { input_index, name } + } + InputIdentifier::StorageEmpty { input_index } => { + benchmark_analyzer::Input::StorageEmpty { input_index } + } + InputIdentifier::Balance { input_index } => { + benchmark_analyzer::Input::Balance { input_index } + } + InputIdentifier::Fallback { input_index } => { + benchmark_analyzer::Input::Fallback { input_index } + } + } + } +} diff --git a/compiler_tester/src/summary/benchmark_adapters/metadata.rs b/compiler_tester/src/summary/benchmark_adapters/metadata.rs new file mode 100644 index 00000000..cef3f580 --- /dev/null +++ b/compiler_tester/src/summary/benchmark_adapters/metadata.rs @@ -0,0 +1,11 @@ +//! +//! Converts `[TestDescription]` to the representation used by the benchmark. +//! + +use crate::test::description::TestDescription; + +impl From for benchmark_analyzer::ExecutableMetadata { + fn from(_: TestDescription) -> Self { + benchmark_analyzer::ExecutableMetadata {} + } +} diff --git a/compiler_tester/src/summary/benchmark_adapters/mod.rs b/compiler_tester/src/summary/benchmark_adapters/mod.rs new file mode 100644 index 00000000..24643d12 --- /dev/null +++ b/compiler_tester/src/summary/benchmark_adapters/mod.rs @@ -0,0 +1,9 @@ +//! +//! Adapters to convert the test information defined in `compiler_tester` to the +//! representation used by `benchmark_analyzer`. +//! + +pub mod input; +pub mod metadata; +pub mod mode; +pub mod selector; diff --git a/compiler_tester/src/summary/benchmark_adapters/mode.rs b/compiler_tester/src/summary/benchmark_adapters/mode.rs new file mode 100644 index 00000000..76b063de --- /dev/null +++ b/compiler_tester/src/summary/benchmark_adapters/mode.rs @@ -0,0 +1,36 @@ +//! +//! Representation of compiler mode stored in the benchmark. +//! + +use crate::compilers::mode::imode::IMode; + +const DEFAULT_CODEGEN: &str = "NoCodegen"; +const DEFAULT_OPTIMIZATIONS: &str = "NoOptimizations"; +const DEFAULT_VERSION: &str = "NoVersion"; + +/// +/// Representation of compiler mode stored in the benchmark. +/// +pub struct ModeInfo { + /// Codegen type if applicable, or a default value [`DEFAULT_CODEGEN`]. + pub codegen: String, + /// Optimization level if applicable, or a default value [`DEFAULT_OPTIMIZATIONS`]. + pub optimizations: String, + /// Language version if applicable, or a default value [`DEFAULT_VERSION`]. + pub version: String, +} + +impl From for ModeInfo +where + T: IMode, +{ + fn from(value: T) -> ModeInfo { + ModeInfo { + codegen: value.codegen().unwrap_or(DEFAULT_CODEGEN.into()), + optimizations: value + .optimizations() + .unwrap_or(DEFAULT_OPTIMIZATIONS.into()), + version: value.version().unwrap_or(DEFAULT_VERSION.into()), + } + } +} diff --git a/compiler_tester/src/summary/benchmark_adapters/selector.rs b/compiler_tester/src/summary/benchmark_adapters/selector.rs new file mode 100644 index 00000000..9f027e63 --- /dev/null +++ b/compiler_tester/src/summary/benchmark_adapters/selector.rs @@ -0,0 +1,13 @@ +//! +//! Converts `[TestSelector]` to the representation used by the benchmark. +//! + +use crate::test::selector::TestSelector; + +impl From for benchmark_analyzer::TestSelector { + fn from(selector: TestSelector) -> Self { + let TestSelector { path, case, input } = selector; + let input = input.map(Into::into); + benchmark_analyzer::TestSelector { path, case, input } + } +} diff --git a/compiler_tester/src/summary/element/mod.rs b/compiler_tester/src/summary/element/mod.rs index fd0f6e48..f1a6a01c 100644 --- a/compiler_tester/src/summary/element/mod.rs +++ b/compiler_tester/src/summary/element/mod.rs @@ -6,7 +6,7 @@ pub mod outcome; use colored::Colorize; -use crate::compilers::mode::Mode; +use crate::test::description::TestDescription; use self::outcome::passed_variant::PassedVariant; use self::outcome::Outcome; @@ -16,10 +16,8 @@ use self::outcome::Outcome; /// #[derive(Debug)] pub struct Element { - /// The mode. - pub mode: Option, - /// The test name. - pub name: String, + /// Information about test instance. + pub test_description: TestDescription, /// The test outcome. pub outcome: Outcome, } @@ -28,10 +26,9 @@ impl Element { /// /// A shortcut constructor. /// - pub fn new(mode: Option, name: String, outcome: Outcome) -> Self { + pub fn new(name: TestDescription, outcome: Outcome) -> Self { Self { - mode, - name, + test_description: name, outcome, } } @@ -103,13 +100,14 @@ impl Element { Some(format!( "{:16} {:>7} {} {}", - self.mode + self.test_description + .mode .as_ref() .map(|mode| mode.to_string()) .unwrap_or_default() .bright_white(), outcome, - self.name, + self.test_description.selector, details )) } diff --git a/compiler_tester/src/summary/mod.rs b/compiler_tester/src/summary/mod.rs index a3ab5a56..fdf5ef0a 100644 --- a/compiler_tester/src/summary/mod.rs +++ b/compiler_tester/src/summary/mod.rs @@ -2,20 +2,27 @@ //! The compiler tester summary. //! +pub mod benchmark_adapters; pub mod element; use std::sync::Arc; use std::sync::Mutex; +use benchmark_adapters::mode::ModeInfo; use colored::Colorize; -use crate::compilers::mode::Mode; use crate::test::case::input::output::Output; +use crate::test::description::TestDescription; +use crate::toolchain::Toolchain; +use crate::utils::timer::Timer; use self::element::outcome::passed_variant::PassedVariant; use self::element::outcome::Outcome; use self::element::Element; +const BENCHMARK_FORMAT_VERSION: benchmark_analyzer::BenchmarkVersion = + benchmark_analyzer::BenchmarkVersion::V2; + /// /// The compiler tester summary. /// @@ -35,6 +42,7 @@ pub struct Summary { invalid: usize, /// The ignored tests counter. ignored: usize, + timer: Timer, } impl Summary { @@ -53,9 +61,33 @@ impl Summary { failed: 0, invalid: 0, ignored: 0, + timer: Timer::default(), } } + /// Starts the timer associated with the object. + /// + /// # Returns + /// + /// `anyhow::Result`: If the timer is successfully started, the function + /// returns `Ok(self)`, allowing method chaining. If the timer is in an invalid + /// state (e.g., already started or stopped), it returns an error. + pub fn start_timer(mut self) -> anyhow::Result { + self.timer.start()?; + Ok(self) + } + + /// Stops the timer associated with the object. + /// + /// # Returns + /// + /// `anyhow::Result`: If the timer is successfully stopped, the function + /// returns `Ok(self)`, permitting method chaining. An error is returned if the + /// timer is in an invalid state (e.g., not started or already stopped). + pub fn stop_timer(mut self) -> anyhow::Result { + self.timer.stop()?; + Ok(self) + } /// /// Whether the test run has been successful. /// @@ -75,27 +107,39 @@ impl Summary { /// /// Returns the benchmark structure. /// - pub fn benchmark(&self) -> anyhow::Result { + pub fn benchmark( + &self, + toolchain: Toolchain, + context: Option, + ) -> anyhow::Result { + if let Toolchain::SolcLLVM = toolchain { + anyhow::bail!("The benchmarking is not supported for the SolcLLVM toolchain.") + } + let mut benchmark = benchmark_analyzer::Benchmark::default(); - benchmark.groups.insert( - format!( - "{} {}", - benchmark_analyzer::BENCHMARK_ALL_GROUP_NAME, - era_compiler_llvm_context::OptimizerSettings::cycles(), - ), - benchmark_analyzer::BenchmarkGroup::default(), - ); - benchmark.groups.insert( - format!( - "{} {}", - benchmark_analyzer::BENCHMARK_ALL_GROUP_NAME, - era_compiler_llvm_context::OptimizerSettings::size(), - ), - benchmark_analyzer::BenchmarkGroup::default(), - ); - for element in self.elements.iter() { - let (size, cycles, ergs, group, gas) = match &element.outcome { + if let (Some(start), Some(end)) = (self.timer.get_start(), self.timer.get_end()) { + benchmark.metadata = benchmark_analyzer::BenchmarkMetadata { + version: BENCHMARK_FORMAT_VERSION, + start, + end, + context, + }; + } else { + anyhow::bail!("Invalid state: the time of running the benchmark was not measured."); + } + + for Element { + test_description: + TestDescription { + group, + mode, + selector, + }, + outcome, + } in self.elements.iter() + { + let (size, cycles, ergs, gas) = match outcome { Outcome::Passed { variant: PassedVariant::Deploy { @@ -104,45 +148,51 @@ impl Summary { ergs, gas, }, - group, - } => (Some(*size), *cycles, *ergs, group.clone(), *gas), + .. + } => (Some(*size), *cycles, *ergs, *gas), Outcome::Passed { variant: PassedVariant::Runtime { cycles, ergs, gas }, - group, - } => (None, *cycles, *ergs, group.clone(), *gas), + .. + } => (None, *cycles, *ergs, *gas), _ => continue, }; - let key = format!( - "{:24} {}", - element - .mode - .as_ref() - .map(|mode| mode.to_string()) - .unwrap_or_default(), - element.name - ); - let mode = element - .mode - .as_ref() - .and_then(|mode| mode.llvm_optimizer_settings().cloned()) - .unwrap_or(era_compiler_llvm_context::OptimizerSettings::none()); - - let benchmark_element = - benchmark_analyzer::BenchmarkElement::new(size, cycles, ergs, gas); - if let Some(group) = group { - benchmark - .groups - .entry(format!("{} {}", group, mode)) - .or_default() - .elements - .insert(key.clone(), benchmark_element.clone()); - } - - let group_key = format!("{} {}", benchmark_analyzer::BENCHMARK_ALL_GROUP_NAME, mode); - if let Some(group) = benchmark.groups.get_mut(group_key.as_str()) { - group.elements.insert(key, benchmark_element); - } + let test_name = selector.to_string(); + + let tags: Vec = group.iter().cloned().collect(); + + let ModeInfo { + codegen, + optimizations, + version, + } = mode + .clone() + .expect("The compiler mode is missing from description.") + .into(); + + benchmark + .tests + .entry(test_name) + .or_insert(benchmark_analyzer::Test::new( + benchmark_analyzer::TestMetadata::new(selector.clone().into(), tags), + )) + .codegen_groups + .entry(codegen) + .or_insert(Default::default()) + .versioned_groups + .entry(version) + .or_insert(Default::default()) + .executables + .entry(optimizations) + .or_insert(benchmark_analyzer::Executable { + metadata: benchmark_analyzer::ExecutableMetadata {}, + run: benchmark_analyzer::Run { + size, + cycles, + ergs, + gas, + }, + }); } Ok(benchmark) } @@ -169,9 +219,7 @@ impl Summary { /// pub fn passed_deploy( summary: Arc>, - mode: Mode, - name: String, - group: Option, + test: TestDescription, size: usize, cycles: usize, ergs: u64, @@ -183,7 +231,7 @@ impl Summary { ergs, gas, }; - Self::passed(summary, mode, name, group, passed_variant); + Self::passed(summary, test, passed_variant); } /// @@ -191,28 +239,21 @@ impl Summary { /// pub fn passed_runtime( summary: Arc>, - mode: Mode, - name: String, - group: Option, + test: TestDescription, cycles: usize, ergs: u64, gas: u64, ) { let passed_variant = PassedVariant::Runtime { cycles, ergs, gas }; - Self::passed(summary, mode, name, group, passed_variant); + Self::passed(summary, test, passed_variant); } /// /// Adds a passed outcome of a special call, like `storageEmpty` or `balance`. /// - pub fn passed_special( - summary: Arc>, - mode: Mode, - name: String, - group: Option, - ) { + pub fn passed_special(summary: Arc>, test: TestDescription) { let passed_variant = PassedVariant::Special; - Self::passed(summary, mode, name, group, passed_variant); + Self::passed(summary, test, passed_variant); } /// @@ -220,46 +261,40 @@ impl Summary { /// pub fn failed( summary: Arc>, - mode: Mode, - name: String, + test: TestDescription, expected: Output, found: Output, calldata: Vec, ) { - let element = Element::new(Some(mode), name, Outcome::failed(expected, found, calldata)); + let element = Element::new(test, Outcome::failed(expected, found, calldata)); summary.lock().expect("Sync").push_element(element); } /// /// Adds an invalid outcome. /// - pub fn invalid(summary: Arc>, mode: Option, name: String, error: S) + pub fn invalid(summary: Arc>, test: TestDescription, error: S) where S: ToString, { - let element = Element::new(mode, name, Outcome::invalid(error)); + let element = Element::new(test, Outcome::invalid(error)); summary.lock().expect("Sync").push_element(element); } /// /// Adds an ignored outcome. /// - pub fn ignored(summary: Arc>, name: String) { - let element = Element::new(None, name, Outcome::ignored()); + pub fn ignored(summary: Arc>, test: TestDescription) { + let element = Element::new(test.with_erased_mode(), Outcome::ignored()); summary.lock().expect("Sync").push_element(element); } /// /// The unified function for passed outcomes. /// - fn passed( - summary: Arc>, - mode: Mode, - name: String, - group: Option, - passed_variant: PassedVariant, - ) { - let element = Element::new(Some(mode), name, Outcome::passed(group, passed_variant)); + fn passed(summary: Arc>, test: TestDescription, passed_variant: PassedVariant) { + let group = test.group.clone(); + let element = Element::new(test, Outcome::passed(group, passed_variant)); summary.lock().expect("Sync").push_element(element); } diff --git a/compiler_tester/src/test/case/input/balance.rs b/compiler_tester/src/test/case/input/balance.rs index 9da934c6..db6ad675 100644 --- a/compiler_tester/src/test/case/input/balance.rs +++ b/compiler_tester/src/test/case/input/balance.rs @@ -5,10 +5,11 @@ use std::sync::Arc; use std::sync::Mutex; -use web3::types::U256; - -use crate::compilers::mode::Mode; use crate::summary::Summary; +use crate::test::case::input::identifier::InputIdentifier; +use crate::test::context::input::InputContext; +use crate::test::description::TestDescription; +use crate::vm::eravm::system_context::SystemContext; use crate::vm::eravm::EraVM; use crate::vm::evm::EVM; use crate::vm::revm::revm_type_conversions::web3_address_to_revm_address; @@ -41,21 +42,31 @@ impl Balance { pub fn run_eravm( self, summary: Arc>, - vm: &EraVM, - mode: Mode, - test_group: Option, - name_prefix: String, - index: usize, + vm: &mut EraVM, + context: InputContext<'_>, ) { - let name = format!("{name_prefix}[#balance_check:{index}]"); + let input_index = context.selector; + let identifier = + TestDescription::from_context(context, InputIdentifier::Balance { input_index }); + let rich_addresses = SystemContext::get_rich_addresses(); + if rich_addresses.contains(&self.address) { + vm.mint_ether( + self.address, + web3::types::U256::from_str_radix( + "10000000000000000000000000", + era_compiler_common::BASE_HEXADECIMAL, + ) + .expect("Always valid"), + ); + } + let found = vm.get_balance(self.address); if found == self.balance { - Summary::passed_special(summary, mode, name, test_group); + Summary::passed_special(summary, identifier); } else { Summary::failed( summary, - mode, - name, + identifier, self.balance.into(), found.into(), self.address.to_fixed_bytes().to_vec(), @@ -70,10 +81,7 @@ impl Balance { self, _summary: Arc>, _vm: &EVM, - _mode: Mode, - _test_group: Option, - _name_prefix: String, - _index: usize, + _context: InputContext<'_>, ) { todo!() } @@ -81,16 +89,9 @@ impl Balance { /// /// Runs the balance check on REVM. /// - pub fn run_revm( - self, - summary: Arc>, - vm: &mut Revm, - mode: Mode, - test_group: Option, - name_prefix: String, - index: usize, - ) { - let name = format!("{name_prefix}[#balance_check:{index}]"); + pub fn run_revm(self, summary: Arc>, vm: &mut Revm, context: InputContext<'_>) { + let input_index = context.selector; + let test = TestDescription::from_context(context, InputIdentifier::Balance { input_index }); let found = vm .state .context @@ -98,14 +99,13 @@ impl Balance { .balance(web3_address_to_revm_address(&self.address)); match found { Ok(found) => { - let u256_found = U256::from(found.data.to_be_bytes()); + let u256_found = web3::types::U256::from(found.data.to_be_bytes()); if u256_found == self.balance { - Summary::passed_special(summary, mode, name, test_group); + Summary::passed_special(summary, test); } else { Summary::failed( summary, - mode, - name, + test, self.balance.into(), u256_found.into(), self.address.to_fixed_bytes().to_vec(), @@ -115,10 +115,9 @@ impl Balance { Err(_) => { Summary::failed( summary, - mode, - name, + test, self.balance.into(), - U256::zero().into(), + web3::types::U256::zero().into(), self.address.to_fixed_bytes().to_vec(), ); } @@ -132,20 +131,17 @@ impl Balance { self, summary: Arc>, vm: &EraVM, - mode: Mode, - test_group: Option, - name_prefix: String, - index: usize, + context: InputContext<'_>, ) { - let name = format!("{name_prefix}[#balance_check:{index}]"); + let input_index = context.selector; + let test = TestDescription::from_context(context, InputIdentifier::Balance { input_index }); let found = vm.get_balance(self.address); if found == self.balance { - Summary::passed_special(summary, mode, name, test_group); + Summary::passed_special(summary, test); } else { Summary::failed( summary, - mode, - name, + test, self.balance.into(), found.into(), self.address.to_fixed_bytes().to_vec(), diff --git a/compiler_tester/src/test/case/input/deploy_eravm.rs b/compiler_tester/src/test/case/input/deploy_eravm.rs index 6e0493c4..790b9e1c 100644 --- a/compiler_tester/src/test/case/input/deploy_eravm.rs +++ b/compiler_tester/src/test/case/input/deploy_eravm.rs @@ -5,11 +5,13 @@ use std::sync::Arc; use std::sync::Mutex; -use crate::compilers::mode::Mode; use crate::summary::Summary; use crate::test::case::input::calldata::Calldata; +use crate::test::case::input::identifier::InputIdentifier; use crate::test::case::input::output::Output; use crate::test::case::input::storage::Storage; +use crate::test::description::TestDescription; +use crate::test::InputContext; use crate::vm::eravm::deployers::EraVMDeployer; use crate::vm::eravm::EraVM; @@ -67,18 +69,21 @@ impl DeployEraVM { self, summary: Arc>, vm: &mut EraVM, - mode: Mode, deployer: &mut D, - test_group: Option, - name_prefix: String, + context: InputContext<'_>, ) where D: EraVMDeployer, { - let name = format!("{}[#deployer:{}]", name_prefix, self.path); - + let test = TestDescription::from_context( + context, + InputIdentifier::Deployer { + contract_identifier: self.path, + }, + ); + let name = test.selector.path.to_string(); vm.populate_storage(self.storage.inner); let result = match deployer.deploy_eravm::( - name.clone(), + name, self.caller, self.hash, self.calldata.inner.clone(), @@ -87,7 +92,7 @@ impl DeployEraVM { ) { Ok(result) => result, Err(error) => { - Summary::invalid(summary, Some(mode), name, error); + Summary::invalid(summary, test, error); return; } }; @@ -96,9 +101,7 @@ impl DeployEraVM { let build_size = vm.get_contract_size(self.hash); Summary::passed_deploy( summary, - mode, - name, - test_group, + test, build_size, result.cycles, result.ergs, @@ -107,8 +110,7 @@ impl DeployEraVM { } else { Summary::failed( summary, - mode, - name, + test, self.expected, result.output, self.calldata.inner, diff --git a/compiler_tester/src/test/case/input/deploy_evm.rs b/compiler_tester/src/test/case/input/deploy_evm.rs index b6d9ca30..ebb9fdf6 100644 --- a/compiler_tester/src/test/case/input/deploy_evm.rs +++ b/compiler_tester/src/test/case/input/deploy_evm.rs @@ -2,8 +2,6 @@ //! The EVM deploy contract call input variant. //! -use std::collections::HashMap; -use std::hash::RandomState; use std::sync::Arc; use std::sync::Mutex; @@ -11,14 +9,15 @@ use revm::primitives::EVMError; use revm::primitives::ExecutionResult; use solidity_adapter::EVMVersion; -use crate::compilers::mode::Mode; use crate::summary::Summary; use crate::test::case::input::calldata::Calldata; +use crate::test::case::input::identifier::InputIdentifier; use crate::test::case::input::output::Output; use crate::test::case::input::storage::Storage; +use crate::test::description::TestDescription; +use crate::test::InputContext; use crate::vm::eravm::deployers::EraVMDeployer; use crate::vm::eravm::EraVM; -use crate::vm::evm::input::build::Build; use crate::vm::evm::EVM; use crate::vm::revm::revm_type_conversions::revm_bytes_to_vec_value; @@ -32,8 +31,8 @@ use crate::vm::revm::Revm; pub struct DeployEVM { /// The contract identifier. identifier: String, - /// The contract init code. - init_code: Vec, + /// The contract deploy code. + deploy_code: Vec, /// The calldata. calldata: Calldata, /// The caller. @@ -52,7 +51,7 @@ impl DeployEVM { /// pub fn new( identifier: String, - init_code: Vec, + deploy_code: Vec, calldata: Calldata, caller: web3::types::Address, value: Option, @@ -61,7 +60,7 @@ impl DeployEVM { ) -> Self { Self { identifier, - init_code, + deploy_code, calldata, caller, value, @@ -79,15 +78,19 @@ impl DeployEVM { self, summary: Arc>, vm: &mut EVM, - mode: Mode, - test_group: Option, - name_prefix: String, + context: InputContext<'_>, ) { - let name = format!("{}[#deployer:{}]", name_prefix, self.identifier); + let test = TestDescription::from_context( + context, + InputIdentifier::Deployer { + contract_identifier: self.identifier.clone(), + }, + ); + let name = test.selector.to_string(); vm.populate_storage(self.storage.inner); let result = match vm.execute_deploy_code( - name.clone(), + name, self.identifier.as_str(), self.caller, self.value, @@ -95,25 +98,16 @@ impl DeployEVM { ) { Ok(execution_result) => execution_result, Err(error) => { - Summary::invalid(summary, Some(mode), name, error); + Summary::invalid(summary, test, error); return; } }; if result.output == self.expected { - Summary::passed_runtime( - summary, - mode, - name, - test_group, - result.cycles, - 0, - result.gas, - ); + Summary::passed_runtime(summary, test, result.cycles, 0, result.gas); } else { Summary::failed( summary, - mode, - name, + test, self.expected, result.output, self.calldata.inner, @@ -124,109 +118,67 @@ impl DeployEVM { /// /// Runs the deploy transaction on native REVM. /// - pub fn run_revm<'a>( + pub fn run_revm<'b>( self, summary: Arc>, - vm: Revm<'a>, - mode: Mode, - test_group: Option, - name_prefix: String, - evm_builds: &HashMap, + vm: Revm<'b>, evm_version: Option, - ) -> Revm<'a> { - let name = format!("{}[#deployer:{}]", name_prefix, self.identifier); - - let build = evm_builds - .get(self.identifier.as_str()) - .expect("Always valid"); - let mut deploy_code = build.deploy_build.bytecode.to_owned(); - deploy_code.extend(self.calldata.inner.clone()); + context: InputContext<'_>, + ) -> Revm<'b> { + let test = TestDescription::from_context( + context, + InputIdentifier::Deployer { + contract_identifier: self.identifier.clone(), + }, + ); + + let size = self.deploy_code.len(); + let calldata = self.calldata.inner.clone(); + let mut code = self.deploy_code; + code.extend(self.calldata.inner); let vm = vm.update_deploy_balance(&self.caller); - let mut vm = - vm.fill_deploy_new_transaction(self.caller, self.value, evm_version, deploy_code); + let mut vm = vm.fill_deploy_new_transaction(self.caller, self.value, evm_version, code); let result = match vm.state.transact_commit() { Ok(res) => res, Err(error) => { - match error { - EVMError::Transaction(error) => { - Summary::invalid( - summary.clone(), - Some(mode.clone()), - name.clone(), - format!("Error on Transaction: {error:?}"), - ); - } - EVMError::Header(error) => { - Summary::invalid( - summary.clone(), - Some(mode.clone()), - name.clone(), - format!("Error on Header: {error:?}"), - ); - } - EVMError::Database(_error) => { - Summary::invalid( - summary.clone(), - Some(mode.clone()), - name.clone(), - "Error on Database", - ); - } - EVMError::Custom(error) => { - Summary::invalid( - summary.clone(), - Some(mode.clone()), - name.clone(), - format!("Error on Custom: {error:?}"), - ); - } - EVMError::Precompile(error) => { - Summary::invalid( - summary.clone(), - Some(mode.clone()), - name.clone(), - format!("Error on Precompile: {error:?}"), - ); - } - } + let error_msg = match error { + EVMError::Transaction(error) => format!("Error on Transaction: {error:?}"), + EVMError::Header(error) => format!("Error on Header: {error:?}"), + EVMError::Database(_error) => "Error on Database".into(), + EVMError::Custom(error) => format!("Error on Custom: {error:?}"), + EVMError::Precompile(error) => format!("Error on Precompile: {error:?}"), + }; + + Summary::invalid(summary.clone(), test, error_msg); return vm; } }; - let output = match result { + let (output, gas, error) = match result { ExecutionResult::Success { reason: _, - gas_used: _, + gas_used, gas_refunded: _, logs, output, - } => transform_success_output(output, logs), - ExecutionResult::Revert { - gas_used: _, - output, - } => { + } => (transform_success_output(output, logs), gas_used, None), + ExecutionResult::Revert { gas_used, output } => { let return_data_value = revm_bytes_to_vec_value(output); - Output::new(return_data_value, true, vec![]) + (Output::new(return_data_value, true, vec![]), gas_used, None) + } + ExecutionResult::Halt { reason, gas_used } => { + (Output::new(vec![], true, vec![]), gas_used, Some(reason)) } - ExecutionResult::Halt { - reason: _, - gas_used: _, - } => Output::new(vec![], true, vec![]), }; if output == self.expected { - Summary::passed_deploy(summary, mode, name, test_group, 0, 0, 0, 0); + Summary::passed_deploy(summary, test, size, 0, 0, gas); + } else if let Some(error) = error { + Summary::invalid(summary, test, format!("{error:?}")); } else { - Summary::failed( - summary, - mode, - name, - self.expected, - output, - self.calldata.inner, - ); + Summary::failed(summary, test, self.expected, output, calldata); } vm @@ -239,48 +191,42 @@ impl DeployEVM { self, summary: Arc>, vm: &mut EraVM, - mode: Mode, deployer: &mut D, - test_group: Option, - name_prefix: String, + context: InputContext<'_>, ) where D: EraVMDeployer, { - let name = format!("{}[#deployer:{}]", name_prefix, self.identifier); + let test = TestDescription::from_context( + context, + InputIdentifier::Deployer { + contract_identifier: self.identifier.clone(), + }, + ); - let size = self.init_code.len(); + let name = test.selector.to_string(); + let size = self.deploy_code.len(); vm.populate_storage(self.storage.inner); let result = match deployer.deploy_evm::( - name.clone(), + name, self.caller, - self.init_code, + self.deploy_code, self.calldata.inner.clone(), self.value, vm, ) { Ok(result) => result, Err(error) => { - Summary::invalid(summary, Some(mode), name, error); + Summary::invalid(summary, test, error); return; } }; if result.output == self.expected { - Summary::passed_deploy( - summary, - mode, - name, - test_group, - size, - result.cycles, - result.ergs, - result.gas, - ); + Summary::passed_deploy(summary, test, size, result.cycles, result.ergs, result.gas); } else { Summary::failed( summary, - mode, - name, + test, self.expected, result.output, self.calldata.inner, diff --git a/compiler_tester/src/test/case/input/identifier.rs b/compiler_tester/src/test/case/input/identifier.rs new file mode 100644 index 00000000..21bcbd8b --- /dev/null +++ b/compiler_tester/src/test/case/input/identifier.rs @@ -0,0 +1,42 @@ +//! +//! Identifier for the test input. Describes the input type and position but not the actual contents. +//! + +/// +/// Identifier for the test input. Describes the input type and position but not the actual contents. +/// +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum InputIdentifier { + /// The contract deploy, regardless of target. + Deployer { contract_identifier: String }, + /// The fallback method. + Fallback { input_index: usize }, + /// The contract call. + Runtime { input_index: usize, name: String }, + /// The storage empty check. + StorageEmpty { input_index: usize }, + /// Check account balance. + Balance { input_index: usize }, +} + +impl std::fmt::Display for InputIdentifier { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + InputIdentifier::Deployer { + contract_identifier, + } => f.write_fmt(format_args!("#deployer:{contract_identifier}")), + InputIdentifier::Runtime { input_index, name } => { + f.write_fmt(format_args!("{name}:{input_index}")) + } + InputIdentifier::StorageEmpty { input_index } => { + f.write_fmt(format_args!("#storage_empty_check:{input_index}")) + } + InputIdentifier::Balance { input_index } => { + f.write_fmt(format_args!("#balance_check:{input_index}")) + } + InputIdentifier::Fallback { input_index } => { + f.write_fmt(format_args!("#fallback:{input_index}")) + } + } + } +} diff --git a/compiler_tester/src/test/case/input/mod.rs b/compiler_tester/src/test/case/input/mod.rs index e254cca4..663420a0 100644 --- a/compiler_tester/src/test/case/input/mod.rs +++ b/compiler_tester/src/test/case/input/mod.rs @@ -6,6 +6,7 @@ pub mod balance; pub mod calldata; pub mod deploy_eravm; pub mod deploy_evm; +pub mod identifier; pub mod output; pub mod runtime; pub mod storage; @@ -13,21 +14,17 @@ pub mod storage_empty; pub mod value; use std::collections::BTreeMap; -use std::collections::HashMap; -use std::hash::RandomState; use std::str::FromStr; use std::sync::Arc; use std::sync::Mutex; -use solidity_adapter::EVMVersion; - use crate::compilers::mode::Mode; use crate::directories::matter_labs::test::metadata::case::input::Input as MatterLabsTestInput; use crate::summary::Summary; use crate::test::instance::Instance; +use crate::test::InputContext; use crate::vm::eravm::deployers::EraVMDeployer; use crate::vm::eravm::EraVM; -use crate::vm::evm::input::build::Build; use crate::vm::evm::EVM; use crate::vm::revm::Revm; @@ -124,7 +121,7 @@ impl Input { )), Instance::EVM(instance) => Input::DeployEVM(DeployEVM::new( instance.path.to_owned(), - instance.init_code.to_owned(), + instance.deploy_code.to_owned(), calldata, caller, value, @@ -263,7 +260,7 @@ impl Input { ))), Instance::EVM(instance) => Some(Input::DeployEVM(DeployEVM::new( instance.path.to_owned(), - instance.init_code.to_owned(), + instance.deploy_code.to_owned(), calldata.clone().into(), *caller, value, @@ -307,7 +304,7 @@ impl Input { ))), Instance::EVM(instance) => Some(Input::DeployEVM(DeployEVM::new( instance.path.to_owned(), - instance.init_code.to_owned(), + instance.deploy_code.to_owned(), Calldata::default(), *caller, None, @@ -372,35 +369,19 @@ impl Input { self, summary: Arc>, vm: &mut EraVM, - mode: Mode, deployer: &mut D, - test_group: Option, - name_prefix: String, - index: usize, + context: InputContext<'_>, ) where D: EraVMDeployer, { match self { - Self::DeployEraVM(deploy) => { - deploy.run_eravm::<_, M>(summary, vm, mode, deployer, test_group, name_prefix) - } - Self::DeployEVM(deploy) => deploy.run_evm_interpreter::<_, M>( - summary, - vm, - mode, - deployer, - test_group, - name_prefix, - ), - Self::Runtime(runtime) => { - runtime.run_eravm::(summary, vm, mode, test_group, name_prefix, index) - } - Self::StorageEmpty(storage_empty) => { - storage_empty.run_eravm(summary, vm, mode, test_group, name_prefix, index) - } - Self::Balance(balance_check) => { - balance_check.run_eravm(summary, vm, mode, test_group, name_prefix, index) + Self::DeployEraVM(deploy) => deploy.run_eravm::<_, M>(summary, vm, deployer, context), + Self::DeployEVM(deploy) => { + deploy.run_evm_interpreter::<_, M>(summary, vm, deployer, context) } + Self::Runtime(runtime) => runtime.run_eravm::(summary, vm, context), + Self::StorageEmpty(storage_empty) => storage_empty.run_eravm(summary, vm, context), + Self::Balance(balance_check) => balance_check.run_eravm(summary, vm, context), }; } @@ -411,68 +392,39 @@ impl Input { self, summary: Arc>, vm: &mut EVM, - mode: Mode, - test_group: Option, - name_prefix: String, - index: usize, + context: InputContext<'_>, ) { match self { Self::DeployEraVM { .. } => panic!("EraVM deploy transaction cannot be run on EVM"), - Self::DeployEVM(deploy) => { - deploy.run_evm_emulator(summary, vm, mode, test_group, name_prefix) - } - Self::Runtime(runtime) => { - runtime.run_evm_emulator(summary, vm, mode, test_group, name_prefix, index) - } + Self::DeployEVM(deploy) => deploy.run_evm_emulator(summary, vm, context), + Self::Runtime(runtime) => runtime.run_evm_emulator(summary, vm, context), Self::StorageEmpty(storage_empty) => { - storage_empty.run_evm_emulator(summary, vm, mode, test_group, name_prefix, index) - } - Self::Balance(balance_check) => { - balance_check.run_evm_emulator(summary, vm, mode, test_group, name_prefix, index) + storage_empty.run_evm_emulator(summary, vm, context) } + Self::Balance(balance_check) => balance_check.run_evm_emulator(summary, vm, context), }; } /// /// Runs the input on REVM. /// - pub fn run_revm<'a>( + pub fn run_revm<'b>( self, summary: Arc>, - mut vm: Revm<'a>, - mode: Mode, - test_group: Option, - name_prefix: String, - index: usize, - evm_builds: &HashMap, - evm_version: Option, - ) -> Revm<'a> { + mut vm: Revm<'b>, + evm_version: Option, + context: InputContext<'_>, + ) -> Revm<'b> { match self { Self::DeployEraVM { .. } => panic!("EraVM deploy transaction cannot be run on REVM"), - Self::DeployEVM(deploy) => deploy.run_revm( - summary, - vm, - mode, - test_group, - name_prefix, - evm_builds, - evm_version, - ), - Self::Runtime(runtime) => runtime.run_revm( - summary, - vm, - mode, - test_group, - name_prefix, - index, - evm_version, - ), + Self::DeployEVM(deploy) => deploy.run_revm(summary, vm, evm_version, context), + Self::Runtime(runtime) => runtime.run_revm(summary, vm, evm_version, context), Self::StorageEmpty(storage_empty) => { - storage_empty.run_revm(summary, &mut vm, mode, test_group, name_prefix, index); + storage_empty.run_revm(summary, &mut vm, context); vm } Self::Balance(balance_check) => { - balance_check.run_revm(summary, &mut vm, mode, test_group, name_prefix, index); + balance_check.run_revm(summary, &mut vm, context); vm } } @@ -485,11 +437,8 @@ impl Input { self, summary: Arc>, vm: &mut EraVM, - mode: Mode, deployer: &mut D, - test_group: Option, - name_prefix: String, - index: usize, + context: InputContext<'_>, ) where D: EraVMDeployer, { @@ -497,23 +446,14 @@ impl Input { Self::DeployEraVM { .. } => { panic!("EraVM deploy transaction cannot be run on EVM interpreter") } - Self::DeployEVM(deploy) => deploy.run_evm_interpreter::<_, M>( - summary, - vm, - mode, - deployer, - test_group, - name_prefix, - ), - Self::Runtime(runtime) => { - runtime.run_evm_interpreter::(summary, vm, mode, test_group, name_prefix, index) + Self::DeployEVM(deploy) => { + deploy.run_evm_interpreter::<_, M>(summary, vm, deployer, context) } + Self::Runtime(runtime) => runtime.run_evm_interpreter::(summary, vm, context), Self::StorageEmpty(storage_empty) => { - storage_empty.run_evm_interpreter(summary, vm, mode, test_group, name_prefix, index) - } - Self::Balance(balance_check) => { - balance_check.run_evm_interpreter(summary, vm, mode, test_group, name_prefix, index) + storage_empty.run_evm_interpreter(summary, vm, context) } + Self::Balance(balance_check) => balance_check.run_evm_interpreter(summary, vm, context), }; } } diff --git a/compiler_tester/src/test/case/input/runtime.rs b/compiler_tester/src/test/case/input/runtime.rs index 2c04493e..f6f5cbc5 100644 --- a/compiler_tester/src/test/case/input/runtime.rs +++ b/compiler_tester/src/test/case/input/runtime.rs @@ -10,11 +10,13 @@ use revm::primitives::EVMError; use revm::primitives::ExecutionResult; use solidity_adapter::EVMVersion; -use crate::compilers::mode::Mode; use crate::summary::Summary; use crate::test::case::input::calldata::Calldata; +use crate::test::case::input::identifier::InputIdentifier; use crate::test::case::input::output::Output; use crate::test::case::input::storage::Storage; +use crate::test::context::input::InputContext; +use crate::test::description::TestDescription; use crate::vm::eravm::system_context::SystemContext; use crate::vm::eravm::EraVM; use crate::vm::evm::EVM; @@ -76,22 +78,25 @@ impl Runtime { self, summary: Arc>, vm: &mut EraVM, - mode: Mode, - test_group: Option, - name_prefix: String, - index: usize, + context: InputContext<'_>, ) { - let name = format!("{}[{}:{}]", name_prefix, self.name, index); + let group = context.case_context.group.clone(); + let input_index = context.selector; + let test = TestDescription::from_context( + context, + Self::select_input_identifier(self.name, input_index), + ); + let name = test.selector.to_string(); vm.populate_storage(self.storage.inner); - let vm_function = match test_group.as_deref() { - Some(benchmark_analyzer::Benchmark::EVM_INTERPRETER_GROUP_NAME) => { + let vm_function = match group.as_deref() { + Some(benchmark_analyzer::TEST_GROUP_EVM_INTERPRETER) => { EraVM::execute_evm_interpreter:: } _ => EraVM::execute::, }; let result = match vm_function( vm, - name.clone(), + name, self.address, self.caller, self.value, @@ -100,26 +105,17 @@ impl Runtime { ) { Ok(result) => result, Err(error) => { - Summary::invalid(summary, Some(mode), name, error); + Summary::invalid(summary, test, error); return; } }; if result.output == self.expected { - Summary::passed_runtime( - summary, - mode, - name, - test_group, - result.cycles, - result.ergs, - result.gas, - ); + Summary::passed_runtime(summary, test, result.cycles, result.ergs, result.gas); } else { Summary::failed( summary, - mode, - name, + test, self.expected, result.output, self.calldata.inner, @@ -127,6 +123,13 @@ impl Runtime { } } + fn select_input_identifier(name: String, input_index: usize) -> InputIdentifier { + match name.as_str() { + "#fallback" => InputIdentifier::Fallback { input_index }, + _ => InputIdentifier::Runtime { input_index, name }, + } + } + /// /// Runs the call on EVM emulator. /// @@ -134,15 +137,17 @@ impl Runtime { self, summary: Arc>, vm: &mut EVM, - mode: Mode, - test_group: Option, - name_prefix: String, - index: usize, + context: InputContext<'_>, ) { - let name = format!("{}[{}:{}]", name_prefix, self.name, index); + let input_index = context.selector; + let test = TestDescription::from_context( + context, + Self::select_input_identifier(self.name, input_index), + ); + let name = test.selector.to_string(); vm.populate_storage(self.storage.inner); let result = match vm.execute_runtime_code( - name.clone(), + name, self.address, self.caller, self.value, @@ -150,25 +155,16 @@ impl Runtime { ) { Ok(execution_result) => execution_result, Err(error) => { - Summary::invalid(summary, Some(mode), name, error); + Summary::invalid(summary, test, error); return; } }; if result.output == self.expected { - Summary::passed_runtime( - summary, - mode, - name, - test_group, - result.cycles, - result.ergs, - result.gas, - ); + Summary::passed_runtime(summary, test, result.cycles, result.ergs, result.gas); } else { Summary::failed( summary, - mode, - name, + test, self.expected, result.output, self.calldata.inner, @@ -179,22 +175,26 @@ impl Runtime { /// /// Runs the call on REVM. /// - pub fn run_revm( + pub fn run_revm<'b>( self, summary: Arc>, - vm: Revm, - mode: Mode, - test_group: Option, - name_prefix: String, - index: usize, + vm: Revm<'b>, evm_version: Option, - ) -> Revm { - let name = format!("{}[{}:{}]", name_prefix, self.name, index); + context: InputContext<'_>, + ) -> Revm<'b> { + let input_index = context.selector; + let test = TestDescription::from_context( + context, + InputIdentifier::Runtime { + input_index, + name: self.name, + }, + ); // On revm we can't send a tx with a tx_origin different from the tx_sender, // this specific test expects tx_origin to be that value, so we change the sender let mut caller = self.caller; - if name_prefix == "solidity/test/libsolidity/semanticTests/state/tx_origin.sol" { + if test.selector.path == "solidity/test/libsolidity/semanticTests/state/tx_origin.sol" { caller = web3::types::Address::from_str("0x9292929292929292929292929292929292929292") .unwrap(); } @@ -218,55 +218,22 @@ impl Runtime { let result = match vm.state.transact_commit() { Ok(result) => result, Err(error) => { - match error { - EVMError::Transaction(error) => { - Summary::invalid( - summary.clone(), - Some(mode.clone()), - name.clone(), - format!("Error on Transaction: {error:?}"), - ); - } - EVMError::Header(error) => { - Summary::invalid( - summary.clone(), - Some(mode.clone()), - name.clone(), - format!("Error on Header: {error:?}"), - ); - } - EVMError::Database(_error) => { - Summary::invalid( - summary.clone(), - Some(mode.clone()), - name.clone(), - "Error on Database", - ); - } - EVMError::Custom(error) => { - Summary::invalid( - summary.clone(), - Some(mode.clone()), - name.clone(), - format!("Error on Custom: {error:?}"), - ); - } - EVMError::Precompile(error) => { - Summary::invalid( - summary.clone(), - Some(mode.clone()), - name.clone(), - format!("Error on Precompile: {error:?}"), - ); - } - } + let error_msg = match error { + EVMError::Transaction(error) => format!("Error on Transaction: {error:?}"), + EVMError::Header(error) => format!("Error on Header: {error:?}"), + EVMError::Database(_error) => "Error on Database".into(), + EVMError::Custom(error) => format!("Error on Custom: {error:?}"), + EVMError::Precompile(error) => format!("Error on Precompile: {error:?}"), + }; + + Summary::invalid(summary.clone(), test, error_msg); return vm; } }; - let output = match result { + let (output, gas, error) = match result { ExecutionResult::Success { reason: _, - gas_used: _, + gas_used, gas_refunded: _, logs, output, @@ -276,32 +243,23 @@ impl Runtime { } else { vm }; - transform_success_output(output, logs) + (transform_success_output(output, logs), gas_used, None) } - ExecutionResult::Revert { - gas_used: _, - output, - } => { + ExecutionResult::Revert { gas_used, output } => { let return_data_value = revm_bytes_to_vec_value(output); - Output::new(return_data_value, true, vec![]) + (Output::new(return_data_value, true, vec![]), gas_used, None) + } + ExecutionResult::Halt { reason, gas_used } => { + (Output::new(vec![], true, vec![]), gas_used, Some(reason)) } - ExecutionResult::Halt { - reason: _, - gas_used: _, - } => Output::new(vec![], true, vec![]), }; if output == self.expected { - Summary::passed_runtime(summary, mode, name, test_group, 0, 0, 0); + Summary::passed_runtime(summary, test, 0, 0, gas); + } else if let Some(error) = error { + Summary::invalid(summary, test, format!("{error:?}")); } else { - Summary::failed( - summary, - mode, - name, - self.expected, - output, - self.calldata.inner, - ); + Summary::failed(summary, test, self.expected, output, self.calldata.inner); }; vm } @@ -313,15 +271,20 @@ impl Runtime { self, summary: Arc>, vm: &mut EraVM, - mode: Mode, - test_group: Option, - name_prefix: String, - index: usize, + context: InputContext<'_>, ) { - let name = format!("{}[{}:{}]", name_prefix, self.name, index); + let input_index = context.selector; + let test = TestDescription::from_context( + context, + InputIdentifier::Runtime { + input_index, + name: self.name, + }, + ); + let name = test.selector.to_string(); vm.populate_storage(self.storage.inner); let result = match vm.execute_evm_interpreter::( - name.clone(), + name, self.address, self.caller, self.value, @@ -330,26 +293,17 @@ impl Runtime { ) { Ok(result) => result, Err(error) => { - Summary::invalid(summary, Some(mode), name, error); + Summary::invalid(summary, test, error); return; } }; if result.output == self.expected { - Summary::passed_runtime( - summary, - mode, - name, - test_group, - result.cycles, - result.ergs, - result.gas, - ); + Summary::passed_runtime(summary, test, result.cycles, result.ergs, result.gas); } else { Summary::failed( summary, - mode, - name, + test, self.expected, result.output, self.calldata.inner, diff --git a/compiler_tester/src/test/case/input/storage_empty.rs b/compiler_tester/src/test/case/input/storage_empty.rs index 7807a80d..dce8342f 100644 --- a/compiler_tester/src/test/case/input/storage_empty.rs +++ b/compiler_tester/src/test/case/input/storage_empty.rs @@ -5,8 +5,10 @@ use std::sync::Arc; use std::sync::Mutex; -use crate::compilers::mode::Mode; use crate::summary::Summary; +use crate::test::case::input::identifier::InputIdentifier; +use crate::test::description::TestDescription; +use crate::test::InputContext; use crate::vm::eravm::EraVM; use crate::vm::evm::EVM; use crate::vm::revm::Revm; @@ -33,29 +35,15 @@ impl StorageEmpty { /// /// Runs the storage empty check on EraVM. /// - pub fn run_eravm( - self, - summary: Arc>, - vm: &EraVM, - mode: Mode, - test_group: Option, - name_prefix: String, - index: usize, - ) { - let name = format!("{name_prefix}[#storage_empty_check:{index}]"); - + pub fn run_eravm(self, summary: Arc>, vm: &EraVM, context: InputContext<'_>) { + let input_index = context.selector; + let test = + TestDescription::from_context(context, InputIdentifier::StorageEmpty { input_index }); let found = vm.is_storage_empty(); if found == self.is_empty { - Summary::passed_special(summary, mode, name, test_group); + Summary::passed_special(summary, test); } else { - Summary::failed( - summary, - mode, - name, - self.is_empty.into(), - found.into(), - vec![], - ); + Summary::failed(summary, test, self.is_empty.into(), found.into(), vec![]); } } @@ -66,10 +54,7 @@ impl StorageEmpty { self, _summary: Arc>, _vm: &EVM, - _mode: Mode, - _test_group: Option, - _name_prefix: String, - _index: usize, + _context: InputContext<'_>, ) { todo!() } @@ -77,17 +62,10 @@ impl StorageEmpty { /// /// Runs the storage empty check on REVM. /// - pub fn run_revm( - self, - summary: Arc>, - vm: &mut Revm, - mode: Mode, - test_group: Option, - name_prefix: String, - index: usize, - ) { - let name = format!("{name_prefix}[#storage_empty_check:{index}]"); - + pub fn run_revm(self, summary: Arc>, vm: &mut Revm, context: InputContext<'_>) { + let input_index = context.selector; + let test = + TestDescription::from_context(context, InputIdentifier::StorageEmpty { input_index }); let mut is_empty = true; for cache_account in vm.state.db().cache.accounts.values() { let plain_account = cache_account.clone().account; @@ -101,16 +79,9 @@ impl StorageEmpty { } if is_empty == self.is_empty { - Summary::passed_special(summary, mode, name, test_group); + Summary::passed_special(summary, test); } else { - Summary::failed( - summary, - mode, - name, - self.is_empty.into(), - is_empty.into(), - vec![], - ); + Summary::failed(summary, test, self.is_empty.into(), is_empty.into(), vec![]); } } @@ -121,25 +92,16 @@ impl StorageEmpty { self, summary: Arc>, vm: &EraVM, - mode: Mode, - test_group: Option, - name_prefix: String, - index: usize, + context: InputContext<'_>, ) { - let name = format!("{name_prefix}[#storage_empty_check:{index}]"); - + let input_index = context.selector; + let test = + TestDescription::from_context(context, InputIdentifier::StorageEmpty { input_index }); let found = vm.is_storage_empty(); if found == self.is_empty { - Summary::passed_special(summary, mode, name, test_group); + Summary::passed_special(summary, test); } else { - Summary::failed( - summary, - mode, - name, - self.is_empty.into(), - found.into(), - vec![], - ); + Summary::failed(summary, test, self.is_empty.into(), found.into(), vec![]); } } } diff --git a/compiler_tester/src/test/case/mod.rs b/compiler_tester/src/test/case/mod.rs index 901e0bbd..ba7803d7 100644 --- a/compiler_tester/src/test/case/mod.rs +++ b/compiler_tester/src/test/case/mod.rs @@ -4,10 +4,7 @@ pub mod input; -use solidity_adapter::test::params::evm_version; use std::collections::BTreeMap; -use std::collections::HashMap; -use std::hash::RandomState; use std::sync::Arc; use std::sync::Mutex; @@ -17,12 +14,14 @@ use crate::summary::Summary; use crate::test::instance::Instance; use crate::vm::eravm::deployers::EraVMDeployer; use crate::vm::eravm::EraVM; -use crate::vm::evm::input::build::Build; use crate::vm::evm::EVM; use crate::vm::revm::Revm; use self::input::Input; +use super::CaseContext; +use super::InputContext; + /// /// The test case. /// @@ -104,28 +103,17 @@ impl Case { self, summary: Arc>, mut vm: EraVM, - mode: &Mode, - test_name: String, - test_group: Option, + context: &CaseContext, ) where D: EraVMDeployer, { - let name = if let Some(case_name) = self.name { - format!("{test_name}::{case_name}") - } else { - test_name - }; - for (index, input) in self.inputs.into_iter().enumerate() { - input.run_eravm::<_, M>( - summary.clone(), - &mut vm, - mode.to_owned(), - &mut D::new(), - test_group.clone(), - name.clone(), - index, - ) + let context = InputContext { + case_context: context, + case_name: &self.name, + selector: index, + }; + input.run_eravm::<_, M>(summary.clone(), &mut vm, &mut D::new(), context) } } @@ -136,25 +124,15 @@ impl Case { self, summary: Arc>, mut vm: EVM, - mode: &Mode, - test_name: String, - test_group: Option, + context: &CaseContext, ) { - let name = if let Some(case_name) = self.name { - format!("{test_name}::{case_name}") - } else { - test_name - }; - for (index, input) in self.inputs.into_iter().enumerate() { - input.run_evm_emulator( - summary.clone(), - &mut vm, - mode.clone(), - test_group.clone(), - name.clone(), - index, - ) + let context = InputContext { + case_context: context, + case_name: &self.name, + selector: index, + }; + input.run_evm_emulator(summary.clone(), &mut vm, context) } } @@ -164,30 +142,17 @@ impl Case { pub fn run_revm( self, summary: Arc>, - mode: &Mode, - test_name: String, - test_group: Option, - evm_builds: HashMap, - evm_version: Option, + evm_version: Option, + context: &CaseContext, ) { - let name = if let Some(case_name) = self.name { - format!("{test_name}::{case_name}") - } else { - test_name - }; - let mut vm = Revm::new(); for (index, input) in self.inputs.into_iter().enumerate() { - vm = input.run_revm( - summary.clone(), - vm, - mode.clone(), - test_group.clone(), - name.clone(), - index, - &evm_builds, - evm_version, - ) + let context = InputContext { + case_context: context, + case_name: &self.name, + selector: index, + }; + vm = input.run_revm(summary.clone(), vm, evm_version, context) } } @@ -198,29 +163,19 @@ impl Case { self, summary: Arc>, mut vm: EraVM, - mode: &Mode, - test_name: String, - test_group: Option, + context: &CaseContext<'_>, ) where D: EraVMDeployer, { - let name = if let Some(case_name) = self.name { - format!("{test_name}::{case_name}") - } else { - test_name - }; - for (index, input) in self.inputs.into_iter().enumerate() { vm.increment_evm_block_number_and_timestamp(); - input.run_evm_interpreter::<_, M>( - summary.clone(), - &mut vm, - mode.clone(), - &mut D::new(), - test_group.clone(), - name.clone(), - index, - ) + + let context = InputContext { + case_context: context, + case_name: &self.name, + selector: index, + }; + input.run_evm_interpreter::<_, M>(summary.clone(), &mut vm, &mut D::new(), context) } } } diff --git a/compiler_tester/src/test/context/case.rs b/compiler_tester/src/test/context/case.rs new file mode 100644 index 00000000..079412c6 --- /dev/null +++ b/compiler_tester/src/test/context/case.rs @@ -0,0 +1,15 @@ +//! +//! Context used to process test cases, consisting of a number of inputs. +//! + +use crate::Mode; + +/// +/// Context used to process test cases, consisting of a number of inputs. +/// +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CaseContext<'a> { + pub mode: &'a Mode, + pub group: &'a Option, + pub name: &'a str, +} diff --git a/compiler_tester/src/test/context/input.rs b/compiler_tester/src/test/context/input.rs new file mode 100644 index 00000000..cd710eae --- /dev/null +++ b/compiler_tester/src/test/context/input.rs @@ -0,0 +1,18 @@ +//! +//! Context used to process test inputs, organized in test cases. +//! + +use super::case::CaseContext; + +/// +/// Context used to process test inputs, organized in test cases. +/// +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct InputContext<'a> { + /// Context of the parent case, which contains this input. + pub case_context: &'a CaseContext<'a>, + /// Optional name of the case. + pub case_name: &'a Option, + /// Index of the input in the case's array of inputs. + pub selector: usize, +} diff --git a/compiler_tester/src/test/context/mod.rs b/compiler_tester/src/test/context/mod.rs new file mode 100644 index 00000000..849b7764 --- /dev/null +++ b/compiler_tester/src/test/context/mod.rs @@ -0,0 +1,7 @@ +//! +//! Context accumulates information as we traverse the tree of tests, cases and +//! their inputs. +//! + +pub mod case; +pub mod input; diff --git a/compiler_tester/src/test/description.rs b/compiler_tester/src/test/description.rs new file mode 100644 index 00000000..85755f8b --- /dev/null +++ b/compiler_tester/src/test/description.rs @@ -0,0 +1,68 @@ +//! +//! Test description with additional information such as the compiler mode and test group. +//! + +use crate::Mode; + +use crate::test::case::input::identifier::InputIdentifier; +use crate::test::context::input::InputContext; +use crate::test::selector::TestSelector; + +/// +/// Test description with additional information such as the compiler mode and test group. +/// +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TestDescription { + /// Test group. + pub group: Option, + /// Compiler mode. + pub mode: Option, + /// Test selector, matching a precise input location or a case collecting several inputs. + pub selector: TestSelector, +} + +impl TestDescription { + /// + /// Creates a test description matching specified selector with no additonal + /// information. + /// + pub fn default_for(test: TestSelector) -> Self { + Self { + group: None, + mode: None, + selector: test, + } + } + + /// + /// Erase information about mode from this selector. + /// + pub fn with_erased_mode(self) -> Self { + let Self { + group, + mode: _, + selector: identifier, + } = self; + Self { + group, + mode: None, + selector: identifier, + } + } + + /// + /// Create a selector from accumulated input context and provided input + /// identifier. + /// + pub fn from_context(ctx: InputContext<'_>, input: InputIdentifier) -> Self { + Self { + group: ctx.case_context.group.clone(), + mode: Some(ctx.case_context.mode.clone()), + selector: TestSelector { + path: ctx.case_context.name.to_string(), + case: ctx.case_name.clone(), + input: Some(input), + }, + } + } +} diff --git a/compiler_tester/src/test/instance/evm.rs b/compiler_tester/src/test/instance/evm.rs index d285d46c..618b6aab 100644 --- a/compiler_tester/src/test/instance/evm.rs +++ b/compiler_tester/src/test/instance/evm.rs @@ -15,8 +15,8 @@ pub struct Instance { pub is_main: bool, /// Whether the instance is a library. pub is_library: bool, - /// The init bytecode. - pub init_code: Vec, + /// The deploy bytecode. + pub deploy_code: Vec, } impl Instance { @@ -28,14 +28,14 @@ impl Instance { address: Option, is_main: bool, is_library: bool, - init_code: Vec, + deploy_code: Vec, ) -> Self { Self { path, address, is_main, is_library, - init_code, + deploy_code, } } } diff --git a/compiler_tester/src/test/instance/mod.rs b/compiler_tester/src/test/instance/mod.rs index 751124c5..d51e5610 100644 --- a/compiler_tester/src/test/instance/mod.rs +++ b/compiler_tester/src/test/instance/mod.rs @@ -44,10 +44,14 @@ impl Instance { address: Option, is_main: bool, is_library: bool, - init_code: Vec, + deploy_code: Vec, ) -> Self { Self::EVM(EVMInstance::new( - path, address, is_main, is_library, init_code, + path, + address, + is_main, + is_library, + deploy_code, )) } diff --git a/compiler_tester/src/test/mod.rs b/compiler_tester/src/test/mod.rs index a128f539..06430046 100644 --- a/compiler_tester/src/test/mod.rs +++ b/compiler_tester/src/test/mod.rs @@ -3,7 +3,10 @@ //! pub mod case; +pub mod context; +pub mod description; pub mod instance; +pub mod selector; use solidity_adapter::EVMVersion; use std::collections::HashMap; @@ -13,6 +16,8 @@ use std::sync::Mutex; use crate::compilers::mode::Mode; use crate::summary::Summary; use crate::test::case::Case; +use crate::test::context::case::CaseContext; +use crate::test::context::input::InputContext; use crate::vm::eravm::deployers::EraVMDeployer; use crate::vm::eravm::EraVM; use crate::vm::evm::input::build::Build as EVMBuild; @@ -72,15 +77,14 @@ impl Test { where D: EraVMDeployer, { + let context = CaseContext { + name: &self.name, + mode: &self.mode, + group: &self.group, + }; for case in self.cases { let vm = EraVM::clone_with_contracts(vm.clone(), self.eravm_builds.clone(), None); - case.run_eravm::( - summary.clone(), - vm.clone(), - &self.mode, - self.name.clone(), - self.group.clone(), - ); + case.run_eravm::(summary.clone(), vm.clone(), &context); } } @@ -97,13 +101,13 @@ impl Test { let invoker = EVMInvoker::new(&config, &resolver); let vm = EVM::new(self.evm_builds.clone(), invoker); - case.run_evm_emulator( - summary.clone(), - vm, - &self.mode, - self.name.clone(), - self.group.clone(), - ); + + let context = CaseContext { + name: &self.name, + mode: &self.mode, + group: &self.group, + }; + case.run_evm_emulator(summary.clone(), vm, &context); } } @@ -112,14 +116,12 @@ impl Test { /// pub fn run_revm(self, summary: Arc>) { for case in self.cases { - case.run_revm( - summary.clone(), - &self.mode, - self.name.clone(), - self.group.clone(), - self.evm_builds.clone(), - self.evm_version, - ); + let context = CaseContext { + name: &self.name, + mode: &self.mode, + group: &self.group, + }; + case.run_revm(summary.clone(), self.evm_version, &context); } } @@ -136,13 +138,12 @@ impl Test { self.eravm_builds.clone(), self.evm_version, ); - case.run_evm_interpreter::( - summary.clone(), - vm, - &self.mode, - self.name.clone(), - self.group.clone(), - ); + let context = CaseContext { + name: &self.name, + mode: &self.mode, + group: &self.group, + }; + case.run_evm_interpreter::(summary.clone(), vm, &context); } } } diff --git a/compiler_tester/src/test/selector.rs b/compiler_tester/src/test/selector.rs new file mode 100644 index 00000000..54936d0a --- /dev/null +++ b/compiler_tester/src/test/selector.rs @@ -0,0 +1,36 @@ +//! +//! Test selector, unambiously locating a test suite, or a specific input. +//! + +use crate::test::case::input::identifier::InputIdentifier; + +/// +/// Test selector, unambiously locating a test suite, case, or input. +/// +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TestSelector { + /// Path to the file containing test. + pub path: String, + /// Name of the case, if any. `None` means nameless case. + pub case: Option, + /// Identifier of the specific input. + pub input: Option, +} + +impl std::fmt::Display for TestSelector { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { + path: filename, + case: case_name, + input, + } = self; + f.write_fmt(format_args!("{filename}"))?; + if let Some(case_name) = case_name { + f.write_fmt(format_args!("::{case_name}"))?; + } + if let Some(input) = input { + f.write_fmt(format_args!("[{input}]"))?; + } + Ok(()) + } +} diff --git a/compiler_tester/src/utils.rs b/compiler_tester/src/utils/mod.rs similarity index 99% rename from compiler_tester/src/utils.rs rename to compiler_tester/src/utils/mod.rs index 3d606c98..23b0d796 100644 --- a/compiler_tester/src/utils.rs +++ b/compiler_tester/src/utils/mod.rs @@ -2,6 +2,8 @@ //! The compiler tester utils. //! +pub mod timer; + use sha3::Digest; /// diff --git a/compiler_tester/src/utils/timer.rs b/compiler_tester/src/utils/timer.rs new file mode 100644 index 00000000..a53dbf05 --- /dev/null +++ b/compiler_tester/src/utils/timer.rs @@ -0,0 +1,115 @@ +//! +//! A simple timer capable of measuring time intervals. +//! + +#![allow(dead_code)] + +type TimeStamp = chrono::DateTime; + +/// +/// A simple timer capable of measuring time intervals between invokations of +/// `[start]` and `[stop]` methods. +/// +#[derive(Clone, Default, Debug)] +pub struct Timer { + /// Start time, + start: Option, + /// End time, + end: Option, +} + +impl Timer { + /// Starts the timer. This sets the `start` time to the current time. + /// + /// # Returns + /// + /// An Ok result if the timer was successfully started, or an error if + /// the timer was already started or stopped before. + /// + pub fn start(&mut self) -> anyhow::Result<()> { + match (self.start, self.end) { + (None, None) => { + self.start = Some(chrono::offset::Utc::now()); + Ok(()) + } + _ => anyhow::bail!("Malformed timer state: {self:?}"), + } + } + + /// Stops the timer from ticking. Assumes the timer has been started with + /// `[start]`. + /// + /// # Returns + /// + /// An Ok result if the timer was successfully stopped, or an error if + /// the timer has not been started or if it was already stopped. + /// + pub fn stop(&mut self) -> anyhow::Result<()> { + match (self.start, self.end) { + (Some(_), None) => { + self.end = Some(chrono::offset::Utc::now()); + Ok(()) + } + _ => anyhow::bail!("Malformed timer state: {self:?}"), + } + } + + /// + /// Checks if timer is ticking now. + /// + /// # Returns + /// + /// `true` if the timer has been started and is currently running, `false` otherwise. + /// + pub fn is_started(&self) -> bool { + self.start.is_some() + } + + /// Returns true if the timer was started and then subsequently stopped. + /// + /// # Returns + /// + /// `true` if the timer has finished (started and stopped), `false` otherwise. + /// + pub fn is_finished(&self) -> bool { + self.end.is_some() + } + + /// Returns the start time of this [`Timer`]. + /// + /// # Returns + /// + /// An `Option` containing the start `TimeStamp` if the timer has been started, + /// or `None` if it has not been started. + /// + pub fn get_start(&self) -> Option { + self.start + } + + /// Returns the end time of this [`Timer`]. + /// + /// # Returns + /// + /// An `Option` containing the end `TimeStamp` if the timer has been stopped, + /// or `None` if it is still running or has not been started. + /// + pub fn get_end(&self) -> Option { + self.end + } + + /// Returns the elapsed time between the start and end of the timer. + /// + /// # Returns + /// + /// An Ok result with the `chrono::TimeDelta` representing the elapsed time + /// if the timer was started (and optionally stopped), or an error if the + /// timer was not started correctly. + /// + pub fn elapsed(&self) -> anyhow::Result { + match (self.start, self.end) { + (Some(start), Some(end)) => Ok(end - start), + (Some(start), None) => Ok(chrono::Utc::now() - start), + _ => anyhow::bail!("Malformed timer state: {self:?}"), + } + } +} diff --git a/compiler_tester/src/vm/eravm/deployers/dummy_deployer.rs b/compiler_tester/src/vm/eravm/deployers/dummy_deployer.rs index efd947bd..b7fda707 100644 --- a/compiler_tester/src/vm/eravm/deployers/dummy_deployer.rs +++ b/compiler_tester/src/vm/eravm/deployers/dummy_deployer.rs @@ -100,7 +100,7 @@ impl EraVMDeployer for DummyDeployer { &mut self, _test_name: String, _caller: web3::types::Address, - _init_code: Vec, + _deploy_code: Vec, _constructor_calldata: Vec, _value: Option, _vm: &mut EraVM, diff --git a/compiler_tester/src/vm/eravm/deployers/mod.rs b/compiler_tester/src/vm/eravm/deployers/mod.rs index 8a45f7fb..338892f2 100644 --- a/compiler_tester/src/vm/eravm/deployers/mod.rs +++ b/compiler_tester/src/vm/eravm/deployers/mod.rs @@ -37,7 +37,7 @@ pub trait EraVMDeployer { &mut self, test_name: String, caller: web3::types::Address, - init_code: Vec, + deploy_code: Vec, constructor_calldata: Vec, value: Option, vm: &mut EraVM, diff --git a/compiler_tester/src/vm/eravm/deployers/system_contract_deployer.rs b/compiler_tester/src/vm/eravm/deployers/system_contract_deployer.rs index f185b3e9..dabbf3cf 100644 --- a/compiler_tester/src/vm/eravm/deployers/system_contract_deployer.rs +++ b/compiler_tester/src/vm/eravm/deployers/system_contract_deployer.rs @@ -122,7 +122,7 @@ impl EraVMDeployer for SystemContractDeployer { &mut self, test_name: String, caller: web3::types::Address, - init_code: Vec, + deploy_code: Vec, constructor_calldata: Vec, value: Option, vm: &mut EraVM, @@ -192,7 +192,7 @@ impl EraVMDeployer for SystemContractDeployer { let mut calldata = Vec::with_capacity( era_compiler_common::BYTE_LENGTH_X32 + era_compiler_common::BYTE_LENGTH_FIELD * 2 - + init_code.len() + + deploy_code.len() + constructor_calldata.len(), ); calldata.extend(crate::utils::selector(Self::EVM_CREATE_METHOD_SIGNATURE)); @@ -202,11 +202,11 @@ impl EraVMDeployer for SystemContractDeployer { ); calldata.extend( web3::types::H256::from_low_u64_be( - (init_code.len() + constructor_calldata.len()) as u64, + (deploy_code.len() + constructor_calldata.len()) as u64, ) .as_bytes(), ); - calldata.extend(init_code); + calldata.extend(deploy_code); calldata.extend(constructor_calldata); vm.execute::( diff --git a/compiler_tester/src/vm/eravm/input.rs b/compiler_tester/src/vm/eravm/input.rs index a53f0829..ec19126b 100644 --- a/compiler_tester/src/vm/eravm/input.rs +++ b/compiler_tester/src/vm/eravm/input.rs @@ -51,7 +51,9 @@ impl Input { let build = self.builds.get(name.as_str()).ok_or_else(|| { anyhow::anyhow!("Library `{}` not found in the build artifacts", name) })?; - let code_hash = web3::types::U256::from_big_endian(build.bytecode_hash.as_slice()); + let code_hash = web3::types::U256::from_big_endian( + build.bytecode_hash.expect("Always exists").as_slice(), + ); instances.insert( name.clone(), @@ -66,8 +68,12 @@ impl Input { .ok_or_else(|| { anyhow::anyhow!("Main contract not found in the compiler build artifacts") })?; - let code_hash = - web3::types::U256::from_big_endian(main_contract_build.bytecode_hash.as_slice()); + let code_hash = web3::types::U256::from_big_endian( + main_contract_build + .bytecode_hash + .expect("Always exists") + .as_slice(), + ); instances.insert( "Test".to_owned(), @@ -84,7 +90,9 @@ impl Input { let build = self.builds.get(path.as_str()).ok_or_else(|| { anyhow::anyhow!("{} not found in the compiler build artifacts", path) })?; - let code_hash = web3::types::U256::from_big_endian(build.bytecode_hash.as_slice()); + let code_hash = web3::types::U256::from_big_endian( + build.bytecode_hash.expect("Always exists").as_slice(), + ); instances.insert( instance.to_owned(), diff --git a/compiler_tester/src/vm/eravm/mod.rs b/compiler_tester/src/vm/eravm/mod.rs index c7eabc06..fef2e60c 100644 --- a/compiler_tester/src/vm/eravm/mod.rs +++ b/compiler_tester/src/vm/eravm/mod.rs @@ -59,13 +59,11 @@ impl EraVM { /// The extra amount of gas consumed by every call to the EVM interpreter. pub const EVM_INTERPRETER_GAS_OVERHEAD: u64 = 2500; - /// The `evmStackFrames` variable storage slot in the `EvmGasManager` contract. - pub const EVM_GAS_MANAGER_STACK_FRAME_SLOT: u64 = 2; + /// The `passGas` variable transient storage slot in the `EvmGasManager` contract. + pub const EVM_GAS_MANAGER_GAS_TRANSIENT_SLOT: u64 = 4; - /// The first `evmStackFrames` array element storage slot in the `EvmGasManager` contract. - /// (keccak256(uit256(2))) - pub const EVM_GAS_MANAGER_FIRST_STACK_FRAME: &'static str = - "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"; + /// The `auxData` variable transient storage slot in the `EvmGasManager` contract. + pub const EVM_GAS_MANAGER_AUX_DATA_TRANSIENT_SLOT: u64 = 5; /// The EVM call gas limit. pub const EVM_CALL_GAS_LIMIT: u64 = u32::MAX as u64; @@ -74,7 +72,7 @@ impl EraVM { /// Creates and initializes a new EraVM instance. /// pub fn new( - binary_download_config_paths: Vec, + executable_download_config_paths: Vec, system_contracts_solc_downloader_config_path: PathBuf, system_contracts_debug_config: Option, system_contracts_load_path: Option, @@ -88,23 +86,26 @@ impl EraVM { let http_client = http_client_builder.build()?; let download_time_start = Instant::now(); - println!(" {} compiler binaries", "Downloading".bright_green().bold()); + println!( + " {} compiler executables", + "Downloading".bright_green().bold() + ); let system_contracts_solc_downloader_config = era_compiler_downloader::Downloader::new(http_client.clone()) .download(system_contracts_solc_downloader_config_path.as_path())?; - for config_path in binary_download_config_paths.into_iter() { + for config_path in executable_download_config_paths.into_iter() { era_compiler_downloader::Downloader::new(http_client.clone()) .download(config_path.as_path())?; } println!( - " {} downloading compiler binaries in {}m{:02}s", + " {} downloading compiler executables in {}m{:02}s", "Finished".bright_green().bold(), download_time_start.elapsed().as_secs() / 60, download_time_start.elapsed().as_secs() % 60, ); let solc_version = system_contracts_solc_downloader_config - .binaries + .executables .keys() .next() .ok_or_else(|| { @@ -127,10 +128,18 @@ impl EraVM { let mut vm = Self { known_contracts: HashMap::new(), default_aa_code_hash: web3::types::U256::from_big_endian( - system_contracts.default_aa.bytecode_hash.as_slice(), + system_contracts + .default_aa + .bytecode_hash + .expect("Always exists") + .as_slice(), ), evm_interpreter_code_hash: web3::types::U256::from_big_endian( - system_contracts.evm_interpreter.bytecode_hash.as_slice(), + system_contracts + .evm_emulator + .bytecode_hash + .expect("Always exists") + .as_slice(), ), deployed_contracts: HashMap::new(), storage, @@ -142,26 +151,39 @@ impl EraVM { vm.add_known_contract( system_contracts.default_aa.bytecode, web3::types::U256::from_big_endian( - system_contracts.default_aa.bytecode_hash.as_slice(), + system_contracts + .default_aa + .bytecode_hash + .expect("Always exists") + .as_slice(), ), ); vm.add_known_contract( - system_contracts.evm_interpreter.bytecode, + system_contracts.evm_emulator.bytecode, web3::types::U256::from_big_endian( - system_contracts.evm_interpreter.bytecode_hash.as_slice(), + system_contracts + .evm_emulator + .bytecode_hash + .expect("Always exists") + .as_slice(), ), ); vm.add_known_contract( - era_compiler_vyper::MINIMAL_PROXY_CONTRACT_BYTECODE.to_owned(), + era_compiler_vyper::MINIMAL_PROXY_BUILD.bytecode.clone(), web3::types::U256::from_big_endian( - era_compiler_vyper::MINIMAL_PROXY_CONTRACT_HASH.as_slice(), + era_compiler_vyper::MINIMAL_PROXY_BUILD + .bytecode_hash + .expect("Always exists") + .as_slice(), ), ); for (address, build) in system_contracts.deployed_contracts { vm.add_deployed_contract( address, - web3::types::U256::from_big_endian(build.bytecode_hash.as_slice()), + web3::types::U256::from_big_endian( + build.bytecode_hash.expect("Always exists").as_slice(), + ), Some(build.bytecode), ); } @@ -399,60 +421,23 @@ impl EraVM { calldata: Vec, vm_launch_option: Option, ) -> anyhow::Result { - // legacy EvmGasManager.sol compatibility - // set `evmStackFrames` size to 1 - self.storage.insert( - zkevm_tester::compiler_tests::StorageKey { - address: web3::types::Address::from_low_u64_be(ADDRESS_EVM_GAS_MANAGER.into()), - key: web3::types::U256::from(Self::EVM_GAS_MANAGER_STACK_FRAME_SLOT), - }, - web3::types::H256::from_low_u64_be(1), - ); - - // set `evmStackFrames[0].isStatic` to false - self.storage.insert( - zkevm_tester::compiler_tests::StorageKey { - address: web3::types::Address::from_low_u64_be(ADDRESS_EVM_GAS_MANAGER.into()), - key: web3::types::U256::from(Self::EVM_GAS_MANAGER_FIRST_STACK_FRAME), - }, - web3::types::H256::zero(), - ); - - // set `evmStackFrames[0].passGas` to `EVM_CALL_GAS_LIMIT` - self.storage.insert( - zkevm_tester::compiler_tests::StorageKey { - address: web3::types::Address::from_low_u64_be(ADDRESS_EVM_GAS_MANAGER.into()), - key: web3::types::U256::from(Self::EVM_GAS_MANAGER_FIRST_STACK_FRAME).add(1), - }, - web3::types::H256::from_low_u64_be(Self::EVM_CALL_GAS_LIMIT), - ); - - // updated EvmGasManager.sol compatibility - // set `evmStackFrames` size to 1 - self.storage_transient.insert( - zkevm_tester::compiler_tests::StorageKey { - address: web3::types::Address::from_low_u64_be(ADDRESS_EVM_GAS_MANAGER.into()), - key: web3::types::U256::from(Self::EVM_GAS_MANAGER_STACK_FRAME_SLOT), - }, - web3::types::H256::from_low_u64_be(1), - ); - - // set `evmStackFrames[0].passGas` to `EVM_CALL_GAS_LIMIT` + // add initial frame data in EvmGasManager + // set `passGas` to `EVM_CALL_GAS_LIMIT` self.storage_transient.insert( zkevm_tester::compiler_tests::StorageKey { address: web3::types::Address::from_low_u64_be(ADDRESS_EVM_GAS_MANAGER.into()), - key: web3::types::U256::from(Self::EVM_GAS_MANAGER_STACK_FRAME_SLOT).add(2), + key: web3::types::U256::from(Self::EVM_GAS_MANAGER_GAS_TRANSIENT_SLOT), }, web3::types::H256::from_low_u64_be(Self::EVM_CALL_GAS_LIMIT), ); - // set `evmStackFrames[0].isStatic` to false + // set `isActiveFrame` to true self.storage_transient.insert( zkevm_tester::compiler_tests::StorageKey { address: web3::types::Address::from_low_u64_be(ADDRESS_EVM_GAS_MANAGER.into()), - key: web3::types::U256::from(Self::EVM_GAS_MANAGER_STACK_FRAME_SLOT).add(3), + key: web3::types::U256::from(Self::EVM_GAS_MANAGER_AUX_DATA_TRANSIENT_SLOT), }, - web3::types::H256::zero(), + web3::types::H256::from_low_u64_be(2), // "activeFrame flag" ); let mut result = self.execute::( diff --git a/compiler_tester/src/vm/eravm/system_contracts.rs b/compiler_tester/src/vm/eravm/system_contracts.rs index 29a47a6b..7eb384b3 100644 --- a/compiler_tester/src/vm/eravm/system_contracts.rs +++ b/compiler_tester/src/vm/eravm/system_contracts.rs @@ -2,7 +2,6 @@ //! The EraVM system contracts. //! -use std::collections::BTreeMap; use std::collections::HashMap; use std::fs::File; use std::path::PathBuf; @@ -31,8 +30,8 @@ pub struct SystemContracts { pub deployed_contracts: Vec<(web3::types::Address, era_compiler_llvm_context::EraVMBuild)>, /// The default account abstraction contract build. pub default_aa: era_compiler_llvm_context::EraVMBuild, - /// The EVM interpreter contract build. - pub evm_interpreter: era_compiler_llvm_context::EraVMBuild, + /// The EVM emulator contract build. + pub evm_emulator: era_compiler_llvm_context::EraVMBuild, } impl SystemContracts { @@ -44,9 +43,9 @@ impl SystemContracts { const PATH_DEFAULT_AA: &'static str = r"era-contracts\system-contracts\contracts\DefaultAccount.sol:DefaultAccount"; - /// The EVM interpreter system contract implementation path. - const PATH_EVM_INTERPRETER: &'static str = - r"era-contracts\system-contracts\contracts\EvmInterpreter.yul"; + /// The EVM emulator system contract implementation path. + const PATH_EVM_EMULATOR: &'static str = + r"era-contracts/system-contracts/contracts/EvmEmulator.yul"; /// The `keccak256` system contract implementation path. const PATH_KECCAK256: &'static str = @@ -60,6 +59,9 @@ impl SystemContracts { const PATH_SHA256: &'static str = r"era-contracts\system-contracts\contracts\precompiles\SHA256.yul"; + /// The `identity` system contract implementation path. + const PATH_IDENTITY: &'static str = "tests/solidity/simple/system/identity.sol:Identity"; + /// The `ecadd` system contract implementation path. const PATH_ECADD: &'static str = r"era-contracts\system-contracts\contracts\precompiles\EcAdd.yul"; @@ -114,7 +116,7 @@ impl SystemContracts { /// The EVM gas manager system contract implementation path. const PATH_EVM_GAS_MANAGER: &'static str = - r"era-contracts\system-contracts\contracts\EvmGasManager.sol:EvmGasManager"; + r"era-contracts/system-contracts/contracts/EvmGasManager.yul"; /// /// Loads or builds the system contracts. @@ -187,10 +189,18 @@ impl SystemContracts { web3::types::Address::from_low_u64_be(0x8012), Self::PATH_CODE_ORACLE, ), + ( + web3::types::Address::from_low_u64_be(ADDRESS_EVM_GAS_MANAGER.into()), + Self::PATH_EVM_GAS_MANAGER, + ), ]; let solidity_system_contracts = vec![ (web3::types::Address::zero(), Self::PATH_EMPTY_CONTRACT), + ( + web3::types::Address::from_low_u64_be(zkevm_opcode_defs::ADDRESS_IDENTITY.into()), + Self::PATH_IDENTITY, + ), ( web3::types::Address::from_low_u64_be( zkevm_opcode_defs::ADDRESS_ACCOUNT_CODE_STORAGE.into(), @@ -241,23 +251,28 @@ impl SystemContracts { web3::types::Address::from_low_u64_be(zkevm_opcode_defs::ADDRESS_ETH_TOKEN.into()), Self::PATH_BASE_TOKEN, ), - ( - web3::types::Address::from_low_u64_be(ADDRESS_EVM_GAS_MANAGER.into()), - Self::PATH_EVM_GAS_MANAGER, - ), ]; let mut yul_file_paths = Vec::with_capacity(yul_system_contracts.len() + 1); for (_, path) in yul_system_contracts.into_iter() { yul_file_paths.push(path.to_owned()); } - yul_file_paths.push(Self::PATH_EVM_INTERPRETER.to_owned()); + yul_file_paths.push(Self::PATH_EVM_EMULATOR.to_owned()); let yul_optimizer_settings = era_compiler_llvm_context::OptimizerSettings::cycles(); let yul_mode = YulMode::new(yul_optimizer_settings, true).into(); - let yul_llvm_options = vec!["-eravm-jump-table-density-threshold", "10"] - .into_iter() - .map(|option| option.to_owned()) - .collect(); + let yul_llvm_options = vec![ + "-eravm-jump-table-density-threshold", + "10", + "-tail-dup-size", + "6", + "-eravm-enable-split-loop-phi-live-ranges", + "-tail-merge-only-bbs-without-succ", + "-join-globalcopies", + "-disable-early-taildup", + ] + .into_iter() + .map(|option| option.to_owned()) + .collect(); let mut builds = Self::compile( YulCompiler::new(Toolchain::IrLLVM), yul_file_paths, @@ -266,8 +281,9 @@ impl SystemContracts { debug_config.clone(), )?; - let mut solidity_file_paths = Vec::with_capacity(solidity_system_contracts.len() + 1); + let mut solidity_file_paths = Vec::with_capacity(solidity_system_contracts.len() + 2); for pattern in [ + "tests/solidity/simple/system/identity.sol", "era-contracts/system-contracts/contracts/*.sol", "era-contracts/system-contracts/contracts/libraries/**/*.sol", "era-contracts/system-contracts/contracts/interfaces/**/*.sol", @@ -285,7 +301,7 @@ impl SystemContracts { let solidity_optimizer_settings = era_compiler_llvm_context::OptimizerSettings::cycles(); let solidity_mode = SolidityMode::new( solc_version, - era_compiler_solidity::SolcPipeline::Yul, + era_solc::StandardJsonInputCodegen::Yul, true, true, solidity_optimizer_settings, @@ -304,8 +320,8 @@ impl SystemContracts { let default_aa = builds.remove(Self::PATH_DEFAULT_AA).ok_or_else(|| { anyhow::anyhow!("The default AA code not found in the compiler build artifacts") })?; - let evm_interpreter = builds.remove(Self::PATH_EVM_INTERPRETER).ok_or_else(|| { - anyhow::anyhow!("The EVM interpreter code not found in the compiler build artifacts") + let evm_emulator = builds.remove(Self::PATH_EVM_EMULATOR).ok_or_else(|| { + anyhow::anyhow!("The EVM emulator code not found in the compiler build artifacts") })?; let mut system_contracts = @@ -331,7 +347,7 @@ impl SystemContracts { Ok(Self { deployed_contracts, default_aa, - evm_interpreter, + evm_emulator, }) } @@ -422,7 +438,7 @@ impl SystemContracts { .compile_for_eravm( "system-contracts".to_owned(), sources, - BTreeMap::new(), + era_solc::StandardJsonInputLibraries::default(), mode, llvm_options, debug_config, diff --git a/compiler_tester/src/vm/evm/input/build.rs b/compiler_tester/src/vm/evm/input/build.rs index 8579fa2d..3c9aa198 100644 --- a/compiler_tester/src/vm/evm/input/build.rs +++ b/compiler_tester/src/vm/evm/input/build.rs @@ -8,19 +8,16 @@ #[derive(Debug, Clone)] pub struct Build { /// The contract deploy build. - pub deploy_build: era_compiler_llvm_context::EVMBuild, + pub deploy_build: Vec, /// The contract runtime build. - pub runtime_build: era_compiler_llvm_context::EVMBuild, + pub runtime_build: Vec, } impl Build { /// /// A shortcut constructor. /// - pub fn new( - deploy_build: era_compiler_llvm_context::EVMBuild, - runtime_build: era_compiler_llvm_context::EVMBuild, - ) -> Self { + pub fn new(deploy_build: Vec, runtime_build: Vec) -> Self { Self { deploy_build, runtime_build, diff --git a/compiler_tester/src/vm/evm/input/mod.rs b/compiler_tester/src/vm/evm/input/mod.rs index c9435653..abe25522 100644 --- a/compiler_tester/src/vm/evm/input/mod.rs +++ b/compiler_tester/src/vm/evm/input/mod.rs @@ -56,15 +56,12 @@ impl Input { anyhow::anyhow!("Library `{}` not found in the build artifacts", name) })?; + let mut deploy_code = build.deploy_build.to_owned(); + deploy_code.extend_from_slice(build.runtime_build.as_slice()); + instances.insert( name.clone(), - Instance::evm( - name, - Some(address), - false, - true, - build.deploy_build.bytecode.to_owned(), - ), + Instance::evm(name, Some(address), false, true, deploy_code), ); } @@ -75,6 +72,10 @@ impl Input { .ok_or_else(|| { anyhow::anyhow!("Main contract not found in the compiler build artifacts") })?; + + let mut deploy_code = main_contract_build.deploy_build.to_owned(); + deploy_code.extend_from_slice(main_contract_build.runtime_build.as_slice()); + instances.insert( "Test".to_owned(), Instance::evm( @@ -82,7 +83,7 @@ impl Input { main_address, true, false, - main_contract_build.deploy_build.bytecode.to_owned(), + deploy_code, ), ); } else { @@ -91,15 +92,13 @@ impl Input { anyhow::anyhow!("{} not found in the compiler build artifacts", path) })?; let is_main = path.as_str() == self.last_contract.as_str(); + + let mut deploy_code = build.deploy_build.to_owned(); + deploy_code.extend_from_slice(build.runtime_build.as_slice()); + instances.insert( instance.to_owned(), - Instance::evm( - path.to_owned(), - None, - is_main, - false, - build.deploy_build.bytecode.to_owned(), - ), + Instance::evm(path.to_owned(), None, is_main, false, deploy_code), ); } } diff --git a/compiler_tester/src/vm/evm/mod.rs b/compiler_tester/src/vm/evm/mod.rs index 248cd9b7..162cda66 100644 --- a/compiler_tester/src/vm/evm/mod.rs +++ b/compiler_tester/src/vm/evm/mod.rs @@ -49,9 +49,9 @@ impl<'evm> EVM<'evm> { } /// - /// Downloads the necessary compiler binaries. + /// Downloads the necessary compiler executables. /// - pub fn download(binary_download_config_paths: Vec) -> anyhow::Result<()> { + pub fn download(executable_download_config_paths: Vec) -> anyhow::Result<()> { let mut http_client_builder = reqwest::blocking::ClientBuilder::new(); http_client_builder = http_client_builder.connect_timeout(Duration::from_secs(60)); http_client_builder = http_client_builder.pool_idle_timeout(Duration::from_secs(60)); @@ -59,13 +59,16 @@ impl<'evm> EVM<'evm> { let http_client = http_client_builder.build()?; let download_time_start = Instant::now(); - println!(" {} compiler binaries", "Downloading".bright_green().bold()); - for config_path in binary_download_config_paths.into_iter() { + println!( + " {} compiler executables", + "Downloading".bright_green().bold() + ); + for config_path in executable_download_config_paths.into_iter() { era_compiler_downloader::Downloader::new(http_client.clone()) .download(config_path.as_path())?; } println!( - " {} downloading compiler binaries in {}m{:02}s", + " {} downloading compiler executables in {}m{:02}s", "Finished".bright_green().bold(), download_time_start.elapsed().as_secs() / 60, download_time_start.elapsed().as_secs() % 60, @@ -86,7 +89,7 @@ impl<'evm> EVM<'evm> { constructor_args: Vec, ) -> anyhow::Result { let build = self.builds.get(path).expect("Always valid"); - let mut deploy_code = build.deploy_build.bytecode.to_owned(); + let mut deploy_code = build.deploy_build.to_owned(); deploy_code.extend(constructor_args); self.runtime diff --git a/compiler_tester/src/vm/revm/init.rs b/compiler_tester/src/vm/revm/init.rs index e452ceb9..4d95b39a 100644 --- a/compiler_tester/src/vm/revm/init.rs +++ b/compiler_tester/src/vm/revm/init.rs @@ -124,7 +124,7 @@ impl<'a> Revm<'a> { caller: web3::types::Address, value: Option, evm_version: Option, - deploy_code: Vec, + code: Vec, ) -> Self { let vm = self .state @@ -146,7 +146,7 @@ impl<'a> Revm<'a> { env.tx.gas_limit = evm_context.block_gas_limit; env.tx.access_list = vec![]; env.tx.caller = web3_address_to_revm_address(&caller); - env.tx.data = revm::primitives::Bytes::from(deploy_code); + env.tx.data = revm::primitives::Bytes::from(code); env.tx.value = revm::primitives::U256::from(value.unwrap_or_default()); env.tx.transact_to = TxKind::Create; }) diff --git a/compiler_tester/src/workflow.rs b/compiler_tester/src/workflow.rs index 0ef54114..ff37156c 100644 --- a/compiler_tester/src/workflow.rs +++ b/compiler_tester/src/workflow.rs @@ -7,7 +7,7 @@ use std::str::FromStr; /// /// Describes sets of actions that compiler tester is able to perform. /// -#[derive(Debug)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Workflow { /// Only build tests but not execute them. BuildOnly, diff --git a/configs/solc-bin-default.json b/configs/solc-bin-default.json index cde194d8..7c27387e 100644 --- a/configs/solc-bin-default.json +++ b/configs/solc-bin-default.json @@ -481,6 +481,12 @@ "destination": "./solc-bin/solc-${VERSION}" }, "0.8.27": { + "is_enabled": false, + "protocol": "https", + "source": "https://github.com/matter-labs/era-solidity/releases/download/${VERSION}-1.0.1/solc-${PLATFORM}-${VERSION}-1.0.1", + "destination": "./solc-bin/solc-${VERSION}" + }, + "0.8.28": { "is_enabled": true, "protocol": "https", "source": "https://github.com/matter-labs/era-solidity/releases/download/${VERSION}-1.0.1/solc-${PLATFORM}-${VERSION}-1.0.1", diff --git a/configs/solc-bin-llvm.json b/configs/solc-bin-llvm.json new file mode 100644 index 00000000..04646898 --- /dev/null +++ b/configs/solc-bin-llvm.json @@ -0,0 +1,16 @@ +{ + "binaries": { + "0.8.26": { + "is_enabled": true, + "protocol": "https", + "source": "https://github.com/matter-labs/era-solidity/releases/download/mlir-${VERSION}-tag/solc-${PLATFORM}-${VERSION}-mlir", + "destination": "./solc-bin-llvm/solc-${VERSION}" + } + }, + "platforms": { + "linux-amd64": "linux-amd64", + "linux-arm64": "linux-arm64", + "macos-amd64": "macosx-amd64", + "macos-arm64": "macosx-arm64" + } +} diff --git a/configs/solc-bin-upstream.json b/configs/solc-bin-upstream.json index f523e737..df4e1bf6 100644 --- a/configs/solc-bin-upstream.json +++ b/configs/solc-bin-upstream.json @@ -481,6 +481,12 @@ "destination": "./solc-bin-upstream/solc-${VERSION}" }, "0.8.27": { + "is_enabled": false, + "protocol": "compiler-bin-list", + "source": "https://raw.githubusercontent.com/ethereum/solc-bin/gh-pages/${PLATFORM}/list.json", + "destination": "./solc-bin-upstream/solc-${VERSION}" + }, + "0.8.28": { "is_enabled": true, "protocol": "compiler-bin-list", "source": "https://raw.githubusercontent.com/ethereum/solc-bin/gh-pages/${PLATFORM}/list.json", diff --git a/coverage_watcher/Cargo.toml b/coverage_watcher/Cargo.toml index ab4da2b4..39a7b33b 100644 --- a/coverage_watcher/Cargo.toml +++ b/coverage_watcher/Cargo.toml @@ -14,10 +14,10 @@ name = "coverage-watcher" path = "src/coverage_watcher/main.rs" [dependencies] -structopt = { version = "0.3", default-features = false } -anyhow = "1.0" +clap = { version = "=4.5.21", features = ["derive"] } +anyhow = "=1.0.89" -serde = { version = "1.0", features = [ "derive" ] } -serde_yaml = "0.9" +serde = { version = "=1.0.210", features = [ "derive" ] } +serde_yaml = "=0.9.34" era-compiler-common = { git = "https://github.com/matter-labs/era-compiler-common", branch = "main" } diff --git a/coverage_watcher/src/coverage_watcher/arguments.rs b/coverage_watcher/src/coverage_watcher/arguments.rs index 6e55123d..d7889d32 100644 --- a/coverage_watcher/src/coverage_watcher/arguments.rs +++ b/coverage_watcher/src/coverage_watcher/arguments.rs @@ -4,27 +4,15 @@ use std::path::PathBuf; -use structopt::StructOpt; +use clap::Parser; /// /// The coverage watcher arguments. /// -#[derive(Debug, StructOpt)] -#[structopt( - name = "coverage-watcher", - about = "ZKsync toolchain test coverage watcher" -)] +#[derive(Debug, Parser)] +#[command(about, long_about = None)] pub struct Arguments { /// The missed tests output file path. - #[structopt(short = "o", long = "output")] + #[arg(short, long)] pub output: Option, } - -impl Arguments { - /// - /// A shortcut constructor. - /// - pub fn new() -> Self { - Self::from_args() - } -} diff --git a/coverage_watcher/src/coverage_watcher/main.rs b/coverage_watcher/src/coverage_watcher/main.rs index 8eeab2ec..61e9cb8a 100644 --- a/coverage_watcher/src/coverage_watcher/main.rs +++ b/coverage_watcher/src/coverage_watcher/main.rs @@ -9,6 +9,8 @@ use std::io::Read; use std::io::Write; use std::path::PathBuf; +use clap::Parser; + use self::arguments::Arguments; use coverage_watcher::TestsDirectory; @@ -18,7 +20,7 @@ use coverage_watcher::TestsSet; /// The application entry point. /// fn main() -> anyhow::Result<()> { - let arguments = Arguments::new(); + let arguments = Arguments::try_parse()?; let mut data = String::new(); File::open("coverage.yaml") diff --git a/deny.toml b/deny.toml index 7eeccc63..cb4c6042 100644 --- a/deny.toml +++ b/deny.toml @@ -1,17 +1,10 @@ -all-features = false -no-default-features = false - [advisories] -vulnerability = "deny" -unmaintained = "warn" yanked = "warn" -notice = "warn" ignore = [ #"RUSTSEC-0000-0000", ] [licenses] -unlicensed = "deny" allow = [ #"Apache-2.0 WITH LLVM-exception", "MIT", @@ -20,17 +13,12 @@ allow = [ "Unlicense", "MPL-2.0", "Unicode-DFS-2016", + "Unicode-3.0", "CC0-1.0", "BSD-2-Clause", "BSD-3-Clause", "Zlib", ] -deny = [ - #"Nokia", -] -copyleft = "warn" -allow-osi-fsf-free = "neither" -default = "deny" confidence-threshold = 0.93 exceptions = [ { allow = ["OpenSSL"], name = "ring" }, diff --git a/era-contracts b/era-contracts index 220e983c..ed6f4d1f 160000 --- a/era-contracts +++ b/era-contracts @@ -1 +1 @@ -Subproject commit 220e983c9a873e52bfc7e52e3576f67922a132cb +Subproject commit ed6f4d1f8fcde854e084cd1d237fd80698f2da19 diff --git a/ethereum.yaml b/ethereum.yaml index 970b006e..aed98eaa 100644 --- a/ethereum.yaml +++ b/ethereum.yaml @@ -2149,6 +2149,10 @@ entries: modes: - Y+ version: '>=0.4.12' + transient_state_variable_initialization.sol: + hash: '0x702b8ca960d8a816c995de79c5d8134c' + enabled: true + version: '>=0.8.28' constructor_inheritance_init_order.sol: hash: '0x732e47de4aeaedcef778c08b21b2b210' enabled: true @@ -3617,6 +3621,14 @@ entries: - E - I version: '>=0.7.0' + transient_value_types.sol: + hash: '0xb1e434bbc71f843cd4d678eaf26be538' + enabled: true + version: '>=0.8.28' + transient_value_types_multi_frame_call.sol: + hash: '0xb5bdfeb2071e62c3505275035131f306' + enabled: true + version: '>=0.8.28' value_types.sol: hash: '0xba12d166de3a7cf7e09fb51f7bb45240' enabled: true @@ -3807,6 +3819,14 @@ entries: hash: '0xd7e21a5b8052338d07f212197e327a3b' enabled: true version: '>=0.4.12' + transient_storage_state_variable.sol: + hash: '0xf343442238f0126ff68e34b9428e86ed' + enabled: true + version: '>=0.8.28' + transient_storage_state_variable_abstract_contract.sol: + hash: '0x48bd4cb65538a1f033d0ffff71046daf' + enabled: true + version: '>=0.8.28' value_for_constructor.sol: hash: '0xfc70977e16cd72eb8121fffb33ce2abd' enabled: true @@ -3994,6 +4014,10 @@ entries: hash: '0x04cc5fce661ac43a24ff58258ddbdc00' enabled: true version: '>=0.4.12' + inline_assembly_transient_storage_access_inside_function.sol: + hash: '0x9a81fdaadd4790381c2ce5f0efdf6ae7' + enabled: true + version: '>=0.8.28' inline_assembly_write_to_stack.sol: hash: '0xfef6d721eb252e69d0f9b2d50938ba14' enabled: true @@ -4890,6 +4914,10 @@ entries: - E - I version: '>=0.4.14' + transient_state_variable_value_type.sol: + hash: '0x5c021cca1a4512a8730f227c6b36d1e2' + enabled: true + version: '>=0.8.28' multiSource: enabled: true entries: @@ -4960,6 +4988,10 @@ entries: hash: '0x1b5e6e137084de716e0d9d8446564dc7' enabled: true version: '>=0.4.12' + compound_assign_transient_storage.sol: + hash: '0xbd0c4b63b99f5d44ffb9a89f531f6192' + enabled: true + version: '>=0.8.28' shifts: enabled: true entries: @@ -5135,6 +5167,10 @@ entries: hash: '0x4e8524a65fb68db9368603447805c15a' enabled: true version: '>=0.4.21' + transient_storage_variable_increment_decrement.sol: + hash: '0x5d0aa44215d67a5009bec972dd3e44e6' + enabled: true + version: '>=0.8.28' userDefined: enabled: true entries: @@ -6616,6 +6652,14 @@ entries: hash: '0x03f114444079f9008d577cb44bca08f1' enabled: true version: '>=0.4.12' + delete_transient_state_variable.sol: + hash: '0x807c0ba2ce1f5c24a5353d93a1f957e5' + enabled: true + version: '>=0.8.28' + delete_transient_state_variable_non_zero_offset.sol: + hash: '0xc9979162f04813bc1e517a39fc4a3600' + enabled: true + version: '>=0.8.28' mapping_local_assignment.sol: hash: '0x6e2c8c62d5b866f8b2058c2fac97b584' enabled: true @@ -6652,6 +6696,46 @@ entries: hash: '0xae0630569bf5603ed696749ab21c00bc' enabled: true version: '>=0.4.21' + transient_function_type_state_variable.sol: + hash: '0x85b3b01bd9a867454ff3b3a0210afccf' + enabled: true + version: '>=0.8.28' + transient_state_address_variable_members.sol: + hash: '0xbb703fd9fdd2d7edd8f291abc690d643' + enabled: true + version: '>=0.8.28' + transient_state_enum_variable.sol: + hash: '0x901a1be1942a9f1cd22fa6be99fc8808' + enabled: true + version: '>=0.8.28' + transient_state_variable.sol: + hash: '0xe0e4957bc6b30a1aa0711c069d89626f' + enabled: true + version: '>=0.8.28' + transient_state_variable_cleanup_assignment.sol: + hash: '0xe6873be855417289eed3758ee10c1623' + enabled: true + version: '>=0.8.28' + transient_state_variable_cleanup_tstore.sol: + hash: '0x07a01321e9066c7d538ef425f4a35f23' + enabled: true + version: '>=0.8.28' + transient_state_variable_slot_inline_assembly.sol: + hash: '0x7ba508b71048e6d2cb26d03422fcac1c' + enabled: true + version: '>=0.8.28' + transient_state_variable_slots_and_offsets.sol: + hash: '0x3efe44053d16de0f8abd9bfc12e8adb0' + enabled: true + version: '>=0.8.28' + transient_state_variable_tuple_assignment.sol: + hash: '0x10686230bd53840bc3593c731b0f6e23' + enabled: true + version: '>=0.8.28' + transient_state_variable_udvt.sol: + hash: '0x239da4e075afd9b12c2c717e51d5b274' + enabled: true + version: '>=0.8.28' various: enabled: true entries: @@ -6757,6 +6841,10 @@ entries: hash: '0xfc575b0ea2e377c487c4baf0f21f8cb9' enabled: true version: '>=0.4.12' + different_call_type_transient.sol: + hash: '0x53e563a335d8bb3a02b8a021dabe6af5' + enabled: true + version: '>=0.8.28' empty_name_return_parameter.sol: hash: '0x5f095962f4ae9a08b908384aa3be701d' enabled: true @@ -6942,6 +7030,10 @@ entries: hash: '0x4051de6e556f6a42d4486dadce1e24bd' enabled: true version: '>=0.5.0' + transient_storage_reentrancy_lock.sol: + hash: '0x7974f3e336b300ecde5071cf652e2109' + enabled: true + version: '>=0.8.28' tuples.sol: hash: '0xbd8afa8671e0a31c4726453fde7251ca' enabled: true diff --git a/fuzzer/Cargo.toml b/fuzzer/Cargo.toml index 7d4daf5f..d5138c51 100644 --- a/fuzzer/Cargo.toml +++ b/fuzzer/Cargo.toml @@ -26,15 +26,17 @@ doc = false bench = false [dependencies] -libfuzzer-sys = "0.4" -anyhow = "1.0" -semver = { version = "1.0", features = ["serde"] } +anyhow = "=1.0.89" +semver = { version = "=1.0.23", features = ["serde"] } + +libfuzzer-sys = "=0.4.7" zkevm_tester = { git = "https://github.com/matter-labs/era-zkevm_tester", branch = "v1.5.0" } era-compiler-common = { git = "https://github.com/matter-labs/era-compiler-common", branch = "main" } era-compiler-llvm-context = { git = "https://github.com/matter-labs/era-compiler-llvm-context", branch = "main" } era-compiler-solidity = { git = "https://github.com/matter-labs/era-compiler-solidity", branch = "main" } +era-solc = { git = "https://github.com/matter-labs/era-compiler-solidity", branch = "main" } compiler-tester = { path = "../compiler_tester" } solidity-adapter = { path = "../solidity_adapter" } diff --git a/fuzzer/fuzz_targets/common.rs b/fuzzer/fuzz_targets/common.rs index d6213294..630ec565 100644 --- a/fuzzer/fuzz_targets/common.rs +++ b/fuzzer/fuzz_targets/common.rs @@ -9,7 +9,6 @@ use std::{path::PathBuf, sync::Arc}; use compiler_tester::{ Buildable, EthereumTest, Mode, SolidityCompiler, SolidityMode, Summary, Workflow, }; -use era_compiler_solidity::SolcPipeline; pub use solidity_adapter::{ test::function_call::parser::{ @@ -160,7 +159,7 @@ pub fn build_and_run(test: EthereumTest) -> anyhow::Result { let solc_version = semver::Version::new(0, 8, 26); let mode = Mode::Solidity(SolidityMode::new( solc_version, - SolcPipeline::Yul, + era_solc::StandardJsonInputCodegen::Yul, true, true, era_compiler_llvm_context::OptimizerSettings::try_from_cli('3') diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 2cb44b1c..1a07338a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] profile = "default" -channel = "1.80.1" +channel = "1.82.0" diff --git a/solidity b/solidity index 40a35a09..71988f75 160000 --- a/solidity +++ b/solidity @@ -1 +1 @@ -Subproject commit 40a35a097cb1e03550c7ce415f2b46ad81e882a6 +Subproject commit 71988f7546063a9d6d63d54ece85839400b46264 diff --git a/solidity_adapter/Cargo.toml b/solidity_adapter/Cargo.toml index a468f761..5dd255ac 100644 --- a/solidity_adapter/Cargo.toml +++ b/solidity_adapter/Cargo.toml @@ -17,19 +17,20 @@ path = "src/tests_updater/main.rs" doctest = false [dependencies] -structopt = { version = "0.3", default-features = false } -anyhow = "1.0" -colored = "2.0" +clap = { version = "=4.5.21", features = ["derive"] } +anyhow = "=1.0.89" +colored = "=2.1.0" -serde = { version = "1.0", features = [ "derive" ] } -serde_yaml = "0.9" -semver = { version = "1.0", features = [ "serde" ] } -regex = "1.10" -md5 = "0.7" +serde = { version = "=1.0.210", features = [ "derive" ] } +serde_yaml = "=0.9.34" +semver = { version = "=1.0.23", features = [ "serde" ] } +regex = "=1.11.0" +md5 = "=0.7.0" era-compiler-common = { git = "https://github.com/matter-labs/era-compiler-common", branch = "main" } [dependencies.web3] -version = "0.19" +git = "https://github.com/jacques-kigo/rust-web3" +branch = "master" default-features = false features = ["http-rustls-tls", "test", "signing"] diff --git a/solidity_adapter/src/tests_updater/arguments.rs b/solidity_adapter/src/tests_updater/arguments.rs index 380ecd12..cafa90d9 100644 --- a/solidity_adapter/src/tests_updater/arguments.rs +++ b/solidity_adapter/src/tests_updater/arguments.rs @@ -4,43 +4,27 @@ use std::path::PathBuf; -use structopt::StructOpt; +use clap::Parser; /// /// The tests updater's arguments. /// -#[derive(Debug, StructOpt)] -#[structopt( - name = "tests-updater", - about = "ZKsync toolchain test updater for Ethereum Solidity tests" -)] +#[derive(Debug, Parser)] +#[command(about, long_about = None)] pub struct Arguments { /// Source directory of changed tests. - #[structopt( - default_value = "solidity/test/libsolidity/semanticTests", - short = "s", - long = "source" - )] + #[arg(short, long, default_value = "solidity/test/libsolidity/semanticTests")] pub source: PathBuf, /// Path of the tests' index. - #[structopt(short = "i", long = "index")] + #[arg(short, long)] pub index: PathBuf, /// Destination directory for tests to be updated. - #[structopt(short = "d", long = "destination")] + #[arg(short, long)] pub destination: PathBuf, /// Whether to only update the index, and do not touch the files. - #[structopt(long = "index-only")] + #[arg(long)] pub index_only: bool, } - -impl Arguments { - /// - /// A shortcut constructor. - /// - pub fn new() -> Self { - Self::from_args() - } -} diff --git a/solidity_adapter/src/tests_updater/main.rs b/solidity_adapter/src/tests_updater/main.rs index e5e224d8..d4715668 100644 --- a/solidity_adapter/src/tests_updater/main.rs +++ b/solidity_adapter/src/tests_updater/main.rs @@ -8,6 +8,7 @@ use std::fs::OpenOptions; use std::io::BufReader; use std::io::Write; +use clap::Parser; use colored::Colorize; use self::arguments::Arguments; @@ -16,7 +17,7 @@ use self::arguments::Arguments; /// Run updating /// fn main() { - let arguments = Arguments::new(); + let arguments = Arguments::parse(); let file = OpenOptions::new() .read(true) diff --git a/system-contracts-stable-build b/system-contracts-stable-build index eda61935..0da7f24c 100644 Binary files a/system-contracts-stable-build and b/system-contracts-stable-build differ diff --git a/tests b/tests index 21b0bf0e..bc1cd8e1 160000 --- a/tests +++ b/tests @@ -1 +1 @@ -Subproject commit 21b0bf0e044ee6b136fb3065aaf33ab7cd985d24 +Subproject commit bc1cd8e1ac2cf7f6ce5f5e9ec1f68188c171607a