From f8ac5f1f30db9aa09878ccf1572983b83f7a7d72 Mon Sep 17 00:00:00 2001 From: Oleksandr Zarudnyi Date: Tue, 18 Jul 2023 12:48:37 +0200 Subject: [PATCH] Release zksolc v1.3.13 and zkvyper v1.3.9 --- Cargo.lock | 580 +++++++++--------- LLVM.lock | 2 +- README.md | 81 ++- .../src/benchmark/group/element.rs | 6 +- benchmark_analyzer/src/benchmark/group/mod.rs | 34 + .../src/benchmark/group/results.rs | 92 +++ compiler_tester/Cargo.toml | 10 +- .../src/compiler_tester/arguments.rs | 10 + compiler_tester/src/compiler_tester/main.rs | 45 +- compiler_tester/src/compilers/cache/mod.rs | 112 ++-- compiler_tester/src/compilers/cache/value.rs | 11 +- compiler_tester/src/compilers/llvm.rs | 124 ++-- compiler_tester/src/compilers/mod.rs | 56 +- compiler_tester/src/compilers/mode/llvm.rs | 5 +- compiler_tester/src/compilers/mode/mod.rs | 110 ++++ .../src/compilers/mode/solidity.rs | 67 +- compiler_tester/src/compilers/mode/vyper.rs | 27 +- compiler_tester/src/compilers/mode/yul.rs | 5 +- compiler_tester/src/compilers/mode/zkevm.rs | 7 +- .../src/compilers/{ => output}/build.rs | 0 compiler_tester/src/compilers/output/mod.rs | 40 ++ .../src/compilers/solidity/cached_project.rs | 34 - compiler_tester/src/compilers/solidity/mod.rs | 525 +++++++--------- .../src/compilers/solidity/solc_cache_key.rs | 41 ++ .../src/compilers/solidity/subprocess_mode.rs | 33 - .../src/compilers/vyper/cached_project.rs | 20 - compiler_tester/src/compilers/vyper/mod.rs | 331 ++++------ .../src/compilers/vyper/subprocess_mode.rs | 23 - .../src/compilers/vyper/vyper_cache_key.rs | 29 + compiler_tester/src/compilers/yul.rs | 106 ++-- compiler_tester/src/compilers/zkevm.rs | 62 +- .../src/deployers/native_deployer.rs | 1 + .../src/directories/ethereum/mod.rs | 18 +- .../src/directories/ethereum/test.rs | 238 ++++--- .../src/directories/matter_labs/mod.rs | 26 +- .../src/directories/matter_labs/test/mod.rs | 271 ++++---- compiler_tester/src/directories/mod.rs | 16 +- compiler_tester/src/filters.rs | 72 +-- compiler_tester/src/lib.rs | 61 +- compiler_tester/src/llvm_options.rs | 4 +- compiler_tester/src/summary/element/mod.rs | 8 +- .../summary/element/outcome/passed_variant.rs | 4 + compiler_tester/src/summary/mod.rs | 18 +- compiler_tester/src/test/case/input/deploy.rs | 10 +- compiler_tester/src/test/case/input/mod.rs | 34 +- .../src/test/case/input/runtime.rs | 2 +- compiler_tester/src/test/case/mod.rs | 22 +- compiler_tester/src/zkevm/execution_result.rs | 11 +- compiler_tester/src/zkevm/mod.rs | 12 + compiler_tester/src/zkevm/system_contracts.rs | 43 +- solidity | 2 +- solidity_adapter/Cargo.toml | 2 +- .../src/test/function_call/gas_option.rs | 2 +- .../src/test/function_call/mod.rs | 2 +- system-contracts | 2 +- tests | 2 +- 56 files changed, 1815 insertions(+), 1696 deletions(-) rename compiler_tester/src/compilers/{ => output}/build.rs (100%) create mode 100644 compiler_tester/src/compilers/output/mod.rs delete mode 100644 compiler_tester/src/compilers/solidity/cached_project.rs create mode 100644 compiler_tester/src/compilers/solidity/solc_cache_key.rs delete mode 100644 compiler_tester/src/compilers/solidity/subprocess_mode.rs delete mode 100644 compiler_tester/src/compilers/vyper/cached_project.rs delete mode 100644 compiler_tester/src/compilers/vyper/subprocess_mode.rs create mode 100644 compiler_tester/src/compilers/vyper/vyper_cache_key.rs diff --git a/Cargo.lock b/Cargo.lock index 78a1e4a8..8b8d4dd4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,26 +2,41 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "atty" @@ -40,6 +55,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base16ct" version = "0.1.1" @@ -93,9 +123,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.1" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6776fc96284a0bb647b615056fc496d1fe1644a7ab01829818a6d91cae888b84" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" [[package]] name = "bitvec" @@ -192,13 +222,13 @@ dependencies = [ [[package]] name = "colored" -version = "2.0.0" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ - "atty", + "is-terminal", "lazy_static", - "winapi", + "windows-sys", ] [[package]] @@ -209,7 +239,7 @@ source = "git+https://github.com/matter-labs/era-compiler-common?branch=main#a6c [[package]] name = "compiler-llvm-context" version = "1.3.2" -source = "git+https://github.com/matter-labs/era-compiler-llvm-context?branch=main#26b873fe842b7203677db132a5c5d731b0a85dec" +source = "git+https://github.com/matter-labs/era-compiler-llvm-context?branch=main#7d20d1323787ff50fb043cb4f798b3d9a9369ae8" dependencies = [ "anyhow", "compiler-common", @@ -230,8 +260,8 @@ dependencies = [ [[package]] name = "compiler-solidity" -version = "1.3.11" -source = "git+https://github.com/matter-labs/era-compiler-solidity?branch=main#f680f769e22b3ea3a63f0a2c9f6efa2754a61527" +version = "1.3.13" +source = "git+https://github.com/matter-labs/era-compiler-solidity?branch=main#f7573459d185cea382c3daf95c59ace1f86b8322" dependencies = [ "anyhow", "colored", @@ -242,12 +272,14 @@ dependencies = [ "md5", "mimalloc", "num", + "once_cell", "rand 0.8.5", "rayon", "regex", "semver", "serde", "serde_json", + "serde_stacker", "sha3 0.10.6", "structopt", "thiserror", @@ -293,8 +325,8 @@ dependencies = [ [[package]] name = "compiler-vyper" -version = "1.3.7" -source = "git+https://github.com/matter-labs/era-compiler-vyper?branch=main#0cc89e95730873c33df056e75ac2b4427fe0ac3e" +version = "1.3.9" +source = "git+https://github.com/matter-labs/era-compiler-vyper?branch=main#e37641df708791c8d578be70cb1e475ca8e622d6" dependencies = [ "anyhow", "colored", @@ -304,6 +336,7 @@ dependencies = [ "inkwell", "lazy_static", "mimalloc", + "once_cell", "rayon", "semver", "serde", @@ -317,9 +350,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" +checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747" [[package]] name = "convert_case" @@ -340,9 +373,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -370,9 +403,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if", @@ -383,9 +416,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -510,17 +543,23 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" dependencies = [ + "atty", "humantime", - "is-terminal", "log", "regex", "termcolor", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.1" @@ -529,7 +568,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -614,9 +653,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -689,7 +728,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -740,15 +779,21 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", "wasi", ] +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + [[package]] name = "glob" version = "0.3.1" @@ -768,9 +813,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" dependencies = [ "bytes", "fnv", @@ -778,7 +823,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -791,6 +836,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + [[package]] name = "headers" version = "0.3.8" @@ -836,18 +887,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -906,9 +948,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.26" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -930,10 +972,11 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" +checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ + "futures-util", "http", "hyper", "rustls", @@ -954,9 +997,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1007,7 +1050,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", ] [[package]] @@ -1034,33 +1087,21 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "ipnet" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "is-terminal" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", + "hermit-abi 0.3.2", "rustix", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1074,15 +1115,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -1131,9 +1172,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libmath" @@ -1156,9 +1197,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.3.8" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" [[package]] name = "llvm-sys" @@ -1174,9 +1215,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -1184,9 +1225,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.18" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "matches" @@ -1208,9 +1249,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg", ] @@ -1236,6 +1277,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.8" @@ -1244,7 +1294,7 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1259,9 +1309,9 @@ dependencies = [ [[package]] name = "num" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" dependencies = [ "num-bigint", "num-complex", @@ -1335,19 +1385,28 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.2", "libc", ] +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" -version = "1.17.2" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "opaque-debug" @@ -1393,48 +1452,48 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.45.0", + "windows-targets", ] [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pin-project" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" [[package]] name = "pin-utils" @@ -1507,9 +1566,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -1525,9 +1584,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" dependencies = [ "proc-macro2", ] @@ -1639,18 +1698,30 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.8.3" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" dependencies = [ "aho-corasick", "memchr", @@ -1659,9 +1730,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "reqwest" @@ -1749,6 +1820,12 @@ dependencies = [ "serde", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -1766,23 +1843,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.19" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.3.3", "errno", - "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "rustls" -version = "0.21.1" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e" +checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36" dependencies = [ "log", "ring", @@ -1792,18 +1868,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ "base64 0.21.2", ] [[package]] name = "rustls-webpki" -version = "0.100.1" +version = "0.101.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" +checksum = "15f36a6828982f422756984e47912a7a51dcbc2a197aa791158f8ca61cd8204e" dependencies = [ "ring", "untrusted", @@ -1811,15 +1887,15 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" @@ -1865,38 +1941,38 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.163" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" dependencies = [ "itoa", "ryu", @@ -1905,9 +1981,9 @@ dependencies = [ [[package]] name = "serde_stacker" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f5557f4c1103cecd0e639a17ab22d670b89912d8a506589ee627bf738a15a5d" +checksum = "7f5321e680f77e7b5cfccc78708ff86a814d39aba030610aee67bd5eaf8a1c30" dependencies = [ "serde", "stacker", @@ -1927,11 +2003,11 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.21" +version = "0.9.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c" +checksum = "bd5f51e3fdb5b9cdd1577e1cb7a733474191b1aca6a72c2e50913241632c1180" dependencies = [ - "indexmap", + "indexmap 2.0.0", "itoa", "ryu", "serde", @@ -2003,9 +2079,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "socket2" @@ -2111,9 +2187,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" dependencies = [ "proc-macro2", "quote", @@ -2146,22 +2222,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -2190,25 +2266,26 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", "num_cpus", "pin-project-lite", "socket2", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "tokio-rustls" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls", "tokio", @@ -2230,17 +2307,17 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.10" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ - "indexmap", + "indexmap 2.0.0", "toml_datetime", "winnow", ] @@ -2265,13 +2342,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -2315,9 +2392,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" @@ -2342,9 +2419,9 @@ checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unsafe-libyaml" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6" +checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" [[package]] name = "untrusted" @@ -2354,12 +2431,12 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", - "idna 0.3.0", + "idna 0.4.0", "percent-encoding", ] @@ -2377,11 +2454,10 @@ checksum = "2266fcb904c50fb17fda4c9a751a1715629ecf8b21f4c9d78b4890fb71525d71" [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -2393,9 +2469,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2403,24 +2479,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.36" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ "cfg-if", "js-sys", @@ -2430,9 +2506,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2440,28 +2516,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "web-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -2548,132 +2624,66 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets", ] [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[package]] name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[package]] name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.48.0" @@ -2682,9 +2692,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.6" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" +checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" dependencies = [ "memchr", ] @@ -2712,21 +2722,34 @@ checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" [[package]] name = "zk_evm" -version = "1.3.2" -source = "git+https://github.com/matter-labs/era-zk_evm?branch=v1.3.2#4262966337708702b5a6cdad902a757acc968dbb" +version = "1.3.3" +source = "git+https://github.com/matter-labs/era-zk_evm?branch=v1.3.3#c08a8581421d2a0cf1fc8cbbdcd06c00da01fe0e" dependencies = [ + "anyhow", "lazy_static", "num", "serde", "serde_json", "static_assertions", + "zk_evm_abstractions", + "zkevm_opcode_defs", +] + +[[package]] +name = "zk_evm_abstractions" +version = "0.1.0" +source = "git+https://github.com/matter-labs/era-zk_evm_abstractions.git#973a1f661c045e0e8b9a287505f353659279b3b3" +dependencies = [ + "anyhow", + "serde", + "static_assertions", "zkevm_opcode_defs", ] [[package]] name = "zkevm-assembly" version = "1.3.2" -source = "git+https://github.com/matter-labs/era-zkEVM-assembly?branch=v1.3.2#8a339104582d175627feba2bc4f176304b67b943" +source = "git+https://github.com/matter-labs/era-zkEVM-assembly?branch=v1.3.2#edc364e59a2eea9c4b1d4ce79f15d0b7c6b55b98" dependencies = [ "env_logger", "hex", @@ -2735,7 +2758,6 @@ dependencies = [ "nom", "num-bigint", "num-traits", - "regex", "sha3 0.10.6", "smallvec", "structopt", @@ -2748,7 +2770,7 @@ name = "zkevm_opcode_defs" version = "1.3.2" source = "git+https://github.com/matter-labs/era-zkevm_opcode_defs?branch=v1.3.2#2f69c6975a272e8c31d2d82c136a4ea81df25115" dependencies = [ - "bitflags 2.3.1", + "bitflags 2.3.3", "blake2", "ethereum-types", "k256", @@ -2759,8 +2781,8 @@ dependencies = [ [[package]] name = "zkevm_tester" -version = "1.3.2" -source = "git+https://github.com/matter-labs/era-zkevm_tester?branch=v1.3.2#f2f659bd1405c08f4a5606d3a9435b9c00ff4fd3" +version = "1.3.3" +source = "git+https://github.com/matter-labs/era-zkevm_tester?branch=v1.3.3#d26312f50971f7ed2a7f2b0ccd0da1ac0b41a550" dependencies = [ "anyhow", "futures", diff --git a/LLVM.lock b/LLVM.lock index 8dd66382..85412c17 100644 --- a/LLVM.lock +++ b/LLVM.lock @@ -1,2 +1,2 @@ url = "https://github.com/matter-labs/era-compiler-llvm" -branch = "v1.3.2" +branch = "v1.3.4" diff --git a/README.md b/README.md index 27342f56..85c8dedc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# zkSync Era: The zkEVM Compiler Integration Test Framework +# zkSync Era: The EraVM Compiler Integration Test Framework [![Logo](eraLogo.svg)](https://zksync.io/) @@ -7,8 +7,8 @@ or decentralization. As it's EVM-compatible (with Solidity/Vyper), 99% of Ethere needing to refactor or re-audit any code. zkSync Era also uses an LLVM-based compiler that will eventually enable developers to write smart contracts in popular languages such as C++ and Rust. -The `compiler-tester` integration test framework runs tests for Matter Labs compilers which target the zkEVM, -for supported languages listed below. It compiles source code via internal API calls, +The `compiler-tester` integration test framework runs tests for Matter Labs compilers which target the EraVM, +for supported languages listed below. It compiles source code via external API calls, e.g. to [Inkwell](https://thedan64.github.io/inkwell/inkwell/index.html). In software quality assurance jargon, this makes it a whitebox testing framework. @@ -16,7 +16,7 @@ The `compiler-tester` repository includes the Compiler Tests Collection reposito By default, the Tester SHOULD run the entire Collection in all possible combinations of compiler versions and settings, 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 of running tests in all LLVM optimization modes. +made, and there is no point in running tests in all LLVM optimization modes. ## Building @@ -26,17 +26,29 @@ made, and there is no point of running tests in all LLVM optimization modes. 1.c. On MacOS, install the [HomeBrew](https://brew.sh) package manager (being careful to install it as the appropriate user), then `brew install cmake ninja coreutils parallel`. Install your choice of a recent LLVM/[Clang](https://clang.llvm.org) compiler, e.g. via [Xcode](https://developer.apple.com/xcode/), [Apple’s Command Line Tools](https://developer.apple.com/library/archive/technotes/tn2339/_index.html), or your preferred package manager. 1.d. Their equivalents with other package managers -1. [Install Rust](https://www.rust-lang.org/tools/install). +2. [Install Rust](https://www.rust-lang.org/tools/install). -1. Check out or clone the appropriate branch of this repository using the `--recursive` option. +3. Check out or clone the appropriate branch of this repository using the `--recursive` option. -1. Install the LLVM building tool: `cargo install compiler-llvm-builder`. +4. Install the LLVM building tool: `cargo install compiler-llvm-builder`. -1. Clone and build the LLVM framework: `zkevm-llvm clone && zkevm-llvm build`. +5. Pull and build the LLVM framework: + 5.a. If you have not cloned the LLVM repository yet: + ``` + zkevm-llvm clone && zkevm-llvm build + ``` + 5.b. If you have already cloned the LLVM repository: + ``` + zkevm-llvm checkout + git -C './llvm/' pull + zkevm-llvm build + ``` -1. Build the Tester with `cargo build --release`. +6. 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. -Then run the tests using the examples below under “Usage.” +7. Build the Tester with `cargo build --release`. + +8. Run the tests using the examples below under “Usage”. ## What is supported @@ -46,22 +58,27 @@ Then run the tests using the examples below under “Usage.” - Yul - Vyper - LLVM IR -- zkEVM assembly +- EraVM assembly -### Optimization modes +### Optimizers -- LLVM middle-end (levels 0 to 3, s, z, e.g. `M0`, `M1` etc.) -- LLVM back-end (levels 0 to 3, e.g. `B0`, `B1` etc.) -- `solc` compiler (disabled or enabled), marked as one of [`Y-`, `Y+`, `E-`, `E+`] -- `vyper` compiler (disabled or enabled), marked as one of [`V-`, `V+`] +- LLVM middle-end optimizer (levels 0 to 3, s, z, e.g. `M0`, `M1` etc.) +- LLVM back-end optimizer (levels 0 to 3, e.g. `B0`, `B1` etc.) +- `solc` optimizer (`-` or `+`) +- `vyper` optimizer (`-` or `+`) -### Compiler versions +### Solidity codegens + +- Yul pure (`Y`) +- EVM assembly from Yul (`y`) +- EVM assembly (`E`) -Only relevant for Solidity and Vyper tests: +### Compiler versions -- `^0.8` for compiling Solidity via Yul +- `>=0.8` for compiling Solidity via Yul +- `>=0.8.13` for compiling Solidity via EVM assembly from Yul - [0.4.10; latest] for compiling Solidity via EVM assembly -- [0.3.3; latest] for compiling Vyper via LLL IR +- [0.3.3, 0.3.9] for compiling Vyper via LLL IR ### Compiler pipelines @@ -91,7 +108,7 @@ There are more rarely used options, which you may check out with `./target/relea ### Example 1 -Run a simple Solidity test, dumping Yul, unoptimized and optimized LLVM IR, and zkEVM assembly to the specified directory. +Run a simple Solidity test, dumping Yul, unoptimized and optimized LLVM IR, and EraVM assembly to the specified directory. Use: @@ -99,7 +116,7 @@ Use: - Yul optimizations enabled (`+`) - level 3 optimizations in LLVM middle-end (`M3`) - level 3 optimizations in LLVM back-end (`B3`) -- Solidity compiler version (`0.8.19`) +- Solidity compiler version (`0.8.20`) Output: @@ -110,12 +127,13 @@ Output: ```bash cargo run --release --bin compiler-tester -- -DT \ --path='tests/solidity/simple/default.sol' \ - --mode='Y+M3B3 0.8.19' + --mode='Y+M3B3 0.8.20' \ + --zksolc '../compiler-solidity/target/release/zksolc' ``` ### Example 2 -Run all simple Solidity tests. This currently runs about three hundred tests and takes about eight minutes. +Run all simple Yul tests. This currently runs about three hundred tests and takes about eight minutes. Use: @@ -139,9 +157,16 @@ Run all tests (currently about three million) in all modes. This takes a few hours on the CI server, and probably much longer on your personal machine. ```bash -cargo run --release --bin compiler-tester +cargo run --release --bin compiler-tester -- \ + --zksolc '../compiler-solidity/target/release/zksolc' \ + --zkvyper '../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 1. Change the LLVM branch to the base in the `LLVM.lock` file at the repository root, checkout and build it: @@ -153,7 +178,7 @@ zkevm-llvm checkout && zkevm-llvm build ``` ./target/release/compiler-tester \ --path='tests/solidity/simple/default.sol' \ - --mode='Y+M^B3 0.8.19' \ + --mode='Y+M^B3 0.8.20' \ --benchmark='reference.json' ``` @@ -166,7 +191,7 @@ zkevm-llvm checkout && zkevm-llvm build ``` ./target/release/compiler-tester \ --path='tests/solidity/simple/default.sol' \ - --mode='Y+M^B3 0.8.19' \ + --mode='Y+M^B3 0.8.20' \ --benchmark='candidate.json' ``` @@ -183,7 +208,7 @@ After you make any changes in LLVM, you only need to repeat steps 2-3 to update then prepending the `cargo` command with `CARGO_NET_GIT_FETCH_WITH_CLI=true` may help. - On MacOS, `git config --global credential.helper osxkeychain` followed by cloning a repository manually with a personal access token may help. -- 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` +- 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 diff --git a/benchmark_analyzer/src/benchmark/group/element.rs b/benchmark_analyzer/src/benchmark/group/element.rs index df2db48c..70ff3a0b 100644 --- a/benchmark_analyzer/src/benchmark/group/element.rs +++ b/benchmark_analyzer/src/benchmark/group/element.rs @@ -14,13 +14,15 @@ pub struct Element { pub size: Option, /// The number of cycles. pub cycles: usize, + /// The number of ergs. + pub ergs: u32, } impl Element { /// /// A shortcut constructor. /// - pub fn new(size: Option, cycles: usize) -> Self { - Self { size, cycles } + pub fn new(size: Option, cycles: usize, ergs: u32) -> Self { + Self { size, cycles, ergs } } } diff --git a/benchmark_analyzer/src/benchmark/group/mod.rs b/benchmark_analyzer/src/benchmark/group/mod.rs index 6ff7e7d5..f7cd7335 100644 --- a/benchmark_analyzer/src/benchmark/group/mod.rs +++ b/benchmark_analyzer/src/benchmark/group/mod.rs @@ -45,6 +45,14 @@ impl Group { 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() { let candidate = match candidate.elements.get(path.as_str()) { Some(candidate) => candidate, @@ -68,6 +76,23 @@ impl Group { } cycles_factors.push(cycles_factor); + ergs_total_reference += reference.ergs as u64; + ergs_total_candidate += candidate.ergs as u64; + 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, @@ -100,6 +125,9 @@ impl Group { let cycles_geomean = math::mean::geometric(cycles_factors.as_slice()); let cycles_total = (cycles_total_candidate as f64) / (cycles_total_reference as f64); + let ergs_geomean = math::mean::geometric(ergs_factors.as_slice()); + let ergs_total = (ergs_total_candidate as f64) / (ergs_total_reference as f64); + Results::new( size_geomean, size_min, @@ -113,6 +141,12 @@ impl Group { cycles_total, cycles_negatives, cycles_positives, + ergs_geomean, + ergs_min, + ergs_max, + ergs_total, + ergs_negatives, + ergs_positives, ) } } diff --git a/benchmark_analyzer/src/benchmark/group/results.rs b/benchmark_analyzer/src/benchmark/group/results.rs index 3be79465..d84d959e 100644 --- a/benchmark_analyzer/src/benchmark/group/results.rs +++ b/benchmark_analyzer/src/benchmark/group/results.rs @@ -35,6 +35,19 @@ pub struct Results<'a> { pub cycles_negatives: Vec<(f64, &'a str)>, /// The cycles positive result test names. pub cycles_positives: Vec<(f64, &'a str)>, + + /// The ergs geometric mean. + pub ergs_mean: f64, + /// The ergs best result. + pub ergs_best: f64, + /// The ergs worst result. + pub ergs_worst: f64, + /// The ergs total decrease result. + pub ergs_total: f64, + /// The ergs negative result test names. + pub ergs_negatives: Vec<(f64, &'a str)>, + /// The ergs positive result test names. + pub ergs_positives: Vec<(f64, &'a str)>, } impl<'a> Results<'a> { @@ -56,6 +69,13 @@ impl<'a> Results<'a> { cycles_total: f64, cycles_negatives: Vec<(f64, &'a str)>, cycles_positives: Vec<(f64, &'a str)>, + + ergs_mean: f64, + ergs_best: f64, + ergs_worst: f64, + ergs_total: f64, + ergs_negatives: Vec<(f64, &'a str)>, + ergs_positives: Vec<(f64, &'a str)>, ) -> Self { Self { size_mean, @@ -71,6 +91,13 @@ impl<'a> Results<'a> { cycles_total, cycles_negatives, cycles_positives, + + ergs_mean, + ergs_best, + ergs_worst, + ergs_total, + ergs_negatives, + ergs_positives, } } @@ -92,6 +119,13 @@ impl<'a> Results<'a> { std::cmp::Ordering::Equal } }); + self.ergs_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 @@ -106,6 +140,13 @@ impl<'a> Results<'a> { std::cmp::Ordering::Equal } }); + self.ergs_positives.sort_by(|a, b| { + if a.0 < b.0 { + std::cmp::Ordering::Less + } else { + std::cmp::Ordering::Equal + } + }); } /// @@ -132,6 +173,16 @@ impl<'a> Results<'a> { println!("{:010}: {}", Self::format_geomean(*value), path); } println!(); + println!( + "Group '{}' ergs (-%) worst {} out of {}:", + group_name, + count, + self.ergs_negatives.len() + ); + for (value, path) in self.ergs_negatives.iter().take(count) { + println!("{:010}: {}", Self::format_geomean(*value), path); + } + println!(); println!( "Group '{}' size (-%) best {} out of {}:", group_name, @@ -152,6 +203,16 @@ impl<'a> Results<'a> { println!("{:010}: {}", Self::format_geomean(*value), path); } println!(); + println!( + "Group '{}' ergs (-%) best {} out of {}:", + group_name, + count, + self.ergs_positives.len() + ); + for (value, path) in self.ergs_positives.iter().take(count) { + println!("{:010}: {}", Self::format_geomean(*value), path); + } + println!(); } /// @@ -236,6 +297,37 @@ impl<'a> Results<'a> { "Total".bright_white(), Self::format_geomean(self.cycles_total) )?; + writeln!( + w, + "╠═╡ {} ╞{}╡ {} ╞═╣", + "Ergs (-%)".bright_white(), + "═".repeat(cmp::max(24 - group_name.len(), 0)), + group_name.bright_white() + )?; + writeln!( + w, + "║ {:33} {:07} ║", + "Mean".bright_white(), + Self::format_geomean(self.ergs_mean) + )?; + writeln!( + w, + "║ {:33} {:07} ║", + "Best".bright_white(), + Self::format_geomean(self.ergs_best) + )?; + writeln!( + w, + "║ {:33} {:07} ║", + "Worst".bright_white(), + Self::format_geomean(self.ergs_worst) + )?; + writeln!( + w, + "║ {:33} {:07} ║", + "Total".bright_white(), + Self::format_geomean(self.ergs_total) + )?; writeln!(w, "╚═══════════════════════════════════════════╝")?; Ok(()) diff --git a/compiler_tester/Cargo.toml b/compiler_tester/Cargo.toml index b8b5ee44..7c785c3b 100644 --- a/compiler_tester/Cargo.toml +++ b/compiler_tester/Cargo.toml @@ -28,7 +28,7 @@ md5 = "0.7" hex = "0.4" sha3 = "0.10" ron = "0.8" -regex = "1.8" +regex = "1.9" glob = "0.3" semver = { version = "1.0", features = [ "serde" ] } itertools = "0.10" @@ -36,11 +36,10 @@ rayon = "1.7" once_cell = "1.17" lazy_static = "1.4" bincode = "1.3" -web3 = { version= "0.18", default-features = false, features = ["http-rustls-tls", "test", "signing"] } zkevm-assembly = { git = "https://github.com/matter-labs/era-zkEVM-assembly", branch = "v1.3.2" } zkevm_opcode_defs = { git = "https://github.com/matter-labs/era-zkevm_opcode_defs", branch = "v1.3.2" } -zkevm_tester = { git = "https://github.com/matter-labs/era-zkevm_tester", branch = "v1.3.2" } +zkevm_tester = { git = "https://github.com/matter-labs/era-zkevm_tester", branch = "v1.3.3" } compiler-common = { git = "https://github.com/matter-labs/era-compiler-common", branch = "main" } compiler-llvm-context = { git = "https://github.com/matter-labs/era-compiler-llvm-context", branch = "main" } @@ -55,6 +54,11 @@ version = "1.28" default-features = false features = ["rt-multi-thread"] +[dependencies.web3] +version = "0.18" +default-features = false +features = ["http-rustls-tls", "test", "signing"] + [dependencies.reqwest] version = "0.11" default-features = false diff --git a/compiler_tester/src/compiler_tester/arguments.rs b/compiler_tester/src/compiler_tester/arguments.rs index f11608a1..e1a8a868 100644 --- a/compiler_tester/src/compiler_tester/arguments.rs +++ b/compiler_tester/src/compiler_tester/arguments.rs @@ -64,6 +64,16 @@ pub struct Arguments { #[structopt(long = "disable-value-simulator")] pub disable_value_simulator: bool, + /// Path to the `zksolc` binary. + /// Is set to `zksolc` by default. + #[structopt(long = "zksolc")] + pub zksolc: Option, + + /// Path to the `zkvyper` binary. + /// Is set to `zkvyper` by default. + #[structopt(long = "zkvyper")] + pub zkvyper: Option, + /// Path to the default `solc` binaries download configuration file. #[structopt(long = "solc-bin-config-path")] pub solc_bin_config_path: Option, diff --git a/compiler_tester/src/compiler_tester/main.rs b/compiler_tester/src/compiler_tester/main.rs index 6c28f676..18903ef9 100644 --- a/compiler_tester/src/compiler_tester/main.rs +++ b/compiler_tester/src/compiler_tester/main.rs @@ -40,6 +40,27 @@ fn main_inner(arguments: Arguments) -> anyhow::Result<()> { inkwell::support::get_commit_id().to_string(), ); + inkwell::support::enable_llvm_pretty_stack_trace(); + compiler_llvm_context::initialize_target(); + compiler_tester::LLVMOptions::initialize( + arguments.llvm_verify_each, + arguments.llvm_debug_logging, + )?; + compiler_solidity::EXECUTABLE + .set( + arguments + .zksolc + .unwrap_or_else(|| PathBuf::from(compiler_solidity::DEFAULT_EXECUTABLE_NAME)), + ) + .expect("Always valid"); + compiler_vyper::EXECUTABLE + .set( + arguments + .zkvyper + .unwrap_or_else(|| PathBuf::from(compiler_vyper::DEFAULT_EXECUTABLE_NAME)), + ) + .expect("Always valid"); + let debug_config = if arguments.debug { std::fs::create_dir_all(compiler_tester::DEBUG_DIRECTORY)?; Some(compiler_llvm_context::DebugConfig::new(PathBuf::from_str( @@ -68,13 +89,6 @@ fn main_inner(arguments: Arguments) -> anyhow::Result<()> { let summary = compiler_tester::Summary::new(arguments.verbosity, arguments.quiet).wrap(); - inkwell::support::enable_llvm_pretty_stack_trace(); - compiler_llvm_context::initialize_target(); - compiler_tester::LLVMOptions::initialize( - arguments.llvm_verify_each, - arguments.llvm_debug_logging, - )?; - let filters = compiler_tester::Filters::new(arguments.paths, arguments.modes, arguments.groups); let system_contract_debug_config = if arguments.dump_system { debug_config.clone() @@ -151,23 +165,24 @@ mod tests { let arguments = Arguments { verbosity: false, quiet: false, + debug: false, trace: 2, - modes: vec!["Y+M3I+B3 0.8.17".to_owned()], - paths: vec![ - "tests/solidity/complex/solidity_by_example/simple/import/test.json".to_owned(), - ], + modes: vec!["Y+M3B3 0.8.20".to_owned()], + paths: vec!["tests/solidity/simple/default.sol".to_owned()], groups: vec![], benchmark: None, threads: Some(1), - llvm_options: None, dump_system: false, - debug_output_directory: None, disable_deployer: false, disable_value_simulator: false, - solc_bin_config_path: None, - vyper_bin_config_path: None, + zksolc: Some(PathBuf::from(compiler_solidity::DEFAULT_EXECUTABLE_NAME)), + zkvyper: Some(PathBuf::from(compiler_vyper::DEFAULT_EXECUTABLE_NAME)), + solc_bin_config_path: Some(PathBuf::from("configs/solc-bin-default.json")), + vyper_bin_config_path: Some(PathBuf::from("configs/vyper-bin-default.json")), load_system_contracts: None, save_system_contracts: None, + llvm_verify_each: false, + llvm_debug_logging: false, }; main_inner(arguments).expect("Manual testing failed"); diff --git a/compiler_tester/src/compilers/cache/mod.rs b/compiler_tester/src/compilers/cache/mod.rs index b030e088..2e094ca0 100644 --- a/compiler_tester/src/compilers/cache/mod.rs +++ b/compiler_tester/src/compilers/cache/mod.rs @@ -1,33 +1,31 @@ //! -//! The cache of compiled tests. +//! The thread-safe cache implementation. //! pub mod value; use std::collections::HashMap; use std::hash::Hash; -use std::sync::Arc; -use std::sync::Condvar; -use std::sync::Mutex; use std::sync::RwLock; -use std::sync::RwLockReadGuard; use self::value::Value; /// -/// The cache of compiled tests. +/// The thread-safe cache implementation. /// pub struct Cache where - K: Eq + Hash, + K: Eq + Hash + Clone, + V: Clone, { /// The cache inner data structure. - inner: RwLock>>, + inner: RwLock>>>, } impl Cache where - K: Eq + Hash, + K: Eq + Hash + Clone, + V: Clone, { /// /// Creates an empty cache instance. @@ -39,68 +37,86 @@ where } /// - /// Start computing the cache value, returns a write lock. + /// Compute and save the cache value, if a value already started computing will do nothing. /// - pub fn start(&self, key: K) -> Option, Condvar)>> { - let mut inner = self.inner.write().expect("Sync"); + pub fn compute(&self, key: K, f: F) + where + F: FnOnce() -> anyhow::Result, + { + let waiter = Value::::waiter(); + let _lock = waiter.lock().expect("Sync"); + { + let mut inner = self.inner.write().expect("Sync"); + + if inner.contains_key(&key) { + return; + } - if inner.contains_key(&key) { - return None; + inner.insert(key.clone(), Value::Waiter(waiter.clone())); } - let waiter = Value::::waiter(); + let value = f(); - inner.insert(key, Value::Waiter(waiter.clone())); + let mut inner = self.inner.write().expect("Sync"); + let entry_value = inner + .get_mut(&key) + .expect("The value is not being computed"); + + assert!( + matches!(entry_value, Value::Waiter(_)), + "The value is already computed" + ); - Some(waiter) + *entry_value = Value::Value(value); } /// - /// Waits until value will be computed. + /// Checks if value for the key is cached. /// - pub fn wait(&self, key: &K) { - let waiter = if let Value::Waiter(waiter) = self.read().get(key).expect("Always valid") { - waiter.clone() - } else { - return; - }; - let _guard = waiter.1.wait(waiter.0.lock().expect("Sync")); + pub fn contains(&self, key: &K) -> bool { + self.inner.read().expect("Sync").contains_key(key) } /// - /// Finishes computing the cache value, returns a write lock. + /// Get the cloned value by the key. + /// Will wait if the value is computing. /// /// # Panics /// /// If the value is not being computed. /// - pub fn finish(&self, key: K, value: V, waiter: Arc<(Mutex<()>, Condvar)>) { - let mut inner = self.inner.write().expect("Sync"); - - assert!( - matches!( - inner - .insert(key, Value::Value(value)) - .expect("The value is not being computed"), - Value::Waiter(_) - ), - "The value is already computed" - ); - - waiter.1.notify_all(); + pub fn get_cloned(&self, key: &K) -> anyhow::Result { + self.wait(key); + self.inner + .read() + .expect("Sync") + .get(key) + .expect("The value is not being computed") + .unwrap_value() + .as_ref() + .map(|value| value.clone()) + .map_err(|error| anyhow::anyhow!("{}", error)) } /// - /// Checks if value for the key is cached. + /// Waits until value will be computed if needed. /// - pub fn contains(&self, key: &K) -> bool { - self.inner.read().expect("Sync").contains_key(key) - } - + /// # Panics /// - /// Locks the cache for reading. + /// If the value is not being computed. /// - pub fn read(&self) -> RwLockReadGuard>> { - self.inner.read().expect("Sync") + fn wait(&self, key: &K) { + let waiter = if let Value::Waiter(waiter) = self + .inner + .read() + .expect("Sync") + .get(key) + .expect("The value is not being computed") + { + waiter.clone() + } else { + return; + }; + let _lock = waiter.lock().expect("Sync"); } } diff --git a/compiler_tester/src/compilers/cache/value.rs b/compiler_tester/src/compilers/cache/value.rs index fca52908..d7644829 100644 --- a/compiler_tester/src/compilers/cache/value.rs +++ b/compiler_tester/src/compilers/cache/value.rs @@ -3,7 +3,6 @@ //! use std::sync::Arc; -use std::sync::Condvar; use std::sync::Mutex; /// @@ -11,7 +10,7 @@ use std::sync::Mutex; /// pub enum Value { /// The value is being computed. - Waiter(Arc<(Mutex<()>, Condvar)>), + Waiter(Arc>), /// The value is already computed. Value(T), } @@ -20,8 +19,8 @@ impl Value { /// /// A shortcut waiter constructor. /// - pub fn waiter() -> Arc<(Mutex<()>, Condvar)> { - Arc::new((Mutex::new(()), Condvar::new())) + pub fn waiter() -> Arc> { + Arc::new(Mutex::new(())) } /// @@ -29,12 +28,12 @@ impl Value { /// /// # Panics /// - /// If the value is being waited for. + /// If the value is computed. /// pub fn unwrap_value(&self) -> &T { match self { Self::Value(value) => value, - _ => panic!("Not a value"), + _ => panic!("Value is not computed"), } } } diff --git a/compiler_tester/src/compilers/llvm.rs b/compiler_tester/src/compilers/llvm.rs index 1b0ad419..95b7e0b1 100644 --- a/compiler_tester/src/compilers/llvm.rs +++ b/compiler_tester/src/compilers/llvm.rs @@ -5,20 +5,18 @@ use std::collections::BTreeMap; use std::collections::HashMap; -use super::build::Build as zkEVMContractBuild; +use sha3::Digest; + use super::mode::llvm::Mode as LLVMMode; use super::mode::Mode; +use super::output::build::Build as zkEVMContractBuild; +use super::output::Output; use super::Compiler; /// /// The LLVM compiler. /// -pub struct LLVMCompiler { - /// The name-to-code source files mapping. - sources: Vec<(String, String)>, - /// The compiler debug config. - debug_config: Option, -} +pub struct LLVMCompiler; lazy_static::lazy_static! { /// @@ -33,18 +31,22 @@ lazy_static::lazy_static! { } impl LLVMCompiler { + /// + /// A shortcut constructor. + /// + pub fn new() -> Self { + Self + } + /// /// Compiles the source. /// fn compile_source( - &self, source_code: &str, name: &str, mode: &LLVMMode, + debug_config: Option, ) -> anyhow::Result { - let target_machine = - compiler_llvm_context::TargetMachine::new(&mode.llvm_optimizer_settings)?; - let llvm = inkwell::context::Context::create(); let memory_buffer = inkwell::memory_buffer::MemoryBuffer::create_from_memory_range_copy( source_code.as_bytes(), @@ -53,100 +55,60 @@ impl LLVMCompiler { let module = llvm .create_module_from_ir(memory_buffer) .map_err(|error| anyhow::anyhow!(error.to_string()))?; - - if let Some(ref debug_config) = self.debug_config { - debug_config.dump_llvm_ir_unoptimized(name, &module)?; - } - module - .verify() - .map_err(|error| anyhow::anyhow!("Unoptimized LLVM IR verification: {}", error))?; - - let optimizer = compiler_llvm_context::Optimizer::new( - target_machine, - mode.llvm_optimizer_settings.clone(), + let optimizer = compiler_llvm_context::Optimizer::new(mode.llvm_optimizer_settings.clone()); + let source_hash = sha3::Keccak256::digest(source_code.as_bytes()).into(); + + let context = compiler_llvm_context::Context::::new( + &llvm, + module, + optimizer, + None, + true, + debug_config, ); - optimizer - .run(&module) - .map_err(|error| anyhow::anyhow!(error.to_string()))?; - if let Some(ref debug_config) = self.debug_config { - debug_config.dump_llvm_ir_optimized(name, &module)?; - } - module - .verify() - .map_err(|error| anyhow::anyhow!("Optimized LLVM IR verification: {}", error))?; - - let assembly_text = match optimizer.target_machine().write_to_memory_buffer(&module) { - Ok(assembly) => String::from_utf8_lossy(assembly.as_slice()).to_string(), - Err(error) => { - anyhow::bail!("LLVM module compiling: {}", error); - } - }; - - if let Some(ref debug_config) = self.debug_config { - debug_config.dump_assembly(name, assembly_text.as_str())?; - } - - let assembly = zkevm_assembly::Assembly::try_from(assembly_text) - .map_err(|error| anyhow::anyhow!(error))?; + let build = context.build(name, Some(source_hash))?; + let assembly = + zkevm_assembly::Assembly::from_string(build.assembly_text, build.metadata_hash)?; zkEVMContractBuild::new(assembly) } } impl Compiler for LLVMCompiler { - fn new( - sources: Vec<(String, String)>, - _libraries: BTreeMap>, - debug_config: Option, - _is_system_mode: bool, - ) -> Self { - Self { - sources, - debug_config, - } - } - - fn modes() -> Vec { + fn modes(&self) -> Vec { MODES.clone() } fn compile( &self, + _test_path: String, + sources: Vec<(String, String)>, + _libraries: BTreeMap>, mode: &Mode, - _is_system_contract_mode: bool, - ) -> anyhow::Result> { + _is_system_mode: bool, + _is_system_contracts_mode: bool, + debug_config: Option, + ) -> anyhow::Result { let mode = LLVMMode::unwrap(mode); - self.sources + + let builds = sources .iter() .map(|(path, source)| { - self.compile_source(source, path, mode) + Self::compile_source(source, path, mode, debug_config.clone()) .map(|build| (path.to_owned(), build)) }) - .collect() - } + .collect::>>()?; - fn last_contract( - &self, - _mode: &Mode, - _is_system_contract_mode: bool, - ) -> anyhow::Result { - Ok(self - .sources + let last_contract = sources .last() .ok_or_else(|| anyhow::anyhow!("Sources is empty"))? .0 - .clone()) - } + .clone(); - fn has_many_contracts() -> bool { - false - } - - fn check_pragmas(&self, _mode: &Mode) -> bool { - true + Ok(Output::new(builds, None, last_contract)) } - fn check_ethereum_tests_params(_mode: &Mode, _params: &solidity_adapter::Params) -> bool { - true + fn has_many_contracts(&self) -> bool { + false } } diff --git a/compiler_tester/src/compilers/mod.rs b/compiler_tester/src/compilers/mod.rs index 5107b230..20fdd7dd 100644 --- a/compiler_tester/src/compilers/mod.rs +++ b/compiler_tester/src/compilers/mod.rs @@ -2,81 +2,47 @@ //! The contract compilers for different languages. //! -pub mod build; pub mod cache; pub mod downloader; pub mod llvm; pub mod mode; +pub mod output; pub mod solidity; pub mod vyper; pub mod yul; pub mod zkevm; use std::collections::BTreeMap; -use std::collections::HashMap; -use self::build::Build as zkEVMContractBuild; use self::mode::Mode; +use self::output::Output; /// /// The compiler trait. /// pub trait Compiler: Send + Sync + 'static { - /// - /// The constructor. - /// - fn new( - sources: Vec<(String, String)>, - libraries: BTreeMap>, - debug_config: Option, - is_system_mode: bool, - ) -> Self; - /// /// Returns supported compiler modes. /// - fn modes() -> Vec; + fn modes(&self) -> Vec; /// /// Compile all the sources. /// + #[allow(clippy::too_many_arguments)] fn compile( &self, + test_path: String, + sources: Vec<(String, String)>, + libraries: BTreeMap>, mode: &Mode, + is_system_mode: bool, is_system_contracts_mode: bool, - ) -> anyhow::Result>; - - /// - /// Returns selector by entry. - /// - fn selector( - &self, - _mode: &Mode, - _contract_path: &str, - entry: &str, - _is_system_contracts_mode: bool, - ) -> anyhow::Result { - u32::from_str_radix(entry, compiler_common::BASE_HEXADECIMAL) - .map_err(|err| anyhow::anyhow!("Invalid entry value: {}", err)) - } - - /// - /// Returns the last contract name. - /// - fn last_contract(&self, mode: &Mode, is_system_contracts_mode: bool) -> anyhow::Result; + debug_config: Option, + ) -> anyhow::Result; /// /// Returns true if the one source file can contains many contracts, false otherwise. /// - fn has_many_contracts() -> bool; - - /// - /// Checks the versions in the source code pragmas. - /// - fn check_pragmas(&self, _mode: &Mode) -> bool; - - /// - /// Checks the Ethereum tests params compatability. - /// - fn check_ethereum_tests_params(_mode: &Mode, _params: &solidity_adapter::Params) -> bool; + fn has_many_contracts(&self) -> bool; } diff --git a/compiler_tester/src/compilers/mode/llvm.rs b/compiler_tester/src/compilers/mode/llvm.rs index 9ba896cb..b1896dae 100644 --- a/compiler_tester/src/compilers/mode/llvm.rs +++ b/compiler_tester/src/compilers/mode/llvm.rs @@ -16,9 +16,6 @@ pub struct Mode { } impl Mode { - /// The language name. - pub const LANGUAGE: &'static str = "LLVM"; - /// /// A shortcut constructor. /// @@ -49,6 +46,6 @@ impl Mode { impl std::fmt::Display for Mode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:>8} {}", Self::LANGUAGE, self.llvm_optimizer_settings,) + write!(f, "{}", self.llvm_optimizer_settings,) } } diff --git a/compiler_tester/src/compilers/mode/mod.rs b/compiler_tester/src/compilers/mode/mod.rs index 36116df3..31b90ce2 100644 --- a/compiler_tester/src/compilers/mode/mod.rs +++ b/compiler_tester/src/compilers/mode/mod.rs @@ -34,6 +34,45 @@ pub enum Mode { } impl Mode { + /// + /// Checks if the mode is compatible with the filters. + /// + pub fn check_filters(&self, filters: &[String]) -> bool { + filters.is_empty() + || filters + .iter() + .any(|filter| self.normalize(filter).contains(filter)) + } + + /// + /// Checks if the mode is compatible with the extended filters. + /// The extended filter consists of 2 parts: mode substring and version range. + /// + pub fn check_extended_filters(&self, filters: &[String]) -> bool { + if filters.is_empty() { + return true; + } + for filter in filters.iter() { + let mut split = filter.split_whitespace(); + let mode_filter = split.next().unwrap_or_default(); + let normalized_mode = self.normalize(mode_filter); + if !normalized_mode.contains(mode_filter) { + continue; + } + + let version = match split.next() { + Some(version) => version, + None => return true, + }; + if let Ok(version_req) = semver::VersionReq::parse(version) { + if self.check_version(&version_req) { + return true; + } + } + } + false + } + /// /// Checks if the self is compatible with version filter. /// @@ -45,6 +84,77 @@ impl Mode { }; versions.matches(version) } + + /// + /// Checks if the mode is compatible with the source code pragmas. + /// + pub fn check_pragmas(&self, sources: &[(String, String)]) -> bool { + match self { + Mode::Solidity(mode) => mode.check_pragmas(sources), + Mode::Vyper(mode) => mode.check_pragmas(sources), + _ => true, + } + } + + /// + /// Checks if the mode is compatible with the Ethereum tests params. + /// + pub fn check_ethereum_tests_params(&self, params: &solidity_adapter::Params) -> bool { + match self { + Mode::Solidity(mode) => mode.check_ethereum_tests_params(params), + _ => true, + } + } + + /// + /// Normalizes the mode according to the filter. + /// + fn normalize(&self, filter: &str) -> String { + let mut current = self.to_string(); + if filter.contains("Y*") { + current = regex::Regex::new("Y[-+]") + .expect("Always valid") + .replace_all(current.as_str(), "Y*") + .to_string(); + } + if filter.contains("E*") { + current = regex::Regex::new("E[-+]") + .expect("Always valid") + .replace_all(current.as_str(), "E*") + .to_string(); + } + if filter.contains("y*") { + current = regex::Regex::new("y[-+]") + .expect("Always valid") + .replace_all(current.as_str(), "y*") + .to_string(); + } + if filter.contains("V*") { + current = regex::Regex::new("V[-+]") + .expect("Always valid") + .replace_all(current.as_str(), "V*") + .to_string(); + } + if filter.contains("M^") { + current = regex::Regex::new("M[3z]") + .expect("Always valid") + .replace_all(current.as_str(), "M^") + .to_string(); + } + if filter.contains("M*") { + current = regex::Regex::new("M[0123sz]") + .expect("Always valid") + .replace_all(current.as_str(), "M*") + .to_string(); + } + if filter.contains("B*") { + current = regex::Regex::new("B[0123]") + .expect("Always valid") + .replace_all(current.as_str(), "B*") + .to_string(); + } + current + } } impl From for Mode { diff --git a/compiler_tester/src/compilers/mode/solidity.rs b/compiler_tester/src/compilers/mode/solidity.rs index e2c4f5fc..085447ab 100644 --- a/compiler_tester/src/compilers/mode/solidity.rs +++ b/compiler_tester/src/compilers/mode/solidity.rs @@ -2,6 +2,8 @@ //! The compiler tester Solidity mode. //! +use itertools::Itertools; + use crate::llvm_options::LLVMOptions; use super::Mode as ModeWrapper; @@ -15,6 +17,8 @@ pub struct Mode { pub solc_version: semver::Version, /// The Solidity compiler output type. pub solc_pipeline: compiler_solidity::SolcPipeline, + /// Whether to enable the EVMLA codegen via Yul IR. + pub via_ir: bool, /// Whether to run the Solidity compiler optimizer. pub solc_optimize: bool, /// The optimizer settings. @@ -22,15 +26,13 @@ pub struct Mode { } impl Mode { - /// The language name. - pub const LANGUAGE: &'static str = "Solidity"; - /// /// A shortcut constructor. /// pub fn new( solc_version: semver::Version, solc_pipeline: compiler_solidity::SolcPipeline, + via_ir: bool, solc_optimize: bool, mut llvm_optimizer_settings: compiler_llvm_context::OptimizerSettings, ) -> Self { @@ -41,6 +43,7 @@ impl Mode { Self { solc_version, solc_pipeline, + via_ir, solc_optimize, llvm_optimizer_settings, } @@ -59,16 +62,70 @@ impl Mode { _ => panic!("Non-Solidity mode"), } } + + /// + /// Checks if the mode is compatible with the source code pragmas. + /// + pub fn check_pragmas(&self, sources: &[(String, String)]) -> bool { + sources.iter().all(|(_, source_code)| { + match source_code.lines().find_map(|line| { + let mut split = line.split_whitespace(); + if let (Some("pragma"), Some("solidity")) = (split.next(), split.next()) { + let version = split.join(",").replace(';', ""); + semver::VersionReq::parse(version.as_str()).ok() + } else { + None + } + }) { + Some(pragma_version_req) => pragma_version_req.matches(&self.solc_version), + None => true, + } + }) + } + + /// + /// Checks if the mode is compatible with the Ethereum tests params. + /// + pub fn check_ethereum_tests_params(&self, params: &solidity_adapter::Params) -> bool { + if !params.evm_version.matches_any(&[ + solidity_adapter::EVM::TangerineWhistle, + solidity_adapter::EVM::SpuriousDragon, + solidity_adapter::EVM::Byzantium, + solidity_adapter::EVM::Constantinople, + solidity_adapter::EVM::Petersburg, + solidity_adapter::EVM::Istanbul, + solidity_adapter::EVM::Berlin, + solidity_adapter::EVM::London, + solidity_adapter::EVM::Paris, + solidity_adapter::EVM::Shanghai, + ]) { + return false; + } + + match self.solc_pipeline { + compiler_solidity::SolcPipeline::Yul => { + params.compile_via_yul != solidity_adapter::CompileViaYul::False + && params.abi_encoder_v1_only != solidity_adapter::ABIEncoderV1Only::True + } + compiler_solidity::SolcPipeline::EVMLA if self.via_ir => { + params.compile_via_yul != solidity_adapter::CompileViaYul::False + && params.abi_encoder_v1_only != solidity_adapter::ABIEncoderV1Only::True + } + compiler_solidity::SolcPipeline::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, - "{:>8} {}{}{} {}", - Self::LANGUAGE, + "{}{}{} {}", match self.solc_pipeline { compiler_solidity::SolcPipeline::Yul => "Y", + compiler_solidity::SolcPipeline::EVMLA if self.via_ir => "y", compiler_solidity::SolcPipeline::EVMLA => "E", }, if self.solc_optimize { '+' } else { '-' }, diff --git a/compiler_tester/src/compilers/mode/vyper.rs b/compiler_tester/src/compilers/mode/vyper.rs index 2b79f55e..57022692 100644 --- a/compiler_tester/src/compilers/mode/vyper.rs +++ b/compiler_tester/src/compilers/mode/vyper.rs @@ -20,9 +20,6 @@ pub struct Mode { } impl Mode { - /// The language name. - pub const LANGUAGE: &'static str = "Vyper"; - /// /// A shortcut constructor. /// @@ -55,14 +52,34 @@ impl Mode { _ => panic!("Non-Vyper mode"), } } + + /// + /// Checks if the mode is compatible with the source code pragmas. + /// + pub fn check_pragmas(&self, sources: &[(String, String)]) -> bool { + sources.iter().all(|(_, source_code)| { + match source_code.lines().find_map(|line| { + let mut split = line.split_whitespace(); + if let (Some("#"), Some("@version"), Some(version)) = + (split.next(), split.next(), split.next()) + { + semver::VersionReq::parse(version).ok() + } else { + None + } + }) { + Some(pragma_version_req) => pragma_version_req.matches(&self.vyper_version), + None => true, + } + }) + } } impl std::fmt::Display for Mode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - "{:>8} V{}{} {}", - Self::LANGUAGE, + "V{}{} {}", if self.vyper_optimize { '+' } else { '-' }, self.llvm_optimizer_settings, self.vyper_version, diff --git a/compiler_tester/src/compilers/mode/yul.rs b/compiler_tester/src/compilers/mode/yul.rs index ecc8285e..5ff0fb5e 100644 --- a/compiler_tester/src/compilers/mode/yul.rs +++ b/compiler_tester/src/compilers/mode/yul.rs @@ -16,9 +16,6 @@ pub struct Mode { } impl Mode { - /// The language name. - pub const LANGUAGE: &'static str = "Yul"; - /// /// A shortcut constructor. /// @@ -49,6 +46,6 @@ impl Mode { impl std::fmt::Display for Mode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:>8} {}", Self::LANGUAGE, self.llvm_optimizer_settings,) + write!(f, "{}", self.llvm_optimizer_settings) } } diff --git a/compiler_tester/src/compilers/mode/zkevm.rs b/compiler_tester/src/compilers/mode/zkevm.rs index d0c04a9a..1773b918 100644 --- a/compiler_tester/src/compilers/mode/zkevm.rs +++ b/compiler_tester/src/compilers/mode/zkevm.rs @@ -8,13 +8,8 @@ #[derive(Debug, Default, Clone)] pub struct Mode {} -impl Mode { - /// The language name. - pub const LANGUAGE: &'static str = "zkEVM"; -} - impl std::fmt::Display for Mode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:>8}", "zkEVM") + write!(f, "") } } diff --git a/compiler_tester/src/compilers/build.rs b/compiler_tester/src/compilers/output/build.rs similarity index 100% rename from compiler_tester/src/compilers/build.rs rename to compiler_tester/src/compilers/output/build.rs diff --git a/compiler_tester/src/compilers/output/mod.rs b/compiler_tester/src/compilers/output/mod.rs new file mode 100644 index 00000000..f7c05b3d --- /dev/null +++ b/compiler_tester/src/compilers/output/mod.rs @@ -0,0 +1,40 @@ +//! +//! The compiler output. +//! + +pub mod build; + +use std::collections::BTreeMap; +use std::collections::HashMap; + +use self::build::Build; + +/// +/// The compiler output. +/// +#[derive(Debug, Clone)] +pub struct Output { + /// The contract builds. + pub builds: HashMap, + /// The contracts method identifiers. + pub method_identifiers: Option>>, + /// The last contract name. + pub last_contract: String, +} + +impl Output { + /// + /// A shortcut constructor. + /// + pub fn new( + builds: HashMap, + method_identifiers: Option>>, + last_contract: String, + ) -> Self { + Self { + builds, + method_identifiers, + last_contract, + } + } +} diff --git a/compiler_tester/src/compilers/solidity/cached_project.rs b/compiler_tester/src/compilers/solidity/cached_project.rs deleted file mode 100644 index c571ac37..00000000 --- a/compiler_tester/src/compilers/solidity/cached_project.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! -//! The Solidity compiler cached projects. -//! - -use std::collections::BTreeMap; - -/// -/// The Solidity compiler cached projects. -/// -pub struct CachedProject { - /// The Solidity project. - pub project: compiler_solidity::Project, - /// The method identifiers. - pub method_identifiers: BTreeMap>, - /// The last contract name. - pub last_contract: String, -} - -impl CachedProject { - /// - /// A shortcut constructor. - /// - pub fn new( - project: compiler_solidity::Project, - method_identifiers: BTreeMap>, - last_contract: String, - ) -> Self { - Self { - project, - method_identifiers, - last_contract, - } - } -} diff --git a/compiler_tester/src/compilers/solidity/mod.rs b/compiler_tester/src/compilers/solidity/mod.rs index 1c85dc75..1cc15139 100644 --- a/compiler_tester/src/compilers/solidity/mod.rs +++ b/compiler_tester/src/compilers/solidity/mod.rs @@ -2,8 +2,7 @@ //! The Solidity compiler wrapper. //! -pub mod cached_project; -pub mod subprocess_mode; +pub mod solc_cache_key; use std::collections::BTreeMap; use std::collections::HashMap; @@ -11,29 +10,21 @@ use std::path::Path; use itertools::Itertools; -use super::build::Build as zkEVMContractBuild; use super::cache::Cache; use super::mode::solidity::Mode as SolidityMode; use super::mode::Mode; +use super::output::build::Build as zkEVMContractBuild; +use super::output::Output; use super::Compiler; -use self::cached_project::CachedProject; -use self::subprocess_mode::SubprocessMode; +use self::solc_cache_key::SolcCacheKey; /// /// The Solidity compiler wrapper. /// pub struct SolidityCompiler { - /// The name-to-code source files mapping. - sources: Vec<(String, String)>, /// The `solc` process output cache. - cache: Cache>, - /// The libraries addresses. - libraries: BTreeMap>, - /// The debug config. - debug_config: Option, - /// The system mode flag. - is_system_mode: bool, + cache: Cache, } lazy_static::lazy_static! { @@ -44,25 +35,28 @@ lazy_static::lazy_static! { /// static ref MODES: Vec = { let mut solc_pipeline_versions = Vec::new(); - for pipeline in [ - compiler_solidity::SolcPipeline::Yul, - compiler_solidity::SolcPipeline::EVMLA, + for (pipeline, optimize, via_ir) in [ + (compiler_solidity::SolcPipeline::Yul, false, true), + (compiler_solidity::SolcPipeline::Yul, true, true), + (compiler_solidity::SolcPipeline::EVMLA, false, false), + (compiler_solidity::SolcPipeline::EVMLA, true, false), + (compiler_solidity::SolcPipeline::EVMLA, true, true), ] { - for version in SolidityCompiler::all_versions(pipeline).expect("`solc` versions analysis error") { - solc_pipeline_versions.push((pipeline, version)) + for version in SolidityCompiler::all_versions(pipeline, via_ir).expect("`solc` versions analysis error") { + solc_pipeline_versions.push((pipeline, optimize, via_ir, version)); } } compiler_llvm_context::OptimizerSettings::combinations() .into_iter() .cartesian_product(solc_pipeline_versions) - .cartesian_product(vec![false, true]) .map( - |((llvm_optimizer_settings, (solc_pipeline, solc_version)), solc_optimize)| { + |(llvm_optimizer_settings, (pipeline, optimize, via_ir, version))| { SolidityMode::new( - solc_version, - solc_pipeline, - solc_optimize, + version, + pipeline, + via_ir, + optimize, llvm_optimizer_settings, ) .into() @@ -79,25 +73,35 @@ impl SolidityCompiler { /// The solc allow paths argument value. const SOLC_ALLOW_PATHS: &'static str = "tests"; + /// + /// A shortcut constructor. + /// + pub fn new() -> Self { + Self { + cache: Cache::new(), + } + } + /// /// Returns the `solc` compiler path by version. /// - fn get_solc_by_version(version: &semver::Version) -> compiler_solidity::SolcCompiler { + pub fn get_solc_by_version(version: &semver::Version) -> compiler_solidity::SolcCompiler { compiler_solidity::SolcCompiler::new(format!("{}/solc-{}", Self::DIRECTORY, version)) } /// /// Returns the system contract `solc` compiler path. /// - fn get_system_contract_solc() -> compiler_solidity::SolcCompiler { + pub fn get_system_contract_solc() -> compiler_solidity::SolcCompiler { compiler_solidity::SolcCompiler::new(format!("{}/solc-system-contracts", Self::DIRECTORY)) } /// /// Returns the compiler versions downloaded for the specified compilation pipeline. /// - fn all_versions( + pub fn all_versions( pipeline: compiler_solidity::SolcPipeline, + via_ir: bool, ) -> anyhow::Result> { let mut versions = Vec::new(); for entry in std::fs::read_dir("./solc-bin/")? { @@ -129,60 +133,50 @@ impl SolidityCompiler { if compiler_solidity::SolcPipeline::Yul == pipeline && version.minor < 8 { continue; } + if compiler_solidity::SolcPipeline::EVMLA == pipeline + && via_ir + && version < compiler_solidity::SolcCompiler::FIRST_VIA_IR_VERSION + { + continue; + } + versions.push(version); } Ok(versions) } /// - /// Processes a project and stores its representation in the cache. + /// Runs the solc subprocess and returns the output. /// - fn compute_cache(&self, subprocess_mode: &SubprocessMode, is_system_contracts_mode: bool) { - if !self.cache.contains(subprocess_mode) { - if let Some(waiter) = self.cache.start(subprocess_mode.clone()) { - self.cache.finish( - subprocess_mode.clone(), - self.get_cached_project(subprocess_mode, is_system_contracts_mode), - waiter, - ); - }; - } - } - - /// - /// Processes a project and returns its representation for the cache. - /// - fn get_cached_project( - &self, - subprocess_mode: &SubprocessMode, + fn run_solc( + sources: &[(String, String)], + libraries: &BTreeMap>, + mode: &SolidityMode, is_system_contracts_mode: bool, - ) -> anyhow::Result { - let solc = if is_system_contracts_mode { + ) -> anyhow::Result { + let mut solc = if is_system_contracts_mode { Self::get_system_contract_solc() } else { - Self::get_solc_by_version(&subprocess_mode.version) + Self::get_solc_by_version(&mode.solc_version) }; let output_selection = compiler_solidity::SolcStandardJsonInputSettingsSelection::new_required( - subprocess_mode.pipeline, + mode.solc_pipeline, ); let optimizer = compiler_solidity::SolcStandardJsonInputSettingsOptimizer::new( - subprocess_mode.optimize, + mode.solc_optimize, None, ); - let via_ir = subprocess_mode.version >= compiler_solidity::SolcCompiler::FIRST_YUL_VERSION - && subprocess_mode.pipeline == compiler_solidity::SolcPipeline::Yul; - let solc_input = compiler_solidity::SolcStandardJsonInput::try_from_sources( - self.sources.clone().into_iter().collect(), - self.libraries.clone(), + sources.iter().cloned().collect(), + libraries.clone(), output_selection, optimizer, None, - via_ir, + mode.via_ir, ) .map_err(|error| anyhow::anyhow!("Failed to build solc input standard json: {}", error))?; @@ -192,55 +186,110 @@ impl SolidityCompiler { .to_string_lossy() .to_string(); - let mut solc_output = solc.standard_json( + solc.standard_json( solc_input, - subprocess_mode.pipeline, + mode.solc_pipeline, None, vec![], Some(allow_paths), - )?; - - 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()); - } - } + /// + /// Computes or loads from the cache solc output. Updates the cache if needed. + /// + fn run_solc_cached( + &self, + test_path: String, + sources: &[(String, String)], + libraries: &BTreeMap>, + mode: &SolidityMode, + is_system_contracts_mode: bool, + ) -> anyhow::Result { + let cache_key = SolcCacheKey::new( + test_path, + mode.solc_version.clone(), + mode.solc_pipeline, + mode.via_ir, + mode.solc_optimize, + ); - if has_errors { - anyhow::bail!("Errors found: {:?}", error_messages); - } + if !self.cache.contains(&cache_key) { + self.cache.compute(cache_key.clone(), || { + Self::run_solc(sources, libraries, mode, is_system_contracts_mode) + }); } - let last_contract = solc_output - .sources - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Sources not found in the output")) - .and_then(|sources| { - for (path, _source) in self.sources.iter().rev() { - match sources - .get(path) - .ok_or_else(|| anyhow::anyhow!("Last source not found in the output"))? - .last_contract_name() - { - Ok(name) => return Ok(format!("{path}:{name}")), - Err(_error) => continue, - } - } - anyhow::bail!("Last contract not found in all contracts") + self.cache.get_cloned(&cache_key) + } + + /// + /// Compile the contracts for a given solc output. + /// + fn compile( + mut solc_output: compiler_solidity::SolcStandardJsonOutput, + sources: Vec<(String, String)>, + libraries: BTreeMap>, + mode: &SolidityMode, + is_system_mode: bool, + debug_config: Option, + ) -> anyhow::Result> { + let project = solc_output.try_to_project( + sources.into_iter().collect::>(), + libraries, + mode.solc_pipeline, + &mode.solc_version, + debug_config.as_ref(), + )?; + + let build = project.compile( + mode.llvm_optimizer_settings.to_owned(), + is_system_mode, + false, + zkevm_assembly::get_encoding_mode(), + debug_config, + )?; + build.write_to_standard_json( + &mut solc_output, + &compiler_solidity::SolcVersion::new( + mode.solc_version.to_string(), + mode.solc_version.to_owned(), + None, + ), + &semver::Version::new(0, 0, 0), + )?; // TODO: set versions + Ok(solc_output + .contracts + .expect("Always exists") + .into_iter() + .flat_map(|(file_name, file)| { + file.into_iter() + .filter_map(|(contract_name, contract)| { + let name = format!("{}:{}", file_name, contract_name); + let evm = contract.evm.expect("Always exists"); + let assembly = + zkevm_assembly::Assembly::from_string(evm.assembly_text?, None) + .expect("Always valid"); + Some(( + name, + zkEVMContractBuild::new_with_hash( + assembly, + contract.hash.expect("Always exists"), + ) + .expect("Always valid"), + )) + }) + .collect::>() }) - .map_err(|error| { - anyhow::anyhow!( - "Failed to get the last contract: {}, output errors: {:?}", - error, - solc_output.errors - ) - })?; + .collect()) + } + /// + /// Get the method identifiers from the solc output. + /// + fn get_method_identifiers( + solc_output: &compiler_solidity::SolcStandardJsonOutput, + ) -> anyhow::Result>> { let files = solc_output .contracts .as_ref() @@ -265,234 +314,118 @@ impl SolidityCompiler { })? .iter() { - contract_identifiers.insert(entry.clone(), selector.clone()); + let selector = u32::from_str_radix(selector, compiler_common::BASE_HEXADECIMAL) + .map_err(|error| { + anyhow::anyhow!( + "Invalid selector from the Solidity compiler: {}", + error + ) + })?; + contract_identifiers.insert(entry.clone(), selector); } method_identifiers.insert(format!("{path}:{name}"), contract_identifiers); } } + Ok(method_identifiers) + } - let project = solc_output.try_to_project( - self.sources - .clone() - .into_iter() - .collect::>(), - self.libraries.clone(), - subprocess_mode.pipeline, - &subprocess_mode.version, - self.debug_config.as_ref(), - )?; - - Ok(CachedProject::new( - project, - method_identifiers, - last_contract, - )) + /// + /// Get the last contract from the solc output. + /// + fn get_last_contract( + solc_output: &compiler_solidity::SolcStandardJsonOutput, + sources: &[(String, String)], + ) -> anyhow::Result { + solc_output + .sources + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Sources not found in the output")) + .and_then(|output_sources| { + for (path, _source) in sources.iter().rev() { + match output_sources + .get(path) + .ok_or_else(|| anyhow::anyhow!("Last source not found in the output"))? + .last_contract_name() + { + Ok(name) => return Ok(format!("{path}:{name}")), + Err(_error) => continue, + } + } + anyhow::bail!("Last contract not found in all contracts") + }) + .map_err(|error| { + anyhow::anyhow!( + "Failed to get the last contract: {}, output errors: {:?}", + error, + solc_output.errors + ) + }) } } impl Compiler for SolidityCompiler { - fn new( - sources: Vec<(String, String)>, - libraries: BTreeMap>, - debug_config: Option, - is_system_mode: bool, - ) -> Self { - Self { - sources, - libraries, - cache: Cache::new(), - debug_config, - is_system_mode, - } - } - - fn modes() -> Vec { + fn modes(&self) -> Vec { MODES.clone() } fn compile( &self, + test_path: String, + sources: Vec<(String, String)>, + libraries: BTreeMap>, mode: &Mode, + is_system_mode: bool, is_system_contracts_mode: bool, - ) -> anyhow::Result> { - let mode = SolidityMode::unwrap(mode); - - let subprocess_mode = SubprocessMode::new( - mode.solc_version.clone(), - mode.solc_pipeline, - mode.solc_optimize, - ); - - self.compute_cache(&subprocess_mode, is_system_contracts_mode); - - let project = { - self.cache.wait(&subprocess_mode); - let lock = self.cache.read(); - let cached_project = lock - .get(&subprocess_mode) - .expect("Always valid") - .unwrap_value(); - cached_project - .as_ref() - .map_err(|error| anyhow::anyhow!(error.to_string()))? - .project - .clone() - }; - - let target_machine = - compiler_llvm_context::TargetMachine::new(&mode.llvm_optimizer_settings)?; - - let builds = project - .compile_all( - target_machine, - mode.llvm_optimizer_settings.clone(), - self.is_system_mode, - true, - self.debug_config.clone(), - )? - .contracts - .into_iter() - .map(|(name, contract)| { - Ok(( - name, - zkEVMContractBuild::new_with_hash( - contract.build.assembly, - contract.build.bytecode_hash, - )?, - )) - }) - .collect::>>()?; - - Ok(builds) - } - - fn selector( - &self, - mode: &Mode, - contract_path: &str, - entry: &str, - is_system_contracts_mode: bool, - ) -> anyhow::Result { + debug_config: Option, + ) -> anyhow::Result { let mode = SolidityMode::unwrap(mode); - let subprocess_mode = SubprocessMode::new( - mode.solc_version.clone(), - mode.solc_pipeline, - mode.solc_optimize, - ); - - self.compute_cache(&subprocess_mode, is_system_contracts_mode); + let solc_output = self + .run_solc_cached( + test_path, + &sources, + &libraries, + mode, + is_system_contracts_mode, + ) + .map_err(|error| anyhow::anyhow!("Failed to run solc: {}", error))?; - self.cache.wait(&subprocess_mode); - let lock = self.cache.read(); - let cached_project = lock - .get(&subprocess_mode) - .expect("Always valid") - .unwrap_value(); + if let Some(errors) = solc_output.errors.as_deref() { + let mut has_errors = false; + let mut error_messages = Vec::with_capacity(errors.len()); - let method_identifiers = &cached_project - .as_ref() - .map_err(|error| anyhow::anyhow!(error.to_string()))? - .method_identifiers; - - let contract_identifiers = method_identifiers - .get(contract_path) - .ok_or_else(|| anyhow::anyhow!("Contract not found"))?; - - contract_identifiers - .iter() - .find_map(|(name, selector)| { - if name.starts_with(entry) { - Some( - u32::from_str_radix(selector, compiler_common::BASE_HEXADECIMAL).map_err( - |error| { - anyhow::anyhow!( - "Invalid selector from the Solidity compiler: {}", - error - ) - }, - ), - ) - } else { - None + for error in errors.iter() { + if error.severity.as_str() == "error" { + has_errors = true; + error_messages.push(error.formatted_message.to_owned()); } - }) - .ok_or_else(|| anyhow::anyhow!("Hash of the method `{}` not found", entry))? - } + } - fn last_contract(&self, mode: &Mode, is_system_contracts_mode: bool) -> anyhow::Result { - let mode = SolidityMode::unwrap(mode); + if has_errors { + anyhow::bail!("Errors found: {:?}", error_messages); + } + } - let subprocess_mode = SubprocessMode::new( - mode.solc_version.clone(), - mode.solc_pipeline, - mode.solc_optimize, - ); + let method_identifiers = Self::get_method_identifiers(&solc_output) + .map_err(|error| anyhow::anyhow!("Failed to get method identifiers: {}", error))?; - self.compute_cache(&subprocess_mode, is_system_contracts_mode); + let last_contract = Self::get_last_contract(&solc_output, &sources) + .map_err(|error| anyhow::anyhow!("Failed to get last contract: {}", error))?; - self.cache.wait(&subprocess_mode); - let lock = self.cache.read(); - let cached_project = lock - .get(&subprocess_mode) - .expect("Always valid") - .unwrap_value(); + let builds = Self::compile( + solc_output, + sources, + libraries, + mode, + is_system_mode, + debug_config, + ) + .map_err(|error| anyhow::anyhow!("Failed to compile the contracts: {}", error))?; - cached_project - .as_ref() - .map_err(|error| anyhow::anyhow!(error.to_string())) - .map(|cached_project| cached_project.last_contract.clone()) + Ok(Output::new(builds, Some(method_identifiers), last_contract)) } - fn has_many_contracts() -> bool { + fn has_many_contracts(&self) -> bool { true } - - fn check_pragmas(&self, mode: &Mode) -> bool { - let mode = SolidityMode::unwrap(mode); - - self.sources.iter().all(|(_, source_code)| { - match source_code.lines().find_map(|line| { - let mut split = line.split_whitespace(); - if let (Some("pragma"), Some("solidity")) = (split.next(), split.next()) { - let version = split.join(",").replace(';', ""); - semver::VersionReq::parse(version.as_str()).ok() - } else { - None - } - }) { - Some(pragma_version_req) => pragma_version_req.matches(&mode.solc_version), - None => true, - } - }) - } - - fn check_ethereum_tests_params(mode: &Mode, params: &solidity_adapter::Params) -> bool { - if !params.evm_version.matches_any(&[ - solidity_adapter::EVM::TangerineWhistle, - solidity_adapter::EVM::SpuriousDragon, - solidity_adapter::EVM::Byzantium, - solidity_adapter::EVM::Constantinople, - solidity_adapter::EVM::Petersburg, - solidity_adapter::EVM::Istanbul, - solidity_adapter::EVM::Berlin, - solidity_adapter::EVM::London, - solidity_adapter::EVM::Paris, - solidity_adapter::EVM::Shanghai, - ]) { - return false; - } - - let mode = SolidityMode::unwrap(mode); - - match mode.solc_pipeline { - compiler_solidity::SolcPipeline::Yul => { - params.compile_via_yul != solidity_adapter::CompileViaYul::False - && params.abi_encoder_v1_only != solidity_adapter::ABIEncoderV1Only::True - } - compiler_solidity::SolcPipeline::EVMLA => { - params.compile_via_yul != solidity_adapter::CompileViaYul::True - } - } - } } diff --git a/compiler_tester/src/compilers/solidity/solc_cache_key.rs b/compiler_tester/src/compilers/solidity/solc_cache_key.rs new file mode 100644 index 00000000..4860d539 --- /dev/null +++ b/compiler_tester/src/compilers/solidity/solc_cache_key.rs @@ -0,0 +1,41 @@ +//! +//! The Solidity subprocess compiler cache key. +//! + +/// +/// The Solidity subprocess compiler cache key. +/// +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct SolcCacheKey { + /// The test path. + pub test_path: String, + /// The Solidity compiler version. + pub version: semver::Version, + /// The Solidity compiler output type. + pub pipeline: compiler_solidity::SolcPipeline, + /// Whether to enable the EVMLA codegen via Yul IR. + pub via_ir: bool, + /// Whether to run the Solidity compiler optimizer. + pub optimize: bool, +} + +impl SolcCacheKey { + /// + /// A shortcut constructor. + /// + pub fn new( + test_path: String, + version: semver::Version, + pipeline: compiler_solidity::SolcPipeline, + via_ir: bool, + optimize: bool, + ) -> Self { + Self { + test_path, + version, + pipeline, + via_ir, + optimize, + } + } +} diff --git a/compiler_tester/src/compilers/solidity/subprocess_mode.rs b/compiler_tester/src/compilers/solidity/subprocess_mode.rs deleted file mode 100644 index 577f45b9..00000000 --- a/compiler_tester/src/compilers/solidity/subprocess_mode.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! -//! The Solidity subprocess compiler mode. -//! - -/// -/// The Solidity subprocess compiler mode. -/// -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct SubprocessMode { - /// The Solidity compiler version. - pub version: semver::Version, - /// The Solidity compiler output type. - pub pipeline: compiler_solidity::SolcPipeline, - /// Whether to run the Solidity compiler optimizer. - pub optimize: bool, -} - -impl SubprocessMode { - /// - /// A shortcut constructor. - /// - pub fn new( - solc_version: semver::Version, - solc_pipeline: compiler_solidity::SolcPipeline, - solc_optimize: bool, - ) -> Self { - Self { - version: solc_version, - pipeline: solc_pipeline, - optimize: solc_optimize, - } - } -} diff --git a/compiler_tester/src/compilers/vyper/cached_project.rs b/compiler_tester/src/compilers/vyper/cached_project.rs deleted file mode 100644 index cedc6fb6..00000000 --- a/compiler_tester/src/compilers/vyper/cached_project.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! -//! The Vyper compiler cached projects. -//! - -/// -/// The Vyper compiler cached projects. -/// -pub struct CachedProject { - /// The Vyper project. - pub project: compiler_vyper::Project, -} - -impl CachedProject { - /// - /// A shortcut constructor. - /// - pub fn new(project: compiler_vyper::Project) -> Self { - Self { project } - } -} diff --git a/compiler_tester/src/compilers/vyper/mod.rs b/compiler_tester/src/compilers/vyper/mod.rs index f365c2cf..4b998672 100644 --- a/compiler_tester/src/compilers/vyper/mod.rs +++ b/compiler_tester/src/compilers/vyper/mod.rs @@ -2,8 +2,7 @@ //! The Vyper compiler wrapper. //! -pub mod cached_project; -pub mod subprocess_mode; +pub mod vyper_cache_key; use std::collections::BTreeMap; use std::collections::HashMap; @@ -12,27 +11,22 @@ use std::path::PathBuf; use std::str::FromStr; use itertools::Itertools; -use sha3::Digest; -use super::build::Build as zkEVMContractBuild; use super::cache::Cache; use super::mode::vyper::Mode as VyperMode; use super::mode::Mode; +use super::output::build::Build as zkEVMContractBuild; +use super::output::Output; use super::Compiler; -use self::cached_project::CachedProject; -use self::subprocess_mode::SubprocessMode; +use self::vyper_cache_key::VyperCacheKey; /// /// The Vyper compiler wrapper. /// pub struct VyperCompiler { - /// The name-to-code source files mapping. - sources: Vec<(String, String)>, /// The vyper process output cache. - cache: Cache>, - /// The compiler debug config. - debug_config: Option, + cache: Cache, } lazy_static::lazy_static! { @@ -59,6 +53,15 @@ impl VyperCompiler { /// The compiler binaries directory. pub const DIRECTORY: &'static str = "vyper-bin/"; + /// + /// A shortcut constructor. + /// + pub fn new() -> Self { + Self { + cache: Cache::new(), + } + } + /// /// Returns the Vyper compiler instance by version. /// @@ -103,48 +106,112 @@ impl VyperCompiler { } /// - /// Starts building the project into cache if it has not been built yet. - /// - fn start_building(&self, mode: &SubprocessMode) { - if !self.cache.contains(mode) { - if let Some(waiter) = self.cache.start(mode.clone()) { - self.cache - .finish(mode.clone(), self.get_build(mode), waiter); - }; - } - } - - /// - /// Gets the cached project data from the cache. + /// Runs the vyper subprocess and returns the project. /// - fn get_build(&self, mode: &SubprocessMode) -> anyhow::Result { - let vyper = Self::get_vyper_by_version(&mode.version); + fn run_vyper( + sources: &[(String, String)], + mode: &VyperMode, + ) -> anyhow::Result { + let vyper = Self::get_vyper_by_version(&mode.vyper_version); - let paths = self - .sources + let paths = sources .iter() .map(|(path, _)| { PathBuf::from_str(path).map_err(|error| anyhow::anyhow!("Invalid path: {}", error)) }) .collect::>>()?; - let project = vyper.batch(&mode.version, paths, mode.optimize)?; + vyper.batch(&mode.vyper_version, paths, mode.vyper_optimize) + } + + /// + /// Computes or loads from the cache vyper project. Updates the cache if needed. + /// + fn run_vyper_cached( + &self, + test_path: String, + sources: &[(String, String)], + mode: &VyperMode, + ) -> anyhow::Result { + let cache_key = + VyperCacheKey::new(test_path, mode.vyper_version.clone(), mode.vyper_optimize); + + if !self.cache.contains(&cache_key) { + self.cache + .compute(cache_key.clone(), || Self::run_vyper(sources, mode)); + } + + self.cache.get_cloned(&cache_key) + } + + /// + /// Compile the vyper project. + /// + fn compile( + project: compiler_vyper::Project, + mode: &VyperMode, + debug_config: Option, + ) -> anyhow::Result> { + let build = project.compile( + mode.llvm_optimizer_settings.to_owned(), + true, + zkevm_assembly::get_encoding_mode(), + debug_config, + )?; + build + .contracts + .into_iter() + .map(|(path, contract)| { + let assembly = zkevm_assembly::Assembly::from_string( + contract.build.assembly_text, + contract.build.metadata_hash, + ) + .expect("Always valid"); + Ok(( + path, + zkEVMContractBuild::new_with_hash(assembly, contract.build.bytecode_hash)?, + )) + }) + .collect() + } - Ok(CachedProject::new(project)) + /// + /// Get the method identifiers from the solc output. + /// + fn get_method_identifiers( + project: &compiler_vyper::Project, + ) -> anyhow::Result>> { + let mut method_identifiers = BTreeMap::new(); + for (path, contract) in project.contracts.iter() { + let contract_abi = match contract { + compiler_vyper::Contract::Vyper(inner) => &inner.abi, + compiler_vyper::Contract::LLVMIR(_inner) => panic!("Only used in the Vyper CLI"), + compiler_vyper::Contract::ZKASM(_inner) => panic!("Only used in the Vyper CLI"), + }; + let mut contract_identifiers = BTreeMap::new(); + for (entry, hash) in contract_abi.iter() { + let selector = u32::from_str_radix(&hash[2..], compiler_common::BASE_HEXADECIMAL) + .map_err(|error| { + anyhow::anyhow!("Invalid selector from the Vyper compiler: {}", error) + })?; + contract_identifiers.insert(entry.clone(), selector); + } + method_identifiers.insert(path.clone(), contract_identifiers); + } + Ok(method_identifiers) } /// /// Prints LLL IR if the flag is set. /// fn dump_lll( - &self, + sources: &[(String, String)], debug_config: &compiler_llvm_context::DebugConfig, mode: &VyperMode, ) -> anyhow::Result<()> { let vyper = Self::get_vyper_by_version(&mode.vyper_version); - let lll = self - .sources + let lll = sources .iter() .map(|(path_str, _)| { let path = Path::new(path_str.as_str()); @@ -163,200 +230,46 @@ impl VyperCompiler { } impl Compiler for VyperCompiler { - fn new( - sources: Vec<(String, String)>, - _libraries: BTreeMap>, - debug_config: Option, - _is_system_mode: bool, - ) -> Self { - Self { - sources, - cache: Cache::new(), - debug_config, - } - } - - fn modes() -> Vec { + fn modes(&self) -> Vec { MODES.clone() } fn compile( &self, + test_path: String, + sources: Vec<(String, String)>, + _libraries: BTreeMap>, mode: &Mode, - _is_system_contract_mode: bool, - ) -> anyhow::Result> { + _is_system_mode: bool, + _is_system_contracts_mode: bool, + debug_config: Option, + ) -> anyhow::Result { let mode = VyperMode::unwrap(mode); - if let Some(ref debug_config) = self.debug_config { - self.dump_lll(debug_config, mode)?; + if let Some(ref debug_config) = debug_config { + Self::dump_lll(&sources, debug_config, mode)?; } - let subprocess_mode = SubprocessMode::new(mode.vyper_version.clone(), mode.vyper_optimize); - - self.start_building(&subprocess_mode); - - let cached_project = { - self.cache.wait(&subprocess_mode); - let lock = self.cache.read(); - let cached_project = lock - .get(&subprocess_mode) - .expect("Always valid") - .unwrap_value(); - cached_project - .as_ref() - .map_err(|error| anyhow::anyhow!(error.to_string()))? - .project - .clone() - }; - - let target_machine = - compiler_llvm_context::TargetMachine::new(&mode.llvm_optimizer_settings)?; - let build = cached_project.compile( - target_machine, - mode.llvm_optimizer_settings.clone(), - true, - self.debug_config.clone(), - )?; + let project = self + .run_vyper_cached(test_path, &sources, mode) + .map_err(|error| anyhow::anyhow!("Failed to get vyper project: {}", error))?; - let mut forwarder_needed = false; - let mut builds = build - .contracts - .into_iter() - .map(|(path, contract)| { - if contract - .build - .factory_dependencies - .contains_key(compiler_vyper::FORWARDER_CONTRACT_HASH.as_str()) - { - forwarder_needed = true; - } - Ok(( - path, - zkEVMContractBuild::new_with_hash( - contract.build.assembly, - contract.build.bytecode_hash, - )?, - )) - }) - .collect::>>()?; - - if forwarder_needed { - builds.insert( - compiler_vyper::FORWARDER_CONTRACT_NAME.to_owned(), - zkEVMContractBuild::new_with_hash( - zkevm_assembly::Assembly::from_string( - compiler_vyper::FORWARDER_CONTRACT_ASSEMBLY.to_owned(), - Some( - sha3::Keccak256::digest( - compiler_vyper::FORWARDER_CONTRACT_ASSEMBLY.as_bytes(), - ) - .into(), - ), - ) - .map_err(|error| anyhow::anyhow!("Vyper forwarder assembly: {}", error))?, - compiler_vyper::FORWARDER_CONTRACT_HASH.clone(), - ) - .map_err(|error| anyhow::anyhow!("Vyper forwarder: {}", error))?, - ); - } - - Ok(builds) - } - - fn selector( - &self, - mode: &Mode, - contract_path: &str, - entry: &str, - _is_system_contract_mode: bool, - ) -> anyhow::Result { - let mode = VyperMode::unwrap(mode); - - let subprocess_mode = SubprocessMode::new(mode.vyper_version.clone(), mode.vyper_optimize); - - self.start_building(&subprocess_mode); - - self.cache.wait(&subprocess_mode); - let lock = self.cache.read(); - let cached_project = lock - .get(&subprocess_mode) - .expect("Always valid") - .unwrap_value(); - - let cached_project = cached_project - .as_ref() - .map_err(|error| anyhow::anyhow!(error.to_string()))?; - - let contract_identifiers = match cached_project - .project - .contracts - .get(contract_path) - .ok_or_else(|| anyhow::anyhow!("Contract {} not found", contract_path))? - { - compiler_vyper::Contract::Vyper(inner) => &inner.abi, - compiler_vyper::Contract::LLVMIR(_inner) => panic!("Only used in the Vyper CLI"), - compiler_vyper::Contract::ZKASM(_inner) => panic!("Only used in the Vyper CLI"), - }; - - contract_identifiers - .iter() - .find_map(|(name, hash)| { - if name.starts_with(entry) { - Some( - u32::from_str_radix(&hash[2..], compiler_common::BASE_HEXADECIMAL).map_err( - |error| { - anyhow::anyhow!( - "Invalid selector from the Vyper compiler: {}", - error - ) - }, - ), - ) - } else { - None - } - }) - .ok_or_else(|| anyhow::anyhow!("Hash of the method `{}` not found", entry))? - } + let method_identifiers = Self::get_method_identifiers(&project) + .map_err(|error| anyhow::anyhow!("Failed to get method identifiers: {}", error))?; - fn last_contract( - &self, - _mode: &Mode, - _is_system_contract_mode: bool, - ) -> anyhow::Result { - Ok(self - .sources + let last_contract = sources .last() .ok_or_else(|| anyhow::anyhow!("Sources is empty"))? .0 - .clone()) - } + .clone(); - fn has_many_contracts() -> bool { - false - } - - fn check_pragmas(&self, mode: &Mode) -> bool { - let mode = VyperMode::unwrap(mode); + let builds = Self::compile(project, mode, debug_config) + .map_err(|error| anyhow::anyhow!("Failed to compile the contracts: {}", error))?; - self.sources.iter().all(|(_, source_code)| { - match source_code.lines().find_map(|line| { - let mut split = line.split_whitespace(); - if let (Some("#"), Some("@version"), Some(version)) = - (split.next(), split.next(), split.next()) - { - semver::VersionReq::parse(version).ok() - } else { - None - } - }) { - Some(pragma_version_req) => pragma_version_req.matches(&mode.vyper_version), - None => true, - } - }) + Ok(Output::new(builds, Some(method_identifiers), last_contract)) } - fn check_ethereum_tests_params(_mode: &Mode, _params: &solidity_adapter::Params) -> bool { - true + fn has_many_contracts(&self) -> bool { + false } } diff --git a/compiler_tester/src/compilers/vyper/subprocess_mode.rs b/compiler_tester/src/compilers/vyper/subprocess_mode.rs deleted file mode 100644 index 189ee3e7..00000000 --- a/compiler_tester/src/compilers/vyper/subprocess_mode.rs +++ /dev/null @@ -1,23 +0,0 @@ -//! -//! The Vyper subprocess compiler mode. -//! - -/// -/// The Vyper subprocess compiler mode. -/// -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct SubprocessMode { - /// The Vyper compiler version. - pub version: semver::Version, - /// Whether to run the Vyper compiler optimizer. - pub optimize: bool, -} - -impl SubprocessMode { - /// - /// A shortcut constructor. - /// - pub fn new(version: semver::Version, optimize: bool) -> Self { - Self { version, optimize } - } -} diff --git a/compiler_tester/src/compilers/vyper/vyper_cache_key.rs b/compiler_tester/src/compilers/vyper/vyper_cache_key.rs new file mode 100644 index 00000000..306139dd --- /dev/null +++ b/compiler_tester/src/compilers/vyper/vyper_cache_key.rs @@ -0,0 +1,29 @@ +//! +//! The Vyper subprocess compiler cache key. +//! + +/// +/// The Vyper subprocess compiler cache key. +/// +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct VyperCacheKey { + /// The test path. + pub test_path: String, + /// The Vyper compiler version. + pub version: semver::Version, + /// Whether to run the Vyper compiler optimizer. + pub optimize: bool, +} + +impl VyperCacheKey { + /// + /// A shortcut constructor. + /// + pub fn new(test_path: String, version: semver::Version, optimize: bool) -> Self { + Self { + test_path, + version, + optimize, + } + } +} diff --git a/compiler_tester/src/compilers/yul.rs b/compiler_tester/src/compilers/yul.rs index 80630018..108b5a25 100644 --- a/compiler_tester/src/compilers/yul.rs +++ b/compiler_tester/src/compilers/yul.rs @@ -4,23 +4,19 @@ use std::collections::BTreeMap; use std::collections::HashMap; +use std::path::PathBuf; -use super::build::Build as zkEVMContractBuild; use super::mode::yul::Mode as YulMode; use super::mode::Mode; +use super::output::build::Build as zkEVMContractBuild; +use super::output::Output; +use super::solidity::SolidityCompiler; use super::Compiler; /// /// The Yul compiler. /// -pub struct YulCompiler { - /// The name-to-code source files mapping. - sources: Vec<(String, String)>, - /// The compiler debug config. - debug_config: Option, - /// The compiler system mode flag. - is_system_mode: bool, -} +pub struct YulCompiler; lazy_static::lazy_static! { /// @@ -34,86 +30,84 @@ lazy_static::lazy_static! { }; } -impl Compiler for YulCompiler { - fn new( - sources: Vec<(String, String)>, - _libraries: BTreeMap>, - debug_config: Option, - is_system_mode: bool, - ) -> Self { - Self { - sources, - debug_config, - is_system_mode, - } +impl YulCompiler { + /// + /// A shortcut constructor. + /// + pub fn new() -> Self { + Self } +} - fn modes() -> Vec { +impl Compiler for YulCompiler { + fn modes(&self) -> Vec { MODES.clone() } fn compile( &self, + _test_path: String, + sources: Vec<(String, String)>, + _libraries: BTreeMap>, mode: &Mode, - _is_system_contract_mode: bool, - ) -> anyhow::Result> { + is_system_mode: bool, + _is_system_contracts_mode: bool, + debug_config: Option, + ) -> anyhow::Result { let mode = YulMode::unwrap(mode); - self.sources + let solc_validator = if is_system_mode { + None + } else { + Some(SolidityCompiler::get_solc_by_version( + &compiler_solidity::SolcCompiler::LAST_SUPPORTED_VERSION, + )) + }; + + let builds = sources .iter() .map(|(path, source)| { let project = compiler_solidity::Project::try_from_yul_string( - path.as_str(), + PathBuf::from(path.as_str()).as_path(), source.as_str(), + solc_validator.as_ref(), )?; - let target_machine = - compiler_llvm_context::TargetMachine::new(&mode.llvm_optimizer_settings)?; let contract = project - .compile_all( - target_machine, - mode.llvm_optimizer_settings.clone(), - self.is_system_mode, + .compile( + mode.llvm_optimizer_settings.to_owned(), + is_system_mode, true, - self.debug_config.clone(), + zkevm_assembly::get_encoding_mode(), + debug_config.clone(), )? .contracts .remove(path) .ok_or_else(|| { anyhow::anyhow!("Contract `{}` not found in yul project", path) })?; + let assembly = zkevm_assembly::Assembly::from_string( + contract.build.assembly_text, + contract.build.metadata_hash, + ) + .expect("Always valid"); - let build = zkEVMContractBuild::new_with_hash( - contract.build.assembly, - contract.build.bytecode_hash, - )?; + let build = + zkEVMContractBuild::new_with_hash(assembly, contract.build.bytecode_hash)?; Ok((path.to_owned(), build)) }) - .collect() - } + .collect::>>()?; - fn last_contract( - &self, - _mode: &Mode, - _is_system_contract_mode: bool, - ) -> anyhow::Result { - Ok(self - .sources + let last_contract = sources .last() .ok_or_else(|| anyhow::anyhow!("Sources is empty"))? .0 - .clone()) - } + .clone(); - fn has_many_contracts() -> bool { - false + Ok(Output::new(builds, None, last_contract)) } - fn check_pragmas(&self, _mode: &Mode) -> bool { - true - } - - fn check_ethereum_tests_params(_mode: &Mode, _params: &solidity_adapter::Params) -> bool { - true + fn has_many_contracts(&self) -> bool { + false } } diff --git a/compiler_tester/src/compilers/zkevm.rs b/compiler_tester/src/compilers/zkevm.rs index d13b083c..0425f82f 100644 --- a/compiler_tester/src/compilers/zkevm.rs +++ b/compiler_tester/src/compilers/zkevm.rs @@ -5,40 +5,43 @@ use std::collections::BTreeMap; use std::collections::HashMap; -use super::build::Build as zkEVMContractBuild; use super::mode::zkevm::Mode as ZKEVMMode; use super::mode::Mode; +use super::output::build::Build as zkEVMContractBuild; +use super::output::Output; use super::Compiler; /// /// The zkEVM compiler. /// #[allow(non_camel_case_types)] -pub struct zkEVMCompiler { - /// The name-to-code source files mapping. - sources: Vec<(String, String)>, -} +pub struct zkEVMCompiler; -impl Compiler for zkEVMCompiler { - fn new( - sources: Vec<(String, String)>, - _libraries: BTreeMap>, - _debug_config: Option, - _is_system_mode: bool, - ) -> Self { - Self { sources } +impl zkEVMCompiler { + /// + /// A shortcut constructor. + /// + pub fn new() -> Self { + Self } +} - fn modes() -> Vec { +impl Compiler for zkEVMCompiler { + fn modes(&self) -> Vec { vec![ZKEVMMode::default().into()] } fn compile( &self, + _test_path: String, + sources: Vec<(String, String)>, + _libraries: BTreeMap>, _mode: &Mode, - _is_system_contract_mode: bool, - ) -> anyhow::Result> { - self.sources + _is_system_mode: bool, + _is_system_contracts_mode: bool, + _debug_config: Option, + ) -> anyhow::Result { + let builds = sources .iter() .map(|(path, source_code)| { zkevm_assembly::Assembly::try_from(source_code.to_owned()) @@ -46,31 +49,18 @@ impl Compiler for zkEVMCompiler { .and_then(zkEVMContractBuild::new) .map(|build| (path.to_string(), build)) }) - .collect() - } + .collect::>>()?; - fn last_contract( - &self, - _mode: &Mode, - _is_system_contract_mode: bool, - ) -> anyhow::Result { - Ok(self - .sources + let last_contract = sources .last() .ok_or_else(|| anyhow::anyhow!("Sources is empty"))? .0 - .clone()) - } + .clone(); - fn has_many_contracts() -> bool { - false + Ok(Output::new(builds, None, last_contract)) } - fn check_pragmas(&self, _mode: &Mode) -> bool { - true - } - - fn check_ethereum_tests_params(_mode: &Mode, _params: &solidity_adapter::Params) -> bool { - true + fn has_many_contracts(&self) -> bool { + false } } diff --git a/compiler_tester/src/deployers/native_deployer.rs b/compiler_tester/src/deployers/native_deployer.rs index 2f00b09b..c3b9766a 100644 --- a/compiler_tester/src/deployers/native_deployer.rs +++ b/compiler_tester/src/deployers/native_deployer.rs @@ -83,6 +83,7 @@ impl Deployer for NativeDeployer { Ok(ExecutionResult::new( Output::new(return_data, false, result.output.events), result.cycles, + result.ergs, )) } } diff --git a/compiler_tester/src/directories/ethereum/mod.rs b/compiler_tester/src/directories/ethereum/mod.rs index 45929265..c78891f9 100644 --- a/compiler_tester/src/directories/ethereum/mod.rs +++ b/compiler_tester/src/directories/ethereum/mod.rs @@ -8,7 +8,6 @@ use std::path::Path; use std::sync::Arc; use std::sync::Mutex; -use crate::compilers::Compiler; use crate::filters::Filters; use crate::Summary; @@ -19,7 +18,7 @@ use self::test::EthereumTest; /// /// The Ethereum tests directory. /// -pub struct EthereumDirectory {} +pub struct EthereumDirectory; impl EthereumDirectory { /// @@ -28,17 +27,13 @@ impl EthereumDirectory { const INDEX_NAME: &'static str = "index.yaml"; } -impl TestsDirectory for EthereumDirectory -where - C: Compiler, -{ - type Test = EthereumTest; +impl TestsDirectory for EthereumDirectory { + type Test = EthereumTest; fn all_tests( directory_path: &Path, _extension: &'static str, summary: Arc>, - debug_config: Option, filters: &Filters, ) -> anyhow::Result> { let mut index_path = directory_path.to_path_buf(); @@ -48,9 +43,7 @@ where let tests = index .into_enabled_list(directory_path) .into_iter() - .filter_map(|test| { - EthereumTest::new(test, summary.clone(), debug_config.clone(), filters) - }) + .filter_map(|test| EthereumTest::new(test, summary.clone(), filters)) .collect(); Ok(tests) @@ -61,7 +54,6 @@ where test_path: &Path, _extension: &'static str, summary: Arc>, - debug_config: Option, filters: &Filters, ) -> anyhow::Result> { let mut index_path = directory_path.to_path_buf(); @@ -71,6 +63,6 @@ where index .into_enabled_test(directory_path, test_path) .ok_or_else(|| anyhow::anyhow!("Test not found")) - .map(|test| EthereumTest::new(test, summary, debug_config, filters)) + .map(|test| EthereumTest::new(test, summary, filters)) } } diff --git a/compiler_tester/src/directories/ethereum/test.rs b/compiler_tester/src/directories/ethereum/test.rs index 512f1c28..5e576036 100644 --- a/compiler_tester/src/directories/ethereum/test.rs +++ b/compiler_tester/src/directories/ethereum/test.rs @@ -20,65 +20,76 @@ use crate::test::Test; /// /// The Ethereum compiler test. /// -pub struct EthereumTest -where - C: Compiler, -{ - /// The test name. - test_name: String, +pub struct EthereumTest { /// The index test entity. index_entity: solidity_adapter::EnabledTest, - /// The test compiler. - compiler: C, - /// The test function calls. - calls: Vec, - /// The test params. - params: solidity_adapter::Params, - /// The main contract address. - contract_address: web3::types::Address, - /// The libraries addresses. - libraries_addresses: HashMap, - /// The last source name. - last_source: String, + /// The test data. + test: solidity_adapter::Test, } -impl EthereumTest -where - C: Compiler, -{ +impl EthereumTest { /// /// Try to create new test. /// pub fn new( index_entity: solidity_adapter::EnabledTest, summary: Arc>, - debug_config: Option, filters: &Filters, ) -> Option { - let test_name = index_entity.path.to_string_lossy().to_string(); + let test_path = index_entity.path.to_string_lossy().to_string(); - if !filters.check_group(&index_entity.group) { + if !filters.check_case_path(&test_path) { return None; } - if !filters.check_case_path(&test_name) { + if !filters.check_group(&index_entity.group) { return None; } let test = match solidity_adapter::Test::try_from(index_entity.path.as_path()) { Ok(test) => test, Err(error) => { - Summary::invalid(summary, None, test_name, error); + Summary::invalid(summary, None, test_path, error); return None; } }; - let solidity_adapter::Test { - sources, - mut calls, - params, - } = test; + Some(Self { index_entity, test }) + } +} + +impl Buildable for EthereumTest { + fn build( + &self, + mode: Mode, + compiler: Arc, + summary: Arc>, + filters: &Filters, + debug_config: Option, + ) -> Option { + let test_path = self.index_entity.path.to_string_lossy().to_string(); + + if !filters.check_mode(&mode) { + return None; + } + + if let Some(filters) = self.index_entity.modes.as_ref() { + if !mode.check_extended_filters(filters.as_slice()) { + return None; + } + } + + if let Some(versions) = self.index_entity.version.as_ref() { + if !mode.check_version(versions) { + return None; + } + } + + if !mode.check_ethereum_tests_params(&self.test.params) { + return None; + } + let mut calls = self.test.calls.clone(); if !calls .iter() .any(|call| matches!(call, solidity_adapter::FunctionCall::Constructor { .. })) @@ -96,13 +107,13 @@ where calls.insert(constructor_insert_index, constructor); } - let last_source = match sources.last() { + let last_source = match self.test.sources.last() { Some(last_source) => last_source.0.clone(), None => { Summary::invalid( summary, - None, - test_name, + Some(mode), + test_path, anyhow::anyhow!("Sources is empty"), ); return None; @@ -123,8 +134,8 @@ where if contract_address.is_some() { Summary::invalid( summary, - None, - test_name, + Some(mode), + test_path, anyhow::anyhow!("Two constructors in test"), ); return None; @@ -148,8 +159,8 @@ where if !expected.eq(&address) { Summary::invalid( summary, - None, - test_name, + Some(mode), + test_path, anyhow::anyhow!( "Expected address: {}, but found {}", expected, @@ -166,118 +177,87 @@ where let contract_address = contract_address.expect("Always valid"); - Some(Self { - test_name, - index_entity, - compiler: C::new(sources, libraries_for_compiler, debug_config, false), - calls, - params, - contract_address, - libraries_addresses, - last_source, - }) - } -} - -impl Buildable for EthereumTest -where - C: Compiler, -{ - fn build(&self, mode: Mode, summary: Arc>, filters: &Filters) -> Option { - let test_name = self.index_entity.path.to_string_lossy().to_string(); - - if !filters.check_mode(&mode) { - return None; - } - - if let Some(filters) = self.index_entity.modes.as_ref() { - if !Filters::check_mode_filters(&mode, filters.as_slice()) { - return None; - } - } - - if let Some(versions) = self.index_entity.version.as_ref() { - if !mode.check_version(versions) { - return None; - } - } - - if !C::check_ethereum_tests_params(&mode, &self.params) { - return None; - } - - let main_contract = match self - .compiler - .last_contract(&mode, false) - .map_err(|error| anyhow::anyhow!("Failed to get main contract: {}", error)) + let compiler_output = match compiler + .compile( + test_path.clone(), + self.test.sources.clone(), + libraries_for_compiler, + &mode, + false, + false, + debug_config, + ) + .map_err(|error| anyhow::anyhow!("Failed to compile sources: {}", error)) { - Ok(main_contract) => main_contract, + Ok(output) => output, Err(error) => { - Summary::invalid(summary, Some(mode.clone()), test_name, error); + Summary::invalid(summary, Some(mode), test_path, error); return None; } }; - let mut main_contract_instance = None; - let mut libraries_instances = HashMap::with_capacity(self.libraries_addresses.len()); - - let builds = match self - .compiler - .compile(&mode, false) - .map_err(|error| anyhow::anyhow!("Failed to compile sources: {}", error)) - .and_then(|builds| { - let main_contract_build = builds.get(main_contract.as_str()).ok_or_else(|| { - anyhow::anyhow!("Main contract not found in the compiler build artifacts") - })?; - main_contract_instance = Some(Instance::new( - main_contract.clone(), - Some(self.contract_address), - main_contract_build.bytecode_hash, - )); + let main_contract = compiler_output.last_contract; - for (library_name, library_address) in self.libraries_addresses.iter() { - let build = builds.get(library_name).ok_or_else(|| { - anyhow::anyhow!( - "Library {} not found in the compiler build artifacts", - library_name - ) - })?; - libraries_instances.insert( - library_name.clone(), - Instance::new( - library_name.clone(), - Some(*library_address), - build.bytecode_hash, - ), - ); - } - Ok(builds - .into_values() - .map(|build| (build.bytecode_hash, build.assembly)) - .collect()) + let main_contract_build = match compiler_output + .builds + .get(main_contract.as_str()) + .ok_or_else(|| { + anyhow::anyhow!("Main contract not found in the compiler build artifacts") }) { - Ok(builds) => builds, + Ok(build) => build, Err(error) => { - Summary::invalid(summary, Some(mode.clone()), test_name, error); + Summary::invalid(summary, Some(mode), test_path, error); return None; } }; + let main_contract_instance = Instance::new( + main_contract, + Some(contract_address), + main_contract_build.bytecode_hash, + ); - let case = match Case::from_ethereum::( - &self.calls, - &main_contract_instance.expect("Always valid"), + let mut libraries_instances = HashMap::with_capacity(libraries_addresses.len()); + + for (library_name, library_address) in libraries_addresses { + let build = match compiler_output.builds.get(&library_name).ok_or_else(|| { + anyhow::anyhow!( + "Library {} not found in the compiler build artifacts", + library_name + ) + }) { + Ok(build) => build, + Err(error) => { + Summary::invalid(summary, Some(mode), test_path, error); + return None; + } + }; + libraries_instances.insert( + library_name.clone(), + Instance::new(library_name, Some(library_address), build.bytecode_hash), + ); + } + + let case = match Case::try_from_ethereum( + &calls, + &main_contract_instance, &libraries_instances, - &self.last_source, + &last_source, ) { Ok(case) => case, Err(error) => { - Summary::invalid(summary, Some(mode), self.test_name.clone(), error); + Summary::invalid(summary, Some(mode), test_path, error); return None; } }; + let builds = compiler_output + .builds + .into_values() + .map(|build| (build.bytecode_hash, build.assembly)) + .collect(); + Some(Test::new( - test_name, + test_path, self.index_entity.group.clone(), mode, builds, diff --git a/compiler_tester/src/directories/matter_labs/mod.rs b/compiler_tester/src/directories/matter_labs/mod.rs index 8379a8d4..f55cf7d1 100644 --- a/compiler_tester/src/directories/matter_labs/mod.rs +++ b/compiler_tester/src/directories/matter_labs/mod.rs @@ -9,7 +9,6 @@ use std::path::Path; use std::sync::Arc; use std::sync::Mutex; -use crate::compilers::Compiler; use crate::filters::Filters; use crate::summary::Summary; @@ -20,19 +19,15 @@ use self::test::MatterLabsTest; /// /// The Matter Labs compiler tests directory. /// -pub struct MatterLabsDirectory {} +pub struct MatterLabsDirectory; -impl TestsDirectory for MatterLabsDirectory -where - C: Compiler, -{ - type Test = MatterLabsTest; +impl TestsDirectory for MatterLabsDirectory { + type Test = MatterLabsTest; fn all_tests( directory_path: &Path, extension: &'static str, summary: Arc>, - debug_config: Option, filters: &Filters, ) -> anyhow::Result> { let mut tests = Vec::new(); @@ -49,13 +44,7 @@ where })?; if entry_type.is_dir() { - tests.extend(Self::all_tests( - &path, - extension, - summary.clone(), - debug_config.clone(), - filters, - )?); + tests.extend(Self::all_tests(&path, extension, summary.clone(), filters)?); continue; } else if !entry_type.is_file() { anyhow::bail!("Invalid file type: {}", path.to_string_lossy()); @@ -72,9 +61,7 @@ where continue; } - if let Some(test) = - MatterLabsTest::new(path, summary.clone(), debug_config.clone(), filters) - { + if let Some(test) = MatterLabsTest::new(path, summary.clone(), filters) { tests.push(test); } } @@ -87,7 +74,6 @@ where test_path: &Path, extension: &'static str, summary: Arc>, - debug_config: Option, filters: &Filters, ) -> anyhow::Result> { let file_extension = test_path.extension().ok_or_else(|| { @@ -103,6 +89,6 @@ where let mut path = directory_path.to_path_buf(); path.push(test_path); - Ok(MatterLabsTest::new(path, summary, debug_config, filters)) + Ok(MatterLabsTest::new(path, summary, filters)) } } diff --git a/compiler_tester/src/directories/matter_labs/test/mod.rs b/compiler_tester/src/directories/matter_labs/test/mod.rs index 5f6b756b..d90a841d 100644 --- a/compiler_tester/src/directories/matter_labs/test/mod.rs +++ b/compiler_tester/src/directories/matter_labs/test/mod.rs @@ -51,45 +51,30 @@ pub fn default_caller_address() -> String { /// /// The Matter Labs compiler test. /// -pub struct MatterLabsTest -where - C: Compiler, -{ - /// The test name. - test_name: String, - /// The test compiler. - compiler: C, - /// The address predictor. - address_predictor: AddressPredictor, +pub struct MatterLabsTest { + /// The test path. + path: PathBuf, /// The test metadata. metadata: Metadata, - /// The libraries addresses. - libraries_instances: HashMap, + /// The test sources. + sources: Vec<(String, String)>, } -impl MatterLabsTest -where - C: Compiler, -{ +impl MatterLabsTest { /// /// Try to create new test. /// - pub fn new( - path: PathBuf, - summary: Arc>, - debug_config: Option, - filters: &Filters, - ) -> Option { - let test_name = path.to_string_lossy().to_string(); + pub fn new(path: PathBuf, summary: Arc>, filters: &Filters) -> Option { + let test_path = path.to_string_lossy().to_string(); - if !filters.check_test_path(&test_name) { + if !filters.check_test_path(&test_path) { return None; } let metadata_file_string = match std::fs::read_to_string(path.as_path()) { Ok(metadata_file_string) => metadata_file_string, Err(error) => { - Summary::invalid(summary, None, test_name, error); + Summary::invalid(summary, None, test_path, error); return None; } }; @@ -99,13 +84,13 @@ where { Ok(metadata) => metadata, Err(error) => { - Summary::invalid(summary, None, test_name, error); + Summary::invalid(summary, None, test_path, error); return None; } }; if metadata.ignore { - Summary::ignored(summary, test_name); + Summary::ignored(summary, test_path); return None; } @@ -114,14 +99,6 @@ where } let sources = if metadata.contracts.is_empty() { - let contract_name = if C::has_many_contracts() { - format!("{}:{}", path.to_string_lossy(), SIMPLE_TESTS_CONTRACT_NAME) - } else { - path.to_string_lossy().to_string() - }; - metadata - .contracts - .insert(SIMPLE_TESTS_INSTANCE.to_owned(), contract_name); vec![(path.to_string_lossy().to_string(), metadata_file_string)] } else { let mut sources = HashMap::new(); @@ -156,7 +133,7 @@ where { Ok(source) => source, Err(error) => { - Summary::invalid(summary, None, test_name, error); + Summary::invalid(summary, None, test_path, error); return None; } }; @@ -165,141 +142,147 @@ where sources.into_iter().collect() }; - let mut address_predictor = AddressPredictor::new(); - - let instances = metadata - .contracts - .keys() - .cloned() - .collect::>(); - - let mut libraries_instances = Vec::new(); - let mut libraries_for_compiler = BTreeMap::new(); - let mut libraries_instances_addresses = HashMap::new(); - - for (file, metadata_file_libraries) in metadata.libraries.iter() { - let mut file_path = path.clone(); - file_path.pop(); - file_path.push(file); - let mut file_libraries = BTreeMap::new(); - for (name, instance) in metadata_file_libraries.iter() { - let address = address_predictor.next_address( - web3::types::Address::from_str(DEFAULT_CALLER_ADDRESS) - .expect("Invalid default caller address constant"), - ); - file_libraries.insert( - name.to_owned(), - format!("0x{}", crate::utils::address_as_string(&address)), - ); - libraries_instances_addresses.insert(instance.to_owned(), address); - libraries_instances.push(instance.to_owned()); - } - libraries_for_compiler.insert(file_path.to_string_lossy().to_string(), file_libraries); - } - - let mut cases = Vec::with_capacity(metadata.cases.len()); - for mut case in metadata.cases.into_iter() { - let case_name = format!("{}::{}", test_name, case.name); + metadata.cases.retain(|case| { + let case_name = format!("{}::{}", test_path, case.name); if case.ignore { Summary::ignored(summary.clone(), case_name); - continue; + return false; } if !filters.check_case_path(&case_name) { - continue; + return false; } - - match case.normalize_deployer_calls(&instances, &libraries_instances) { - Ok(_) => {} - Err(error) => { - Summary::invalid(summary, None, test_name, error); - return None; - } - } - case.normalize_expected(); - cases.push(case); - } - - metadata.cases = cases; + true + }); Some(Self { - test_name, - compiler: C::new( - sources, - libraries_for_compiler, - debug_config, - metadata.system_mode, - ), - address_predictor, + path, metadata, - libraries_instances: libraries_instances_addresses, + sources, }) } } -impl Buildable for MatterLabsTest -where - C: Compiler, -{ - fn build(&self, mode: Mode, summary: Arc>, filters: &Filters) -> Option { +impl Buildable for MatterLabsTest { + fn build( + &self, + mode: Mode, + compiler: Arc, + summary: Arc>, + filters: &Filters, + debug_config: Option, + ) -> Option { + let test_path = self.path.to_string_lossy().to_string(); if !filters.check_mode(&mode) { return None; } if let Some(filters) = self.metadata.modes.as_ref() { - if !Filters::check_mode_filters(&mode, filters.as_slice()) { + if !mode.check_extended_filters(filters.as_slice()) { return None; } } - if !self.compiler.check_pragmas(&mode) { + if !mode.check_pragmas(&self.sources) { return None; } - let mut instances = HashMap::new(); + let mut contracts = self.metadata.contracts.clone(); + if contracts.is_empty() { + let contract_name = if compiler.has_many_contracts() { + format!("{}:{}", test_path, SIMPLE_TESTS_CONTRACT_NAME) + } else { + test_path.clone() + }; + contracts.insert(SIMPLE_TESTS_INSTANCE.to_owned(), contract_name); + } - let builds = match self - .compiler - .compile(&mode, false) + let mut address_predictor = AddressPredictor::new(); + + let mut libraries_instances_names = Vec::new(); + let mut libraries_for_compiler = BTreeMap::new(); + let mut libraries_instances_addresses = HashMap::new(); + + for (file, metadata_file_libraries) in self.metadata.libraries.iter() { + let mut file_path = self.path.clone(); + file_path.pop(); + file_path.push(file); + let mut file_libraries = BTreeMap::new(); + for (name, instance) in metadata_file_libraries.iter() { + let address = address_predictor.next_address( + web3::types::Address::from_str(DEFAULT_CALLER_ADDRESS) + .expect("Invalid default caller address constant"), + ); + file_libraries.insert( + name.to_owned(), + format!("0x{}", crate::utils::address_as_string(&address)), + ); + libraries_instances_addresses.insert(instance.to_owned(), address); + libraries_instances_names.push(instance.to_owned()); + } + libraries_for_compiler.insert(file_path.to_string_lossy().to_string(), file_libraries); + } + + let compiler_output = match compiler + .compile( + test_path.clone(), + self.sources.clone(), + libraries_for_compiler, + &mode, + self.metadata.system_mode, + false, + debug_config, + ) .map_err(|error| anyhow::anyhow!("Failed to compile sources: {}", error)) - .and_then(|builds| { - for (instance, path) in self.metadata.contracts.iter() { - let build = builds.get(path).ok_or_else(|| { - anyhow::anyhow!("{} not found in the compiler build artifacts", path) - })?; - let hash = build.bytecode_hash; - let address = self.libraries_instances.get(instance).cloned(); - instances.insert(instance.clone(), Instance::new(path.clone(), address, hash)); - } - Ok(builds - .into_values() - .map(|build| (build.bytecode_hash, build.assembly)) - .collect()) - }) { - Ok(builds) => builds, + { + Ok(output) => output, Err(error) => { - Summary::invalid(summary, Some(mode.clone()), self.test_name.clone(), error); + Summary::invalid(summary, Some(mode), test_path, error); return None; } }; + let instances_names = contracts.keys().cloned().collect::>(); + let mut instances = HashMap::new(); + + for (instance, path) in contracts.into_iter() { + let build = match compiler_output.builds.get(&path).ok_or_else(|| { + anyhow::anyhow!("{} not found in the compiler build artifacts", path) + }) { + Ok(build) => build, + Err(error) => { + Summary::invalid(summary, Some(mode), test_path, error); + return None; + } + }; + let hash = build.bytecode_hash; + let address = libraries_instances_addresses.get(&instance).cloned(); + instances.insert(instance, Instance::new(path, address, hash)); + } + let mut cases = Vec::with_capacity(self.metadata.cases.len()); for case in self.metadata.cases.iter() { - let mut address_predictor = self.address_predictor.clone(); - if let Some(filters) = case.modes.as_ref() { - if !Filters::check_mode_filters(&mode, filters.as_slice()) { + if !mode.check_extended_filters(filters.as_slice()) { continue; } } + let mut case = case.clone(); + match case.normalize_deployer_calls(&instances_names, &libraries_instances_names) { + Ok(_) => {} + Err(error) => { + Summary::invalid(summary, Some(mode), test_path, error); + return None; + } + } + case.normalize_expected(); + + let mut address_predictor = address_predictor.clone(); + let instances_addresses = match case .instances_addresses( - &self - .libraries_instances - .keys() - .cloned() - .collect::>(), + &libraries_instances_names.clone().into_iter().collect(), &mut address_predictor, &mode, ) @@ -312,23 +295,29 @@ where }) { Ok(addresses) => addresses, Err(error) => { - Summary::invalid(summary, Some(mode.clone()), self.test_name.clone(), error); + Summary::invalid(summary, Some(mode), test_path, error); return None; } }; let mut instances = instances.clone(); for (instance, address) in instances_addresses { - if let Some(instance) = instances.get_mut(&instance) { - instance.address = Some(address); - } + let instance = instances + .get_mut(&instance) + .expect("Redundant instance from the instances_addresses case method"); + instance.address = Some(address); } - let case = match Case::from_matter_labs(case, &mode, &instances, &self.compiler) - .map_err(|error| anyhow::anyhow!("Case `{}` is invalid: {}", case.name, error)) + let case = match Case::try_from_matter_labs( + &case, + &mode, + &instances, + &compiler_output.method_identifiers, + ) + .map_err(|error| anyhow::anyhow!("Case `{}` is invalid: {}", case.name, error)) { Ok(case) => case, Err(error) => { - Summary::invalid(summary, Some(mode.clone()), self.test_name.clone(), error); + Summary::invalid(summary, Some(mode), test_path, error); return None; } }; @@ -336,8 +325,14 @@ where cases.push(case); } + let builds = compiler_output + .builds + .into_values() + .map(|build| (build.bytecode_hash, build.assembly)) + .collect(); + Some(Test::new( - self.test_name.clone(), + test_path, self.metadata.group.clone(), mode, builds, diff --git a/compiler_tester/src/directories/mod.rs b/compiler_tester/src/directories/mod.rs index ae1568f4..f44e84be 100644 --- a/compiler_tester/src/directories/mod.rs +++ b/compiler_tester/src/directories/mod.rs @@ -22,16 +22,20 @@ pub trait Buildable: Send + Sync + 'static { /// /// Builds the test. /// - fn build(&self, mode: Mode, summary: Arc>, filters: &Filters) -> Option; + fn build( + &self, + mode: Mode, + compiler: Arc, + summary: Arc>, + filters: &Filters, + debug_config: Option, + ) -> Option; } /// /// The compiler tests directory trait. /// -pub trait TestsDirectory -where - C: Compiler, -{ +pub trait TestsDirectory { /// /// The test type. /// @@ -44,7 +48,6 @@ where directory_path: &Path, extension: &'static str, summary: Arc>, - debug_config: Option, filters: &Filters, ) -> anyhow::Result>; @@ -56,7 +59,6 @@ where test_path: &Path, extension: &'static str, summary: Arc>, - debug_config: Option, filters: &Filters, ) -> anyhow::Result>; } diff --git a/compiler_tester/src/filters.rs b/compiler_tester/src/filters.rs index 95aa632a..8f748d0e 100644 --- a/compiler_tester/src/filters.rs +++ b/compiler_tester/src/filters.rs @@ -56,11 +56,7 @@ impl Filters { /// Check if the mode is compatible with the filters. /// pub fn check_mode(&self, mode: &Mode) -> bool { - self.mode_filters.is_empty() - || self - .mode_filters - .iter() - .any(|filter| Self::normalize_mode(mode, filter).contains(filter)) + mode.check_filters(self.mode_filters.as_slice()) } /// @@ -76,70 +72,4 @@ impl Filters { false } } - - /// - /// Checks if the mode is compatible with the specified filters. - /// - pub fn check_mode_filters(mode: &Mode, filters: &[String]) -> bool { - if filters.is_empty() { - return true; - } - for filter in filters.iter() { - let mut split = filter.split_whitespace(); - let mode_filter = split.next().unwrap_or_default(); - let normalized_mode = Self::normalize_mode(mode, mode_filter); - if !normalized_mode.contains(mode_filter) { - continue; - } - - let version = match split.next() { - Some(version) => version, - None => return true, - }; - if let Ok(version_req) = semver::VersionReq::parse(version) { - if mode.check_version(&version_req) { - return true; - } - } - } - false - } - - /// - /// Normalizes the mode according to the filter. - /// - fn normalize_mode(mode: &Mode, filter: &str) -> String { - let mut current = mode.to_string(); - if filter.contains("Y*") { - current = regex::Regex::new("Y[-+]") - .expect("Always valid") - .replace_all(current.as_str(), "Y*") - .to_string(); - } - if filter.contains("E*") { - current = regex::Regex::new("E[-+]") - .expect("Always valid") - .replace_all(current.as_str(), "E*") - .to_string(); - } - if filter.contains("M^") { - current = regex::Regex::new("M[3z]") - .expect("Always valid") - .replace_all(current.as_str(), "M^") - .to_string(); - } - if filter.contains("M*") { - current = regex::Regex::new("M[0123sz]") - .expect("Always valid") - .replace_all(current.as_str(), "M*") - .to_string(); - } - if filter.contains("B*") { - current = regex::Regex::new("B[0123]") - .expect("Always valid") - .replace_all(current.as_str(), "B*") - .to_string(); - } - current - } } diff --git a/compiler_tester/src/lib.rs b/compiler_tester/src/lib.rs index 2c93e8bd..6bedf6c5 100644 --- a/compiler_tester/src/lib.rs +++ b/compiler_tester/src/lib.rs @@ -54,7 +54,7 @@ pub const TRACE_DIRECTORY: &str = "./trace/"; /// /// The compiler test generic representation. /// -type Test = (Arc, Mode); +type Test = (Arc, Arc, Mode); /// /// The compiler-tester. @@ -156,50 +156,71 @@ impl CompilerTester { where D: Deployer, { + let solidity_compiler = Arc::new(SolidityCompiler::new()); + let vyper_compiler = Arc::new(VyperCompiler::new()); + let yul_compiler = Arc::new(YulCompiler::new()); + let llvm_compiler = Arc::new(LLVMCompiler::new()); + let zkevm_compiler = Arc::new(zkEVMCompiler::new()); + let mut tests = Vec::new(); - tests.extend(self.directory::( + tests.extend(self.directory::( Self::SOLIDITY_SIMPLE, compiler_common::EXTENSION_SOLIDITY, + solidity_compiler.clone(), )?); - tests.extend(self.directory::( + tests.extend(self.directory::( Self::VYPER_SIMPLE, compiler_common::EXTENSION_VYPER, + vyper_compiler.clone(), )?); - tests.extend(self.directory::( + tests.extend(self.directory::( Self::YUL_SIMPLE, compiler_common::EXTENSION_YUL, + yul_compiler, )?); - tests.extend(self.directory::( + tests.extend(self.directory::( Self::LLVM_SIMPLE, compiler_common::EXTENSION_LLVM_SOURCE, + llvm_compiler, )?); - tests.extend(self.directory::( + tests.extend(self.directory::( Self::ZKEVM_SIMPLE, compiler_common::EXTENSION_ZKEVM_ASSEMBLY, + zkevm_compiler, )?); - tests.extend(self.directory::( + tests.extend(self.directory::( Self::SOLIDITY_COMPLEX, compiler_common::EXTENSION_JSON, + solidity_compiler.clone(), )?); - tests.extend(self.directory::( + tests.extend(self.directory::( Self::VYPER_COMPLEX, compiler_common::EXTENSION_JSON, + vyper_compiler.clone(), )?); - tests.extend(self.directory::( + tests.extend(self.directory::( Self::SOLIDITY_ETHEREUM, compiler_common::EXTENSION_SOLIDITY, + solidity_compiler, )?); - tests.extend(self.directory::( + tests.extend(self.directory::( Self::VYPER_ETHEREUM, compiler_common::EXTENSION_VYPER, + vyper_compiler, )?); let _: Vec<()> = tests .into_par_iter() - .map(|(test, mode)| { - if let Some(test) = test.build(mode, self.summary.clone(), &self.filters) { + .map(|(test, compiler, mode)| { + if let Some(test) = test.build( + mode, + compiler, + self.summary.clone(), + &self.filters, + self.debug_config.clone(), + ) { test.run::(self.summary.clone(), self.initial_vm.clone()); } }) @@ -209,18 +230,21 @@ impl CompilerTester { } /// - /// Returns all test from the specified directory. + /// Returns all test from the specified directory with the specified compiler. /// - fn directory(&self, path: &str, extension: &'static str) -> anyhow::Result> + fn directory( + &self, + path: &str, + extension: &'static str, + compiler: Arc, + ) -> anyhow::Result> where - C: Compiler, - T: TestsDirectory, + T: TestsDirectory, { Ok(T::all_tests( Path::new(path), extension, self.summary.clone(), - self.debug_config.clone(), &self.filters, ) .map_err(|error| { @@ -228,7 +252,8 @@ impl CompilerTester { })? .into_iter() .map(|test| Arc::new(test) as Arc) - .cartesian_product(C::modes()) + .cartesian_product(compiler.modes()) + .map(|(test, mode)| (test, compiler.clone() as Arc, mode)) .collect()) } } diff --git a/compiler_tester/src/llvm_options.rs b/compiler_tester/src/llvm_options.rs index d81ce3fd..f5c6adfe 100644 --- a/compiler_tester/src/llvm_options.rs +++ b/compiler_tester/src/llvm_options.rs @@ -4,8 +4,6 @@ use std::sync::Mutex; -use once_cell::sync::OnceCell; - /// /// The compiler tester LLVM options. /// @@ -18,7 +16,7 @@ pub struct LLVMOptions { } /// The one-time initialization cell for the global variable. -static LLVM_OPTIONS: OnceCell = OnceCell::new(); +static LLVM_OPTIONS: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); /// The mutex to allow simultaneous access to only one target machine. static LLVM_OPTIONS_LOCK: Mutex<()> = Mutex::new(()); diff --git a/compiler_tester/src/summary/element/mod.rs b/compiler_tester/src/summary/element/mod.rs index 6d880d29..e1ca5dd1 100644 --- a/compiler_tester/src/summary/element/mod.rs +++ b/compiler_tester/src/summary/element/mod.rs @@ -63,8 +63,10 @@ impl Element { details.push(format!("size {size}").bright_white().to_string()) }; match variant { - PassedVariant::Deploy { cycles, .. } | PassedVariant::Runtime { cycles } => { - details.push(format!("cycles {cycles}").bright_white().to_string()) + PassedVariant::Deploy { cycles, ergs, .. } + | PassedVariant::Runtime { cycles, ergs } => { + details.push(format!("cycles {cycles}").bright_white().to_string()); + details.push(format!("ergs {ergs}").bright_white().to_string()) } _ => {} }; @@ -96,7 +98,7 @@ impl Element { }; Some(format!( - "{:24} {:>7} {} {}", + "{:16} {:>7} {} {}", self.mode .as_ref() .map(|mode| mode.to_string()) diff --git a/compiler_tester/src/summary/element/outcome/passed_variant.rs b/compiler_tester/src/summary/element/outcome/passed_variant.rs index c81a5629..9663996f 100644 --- a/compiler_tester/src/summary/element/outcome/passed_variant.rs +++ b/compiler_tester/src/summary/element/outcome/passed_variant.rs @@ -13,11 +13,15 @@ pub enum PassedVariant { size: usize, /// The number of execution cycles. cycles: usize, + /// The number of used ergs. + ergs: u32, }, /// The contract call. Runtime { /// The number of execution cycles. cycles: usize, + /// The number of used ergs. + ergs: u32, }, /// The special function call. Special, diff --git a/compiler_tester/src/summary/mod.rs b/compiler_tester/src/summary/mod.rs index 9d8a4904..304557af 100644 --- a/compiler_tester/src/summary/mod.rs +++ b/compiler_tester/src/summary/mod.rs @@ -82,15 +82,15 @@ impl Summary { benchmark_analyzer::BenchmarkGroup::default(), ); for element in self.elements.iter() { - let (size, cycles, group) = match &element.outcome { + let (size, cycles, ergs, group) = match &element.outcome { Outcome::Passed { - variant: PassedVariant::Deploy { size, cycles }, + variant: PassedVariant::Deploy { size, cycles, ergs }, group, - } => (Some(*size), *cycles, group.clone()), + } => (Some(*size), *cycles, *ergs, group.clone()), Outcome::Passed { - variant: PassedVariant::Runtime { cycles }, + variant: PassedVariant::Runtime { cycles, ergs }, group, - } => (None, *cycles, group.clone()), + } => (None, *cycles, *ergs, group.clone()), _ => continue, }; let key = format!( @@ -102,7 +102,7 @@ impl Summary { .unwrap_or_default(), element.name ); - let benchmark_element = benchmark_analyzer::BenchmarkElement::new(size, cycles); + let benchmark_element = benchmark_analyzer::BenchmarkElement::new(size, cycles, ergs); if let Some(group) = group { benchmark .groups @@ -182,8 +182,9 @@ impl Summary { group: Option, size: usize, cycles: usize, + ergs: u32, ) { - let passed_variant = PassedVariant::Deploy { size, cycles }; + let passed_variant = PassedVariant::Deploy { size, cycles, ergs }; Self::passed(summary, mode, name, group, passed_variant); } @@ -196,8 +197,9 @@ impl Summary { name: String, group: Option, cycles: usize, + ergs: u32, ) { - let passed_variant = PassedVariant::Runtime { cycles }; + let passed_variant = PassedVariant::Runtime { cycles, ergs }; Self::passed(summary, mode, name, group, passed_variant); } diff --git a/compiler_tester/src/test/case/input/deploy.rs b/compiler_tester/src/test/case/input/deploy.rs index 9aa13f9a..b92d5810 100644 --- a/compiler_tester/src/test/case/input/deploy.rs +++ b/compiler_tester/src/test/case/input/deploy.rs @@ -100,7 +100,15 @@ impl Deploy { return; } }; - Summary::passed_deploy(summary, mode, name, test_group, build_size, result.cycles); + Summary::passed_deploy( + summary, + mode, + name, + test_group, + build_size, + result.cycles, + result.ergs, + ); } else { Summary::failed( summary, diff --git a/compiler_tester/src/test/case/input/mod.rs b/compiler_tester/src/test/case/input/mod.rs index c3075966..cf47ea54 100644 --- a/compiler_tester/src/test/case/input/mod.rs +++ b/compiler_tester/src/test/case/input/mod.rs @@ -11,13 +11,13 @@ pub mod storage; pub mod storage_empty; pub mod value; +use std::collections::BTreeMap; use std::collections::HashMap; use std::str::FromStr; use std::sync::Arc; use std::sync::Mutex; use crate::compilers::mode::Mode; -use crate::compilers::Compiler; use crate::deployers::Deployer; use crate::directories::matter_labs::test::metadata::case::input::Input as MatterLabsTestInput; use crate::summary::Summary; @@ -51,15 +51,12 @@ impl Input { /// /// Try convert from Matter Labs compiler test metadata input. /// - pub fn try_from_matter_labs( + pub fn try_from_matter_labs( input: &MatterLabsTestInput, mode: &Mode, instances: &HashMap, - compiler: &C, - ) -> anyhow::Result - where - C: Compiler, - { + method_identifiers: &Option>>, + ) -> anyhow::Result { let caller = web3::types::Address::from_str(input.caller.as_str()) .map_err(|error| anyhow::anyhow!("Invalid caller: {}", error))?; @@ -130,9 +127,26 @@ impl Input { ) })?; let path = instance.path.as_str(); - let selector = compiler - .selector(mode, path, entry, false) - .map_err(|error| anyhow::anyhow!("Failed to get selector: {}", error))?; + let selector = match method_identifiers { + Some(method_identifiers) => method_identifiers + .get(path) + .ok_or_else(|| { + anyhow::anyhow!("Contract {} not found in the method identifiers", path) + })? + .iter() + .find_map(|(name, selector)| { + if name.starts_with(entry) { + Some(*selector) + } else { + None + } + }) + .ok_or_else(|| { + anyhow::anyhow!("Selector of the method `{}` not found", entry) + })?, + None => u32::from_str_radix(entry, compiler_common::BASE_HEXADECIMAL) + .map_err(|err| anyhow::anyhow!("Invalid entry value: {}", err))?, + }; calldata.add_selector(selector); diff --git a/compiler_tester/src/test/case/input/runtime.rs b/compiler_tester/src/test/case/input/runtime.rs index 83e33ed5..ea6df1bc 100644 --- a/compiler_tester/src/test/case/input/runtime.rs +++ b/compiler_tester/src/test/case/input/runtime.rs @@ -88,7 +88,7 @@ impl Runtime { } }; if result.output == self.expected { - Summary::passed_runtime(summary, mode, name, test_group, result.cycles); + Summary::passed_runtime(summary, mode, name, test_group, result.cycles, result.ergs); } else { Summary::failed( summary, diff --git a/compiler_tester/src/test/case/mod.rs b/compiler_tester/src/test/case/mod.rs index 4d3cf578..19830877 100644 --- a/compiler_tester/src/test/case/mod.rs +++ b/compiler_tester/src/test/case/mod.rs @@ -4,12 +4,12 @@ pub mod input; +use std::collections::BTreeMap; use std::collections::HashMap; use std::sync::Arc; use std::sync::Mutex; use crate::compilers::mode::Mode; -use crate::compilers::Compiler; use crate::deployers::Deployer; use crate::directories::matter_labs::test::metadata::case::Case as MatterLabsTestCase; use crate::summary::Summary; @@ -40,20 +40,17 @@ impl Case { /// /// Try convert from Matter Labs compiler test metadata case. /// - pub fn from_matter_labs( + pub fn try_from_matter_labs( case: &MatterLabsTestCase, mode: &Mode, instances: &HashMap, - compiler: &C, - ) -> anyhow::Result - where - C: Compiler, - { + method_identifiers: &Option>>, + ) -> anyhow::Result { let mut inputs = Vec::with_capacity(case.inputs.capacity()); for (index, input) in case.inputs.iter().enumerate() { - let input = - Input::try_from_matter_labs(input, mode, instances, compiler).map_err(|error| { + let input = Input::try_from_matter_labs(input, mode, instances, method_identifiers) + .map_err(|error| { anyhow::anyhow!( "Input {}(After adding deployer calls) is invalid: {}", index, @@ -69,15 +66,12 @@ impl Case { /// /// Try convert from Ethereum compiler test metadata case. /// - pub fn from_ethereum( + pub fn try_from_ethereum( case: &[solidity_adapter::FunctionCall], main_contract_instance: &Instance, libraries_instances: &HashMap, last_source: &str, - ) -> anyhow::Result - where - C: Compiler, - { + ) -> anyhow::Result { let mut inputs = Vec::new(); let mut caller = solidity_adapter::account_address(solidity_adapter::DEFAULT_ACCOUNT_INDEX); diff --git a/compiler_tester/src/zkevm/execution_result.rs b/compiler_tester/src/zkevm/execution_result.rs index 4858aae2..7e93baa4 100644 --- a/compiler_tester/src/zkevm/execution_result.rs +++ b/compiler_tester/src/zkevm/execution_result.rs @@ -13,14 +13,20 @@ pub struct ExecutionResult { pub output: Output, /// The number of executed cycles. pub cycles: usize, + /// The number of used ergs. + pub ergs: u32, } impl ExecutionResult { /// /// A shortcut constructor. /// - pub fn new(output: Output, cycles: usize) -> Self { - Self { output, cycles } + pub fn new(output: Output, cycles: usize, ergs: u32) -> Self { + Self { + output, + cycles, + ergs, + } } } @@ -29,6 +35,7 @@ impl From<&zkevm_tester::runners::compiler_tests::VmSnapshot> for ExecutionResul Self { output: Output::from(snapshot), cycles: snapshot.num_cycles_used, + ergs: snapshot.num_ergs_used, } } } diff --git a/compiler_tester/src/zkevm/mod.rs b/compiler_tester/src/zkevm/mod.rs index 07b4dabd..a11673e6 100644 --- a/compiler_tester/src/zkevm/mod.rs +++ b/compiler_tester/src/zkevm/mod.rs @@ -74,6 +74,18 @@ impl zkEVM { system_contracts.default_aa.assembly, system_contracts.default_aa.bytecode_hash, ); + vm.add_known_contract( + zkevm_assembly::Assembly::from_string( + compiler_vyper::FORWARDER_CONTRACT_ASSEMBLY.to_owned(), + None, + ) + .expect("Always valid"), + web3::types::U256::from_str_radix( + compiler_vyper::FORWARDER_CONTRACT_HASH.as_str(), + compiler_common::BASE_HEXADECIMAL, + ) + .expect("Always valid"), + ); for (address, build) in system_contracts.deployed_contracts { vm.add_deployed_contract(address, build.bytecode_hash, Some(build.assembly)); diff --git a/compiler_tester/src/zkevm/system_contracts.rs b/compiler_tester/src/zkevm/system_contracts.rs index 0b1af82a..43bed1d2 100644 --- a/compiler_tester/src/zkevm/system_contracts.rs +++ b/compiler_tester/src/zkevm/system_contracts.rs @@ -13,10 +13,10 @@ use colored::Colorize; use serde::Deserialize; use serde::Serialize; -use crate::compilers::build::Build as zkEVMContractBuild; use crate::compilers::mode::solidity::Mode as SolidityMode; use crate::compilers::mode::yul::Mode as YulMode; use crate::compilers::mode::Mode; +use crate::compilers::output::build::Build as zkEVMContractBuild; use crate::compilers::solidity::SolidityCompiler; use crate::compilers::yul::YulCompiler; use crate::compilers::Compiler; @@ -205,8 +205,12 @@ impl SystemContracts { yul_file_paths.push(file_path.to_owned()); } let yul_mode = YulMode::new(compiler_llvm_context::OptimizerSettings::cycles()).into(); - let mut builds = - Self::compile::(&yul_mode, yul_file_paths, debug_config.clone())?; + let mut builds = Self::compile( + YulCompiler::new(), + &yul_mode, + yul_file_paths, + debug_config.clone(), + )?; let mut solidity_file_paths = Vec::with_capacity(solidity_system_contracts.len() + 1); for (_, path) in solidity_system_contracts.iter() { @@ -223,10 +227,12 @@ impl SystemContracts { solc_version, compiler_solidity::SolcPipeline::Yul, true, + true, compiler_llvm_context::OptimizerSettings::cycles(), ) .into(); - builds.extend(Self::compile::( + builds.extend(Self::compile( + SolidityCompiler::new(), &solidity_mode, solidity_file_paths, debug_config, @@ -270,7 +276,8 @@ impl SystemContracts { let system_contracts: SystemContracts = bincode::deserialize_from(system_contracts_file) .map_err(|error| anyhow::anyhow!("System contract deserialization: {}", error))?; println!( - "System contracts build successfully loaded from `{}`", + " {} the System Contracts from `{}`", + "Loaded".bright_green().bold(), system_contracts_path.to_string_lossy() ); Ok(system_contracts) @@ -279,21 +286,23 @@ impl SystemContracts { /// /// Save the system contracts build to the given file. /// - fn save(&self, system_contracts_save_path: PathBuf) -> anyhow::Result<()> { - let system_contracts_file = File::create(system_contracts_save_path.as_path())?; + fn save(&self, system_contracts_path: PathBuf) -> anyhow::Result<()> { + let system_contracts_file = File::create(system_contracts_path.as_path())?; bincode::serialize_into(system_contracts_file, self) .map_err(|error| anyhow::anyhow!("System contracts serialization: {}", error,))?; println!( - "System contracts build successfully saved to `{}`", - system_contracts_save_path.to_string_lossy(), + " {} the System Contracts to `{}`", + "Saved".bright_green().bold(), + system_contracts_path.to_string_lossy() ); Ok(()) } /// - /// Compiles the system contracts using the specified compiler. + /// Compiles the system contracts with a compiler. /// fn compile( + compiler: C, mode: &Mode, paths: Vec, debug_config: Option, @@ -303,7 +312,7 @@ impl SystemContracts { { let mut sources = Vec::new(); for path in paths.into_iter() { - let file_path = if C::has_many_contracts() { + let file_path = if compiler.has_many_contracts() { path.split(':').next().expect("Always valid").to_string() } else { path @@ -318,9 +327,17 @@ impl SystemContracts { })?; sources.push((file_path.to_string(), source)); } - let compiler = C::new(sources, BTreeMap::new(), debug_config, true); compiler - .compile(mode, true) + .compile( + "system-contracts".to_owned(), + sources, + BTreeMap::new(), + mode, + true, + true, + debug_config, + ) + .map(|output| output.builds) .map_err(|error| anyhow::anyhow!("Failed to compile system contracts: {}", error)) } } diff --git a/solidity b/solidity index 14d2ae2d..4c4410e0 160000 --- a/solidity +++ b/solidity @@ -1 +1 @@ -Subproject commit 14d2ae2dfaf4336ee4be198ea402c70996fa821d +Subproject commit 4c4410e0c5ec0faf794b497086c9354c8c1d223a diff --git a/solidity_adapter/Cargo.toml b/solidity_adapter/Cargo.toml index 177fe090..25481a3e 100644 --- a/solidity_adapter/Cargo.toml +++ b/solidity_adapter/Cargo.toml @@ -24,7 +24,7 @@ colored = "2.0" serde = { version = "1.0", features = [ "derive" ] } serde_yaml = "0.9" semver = { version = "1.0", features = [ "serde" ] } -regex = "1.8" +regex = "1.9" md5 = "0.7" web3 = { version= "0.18.0", default-features = false, features = ["http-rustls-tls", "test", "signing"] } diff --git a/solidity_adapter/src/test/function_call/gas_option.rs b/solidity_adapter/src/test/function_call/gas_option.rs index 703c3773..5dc79dd4 100644 --- a/solidity_adapter/src/test/function_call/gas_option.rs +++ b/solidity_adapter/src/test/function_call/gas_option.rs @@ -8,7 +8,7 @@ use crate::test::function_call::parser::GasVariant; /// /// The gas option. /// -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum GasOption { /// `irOptimized` in the metadata. IrOptimized(web3::types::U256), diff --git a/solidity_adapter/src/test/function_call/mod.rs b/solidity_adapter/src/test/function_call/mod.rs index 278855b9..96c37b1e 100644 --- a/solidity_adapter/src/test/function_call/mod.rs +++ b/solidity_adapter/src/test/function_call/mod.rs @@ -18,7 +18,7 @@ use self::gas_option::GasOption; /// /// The function call. /// -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum FunctionCall { /// The library. Library { diff --git a/system-contracts b/system-contracts index 7658f9a1..e96dfe0b 160000 --- a/system-contracts +++ b/system-contracts @@ -1 +1 @@ -Subproject commit 7658f9a18e4642e04c2e06e9468ca111d48ea1f0 +Subproject commit e96dfe0b5093fa95c2fb340c0411c646327db921 diff --git a/tests b/tests index 5242f3f4..64759910 160000 --- a/tests +++ b/tests @@ -1 +1 @@ -Subproject commit 5242f3f493f9894100c79032ac04c7cd47999165 +Subproject commit 647599107ab4f2a05760b2e98ca4e6aaa79f126b