From c9cbcfbe8db0a755e4533ec5992bf4fa8781f51d Mon Sep 17 00:00:00 2001 From: Julian Gonzalez Calderon Date: Wed, 20 Aug 2025 16:50:04 -0300 Subject: [PATCH 1/9] Implement basic Cairo Native integration (#4) * Add local dependencies * Add cairo-native dep to forge * Add new run-native-test-case * Compile with Native * Add sierra_function_id to test detail * Comment the VM test_case execution for easy comparing * Implement run_native_test_case * Use git dependencies * Remove todo! from tests * Use from_native_module --- Cargo.lock | 400 +++++++++++++++++- Cargo.toml | 5 +- .../execution/entry_point.rs | 3 + crates/forge-runner/Cargo.toml | 1 + crates/forge-runner/src/lib.rs | 6 + crates/forge-runner/src/package_tests.rs | 3 + crates/forge-runner/src/running.rs | 136 +++++- .../forge-runner/src/running/with_config.rs | 14 +- crates/forge/Cargo.toml | 1 + crates/forge/src/run_tests/resolve_config.rs | 16 + crates/forge/src/run_tests/test_target.rs | 1 + crates/forge/src/test_filter.rs | 18 + 12 files changed, 574 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48f072a7bb..08c0bcae5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,22 +126,44 @@ version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +[[package]] +name = "apollo_compilation_utils" +version = "0.15.0-rc.2" +source = "git+https://github.com/lambdaclass/sequencer.git?rev=3117630b9470f70832d2a08f758aa3df2486fbe8#3117630b9470f70832d2a08f758aa3df2486fbe8" +dependencies = [ + "apollo_infra_utils", + "cairo-lang-sierra", + "cairo-lang-starknet-classes", + "cairo-lang-utils", + "cairo-native", + "rlimit", + "serde", + "serde_json", + "starknet-types-core", + "starknet_api", + "tempfile", + "thiserror 1.0.69", +] + [[package]] name = "apollo_compile_to_native" version = "0.15.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce72f98e94e249a95dd1bdc95aaf326b4a14c930d8b948864f08734f6526556c" +source = "git+https://github.com/lambdaclass/sequencer.git?rev=3117630b9470f70832d2a08f758aa3df2486fbe8#3117630b9470f70832d2a08f758aa3df2486fbe8" dependencies = [ + "apollo_compilation_utils", "apollo_config", + "apollo_infra_utils", + "cairo-lang-starknet-classes", + "cairo-native", "serde", + "tempfile", "validator", ] [[package]] name = "apollo_config" version = "0.15.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c345b809e6590f25e4cf078006665125b07385c2f633d20d4fb9cab2fb49ce20" +source = "git+https://github.com/lambdaclass/sequencer.git?rev=3117630b9470f70832d2a08f758aa3df2486fbe8#3117630b9470f70832d2a08f758aa3df2486fbe8" dependencies = [ "apollo_infra_utils", "clap", @@ -159,11 +181,10 @@ dependencies = [ [[package]] name = "apollo_infra_utils" version = "0.15.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fdb3fb6422e6ebf266e6c0d3bfc64b7c1847620548a8010da5fb71213075456" +source = "git+https://github.com/lambdaclass/sequencer.git?rev=3117630b9470f70832d2a08f758aa3df2486fbe8#3117630b9470f70832d2a08f758aa3df2486fbe8" dependencies = [ "assert-json-diff", - "colored", + "colored 3.0.0", "num_enum", "serde", "serde_json", @@ -177,8 +198,7 @@ dependencies = [ [[package]] name = "apollo_metrics" version = "0.15.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a36e50d43a288fb99669cc3f97b42433bc5c077cfac4f218dfcd0cc64ba10464" +source = "git+https://github.com/lambdaclass/sequencer.git?rev=3117630b9470f70832d2a08f758aa3df2486fbe8#3117630b9470f70832d2a08f758aa3df2486fbe8" dependencies = [ "indexmap 2.10.0", "metrics", @@ -187,6 +207,20 @@ dependencies = [ "regex", ] +[[package]] +name = "aquamarine" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f50776554130342de4836ba542aa85a4ddb361690d7e8df13774d7284c3d5c2" +dependencies = [ + "include_dir", + "itertools 0.10.5", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "ark-ec" version = "0.4.2" @@ -215,7 +249,7 @@ dependencies = [ "ark-poly 0.5.0", "ark-serialize 0.5.0", "ark-std 0.5.0", - "educe", + "educe 0.6.0", "fnv", "hashbrown 0.15.4", "itertools 0.13.0", @@ -257,7 +291,7 @@ dependencies = [ "ark-std 0.5.0", "arrayvec", "digest", - "educe", + "educe 0.6.0", "itertools 0.13.0", "num-bigint", "num-traits", @@ -334,7 +368,7 @@ dependencies = [ "ark-ff 0.5.0", "ark-serialize 0.5.0", "ark-std 0.5.0", - "educe", + "educe 0.6.0", "fnv", "hashbrown 0.15.4", ] @@ -674,6 +708,26 @@ dependencies = [ "virtue", ] +[[package]] +name = "bindgen" +version = "0.71.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" +dependencies = [ + "bitflags 2.9.1", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 2.1.1", + "shlex", + "syn 2.0.104", +] + [[package]] name = "bit-set" version = "0.8.0" @@ -737,10 +791,10 @@ dependencies = [ [[package]] name = "blockifier" version = "0.15.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbaf04063930d0b2a0cbcb1760a2d1a58abdea5ee0ce78ca261d79f9bfc3430a" +source = "git+https://github.com/lambdaclass/sequencer.git?rev=3117630b9470f70832d2a08f758aa3df2486fbe8#3117630b9470f70832d2a08f758aa3df2486fbe8" dependencies = [ "anyhow", + "apollo_compilation_utils", "apollo_compile_to_native", "apollo_config", "apollo_infra_utils", @@ -754,6 +808,7 @@ dependencies = [ "cairo-lang-casm", "cairo-lang-runner", "cairo-lang-starknet-classes", + "cairo-native", "cairo-vm", "dashmap", "derive_more 0.99.20", @@ -785,8 +840,7 @@ dependencies = [ [[package]] name = "blockifier_test_utils" version = "0.15.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5812279370f6be789f435ae91dcfdd22f4b5405f2ec2895475a6d65f7e5cbc65" +source = "git+https://github.com/lambdaclass/sequencer.git?rev=3117630b9470f70832d2a08f758aa3df2486fbe8#3117630b9470f70832d2a08f758aa3df2486fbe8" dependencies = [ "apollo_infra_utils", "cairo-lang-starknet-classes", @@ -1068,7 +1122,7 @@ dependencies = [ "cairo-lang-syntax", "cairo-lang-syntax-codegen", "cairo-lang-utils", - "colored", + "colored 3.0.0", "itertools 0.14.0", "num-bigint", "num-traits", @@ -1434,7 +1488,7 @@ checksum = "d325a9afabf56b9d20de7799fa370f83a673fc0a9ff62e0abcabf62cb1efbff9" dependencies = [ "cairo-lang-formatter", "cairo-lang-utils", - "colored", + "colored 3.0.0", "log", "pretty_assertions", ] @@ -1456,6 +1510,61 @@ dependencies = [ "smol_str", ] +[[package]] +name = "cairo-native" +version = "0.6.0" +source = "git+https://github.com/lambdaclass/cairo_native.git?rev=5bf88591687b3f3596ac592357b029cfb1ab79b2#5bf88591687b3f3596ac592357b029cfb1ab79b2" +dependencies = [ + "anyhow", + "aquamarine", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-secp256k1 0.5.0", + "ark-secp256r1 0.5.0", + "bumpalo", + "cairo-lang-compiler", + "cairo-lang-defs", + "cairo-lang-filesystem", + "cairo-lang-runner", + "cairo-lang-semantic", + "cairo-lang-sierra", + "cairo-lang-sierra-ap-change", + "cairo-lang-sierra-gas", + "cairo-lang-sierra-generator", + "cairo-lang-sierra-to-casm", + "cairo-lang-starknet", + "cairo-lang-starknet-classes", + "cairo-lang-test-plugin", + "cairo-lang-utils", + "cc", + "clap", + "colored 2.2.0", + "educe 0.5.11", + "itertools 0.14.0", + "keccak", + "lazy_static 1.5.0", + "libc", + "libloading", + "llvm-sys", + "melior", + "mlir-sys", + "num-bigint", + "num-integer", + "num-traits", + "rand 0.9.2", + "serde", + "serde_json", + "sha2", + "starknet-curve 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "starknet-types-core", + "stats_alloc", + "tempfile", + "thiserror 2.0.12", + "tracing", + "tracing-subscriber", + "utf8_iter", +] + [[package]] name = "cairo-serde-macros" version = "1.0.0" @@ -1506,6 +1615,15 @@ dependencies = [ "serde", ] +[[package]] +name = "caseless" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6fd507454086c8edfd769ca6ada439193cdb209c7681712ef6275cccbfe5d8" +dependencies = [ + "unicode-normalization", +] + [[package]] name = "cc" version = "1.2.31" @@ -1515,6 +1633,15 @@ dependencies = [ "shlex", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.1" @@ -1597,6 +1724,17 @@ dependencies = [ "inout", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.5.42" @@ -1663,6 +1801,16 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "colored" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +dependencies = [ + "lazy_static 1.5.0", + "windows-sys 0.59.0", +] + [[package]] name = "colored" version = "3.0.0" @@ -1672,6 +1820,20 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "comrak" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39bff2cbb80102771ca62bd2375bc6f6611dc1493373440b23aa08a155538708" +dependencies = [ + "caseless", + "entities", + "memchr", + "slug", + "typed-arena", + "unicode_categories", +] + [[package]] name = "config" version = "0.14.1" @@ -1816,6 +1978,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "convert_case" version = "0.8.0" @@ -2151,6 +2322,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "deunicode" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04" + [[package]] name = "dialoguer" version = "0.11.0" @@ -2343,6 +2520,18 @@ dependencies = [ "spki", ] +[[package]] +name = "educe" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4bd92664bf78c4d3dba9b7cdafce6fa15b13ed3ed16175218196942e99168a8" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "educe" version = "0.6.0" @@ -2412,6 +2601,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" +[[package]] +name = "entities" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" + [[package]] name = "enum-ordinalize" version = "4.3.0" @@ -2631,6 +2826,7 @@ dependencies = [ "cairo-annotations", "cairo-lang-sierra", "cairo-lang-starknet-classes", + "cairo-native", "cairo-vm", "camino", "cheatnet", @@ -2687,6 +2883,7 @@ dependencies = [ "cairo-lang-starknet-classes", "cairo-lang-test-plugin", "cairo-lang-utils", + "cairo-native", "cairo-vm", "camino", "cheatnet", @@ -3716,6 +3913,16 @@ version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +dependencies = [ + "cfg-if", + "windows-targets 0.53.3", +] + [[package]] name = "libm" version = "0.2.15" @@ -3750,6 +3957,20 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +[[package]] +name = "llvm-sys" +version = "191.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "893cddf1adf0354b93411e413553dd4daf5c43195d73f1acfa1e394bdd371456" +dependencies = [ + "anyhow", + "cc", + "lazy_static 1.5.0", + "libc", + "regex-lite", + "semver", +] + [[package]] name = "lock_api" version = "0.4.13" @@ -3812,6 +4033,32 @@ dependencies = [ "rawpointer", ] +[[package]] +name = "melior" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2af6454b7bcd7edc8c2060a3726a18ceaed60e25c34d9f8de9c6b44e82eb647" +dependencies = [ + "melior-macro", + "mlir-sys", +] + +[[package]] +name = "melior-macro" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a99671327250df8e24e56d8304474a970e7a2c6bb8f6dc71382d188136fe4d1b" +dependencies = [ + "comrak", + "convert_case 0.7.1", + "proc-macro2", + "quote", + "regex", + "syn 2.0.104", + "tblgen", + "unindent", +] + [[package]] name = "memchr" version = "2.7.5" @@ -3879,6 +4126,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "mlir-sys" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee4047ffefa7e9853412025a98b38a66968584543918cf084a6e4df9144b71b" +dependencies = [ + "bindgen", +] + [[package]] name = "mockall" version = "0.12.1" @@ -4573,6 +4829,16 @@ dependencies = [ "yansi", ] +[[package]] +name = "prettyplease" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" +dependencies = [ + "proc-macro2", + "syn 2.0.104", +] + [[package]] name = "primeorder" version = "0.13.6" @@ -4640,6 +4906,27 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", +] + [[package]] name = "proc-macro2" version = "1.0.95" @@ -4958,6 +5245,12 @@ dependencies = [ "regex-syntax 0.8.5", ] +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + [[package]] name = "regex-syntax" version = "0.6.29" @@ -5044,6 +5337,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rlimit" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7043b63bd0cd1aaa628e476b80e6d4023a3b50eb32789f2728908107bd0c793a" +dependencies = [ + "libc", +] + [[package]] name = "rlp" version = "0.5.2" @@ -5806,6 +6108,16 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +[[package]] +name = "slug" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" +dependencies = [ + "deunicode", + "wasm-bindgen", +] + [[package]] name = "smallvec" version = "1.15.1" @@ -6194,8 +6506,7 @@ dependencies = [ [[package]] name = "starknet_api" version = "0.15.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d5bda9bfa1cf2a0903c975b3b6918dddf3197b467d8de3a1e61c8760bcb2cb" +source = "git+https://github.com/lambdaclass/sequencer.git?rev=3117630b9470f70832d2a08f758aa3df2486fbe8#3117630b9470f70832d2a08f758aa3df2486fbe8" dependencies = [ "apollo_infra_utils", "base64 0.13.1", @@ -6232,6 +6543,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "stats_alloc" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c0e04424e733e69714ca1bbb9204c1a57f09f5493439520f9f68c132ad25eec" + [[package]] name = "str-buf" version = "1.0.6" @@ -6377,6 +6694,18 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tblgen" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c155c9310c9e11e6f642b4c8a30ae572ea0cad013d5c9e28bb264b52fa8163bb" +dependencies = [ + "bindgen", + "cc", + "paste", + "thiserror 2.0.12", +] + [[package]] name = "tempfile" version = "3.20.0" @@ -6780,6 +7109,16 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.19" @@ -6790,12 +7129,15 @@ dependencies = [ "nu-ansi-term 0.46.0", "once_cell", "regex", + "serde", + "serde_json", "sharded-slab", "smallvec", "thread_local", "tracing", "tracing-core", "tracing-log", + "tracing-serde", ] [[package]] @@ -6835,6 +7177,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + [[package]] name = "typeid" version = "1.0.3" @@ -6961,6 +7309,18 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "unindent" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" + [[package]] name = "universal-sierra-compiler-api" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index 53f9464a37..74dd85055c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,9 +29,9 @@ license = "MIT" license-file = "LICENSE" [workspace.dependencies] -blockifier = { version = "0.15.0-rc.2", features = ["testing", "tracing"]} +blockifier = { git = "https://github.com/lambdaclass/sequencer.git", rev = "3117630b9470f70832d2a08f758aa3df2486fbe8", features = ["testing", "tracing", "cairo_native"]} bigdecimal = "0.4.8" -starknet_api = "0.15.0-rc.2" +starknet_api = { git = "https://github.com/lambdaclass/sequencer.git", rev = "3117630b9470f70832d2a08f758aa3df2486fbe8" } cairo-lang-casm = { version = "2.12.0", features = ["serde"] } cairo-lang-sierra = "2.12.0" cairo-lang-utils = "2.12.0" @@ -44,6 +44,7 @@ cairo-lang-test-plugin = "2.12.0" cairo-lang-starknet-classes = "2.12.0" cairo-lang-parser = "2.12.0" cairo-vm = "2.2.0" +cairo-native = { git = "https://github.com/lambdaclass/cairo_native.git", rev = "5bf88591687b3f3596ac592357b029cfb1ab79b2", features = ["with-cheatcode"] } cairo-annotations = "0.5.0" dirs = "6.0.0" dialoguer = "0.11.0" diff --git a/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/execution/entry_point.rs b/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/execution/entry_point.rs index 72c877df2e..259e0f99e4 100644 --- a/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/execution/entry_point.rs +++ b/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/execution/entry_point.rs @@ -172,6 +172,9 @@ pub fn execute_call_entry_point( cheatnet_state, context, ), + RunnableCompiledClass::V1Native(_) => { + todo!("execute inner call with Cairo Native") + } }; context .tracked_resource_stack diff --git a/crates/forge-runner/Cargo.toml b/crates/forge-runner/Cargo.toml index 166ef94507..40e343cd27 100644 --- a/crates/forge-runner/Cargo.toml +++ b/crates/forge-runner/Cargo.toml @@ -25,6 +25,7 @@ rand.workspace = true url.workspace = true blockifier.workspace = true cairo-vm.workspace = true +cairo-native.workspace = true itertools.workspace = true indoc.workspace = true camino.workspace = true diff --git a/crates/forge-runner/src/lib.rs b/crates/forge-runner/src/lib.rs index 20109f848e..b6d8b6310c 100644 --- a/crates/forge-runner/src/lib.rs +++ b/crates/forge-runner/src/lib.rs @@ -5,6 +5,7 @@ use crate::test_case_summary::TestCaseSummary; use anyhow::Result; use build_trace_data::save_trace_data; use cairo_lang_sierra::program::{ConcreteTypeLongId, Function, TypeDeclaration}; +use cairo_native::executor::AotNativeExecutor; use camino::Utf8PathBuf; use cheatnet::runtime_extensions::forge_config_extension::config::RawFuzzerConfig; use foundry_ui::UI; @@ -106,6 +107,7 @@ pub fn maybe_generate_coverage( pub fn run_for_test_case( case: Arc, casm_program: Arc, + aot_executor: Arc, forge_config: Arc, versioned_program_path: Arc, send: Sender<()>, @@ -117,6 +119,7 @@ pub fn run_for_test_case( let res = run_test( case, casm_program, + aot_executor, forge_config, versioned_program_path, send, @@ -131,6 +134,7 @@ pub fn run_for_test_case( let res = run_with_fuzzing( case, casm_program, + aot_executor, forge_config.clone(), versioned_program_path, send, @@ -145,6 +149,7 @@ pub fn run_for_test_case( fn run_with_fuzzing( case: Arc, casm_program: Arc, + aot_executor: Arc, forge_config: Arc, versioned_program_path: Arc, send: Sender<()>, @@ -178,6 +183,7 @@ fn run_with_fuzzing( tasks.push(run_fuzz_test( case.clone(), casm_program.clone(), + aot_executor.clone(), forge_config.clone(), versioned_program_path.clone(), send.clone(), diff --git a/crates/forge-runner/src/package_tests.rs b/crates/forge-runner/src/package_tests.rs index 32a981f7e8..327ba58278 100644 --- a/crates/forge-runner/src/package_tests.rs +++ b/crates/forge-runner/src/package_tests.rs @@ -10,6 +10,7 @@ use cairo_lang_sierra::extensions::range_check::{RangeCheck96Type, RangeCheckTyp use cairo_lang_sierra::extensions::segment_arena::SegmentArenaType; use cairo_lang_sierra::ids::GenericTypeId; use cairo_lang_sierra::program::ProgramArtifact; +use cairo_native::executor::AotNativeExecutor; use cairo_vm::serde::deserialize_program::ReferenceManager; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::types::program::Program; @@ -49,6 +50,7 @@ pub enum TestTargetLocation { #[derive(Debug, PartialEq, Clone, Default)] pub struct TestDetails { + pub sierra_function_id: u64, pub sierra_entry_point_statement_idx: usize, pub parameter_types: Vec<(GenericTypeId, i16)>, pub return_types: Vec<(GenericTypeId, i16)>, @@ -103,6 +105,7 @@ pub struct TestTarget { pub sierra_program: ProgramArtifact, pub sierra_program_path: Arc, pub casm_program: Arc, + pub aot_executor: Arc, pub test_cases: Vec>, } diff --git a/crates/forge-runner/src/running.rs b/crates/forge-runner/src/running.rs index fe8c7e8647..2794ade08b 100644 --- a/crates/forge-runner/src/running.rs +++ b/crates/forge-runner/src/running.rs @@ -10,11 +10,16 @@ use blockifier::execution::entry_point::EntryPointExecutionContext; use blockifier::execution::entry_point_execution::{prepare_call_arguments, run_entry_point}; use blockifier::execution::errors::EntryPointExecutionError; use blockifier::state::cached_state::CachedState; +use cairo_lang_sierra::ids::FunctionId; +use cairo_native::Value; +use cairo_native::execution_result::ContractExecutionResult; +use cairo_native::executor::AotNativeExecutor; +use cairo_native::starknet_stub::StubSyscallHandler; use cairo_vm::Felt252; use cairo_vm::vm::errors::cairo_run_errors::CairoRunError; use cairo_vm::vm::errors::vm_errors::VirtualMachineError; use camino::{Utf8Path, Utf8PathBuf}; -use cheatnet::constants as cheatnet_constants; +use cheatnet::constants::{self as cheatnet_constants, build_test_entry_point}; use cheatnet::forking::data::ForkData; use cheatnet::forking::state::ForkStateReader; use cheatnet::runtime_extensions::call_to_blockifier_runtime_extension::CallToBlockifierExtension; @@ -61,7 +66,8 @@ pub use syscall_handler::syscall_handler_offset; #[must_use] pub fn run_test( case: Arc, - casm_program: Arc, + _casm_program: Arc, + _aot_executor: Arc, forge_config: Arc, versioned_program_path: Arc, send: Sender<()>, @@ -74,12 +80,19 @@ pub fn run_test( if send.is_closed() { return TestCaseSummary::Interrupted {}; } - let run_result = run_test_case( + + let run_result = run_native_test_case( &case, - &casm_program, + &_aot_executor, &RuntimeConfig::from(&forge_config.test_runner_config), None, ); + // let run_result = run_test_case( + // &case, + // &_casm_program, + // &RuntimeConfig::from(&forge_config.test_runner_config), + // None, + // ); if send.is_closed() { return TestCaseSummary::Interrupted {}; @@ -98,7 +111,8 @@ pub fn run_test( #[expect(clippy::too_many_arguments)] pub(crate) fn run_fuzz_test( case: Arc, - casm_program: Arc, + _casm_program: Arc, + aot_executor: Arc, forge_config: Arc, versioned_program_path: Arc, send: Sender<()>, @@ -114,9 +128,9 @@ pub(crate) fn run_fuzz_test( return TestCaseSummary::Interrupted {}; } - let run_result = run_test_case( + let run_result = run_native_test_case( &case, - &casm_program, + &aot_executor, &RuntimeConfig::from(&forge_config.test_runner_config), Some(rng), ); @@ -386,6 +400,114 @@ pub fn run_test_case( }) } +/// Executes the given test case with Cairo Native. +pub fn run_native_test_case( + case: &TestCaseWithResolvedConfig, + aot_executor: &AotNativeExecutor, + runtime_config: &RuntimeConfig, + fuzzer_rng: Option>>, +) -> Result { + let function_id = FunctionId::new(case.test_details.sierra_function_id); + let call = build_test_entry_point(); + + // The state reader is currently unused, as it requires support of the + // custom syscall handler. + let mut state_reader = ExtendedStateReader { + dict_state_reader: cheatnet_constants::build_testing_state(), + fork_state_reader: get_fork_state_reader( + runtime_config.cache_dir, + case.config.fork_config.as_ref(), + )?, + }; + if !case.config.disable_predeployed_contracts { + state_reader.predeploy_contracts(); + } + + // The cheatnet state is currently unused, as it requires support of a + // custom syscall handler + let block_info = state_reader.get_block_info()?; + let mut cheatnet_state = CheatnetState { + block_info, + ..Default::default() + }; + + // TODO: Implement a proper syscall handler like `run_test_case`. + // Tracking issue: https://github.com/lambdaclass/starknet-foundry/issues/3. + let mut syscall_handler = StubSyscallHandler::default(); + + // To implement fuzzing we need support of the syscall handler. + // Currently the argument is unused. + _ = fuzzer_rng; + + // Tests don't have any input arguments. Fuzzing tests actually take the + // arguments through cheatcode syscalls. + let args = vec![Value::Struct { + fields: vec![Value::Array(vec![])], + debug_name: None, + }]; + + // NOTE: We are using the AotNativeExecutor as its more generic, but in + // this context we are actually using it more like a contract executor. Consider + // unifying both executors and provide a more general API for executing Native. + let result = match aot_executor.invoke_dynamic_with_syscall_handler( + &function_id, + &args, + Some(call.initial_gas), + &mut syscall_handler, + ) { + Ok(result) => ContractExecutionResult::from_execution_result(result), + Err(err) => Err(err), + }; + + let call_trace = cheatnet_state.trace_data.current_call_stack.top(); + let encountered_errors = cheatnet_state.encountered_errors; + let fuzzer_args = cheatnet_state.fuzzer_args; + + // TODO: Compute resource usage properly. + // It should be the same as when using the Cairo VM. + let used_resources = UsedResources::default(); + let gas_used = GasVector::default(); + + let fork_data = state_reader + .fork_state_reader + .map(|fork_state_reader| ForkData::new(&fork_state_reader.compiled_contract_class_map())) + .unwrap_or_default(); + + Ok(match result { + Ok(result) => RunResult::Completed(Box::new(RunCompleted { + status: { + if !result.failure_flag { + RunStatus::Success(result.return_values) + } else { + RunStatus::Panic(result.return_values) + } + }, + call_trace, + gas_used, + used_resources, + encountered_errors, + fuzzer_args, + fork_data, + })), + Err(err) => { + // TODO: We are reusing a virtual machine error as a quick + // workaround. We should instead define a generic error type that + // supports both Cairo VM and Cairo Native errors. + let error = Box::new(CairoRunError::VirtualMachine(VirtualMachineError::Other( + err.into(), + ))); + + RunResult::Error(RunError { + error, + call_trace, + encountered_errors, + fuzzer_args, + fork_data, + }) + } + }) +} + fn extract_test_case_summary( run_result: Result, case: &TestCaseWithResolvedConfig, diff --git a/crates/forge-runner/src/running/with_config.rs b/crates/forge-runner/src/running/with_config.rs index 9410ac778f..f95c2e091a 100644 --- a/crates/forge-runner/src/running/with_config.rs +++ b/crates/forge-runner/src/running/with_config.rs @@ -7,7 +7,7 @@ use crate::{ }, running::config_run::run_config_pass, }; -use anyhow::{Result, anyhow}; +use anyhow::{Context, Result, anyhow}; use cairo_lang_sierra::{ extensions::core::{CoreLibfunc, CoreType}, ids::ConcreteTypeId, @@ -16,6 +16,7 @@ use cairo_lang_sierra::{ }; use cairo_lang_sierra_type_size::get_type_size_map; use cairo_lang_utils::unordered_hash_map::UnorderedHashMap; +use cairo_native::{context::NativeContext, executor::AotNativeExecutor}; use rayon::iter::IntoParallelRefIterator; use rayon::iter::ParallelIterator; use std::{collections::HashMap, sync::Arc}; @@ -78,12 +79,22 @@ pub fn test_target_with_config( }) .collect::>()?; + let aot_executor = { + let native_context = NativeContext::new(); + let native_module = native_context + .compile(&test_target_raw.sierra_program.program, true, None, None) + .context("failed to compile sierra program to native module")?; + AotNativeExecutor::from_native_module(native_module, cairo_native::OptLevel::Default) + .context("failed to create executor")? + }; + Ok(TestTargetWithConfig { tests_location: test_target_raw.tests_location, test_cases, sierra_program: test_target_raw.sierra_program, sierra_program_path: test_target_raw.sierra_program_path.into(), casm_program, + aot_executor: Arc::new(aot_executor), }) } @@ -104,6 +115,7 @@ fn build_test_details( }; TestDetails { + sierra_function_id: func.id.id, sierra_entry_point_statement_idx: func.entry_point.0, parameter_types: map_types(&func.signature.param_types), return_types: map_types(&func.signature.ret_types), diff --git a/crates/forge/Cargo.toml b/crates/forge/Cargo.toml index d3502911cc..429eba92ce 100644 --- a/crates/forge/Cargo.toml +++ b/crates/forge/Cargo.toml @@ -43,6 +43,7 @@ scarb-metadata.workspace = true scarb-ui.workspace = true semver.workspace = true cairo-vm.workspace = true +cairo-native.workspace = true # openssl is being used, please do not remove it! openssl.workspace = true toml_edit.workspace = true diff --git a/crates/forge/src/run_tests/resolve_config.rs b/crates/forge/src/run_tests/resolve_config.rs index 97dfe5e25b..8fe4b1c9a9 100644 --- a/crates/forge/src/run_tests/resolve_config.rs +++ b/crates/forge/src/run_tests/resolve_config.rs @@ -49,6 +49,7 @@ pub async fn resolve_config( sierra_program_path: test_target.sierra_program_path, casm_program: test_target.casm_program, test_cases, + aot_executor: test_target.aot_executor, }) } @@ -128,6 +129,8 @@ mod tests { use super::*; use cairo_lang_sierra::program::ProgramArtifact; use cairo_lang_sierra::{ids::GenericTypeId, program::Program}; + use cairo_native::context::NativeContext; + use cairo_native::executor::AotNativeExecutor; use forge_runner::package_tests::TestTargetLocation; use forge_runner::package_tests::with_config::{TestCaseConfig, TestCaseWithConfig}; use forge_runner::{expected_result::ExpectedTestResult, package_tests::TestDetails}; @@ -147,6 +150,17 @@ mod tests { } } + fn executor_for_testing() -> Arc { + let native_context = NativeContext::new(); + let native_module = native_context + .compile(&program_for_testing().program, true, None, None) + .unwrap(); + let native_executor = + AotNativeExecutor::from_native_module(native_module, cairo_native::OptLevel::Default) + .unwrap(); + Arc::new(native_executor) + } + #[tokio::test] async fn to_runnable_non_existent_id() { let mocked_tests = TestTargetWithConfig { @@ -170,6 +184,7 @@ mod tests { disable_predeployed_contracts: false, }, test_details: TestDetails { + sierra_function_id: 100, sierra_entry_point_statement_idx: 100, parameter_types: vec![ (GenericTypeId("RangeCheck".into()), 1), @@ -183,6 +198,7 @@ mod tests { }, }], tests_location: TestTargetLocation::Lib, + aot_executor: executor_for_testing(), }; assert!( diff --git a/crates/forge/src/run_tests/test_target.rs b/crates/forge/src/run_tests/test_target.rs index 13973a0f81..99ba2ddc2f 100644 --- a/crates/forge/src/run_tests/test_target.rs +++ b/crates/forge/src/run_tests/test_target.rs @@ -54,6 +54,7 @@ pub async fn run_for_test_target( tasks.push(run_for_test_case( case, casm_program.clone(), + tests.aot_executor.clone(), forge_config.clone(), tests.sierra_program_path.clone(), send.clone(), diff --git a/crates/forge/src/test_filter.rs b/crates/forge/src/test_filter.rs index 361b843b1a..2d99f9c2a0 100644 --- a/crates/forge/src/test_filter.rs +++ b/crates/forge/src/test_filter.rs @@ -135,6 +135,8 @@ mod tests { use crate::test_filter::TestsFilter; use cairo_lang_sierra::program::Program; use cairo_lang_sierra::program::ProgramArtifact; + use cairo_native::context::NativeContext; + use cairo_native::executor::AotNativeExecutor; use forge_runner::expected_result::ExpectedTestResult; use forge_runner::package_tests::with_config_resolved::{ TestCaseResolvedConfig, TestCaseWithResolvedConfig, TestTargetWithResolvedConfig, @@ -155,6 +157,17 @@ mod tests { } } + fn executor_for_testing() -> Arc { + let native_context = NativeContext::new(); + let native_module = native_context + .compile(&program_for_testing().program, true, None, None) + .unwrap(); + let native_executor = + AotNativeExecutor::from_native_module(native_module, cairo_native::OptLevel::Default) + .unwrap(); + Arc::new(native_executor) + } + #[test] #[should_panic(expected = "Arguments only_ignored and include_ignored cannot be both true")] fn from_flags_only_ignored_and_include_ignored_both_true() { @@ -251,6 +264,7 @@ mod tests { }, ], tests_location: TestTargetLocation::Lib, + aot_executor: executor_for_testing(), }; let tests_filter = TestsFilter::from_flags( @@ -486,6 +500,7 @@ mod tests { ), test_cases: vec![], tests_location: TestTargetLocation::Lib, + aot_executor: executor_for_testing(), }; let tests_filter = TestsFilter::from_flags( @@ -587,6 +602,7 @@ mod tests { }, ], tests_location: TestTargetLocation::Tests, + aot_executor: executor_for_testing(), }; let tests_filter = TestsFilter::from_flags( @@ -793,6 +809,7 @@ mod tests { }, ], tests_location: TestTargetLocation::Tests, + aot_executor: executor_for_testing(), }; let tests_filter = TestsFilter::from_flags( @@ -908,6 +925,7 @@ mod tests { }, ], tests_location: TestTargetLocation::Tests, + aot_executor: executor_for_testing(), }; let tests_filter = TestsFilter::from_flags( From 530bb02db6e9e2b35d1f879a002e27c572e0443b Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Wed, 20 Aug 2025 16:55:11 -0300 Subject: [PATCH 2/9] Add cli argument to choose between native and vm --- crates/forge-runner/src/forge_config.rs | 1 + crates/forge-runner/src/running.rs | 27 ++++++++++++++----------- crates/forge/src/combine_configs.rs | 10 +++++++++ crates/forge/src/lib.rs | 4 +++- crates/forge/src/run_tests/package.rs | 1 + 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/crates/forge-runner/src/forge_config.rs b/crates/forge-runner/src/forge_config.rs index 50fea06d52..f1551e4ecf 100644 --- a/crates/forge-runner/src/forge_config.rs +++ b/crates/forge-runner/src/forge_config.rs @@ -27,6 +27,7 @@ pub struct TestRunnerConfig { pub environment_variables: HashMap, pub tracked_resource: ForgeTrackedResource, pub experimental_oracles: bool, + pub use_native: bool, } #[derive(Debug, PartialEq)] diff --git a/crates/forge-runner/src/running.rs b/crates/forge-runner/src/running.rs index 2794ade08b..4bd0721ca8 100644 --- a/crates/forge-runner/src/running.rs +++ b/crates/forge-runner/src/running.rs @@ -81,18 +81,21 @@ pub fn run_test( return TestCaseSummary::Interrupted {}; } - let run_result = run_native_test_case( - &case, - &_aot_executor, - &RuntimeConfig::from(&forge_config.test_runner_config), - None, - ); - // let run_result = run_test_case( - // &case, - // &_casm_program, - // &RuntimeConfig::from(&forge_config.test_runner_config), - // None, - // ); + let run_result = if forge_config.test_runner_config.use_native { + run_native_test_case( + &case, + &_aot_executor, + &RuntimeConfig::from(&forge_config.test_runner_config), + None, + ) + } else { + run_test_case( + &case, + &_casm_program, + &RuntimeConfig::from(&forge_config.test_runner_config), + None, + ) + }; if send.is_closed() { return TestCaseSummary::Interrupted {}; diff --git a/crates/forge/src/combine_configs.rs b/crates/forge/src/combine_configs.rs index 9fcfb05d22..820aa31085 100644 --- a/crates/forge/src/combine_configs.rs +++ b/crates/forge/src/combine_configs.rs @@ -29,6 +29,7 @@ pub fn combine_configs( additional_args: &[OsString], trace_args: TraceArgs, experimental_oracles: bool, + use_native: bool, ) -> ForgeConfig { let execution_data_to_save = ExecutionDataToSave::from_flags( save_trace_data || forge_config_from_scarb.save_trace_data, @@ -53,6 +54,7 @@ pub fn combine_configs( tracked_resource, environment_variables: env::vars().collect(), experimental_oracles, + use_native, }), output_config: Arc::new(OutputConfig { trace_args, @@ -84,6 +86,7 @@ mod tests { &[], TraceArgs::default(), false, + false, ); let config2 = combine_configs( false, @@ -101,6 +104,7 @@ mod tests { &[], TraceArgs::default(), false, + false, ); assert_ne!(config.test_runner_config.fuzzer_seed, 0); @@ -129,6 +133,7 @@ mod tests { &[], TraceArgs::default(), false, + false, ); assert_eq!( config, @@ -144,6 +149,7 @@ mod tests { contracts_data: ContractsData::default(), environment_variables: config.test_runner_config.environment_variables.clone(), experimental_oracles: false, + use_native: false }), output_config: Arc::new(OutputConfig { detailed_resources: false, @@ -185,6 +191,7 @@ mod tests { &[], TraceArgs::default(), false, + false, ); assert_eq!( config, @@ -200,6 +207,7 @@ mod tests { contracts_data: ContractsData::default(), environment_variables: config.test_runner_config.environment_variables.clone(), experimental_oracles: false, + use_native: false }), output_config: Arc::new(OutputConfig { detailed_resources: true, @@ -245,6 +253,7 @@ mod tests { &[], TraceArgs::default(), false, + false, ); assert_eq!( @@ -261,6 +270,7 @@ mod tests { contracts_data: ContractsData::default(), environment_variables: config.test_runner_config.environment_variables.clone(), experimental_oracles: false, + use_native: false }), output_config: Arc::new(OutputConfig { detailed_resources: true, diff --git a/crates/forge/src/lib.rs b/crates/forge/src/lib.rs index 81fb2004d2..52eefb4fb7 100644 --- a/crates/forge/src/lib.rs +++ b/crates/forge/src/lib.rs @@ -220,6 +220,9 @@ pub struct TestArgs { #[arg(long, default_value_t = false, env = "SNFORGE_EXPERIMENTAL_ORACLES")] experimental_oracles: bool, + #[arg(long, default_value_t = false)] + use_native: bool, + #[command(flatten)] scarb_args: ScarbArgs, } @@ -274,7 +277,6 @@ pub enum ExitStatus { pub fn main_execution(ui: Arc) -> Result { let cli = Cli::parse(); - match cli.subcommand { ForgeSubcommand::Init { name } => { init::init(name.as_str(), &ui)?; diff --git a/crates/forge/src/run_tests/package.rs b/crates/forge/src/run_tests/package.rs index a2677a20e0..52f0bdd20e 100644 --- a/crates/forge/src/run_tests/package.rs +++ b/crates/forge/src/run_tests/package.rs @@ -108,6 +108,7 @@ impl RunForPackageArgs { &args.additional_args, args.trace_args.clone(), args.experimental_oracles, + args.use_native, )); let test_filter = TestsFilter::from_flags( From 3e9019d9174fac45a79dcfd31e660f601f34308f Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Thu, 21 Aug 2025 15:05:00 -0300 Subject: [PATCH 3/9] Add missing use_native values --- crates/forge/test_utils/src/running_tests.rs | 1 + crates/forge/tests/integration/setup_fork.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/crates/forge/test_utils/src/running_tests.rs b/crates/forge/test_utils/src/running_tests.rs index c1609ab26c..5faa132ffb 100644 --- a/crates/forge/test_utils/src/running_tests.rs +++ b/crates/forge/test_utils/src/running_tests.rs @@ -79,6 +79,7 @@ pub fn run_test_case( tracked_resource, environment_variables: test.env().clone(), experimental_oracles: false, + use_native: false, }), output_config: Arc::new(OutputConfig { detailed_resources: false, diff --git a/crates/forge/tests/integration/setup_fork.rs b/crates/forge/tests/integration/setup_fork.rs index eb7e9175e3..6ec50be48b 100644 --- a/crates/forge/tests/integration/setup_fork.rs +++ b/crates/forge/tests/integration/setup_fork.rs @@ -161,6 +161,7 @@ fn fork_aliased_decorator() { tracked_resource: ForgeTrackedResource::CairoSteps, environment_variables: test.env().clone(), experimental_oracles: false, + use_native: false, }), output_config: Arc::new(OutputConfig { detailed_resources: false, @@ -254,6 +255,7 @@ fn fork_aliased_decorator_overrding() { tracked_resource: ForgeTrackedResource::CairoSteps, environment_variables: test.env().clone(), experimental_oracles: false, + use_native: false, }), output_config: Arc::new(OutputConfig { detailed_resources: false, From 991ad448cd80b839370ded97c23fadabb0726cb6 Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Thu, 21 Aug 2025 15:06:49 -0300 Subject: [PATCH 4/9] Remove unwanted change --- crates/forge/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/forge/src/lib.rs b/crates/forge/src/lib.rs index 52eefb4fb7..513c686700 100644 --- a/crates/forge/src/lib.rs +++ b/crates/forge/src/lib.rs @@ -277,6 +277,7 @@ pub enum ExitStatus { pub fn main_execution(ui: Arc) -> Result { let cli = Cli::parse(); + match cli.subcommand { ForgeSubcommand::Init { name } => { init::init(name.as_str(), &ui)?; From d34641c8cd02be4eefa5085a2cd6284728ea9c5b Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Thu, 21 Aug 2025 15:12:28 -0300 Subject: [PATCH 5/9] Add docs --- crates/forge/src/lib.rs | 1 + docs/src/appendix/snforge/test.md | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/crates/forge/src/lib.rs b/crates/forge/src/lib.rs index 513c686700..eeb0daf96c 100644 --- a/crates/forge/src/lib.rs +++ b/crates/forge/src/lib.rs @@ -220,6 +220,7 @@ pub struct TestArgs { #[arg(long, default_value_t = false, env = "SNFORGE_EXPERIMENTAL_ORACLES")] experimental_oracles: bool, + /// Run tests with Native. #[arg(long, default_value_t = false)] use_native: bool, diff --git a/docs/src/appendix/snforge/test.md b/docs/src/appendix/snforge/test.md index ca0709615b..447dc24f8b 100644 --- a/docs/src/appendix/snforge/test.md +++ b/docs/src/appendix/snforge/test.md @@ -80,6 +80,10 @@ Control when colored output is used. Valid values: - `always`: always display colors. - `never`: never display colors. +## `--use-native` + +When used, it makes snforge to use Cairo Native instead of the VM to run the tests. + ## `--detailed-resources` Display additional info about used resources for passed tests. From cd505cdd4b5d56b8b94d3049867c9458c1495dba Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Fri, 22 Aug 2025 17:36:36 -0300 Subject: [PATCH 6/9] Remove trailing underscore from varianles names --- crates/forge-runner/src/running.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/forge-runner/src/running.rs b/crates/forge-runner/src/running.rs index 4bd0721ca8..b623187f0a 100644 --- a/crates/forge-runner/src/running.rs +++ b/crates/forge-runner/src/running.rs @@ -66,8 +66,8 @@ pub use syscall_handler::syscall_handler_offset; #[must_use] pub fn run_test( case: Arc, - _casm_program: Arc, - _aot_executor: Arc, + casm_program: Arc, + aot_executor: Arc, forge_config: Arc, versioned_program_path: Arc, send: Sender<()>, @@ -84,14 +84,14 @@ pub fn run_test( let run_result = if forge_config.test_runner_config.use_native { run_native_test_case( &case, - &_aot_executor, + &aot_executor, &RuntimeConfig::from(&forge_config.test_runner_config), None, ) } else { run_test_case( &case, - &_casm_program, + &casm_program, &RuntimeConfig::from(&forge_config.test_runner_config), None, ) From e5fa3bd789d252e26c30c0827d0f03023de7571e Mon Sep 17 00:00:00 2001 From: DiegoC <90105443+DiegoCivi@users.noreply.github.com> Date: Fri, 22 Aug 2025 17:38:39 -0300 Subject: [PATCH 7/9] Fix CI (#9) * Install LLVM on lint job * Install LLVM on all remaining jobs * Fix clippy errors --- .github/workflows/ci.yml | 154 +++++++++++++++++++++++++++++ crates/forge-runner/src/running.rs | 14 +-- 2 files changed, 161 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0cd500cdde..0b8328b86c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,22 +16,46 @@ jobs: test-forge-unit: name: Test Forge / Unit Tests runs-on: ubuntu-latest + env: + MLIR_SYS_190_PREFIX: /usr/lib/llvm-19/ + LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/ + TABLEGEN_190_PREFIX: /usr/lib/llvm-19/ steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + - name: add llvm deb repository + uses: myci-actions/add-deb-repo@11 + with: + repo: deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main + repo-name: llvm-repo + keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key + - name: Install LLVM + run: sudo apt-get install llvm-19 llvm-19-dev llvm-19-runtime clang-19 clang-tools-19 lld-19 libpolly-19-dev libmlir-19-dev mlir-19-tools - uses: software-mansion/setup-scarb@v1 - uses: software-mansion/setup-universal-sierra-compiler@v1 - run: cargo test --release --lib -p forge build-test-forge-nextest-archive: runs-on: ubuntu-latest + env: + MLIR_SYS_190_PREFIX: /usr/lib/llvm-19/ + LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/ + TABLEGEN_190_PREFIX: /usr/lib/llvm-19/ strategy: fail-fast: false steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + - name: add llvm deb repository + uses: myci-actions/add-deb-repo@11 + with: + repo: deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main + repo-name: llvm-repo + keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key + - name: Install LLVM + run: sudo apt-get install llvm-19 llvm-19-dev llvm-19-runtime clang-19 clang-tools-19 lld-19 libpolly-19-dev libmlir-19-dev mlir-19-tools - name: Install nextest uses: taiki-e/install-action@v2 with: @@ -121,10 +145,22 @@ jobs: test-plugin-checks: name: Test plugin across different scarb versions runs-on: ubuntu-latest + env: + MLIR_SYS_190_PREFIX: /usr/lib/llvm-19/ + LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/ + TABLEGEN_190_PREFIX: /usr/lib/llvm-19/ steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + - name: add llvm deb repository + uses: myci-actions/add-deb-repo@11 + with: + repo: deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main + repo-name: llvm-repo + keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key + - name: Install LLVM + run: sudo apt-get install llvm-19 llvm-19-dev llvm-19-runtime clang-19 clang-tools-19 lld-19 libpolly-19-dev libmlir-19-dev mlir-19-tools - uses: software-mansion/setup-universal-sierra-compiler@v1 - uses: asdf-vm/actions/install@1902764435ca0dd2f3388eea723a4f92a4eb8302 - run: cargo test --package forge e2e::plugin_versions @@ -132,10 +168,22 @@ jobs: test-requirements-check-special-conditions: name: Test requirements check special conditions runs-on: ubuntu-latest + env: + MLIR_SYS_190_PREFIX: /usr/lib/llvm-19/ + LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/ + TABLEGEN_190_PREFIX: /usr/lib/llvm-19/ steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + - name: add llvm deb repository + uses: myci-actions/add-deb-repo@11 + with: + repo: deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main + repo-name: llvm-repo + keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key + - name: Install LLVM + run: sudo apt-get install llvm-19 llvm-19-dev llvm-19-runtime clang-19 clang-tools-19 lld-19 libpolly-19-dev libmlir-19-dev mlir-19-tools - uses: software-mansion/setup-universal-sierra-compiler@v1 - run: cargo test --package forge --features no_scarb_installed --lib compatibility_check::tests::failing_tool_not_installed @@ -153,10 +201,22 @@ jobs: test-interact-with-state: name: Test interact with state runs-on: ubuntu-latest + env: + MLIR_SYS_190_PREFIX: /usr/lib/llvm-19/ + LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/ + TABLEGEN_190_PREFIX: /usr/lib/llvm-19/ steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + - name: add llvm deb repository + uses: myci-actions/add-deb-repo@11 + with: + repo: deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main + repo-name: llvm-repo + keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key + - name: Install LLVM + run: sudo apt-get install llvm-19 llvm-19-dev llvm-19-runtime clang-19 clang-tools-19 lld-19 libpolly-19-dev libmlir-19-dev mlir-19-tools - uses: software-mansion/setup-scarb@v1 - uses: software-mansion/setup-universal-sierra-compiler@v1 @@ -166,19 +226,43 @@ jobs: test-forge-runner: name: Test Forge Runner runs-on: ubuntu-latest + env: + MLIR_SYS_190_PREFIX: /usr/lib/llvm-19/ + LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/ + TABLEGEN_190_PREFIX: /usr/lib/llvm-19/ steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + - name: add llvm deb repository + uses: myci-actions/add-deb-repo@11 + with: + repo: deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main + repo-name: llvm-repo + keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key + - name: Install LLVM + run: sudo apt-get install llvm-19 llvm-19-dev llvm-19-runtime clang-19 clang-tools-19 lld-19 libpolly-19-dev libmlir-19-dev mlir-19-tools - run: cargo test --release -p forge_runner test-cheatnet: name: Test Cheatnet runs-on: ubuntu-latest + env: + MLIR_SYS_190_PREFIX: /usr/lib/llvm-19/ + LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/ + TABLEGEN_190_PREFIX: /usr/lib/llvm-19/ steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + - name: add llvm deb repository + uses: myci-actions/add-deb-repo@11 + with: + repo: deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main + repo-name: llvm-repo + keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key + - name: Install LLVM + run: sudo apt-get install llvm-19 llvm-19-dev llvm-19-runtime clang-19 clang-tools-19 lld-19 libpolly-19-dev libmlir-19-dev mlir-19-tools - uses: software-mansion/setup-scarb@v1 - uses: software-mansion/setup-universal-sierra-compiler@v1 - name: Run Cheatnet tests @@ -187,20 +271,44 @@ jobs: test-data-transformer: name: Test Data Transformer runs-on: ubuntu-latest + env: + MLIR_SYS_190_PREFIX: /usr/lib/llvm-19/ + LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/ + TABLEGEN_190_PREFIX: /usr/lib/llvm-19/ steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + - name: add llvm deb repository + uses: myci-actions/add-deb-repo@11 + with: + repo: deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main + repo-name: llvm-repo + keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key + - name: Install LLVM + run: sudo apt-get install llvm-19 llvm-19-dev llvm-19-runtime clang-19 clang-tools-19 lld-19 libpolly-19-dev libmlir-19-dev mlir-19-tools - name: Run Data Transformer tests run: cargo test --release -p data-transformer test-forge-debugging: name: Test Forge Debugging runs-on: ubuntu-latest + env: + MLIR_SYS_190_PREFIX: /usr/lib/llvm-19/ + LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/ + TABLEGEN_190_PREFIX: /usr/lib/llvm-19/ steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 + - name: add llvm deb repository + uses: myci-actions/add-deb-repo@11 + with: + repo: deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main + repo-name: llvm-repo + keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key + - name: Install LLVM + run: sudo apt-get install llvm-19 llvm-19-dev llvm-19-runtime clang-19 clang-tools-19 lld-19 libpolly-19-dev libmlir-19-dev mlir-19-tools - uses: software-mansion/setup-scarb@v1 - uses: software-mansion/setup-universal-sierra-compiler@58146c4184fa6ec5e8aaf02309ab85e35f782ed0 # v1.0.0 - name: Run Forge Debugging tests @@ -235,12 +343,24 @@ jobs: test-cast: name: Test Cast runs-on: ubuntu-latest + env: + MLIR_SYS_190_PREFIX: /usr/lib/llvm-19/ + LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/ + TABLEGEN_190_PREFIX: /usr/lib/llvm-19/ steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b with: toolchain: stable - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + - name: add llvm deb repository + uses: myci-actions/add-deb-repo@11 + with: + repo: deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main + repo-name: llvm-repo + keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key + - name: Install LLVM + run: sudo apt-get install llvm-19 llvm-19-dev llvm-19-runtime clang-19 clang-tools-19 lld-19 libpolly-19-dev libmlir-19-dev mlir-19-tools - uses: asdf-vm/actions/install@05e0d2ed97b598bfce82fd30daf324ae0c4570e6 - uses: software-mansion/setup-scarb@v1 - uses: software-mansion/setup-universal-sierra-compiler@v1 @@ -250,12 +370,24 @@ jobs: test-conversions: name: Test Conversions runs-on: ubuntu-latest + env: + MLIR_SYS_190_PREFIX: /usr/lib/llvm-19/ + LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/ + TABLEGEN_190_PREFIX: /usr/lib/llvm-19/ steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b with: toolchain: stable - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + - name: add llvm deb repository + uses: myci-actions/add-deb-repo@11 + with: + repo: deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main + repo-name: llvm-repo + keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key + - name: Install LLVM + run: sudo apt-get install llvm-19 llvm-19-dev llvm-19-runtime clang-19 clang-tools-19 lld-19 libpolly-19-dev libmlir-19-dev mlir-19-tools - name: Run tests run: cargo test --release -p conversions @@ -313,12 +445,23 @@ jobs: env: # Make sure CI fails on all warnings - including Clippy lints. RUSTFLAGS: "-Dwarnings" + MLIR_SYS_190_PREFIX: /usr/lib/llvm-19/ + LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/ + TABLEGEN_190_PREFIX: /usr/lib/llvm-19/ steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b with: toolchain: stable - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + - name: add llvm deb repository + uses: myci-actions/add-deb-repo@11 + with: + repo: deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main + repo-name: llvm-repo + keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key + - name: Install LLVM + run: sudo apt-get install llvm-19 llvm-19-dev llvm-19-runtime clang-19 clang-tools-19 lld-19 libpolly-19-dev libmlir-19-dev mlir-19-tools - run: cargo lint build-docs: @@ -326,11 +469,22 @@ jobs: runs-on: ubuntu-latest env: MDBOOK_VERSION: 0.4.52 + MLIR_SYS_190_PREFIX: /usr/lib/llvm-19/ + LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/ + TABLEGEN_190_PREFIX: /usr/lib/llvm-19/ steps: - uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b with: toolchain: stable - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + - name: add llvm deb repository + uses: myci-actions/add-deb-repo@11 + with: + repo: deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main + repo-name: llvm-repo + keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key + - name: Install LLVM + run: sudo apt-get install llvm-19 llvm-19-dev llvm-19-runtime clang-19 clang-tools-19 lld-19 libpolly-19-dev libmlir-19-dev mlir-19-tools - uses: actions/checkout@v4 - uses: software-mansion/setup-scarb@v1 - uses: software-mansion/setup-universal-sierra-compiler@v1 diff --git a/crates/forge-runner/src/running.rs b/crates/forge-runner/src/running.rs index 2794ade08b..a8c0b4048d 100644 --- a/crates/forge-runner/src/running.rs +++ b/crates/forge-runner/src/running.rs @@ -67,7 +67,7 @@ pub use syscall_handler::syscall_handler_offset; pub fn run_test( case: Arc, _casm_program: Arc, - _aot_executor: Arc, + aot_executor: Arc, forge_config: Arc, versioned_program_path: Arc, send: Sender<()>, @@ -83,7 +83,7 @@ pub fn run_test( let run_result = run_native_test_case( &case, - &_aot_executor, + &aot_executor, &RuntimeConfig::from(&forge_config.test_runner_config), None, ); @@ -132,7 +132,7 @@ pub(crate) fn run_fuzz_test( &case, &aot_executor, &RuntimeConfig::from(&forge_config.test_runner_config), - Some(rng), + Some(&rng), ); // TODO: code below is added to fix snforge tests @@ -405,7 +405,7 @@ pub fn run_native_test_case( case: &TestCaseWithResolvedConfig, aot_executor: &AotNativeExecutor, runtime_config: &RuntimeConfig, - fuzzer_rng: Option>>, + fuzzer_rng: Option<&Arc>>, ) -> Result { let function_id = FunctionId::new(case.test_details.sierra_function_id); let call = build_test_entry_point(); @@ -476,10 +476,10 @@ pub fn run_native_test_case( Ok(match result { Ok(result) => RunResult::Completed(Box::new(RunCompleted { status: { - if !result.failure_flag { - RunStatus::Success(result.return_values) - } else { + if result.failure_flag { RunStatus::Panic(result.return_values) + } else { + RunStatus::Success(result.return_values) } }, call_trace, From 180ccce710280fb20715287fac7c708755fa3ce8 Mon Sep 17 00:00:00 2001 From: Julian Gonzalez Calderon Date: Fri, 22 Aug 2025 18:18:44 -0300 Subject: [PATCH 8/9] Add initial structure for a Native compatible runtime (#5) * Add starknet syscall handler dummy implementation * Update run_native_test_case to use forge runtime * Revert "Add starknet syscall handler dummy implementation" This reverts commit 65d8e3018ce25acfa2f34cfa46394894bd2dcd27. * Add NativeExtendedRuntime basic definition * Implement NativeExtensionLogic for ForgeExtension * Use new extension mechanism for executing tests * Add NativeStarknetRuntime * Add runtime to handle methods of runtime extension * Add support for cheatable starknet runtime * Add support for call to blockifier runtime * Take some values from the forge runtime * Handle errors in forge extension cheatcode handling * Reuse CheatcodeHandlingResult --- Cargo.lock | 1 + .../mod.rs | 9 +- .../cheatable_starknet_runtime_extension.rs | 5 + .../forge_runtime_extension/mod.rs | 22 + crates/forge-runner/src/running.rs | 93 +- crates/runtime/Cargo.toml | 1 + crates/runtime/src/lib.rs | 1 + crates/runtime/src/native.rs | 995 ++++++++++++++++++ 8 files changed, 1105 insertions(+), 22 deletions(-) create mode 100644 crates/runtime/src/native.rs diff --git a/Cargo.lock b/Cargo.lock index 08c0bcae5e..80781df346 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5434,6 +5434,7 @@ dependencies = [ "blockifier", "cairo-lang-casm", "cairo-lang-utils", + "cairo-native", "cairo-vm", "conversions", "indoc", diff --git a/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/mod.rs b/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/mod.rs index 6b17e35a13..0d39ddd049 100644 --- a/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/mod.rs +++ b/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/mod.rs @@ -13,6 +13,7 @@ use blockifier::execution::{ }; use cairo_vm::types::relocatable::MaybeRelocatable; use cairo_vm::vm::{errors::hint_errors::HintError, vm_core::VirtualMachine}; +use runtime::native::{NativeExtendedRuntime, NativeExtensionLogic}; use runtime::{ExtendedRuntime, ExtensionLogic, SyscallHandlingResult, SyscallPtrAccess}; use starknet_api::contract_class::EntryPointType; use starknet_api::core::ContractAddress; @@ -27,7 +28,9 @@ use crate::runtime_extensions::call_to_blockifier_runtime_extension::{ rpc::{CallFailure, CallResult}, }; -use super::cheatable_starknet_runtime_extension::CheatableStarknetRuntime; +use super::cheatable_starknet_runtime_extension::{ + CheatableStarknetRuntime, CheatableStarknetRuntimeExtension, +}; use conversions::string::TryFromHexStr; use runtime::starknet::constants::TEST_ADDRESS; @@ -81,6 +84,10 @@ impl<'a> ExtensionLogic for CallToBlockifierExtension<'a> { } } +impl<'a> NativeExtensionLogic for CallToBlockifierExtension<'a> { + type Runtime = &'a mut NativeExtendedRuntime>; +} + trait ExecuteCall where Self: SyscallRequest, diff --git a/crates/cheatnet/src/runtime_extensions/cheatable_starknet_runtime_extension.rs b/crates/cheatnet/src/runtime_extensions/cheatable_starknet_runtime_extension.rs index 5b4f43b63e..0845fc6f46 100644 --- a/crates/cheatnet/src/runtime_extensions/cheatable_starknet_runtime_extension.rs +++ b/crates/cheatnet/src/runtime_extensions/cheatable_starknet_runtime_extension.rs @@ -24,6 +24,7 @@ use cairo_vm::{ vm_core::VirtualMachine, }, }; +use runtime::native::{NativeExtensionLogic, NativeStarknetRuntime}; use runtime::{ExtendedRuntime, ExtensionLogic, StarknetRuntime, SyscallHandlingResult}; use starknet_types_core::felt::Felt; @@ -128,6 +129,10 @@ impl<'a> ExtensionLogic for CheatableStarknetRuntimeExtension<'a> { } } +impl<'a> NativeExtensionLogic for CheatableStarknetRuntimeExtension<'a> { + type Runtime = NativeStarknetRuntime<'a>; +} + pub fn felt_from_ptr_immutable( vm: &VirtualMachine, ptr: &Relocatable, diff --git a/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/mod.rs b/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/mod.rs index 6ac7ade5a8..f103d96f6d 100644 --- a/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/mod.rs +++ b/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/mod.rs @@ -41,6 +41,7 @@ use conversions::serde::deserialize::BufferReader; use conversions::serde::serialize::CairoSerialize; use data_transformer::cairo_types::CairoU256; use rand::prelude::StdRng; +use runtime::native::{NativeExtendedRuntime, NativeExtensionLogic}; use runtime::starknet::constants::TEST_CONTRACT_CLASS_HASH; use runtime::{ CheatcodeHandlingResult, EnhancedHintError, ExtendedRuntime, ExtensionLogic, @@ -56,6 +57,8 @@ use std::collections::HashMap; use std::rc::Rc; use std::sync::{Arc, Mutex}; +use super::call_to_blockifier_runtime_extension::CallToBlockifierExtension; + pub mod cheatcodes; pub mod contracts_data; mod file_operations; @@ -567,6 +570,25 @@ impl<'a> ExtensionLogic for ForgeExtension<'a> { } } +impl<'a> NativeExtensionLogic for ForgeExtension<'a> { + type Runtime = &'a mut NativeExtendedRuntime>; + + fn handle_cheatcode( + &mut self, + selector: Felt, + _input: &[Felt], + _runtime: &mut Self::Runtime, + ) -> anyhow::Result { + let selector_bytes = selector.to_bytes_be(); + let selector = std::str::from_utf8(&selector_bytes)?.trim_start_matches('\0'); + + match selector { + "is_config_mode" => Ok(CheatcodeHandlingResult::from_serializable(false)), + _ => Ok(CheatcodeHandlingResult::Forwarded), + } + } +} + #[derive(CairoSerialize)] enum SignError { InvalidSecretKey, diff --git a/crates/forge-runner/src/running.rs b/crates/forge-runner/src/running.rs index a8c0b4048d..9f2f9b1f4c 100644 --- a/crates/forge-runner/src/running.rs +++ b/crates/forge-runner/src/running.rs @@ -9,12 +9,12 @@ use blockifier::execution::contract_class::TrackedResource; use blockifier::execution::entry_point::EntryPointExecutionContext; use blockifier::execution::entry_point_execution::{prepare_call_arguments, run_entry_point}; use blockifier::execution::errors::EntryPointExecutionError; +use blockifier::execution::native::syscall_handler::NativeSyscallHandler; use blockifier::state::cached_state::CachedState; use cairo_lang_sierra::ids::FunctionId; use cairo_native::Value; use cairo_native::execution_result::ContractExecutionResult; use cairo_native::executor::AotNativeExecutor; -use cairo_native::starknet_stub::StubSyscallHandler; use cairo_vm::Felt252; use cairo_vm::vm::errors::cairo_run_errors::CairoRunError; use cairo_vm::vm::errors::vm_errors::VirtualMachineError; @@ -36,6 +36,7 @@ use execution::finalize_execution; use foundry_ui::UI; use hints::hints_by_representation; use rand::prelude::StdRng; +use runtime::native::{NativeExtendedRuntime, NativeStarknetRuntime}; use runtime::starknet::context::{build_context, set_max_steps}; use runtime::{ExtendedRuntime, StarknetRuntime}; use scarb_oracle_hint_service::OracleHintService; @@ -410,8 +411,6 @@ pub fn run_native_test_case( let function_id = FunctionId::new(case.test_details.sierra_function_id); let call = build_test_entry_point(); - // The state reader is currently unused, as it requires support of the - // custom syscall handler. let mut state_reader = ExtendedStateReader { dict_state_reader: cheatnet_constants::build_testing_state(), fork_state_reader: get_fork_state_reader( @@ -423,21 +422,46 @@ pub fn run_native_test_case( state_reader.predeploy_contracts(); } - // The cheatnet state is currently unused, as it requires support of a - // custom syscall handler let block_info = state_reader.get_block_info()?; + let chain_id = state_reader.get_chain_id()?; + let tracked_resource = TrackedResource::from(runtime_config.tracked_resource); + let mut context = build_context(&block_info, chain_id, &tracked_resource); + + let mut cached_state = CachedState::new(state_reader); + + let starknet_runtime = NativeStarknetRuntime { + syscall_handler: NativeSyscallHandler::new(call.clone(), &mut cached_state, &mut context), + }; + let mut cheatnet_state = CheatnetState { block_info, ..Default::default() }; - // TODO: Implement a proper syscall handler like `run_test_case`. - // Tracking issue: https://github.com/lambdaclass/starknet-foundry/issues/3. - let mut syscall_handler = StubSyscallHandler::default(); + let mut cheatable_starknet_runtime = NativeExtendedRuntime { + extension: CheatableStarknetRuntimeExtension { + cheatnet_state: &mut cheatnet_state, + }, + runtime: starknet_runtime, + }; + + let mut call_to_blockifier_runtime = NativeExtendedRuntime { + extension: CallToBlockifierExtension { + lifetime: &PhantomData, + }, + runtime: &mut cheatable_starknet_runtime, + }; - // To implement fuzzing we need support of the syscall handler. - // Currently the argument is unused. - _ = fuzzer_rng; + let mut forge_runtime = NativeExtendedRuntime { + extension: ForgeExtension { + environment_variables: runtime_config.environment_variables, + contracts_data: runtime_config.contracts_data, + fuzzer_rng, + experimental_oracles_enabled: runtime_config.experimental_oracles, + oracle_hint_service: OracleHintService::default(), + }, + runtime: &mut call_to_blockifier_runtime, + }; // Tests don't have any input arguments. Fuzzing tests actually take the // arguments through cheatcode syscalls. @@ -453,22 +477,49 @@ pub fn run_native_test_case( &function_id, &args, Some(call.initial_gas), - &mut syscall_handler, + &mut forge_runtime, ) { - Ok(result) => ContractExecutionResult::from_execution_result(result), + Ok(result) => { + // TODO: Compute resource usage properly. + // It should be the same as when using the Cairo VM. + + ContractExecutionResult::from_execution_result(result) + } Err(err) => Err(err), }; - let call_trace = cheatnet_state.trace_data.current_call_stack.top(); - let encountered_errors = cheatnet_state.encountered_errors; - let fuzzer_args = cheatnet_state.fuzzer_args; + let encountered_errors = forge_runtime + .runtime + .runtime + .extension + .cheatnet_state + .encountered_errors + .clone(); + + let call_trace_ref = forge_runtime + .runtime + .runtime + .extension + .cheatnet_state + .trace_data + .current_call_stack + .top(); + + let fuzzer_args = forge_runtime + .runtime + .runtime + .extension + .cheatnet_state + .fuzzer_args + .clone(); // TODO: Compute resource usage properly. // It should be the same as when using the Cairo VM. - let used_resources = UsedResources::default(); - let gas_used = GasVector::default(); + let used_resources = Default::default(); + let gas_used = Default::default(); - let fork_data = state_reader + let fork_data = cached_state + .state .fork_state_reader .map(|fork_state_reader| ForkData::new(&fork_state_reader.compiled_contract_class_map())) .unwrap_or_default(); @@ -482,7 +533,7 @@ pub fn run_native_test_case( RunStatus::Success(result.return_values) } }, - call_trace, + call_trace: call_trace_ref, gas_used, used_resources, encountered_errors, @@ -499,7 +550,7 @@ pub fn run_native_test_case( RunResult::Error(RunError { error, - call_trace, + call_trace: call_trace_ref, encountered_errors, fuzzer_args, fork_data, diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml index cd5209e44a..e96008cf5f 100644 --- a/crates/runtime/Cargo.toml +++ b/crates/runtime/Cargo.toml @@ -17,6 +17,7 @@ starknet_api.workspace = true starknet.workspace = true blockifier.workspace = true cairo-vm.workspace = true +cairo-native.workspace = true serde_json.workspace = true serde.workspace = true thiserror.workspace = true diff --git a/crates/runtime/src/lib.rs b/crates/runtime/src/lib.rs index 10c15a4e3d..a58f683d39 100644 --- a/crates/runtime/src/lib.rs +++ b/crates/runtime/src/lib.rs @@ -31,6 +31,7 @@ use std::collections::HashMap; use std::io; use thiserror::Error; +pub mod native; pub mod starknet; mod vm; diff --git a/crates/runtime/src/native.rs b/crates/runtime/src/native.rs new file mode 100644 index 0000000000..2a0f2ac298 --- /dev/null +++ b/crates/runtime/src/native.rs @@ -0,0 +1,995 @@ +use anyhow::anyhow; +use blockifier::execution::native::syscall_handler::NativeSyscallHandler; +use cairo_native::starknet::{ + ExecutionInfo, ExecutionInfoV2, Secp256k1Point, Secp256r1Point, StarknetSyscallHandler, + SyscallResult, U256, +}; +use cairo_vm::Felt252; +use conversions::{ + byte_array::ByteArray, + serde::serialize::{SerializeToFeltVec, raw::RawFeltVec}, +}; + +use crate::CheatcodeHandlingResult; + +pub struct NativeExtendedRuntime { + pub extension: E, + pub runtime: E::Runtime, +} + +pub enum NativeSyscallHandlingResult { + Forwarded, + Handled(T), +} + +pub trait NativeExtensionLogic { + type Runtime: StarknetSyscallHandler; + + fn handle_cheatcode( + &mut self, + _selector: Felt252, + _input: &[Felt252], + _runtime: &mut Self::Runtime, + ) -> anyhow::Result { + Ok(CheatcodeHandlingResult::Forwarded) + } + + fn handle_get_block_hash( + &mut self, + _block_number: u64, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_get_execution_info( + &mut self, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_get_execution_info_v2( + &mut self, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_deploy( + &mut self, + _class_hash: Felt252, + _contract_address_salt: Felt252, + _calldata: &[Felt252], + _deploy_from_zero: bool, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult)>> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_replace_class( + &mut self, + _class_hash: Felt252, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_library_call( + &mut self, + _class_hash: Felt252, + _function_selector: Felt252, + _calldata: &[Felt252], + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult>> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_call_contract( + &mut self, + _address: Felt252, + _entry_point_selector: Felt252, + _calldata: &[Felt252], + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult>> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_storage_read( + &mut self, + _address_domain: u32, + _address: Felt252, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_storage_write( + &mut self, + _address_domain: u32, + _address: Felt252, + _value: Felt252, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_emit_event( + &mut self, + _keys: &[Felt252], + _data: &[Felt252], + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_send_message_to_l1( + &mut self, + _to_address: Felt252, + _payload: &[Felt252], + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_keccak( + &mut self, + _input: &[u64], + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_secp256k1_new( + &mut self, + _x: U256, + _y: U256, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult>> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_secp256k1_add( + &mut self, + _p0: Secp256k1Point, + _p1: Secp256k1Point, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_secp256k1_mul( + &mut self, + _p: Secp256k1Point, + _m: U256, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_secp256k1_get_point_from_x( + &mut self, + _x: U256, + _y_parity: bool, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult>> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_secp256k1_get_xy( + &mut self, + _p: Secp256k1Point, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_secp256r1_new( + &mut self, + _x: U256, + _y: U256, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult>> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_secp256r1_add( + &mut self, + _p0: Secp256r1Point, + _p1: Secp256r1Point, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_secp256r1_mul( + &mut self, + _p: Secp256r1Point, + _m: U256, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_secp256r1_get_point_from_x( + &mut self, + _x: U256, + _y_parity: bool, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult>> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_secp256r1_get_xy( + &mut self, + _p: Secp256r1Point, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_sha256_process_block( + &mut self, + _state: &mut [u32; 8], + _block: &[u32; 16], + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_get_class_hash_at( + &mut self, + _contract_address: Felt252, + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult> { + NativeSyscallHandlingResult::Forwarded + } + + fn handle_meta_tx_v0( + &mut self, + _address: Felt252, + _entry_point_selector: Felt252, + _calldata: &[Felt252], + _signature: &[Felt252], + _remaining_gas: &mut u64, + _runtime: &mut Self::Runtime, + ) -> NativeSyscallHandlingResult>> { + NativeSyscallHandlingResult::Forwarded + } +} + +impl StarknetSyscallHandler for &mut NativeExtendedRuntime { + fn cheatcode(&mut self, selector: Felt252, input: &[Felt252]) -> Vec { + match self + .extension + .handle_cheatcode(selector, input, &mut self.runtime) + { + Ok(CheatcodeHandlingResult::Forwarded) => { + return self.runtime.cheatcode(selector, input); + } + Ok(CheatcodeHandlingResult::Handled(result)) => Ok(RawFeltVec::new(result)), + Err(err) => Err(ByteArray::from(err.to_string().as_str())), + } + .serialize_to_vec() + } + + fn get_block_hash( + &mut self, + block_number: u64, + remaining_gas: &mut u64, + ) -> SyscallResult { + match self + .extension + .handle_get_block_hash(block_number, remaining_gas, &mut self.runtime) + { + NativeSyscallHandlingResult::Forwarded => { + self.runtime.get_block_hash(block_number, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn get_execution_info(&mut self, remaining_gas: &mut u64) -> SyscallResult { + match self + .extension + .handle_get_execution_info(remaining_gas, &mut self.runtime) + { + NativeSyscallHandlingResult::Forwarded => { + self.runtime.get_execution_info(remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn get_execution_info_v2(&mut self, remaining_gas: &mut u64) -> SyscallResult { + match self + .extension + .handle_get_execution_info_v2(remaining_gas, &mut self.runtime) + { + NativeSyscallHandlingResult::Forwarded => { + self.runtime.get_execution_info_v2(remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn deploy( + &mut self, + class_hash: Felt252, + contract_address_salt: Felt252, + calldata: &[Felt252], + deploy_from_zero: bool, + remaining_gas: &mut u64, + ) -> SyscallResult<(Felt252, Vec)> { + match self.extension.handle_deploy( + class_hash, + contract_address_salt, + calldata, + deploy_from_zero, + remaining_gas, + &mut self.runtime, + ) { + NativeSyscallHandlingResult::Forwarded => self.runtime.deploy( + class_hash, + contract_address_salt, + calldata, + deploy_from_zero, + remaining_gas, + ), + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn replace_class(&mut self, class_hash: Felt252, remaining_gas: &mut u64) -> SyscallResult<()> { + match self + .extension + .handle_replace_class(class_hash, remaining_gas, &mut self.runtime) + { + NativeSyscallHandlingResult::Forwarded => { + self.runtime.replace_class(class_hash, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn library_call( + &mut self, + class_hash: Felt252, + function_selector: Felt252, + calldata: &[Felt252], + remaining_gas: &mut u64, + ) -> SyscallResult> { + match self.extension.handle_library_call( + class_hash, + function_selector, + calldata, + remaining_gas, + &mut self.runtime, + ) { + NativeSyscallHandlingResult::Forwarded => { + self.runtime + .library_call(class_hash, function_selector, calldata, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn call_contract( + &mut self, + address: Felt252, + entry_point_selector: Felt252, + calldata: &[Felt252], + remaining_gas: &mut u64, + ) -> SyscallResult> { + match self.extension.handle_call_contract( + address, + entry_point_selector, + calldata, + remaining_gas, + &mut self.runtime, + ) { + NativeSyscallHandlingResult::Forwarded => { + self.runtime + .call_contract(address, entry_point_selector, calldata, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn storage_read( + &mut self, + address_domain: u32, + address: Felt252, + remaining_gas: &mut u64, + ) -> SyscallResult { + match self.extension.handle_storage_read( + address_domain, + address, + remaining_gas, + &mut self.runtime, + ) { + NativeSyscallHandlingResult::Forwarded => { + self.runtime + .storage_read(address_domain, address, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn storage_write( + &mut self, + address_domain: u32, + address: Felt252, + value: Felt252, + remaining_gas: &mut u64, + ) -> SyscallResult<()> { + match self.extension.handle_storage_write( + address_domain, + address, + value, + remaining_gas, + &mut self.runtime, + ) { + NativeSyscallHandlingResult::Forwarded => { + self.runtime + .storage_write(address_domain, address, value, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn emit_event( + &mut self, + keys: &[Felt252], + data: &[Felt252], + remaining_gas: &mut u64, + ) -> SyscallResult<()> { + match self + .extension + .handle_emit_event(keys, data, remaining_gas, &mut self.runtime) + { + NativeSyscallHandlingResult::Forwarded => { + self.runtime.emit_event(keys, data, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn send_message_to_l1( + &mut self, + to_address: Felt252, + payload: &[Felt252], + remaining_gas: &mut u64, + ) -> SyscallResult<()> { + match self.extension.handle_send_message_to_l1( + to_address, + payload, + remaining_gas, + &mut self.runtime, + ) { + NativeSyscallHandlingResult::Forwarded => { + self.runtime + .send_message_to_l1(to_address, payload, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn keccak(&mut self, input: &[u64], remaining_gas: &mut u64) -> SyscallResult { + match self + .extension + .handle_keccak(input, remaining_gas, &mut self.runtime) + { + NativeSyscallHandlingResult::Forwarded => self.runtime.keccak(input, remaining_gas), + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn secp256k1_new( + &mut self, + x: U256, + y: U256, + remaining_gas: &mut u64, + ) -> SyscallResult> { + match self + .extension + .handle_secp256k1_new(x, y, remaining_gas, &mut self.runtime) + { + NativeSyscallHandlingResult::Forwarded => { + self.runtime.secp256k1_new(x, y, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn secp256k1_add( + &mut self, + p0: Secp256k1Point, + p1: Secp256k1Point, + remaining_gas: &mut u64, + ) -> SyscallResult { + match self + .extension + .handle_secp256k1_add(p0, p1, remaining_gas, &mut self.runtime) + { + NativeSyscallHandlingResult::Forwarded => { + self.runtime.secp256k1_add(p0, p1, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn secp256k1_mul( + &mut self, + p: Secp256k1Point, + m: U256, + remaining_gas: &mut u64, + ) -> SyscallResult { + match self + .extension + .handle_secp256k1_mul(p, m, remaining_gas, &mut self.runtime) + { + NativeSyscallHandlingResult::Forwarded => { + self.runtime.secp256k1_mul(p, m, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn secp256k1_get_point_from_x( + &mut self, + x: U256, + y_parity: bool, + remaining_gas: &mut u64, + ) -> SyscallResult> { + match self.extension.handle_secp256k1_get_point_from_x( + x, + y_parity, + remaining_gas, + &mut self.runtime, + ) { + NativeSyscallHandlingResult::Forwarded => { + self.runtime + .secp256k1_get_point_from_x(x, y_parity, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn secp256k1_get_xy( + &mut self, + p: Secp256k1Point, + remaining_gas: &mut u64, + ) -> SyscallResult<(U256, U256)> { + match self + .extension + .handle_secp256k1_get_xy(p, remaining_gas, &mut self.runtime) + { + NativeSyscallHandlingResult::Forwarded => { + self.runtime.secp256k1_get_xy(p, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn secp256r1_new( + &mut self, + x: U256, + y: U256, + remaining_gas: &mut u64, + ) -> SyscallResult> { + match self + .extension + .handle_secp256r1_new(x, y, remaining_gas, &mut self.runtime) + { + NativeSyscallHandlingResult::Forwarded => { + self.runtime.secp256r1_new(x, y, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn secp256r1_add( + &mut self, + p0: Secp256r1Point, + p1: Secp256r1Point, + remaining_gas: &mut u64, + ) -> SyscallResult { + match self + .extension + .handle_secp256r1_add(p0, p1, remaining_gas, &mut self.runtime) + { + NativeSyscallHandlingResult::Forwarded => { + self.runtime.secp256r1_add(p0, p1, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn secp256r1_mul( + &mut self, + p: Secp256r1Point, + m: U256, + remaining_gas: &mut u64, + ) -> SyscallResult { + match self + .extension + .handle_secp256r1_mul(p, m, remaining_gas, &mut self.runtime) + { + NativeSyscallHandlingResult::Forwarded => { + self.runtime.secp256r1_mul(p, m, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn secp256r1_get_point_from_x( + &mut self, + x: U256, + y_parity: bool, + remaining_gas: &mut u64, + ) -> SyscallResult> { + match self.extension.handle_secp256r1_get_point_from_x( + x, + y_parity, + remaining_gas, + &mut self.runtime, + ) { + NativeSyscallHandlingResult::Forwarded => { + self.runtime + .secp256r1_get_point_from_x(x, y_parity, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn secp256r1_get_xy( + &mut self, + p: Secp256r1Point, + remaining_gas: &mut u64, + ) -> SyscallResult<(U256, U256)> { + match self + .extension + .handle_secp256r1_get_xy(p, remaining_gas, &mut self.runtime) + { + NativeSyscallHandlingResult::Forwarded => { + self.runtime.secp256r1_get_xy(p, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn sha256_process_block( + &mut self, + state: &mut [u32; 8], + block: &[u32; 16], + remaining_gas: &mut u64, + ) -> SyscallResult<()> { + match self.extension.handle_sha256_process_block( + state, + block, + remaining_gas, + &mut self.runtime, + ) { + NativeSyscallHandlingResult::Forwarded => { + self.runtime + .sha256_process_block(state, block, remaining_gas) + } + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn get_class_hash_at( + &mut self, + contract_address: Felt252, + remaining_gas: &mut u64, + ) -> SyscallResult { + match self.extension.handle_get_class_hash_at( + contract_address, + remaining_gas, + &mut self.runtime, + ) { + NativeSyscallHandlingResult::Forwarded => self + .runtime + .get_class_hash_at(contract_address, remaining_gas), + NativeSyscallHandlingResult::Handled(result) => result, + } + } + + fn meta_tx_v0( + &mut self, + address: Felt252, + entry_point_selector: Felt252, + calldata: &[Felt252], + signature: &[Felt252], + remaining_gas: &mut u64, + ) -> SyscallResult> { + match self.extension.handle_meta_tx_v0( + address, + entry_point_selector, + calldata, + signature, + remaining_gas, + &mut self.runtime, + ) { + NativeSyscallHandlingResult::Forwarded => self.runtime.meta_tx_v0( + address, + entry_point_selector, + calldata, + signature, + remaining_gas, + ), + NativeSyscallHandlingResult::Handled(result) => result, + } + } +} + +pub struct NativeStarknetRuntime<'a> { + pub syscall_handler: NativeSyscallHandler<'a>, +} + +impl<'a> StarknetSyscallHandler for NativeStarknetRuntime<'a> { + fn get_block_hash( + &mut self, + block_number: u64, + remaining_gas: &mut u64, + ) -> SyscallResult { + (&mut self.syscall_handler).get_block_hash(block_number, remaining_gas) + } + + fn get_execution_info(&mut self, remaining_gas: &mut u64) -> SyscallResult { + (&mut self.syscall_handler).get_execution_info(remaining_gas) + } + + fn get_execution_info_v2(&mut self, remaining_gas: &mut u64) -> SyscallResult { + (&mut self.syscall_handler).get_execution_info_v2(remaining_gas) + } + + fn deploy( + &mut self, + class_hash: Felt252, + contract_address_salt: Felt252, + calldata: &[Felt252], + deploy_from_zero: bool, + remaining_gas: &mut u64, + ) -> SyscallResult<(Felt252, Vec)> { + (&mut self.syscall_handler).deploy( + class_hash, + contract_address_salt, + calldata, + deploy_from_zero, + remaining_gas, + ) + } + + fn replace_class(&mut self, class_hash: Felt252, remaining_gas: &mut u64) -> SyscallResult<()> { + (&mut self.syscall_handler).replace_class(class_hash, remaining_gas) + } + + fn library_call( + &mut self, + class_hash: Felt252, + function_selector: Felt252, + calldata: &[Felt252], + remaining_gas: &mut u64, + ) -> SyscallResult> { + (&mut self.syscall_handler).library_call( + class_hash, + function_selector, + calldata, + remaining_gas, + ) + } + + fn call_contract( + &mut self, + address: Felt252, + entry_point_selector: Felt252, + calldata: &[Felt252], + remaining_gas: &mut u64, + ) -> SyscallResult> { + (&mut self.syscall_handler).call_contract( + address, + entry_point_selector, + calldata, + remaining_gas, + ) + } + + fn storage_read( + &mut self, + address_domain: u32, + address: Felt252, + remaining_gas: &mut u64, + ) -> SyscallResult { + (&mut self.syscall_handler).storage_read(address_domain, address, remaining_gas) + } + + fn storage_write( + &mut self, + address_domain: u32, + address: Felt252, + value: Felt252, + remaining_gas: &mut u64, + ) -> SyscallResult<()> { + (&mut self.syscall_handler).storage_write(address_domain, address, value, remaining_gas) + } + + fn emit_event( + &mut self, + keys: &[Felt252], + data: &[Felt252], + remaining_gas: &mut u64, + ) -> SyscallResult<()> { + (&mut self.syscall_handler).emit_event(keys, data, remaining_gas) + } + + fn send_message_to_l1( + &mut self, + to_address: Felt252, + payload: &[Felt252], + remaining_gas: &mut u64, + ) -> SyscallResult<()> { + (&mut self.syscall_handler).send_message_to_l1(to_address, payload, remaining_gas) + } + + fn keccak(&mut self, input: &[u64], remaining_gas: &mut u64) -> SyscallResult { + (&mut self.syscall_handler).keccak(input, remaining_gas) + } + + fn secp256k1_new( + &mut self, + x: U256, + y: U256, + remaining_gas: &mut u64, + ) -> SyscallResult> { + (&mut self.syscall_handler).secp256k1_new(x, y, remaining_gas) + } + + fn secp256k1_add( + &mut self, + p0: Secp256k1Point, + p1: Secp256k1Point, + remaining_gas: &mut u64, + ) -> SyscallResult { + (&mut self.syscall_handler).secp256k1_add(p0, p1, remaining_gas) + } + + fn secp256k1_mul( + &mut self, + p: Secp256k1Point, + m: U256, + remaining_gas: &mut u64, + ) -> SyscallResult { + (&mut self.syscall_handler).secp256k1_mul(p, m, remaining_gas) + } + + fn secp256k1_get_point_from_x( + &mut self, + x: U256, + y_parity: bool, + remaining_gas: &mut u64, + ) -> SyscallResult> { + (&mut self.syscall_handler).secp256k1_get_point_from_x(x, y_parity, remaining_gas) + } + + fn secp256k1_get_xy( + &mut self, + p: Secp256k1Point, + remaining_gas: &mut u64, + ) -> SyscallResult<(U256, U256)> { + (&mut self.syscall_handler).secp256k1_get_xy(p, remaining_gas) + } + + fn secp256r1_new( + &mut self, + x: U256, + y: U256, + remaining_gas: &mut u64, + ) -> SyscallResult> { + (&mut self.syscall_handler).secp256r1_new(x, y, remaining_gas) + } + + fn secp256r1_add( + &mut self, + p0: Secp256r1Point, + p1: Secp256r1Point, + remaining_gas: &mut u64, + ) -> SyscallResult { + (&mut self.syscall_handler).secp256r1_add(p0, p1, remaining_gas) + } + + fn secp256r1_mul( + &mut self, + p: Secp256r1Point, + m: U256, + remaining_gas: &mut u64, + ) -> SyscallResult { + (&mut self.syscall_handler).secp256r1_mul(p, m, remaining_gas) + } + + fn secp256r1_get_point_from_x( + &mut self, + x: U256, + y_parity: bool, + remaining_gas: &mut u64, + ) -> SyscallResult> { + (&mut self.syscall_handler).secp256r1_get_point_from_x(x, y_parity, remaining_gas) + } + + fn secp256r1_get_xy( + &mut self, + p: Secp256r1Point, + remaining_gas: &mut u64, + ) -> SyscallResult<(U256, U256)> { + (&mut self.syscall_handler).secp256r1_get_xy(p, remaining_gas) + } + + fn sha256_process_block( + &mut self, + state: &mut [u32; 8], + block: &[u32; 16], + remaining_gas: &mut u64, + ) -> SyscallResult<()> { + (&mut self.syscall_handler).sha256_process_block(state, block, remaining_gas) + } + + fn get_class_hash_at( + &mut self, + contract_address: Felt252, + remaining_gas: &mut u64, + ) -> SyscallResult { + (&mut self.syscall_handler).get_class_hash_at(contract_address, remaining_gas) + } + + fn meta_tx_v0( + &mut self, + address: Felt252, + entry_point_selector: Felt252, + calldata: &[Felt252], + signature: &[Felt252], + remaining_gas: &mut u64, + ) -> SyscallResult> { + (&mut self.syscall_handler).meta_tx_v0( + address, + entry_point_selector, + calldata, + signature, + remaining_gas, + ) + } + + fn cheatcode(&mut self, selector: Felt252, input: &[Felt252]) -> Vec { + fn cheatcode(selector: Felt252, _input: &[Felt252]) -> anyhow::Result> { + let selector_bytes = selector.to_bytes_be(); + let selector = std::str::from_utf8(&selector_bytes)?.trim_start_matches('\0'); + Err(anyhow!("invalid selector: {}", selector)) + } + + cheatcode(selector, input).serialize_to_vec() + } +} From 8a23327e579fa72b9a7d5fa2455b11bca8ef944d Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Fri, 22 Aug 2025 18:31:57 -0300 Subject: [PATCH 9/9] Fix error --- crates/forge-runner/src/running.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/forge-runner/src/running.rs b/crates/forge-runner/src/running.rs index 2ddda9b3f6..f06b607499 100644 --- a/crates/forge-runner/src/running.rs +++ b/crates/forge-runner/src/running.rs @@ -459,7 +459,7 @@ pub fn run_native_test_case( extension: ForgeExtension { environment_variables: runtime_config.environment_variables, contracts_data: runtime_config.contracts_data, - fuzzer_rng, + fuzzer_rng: fuzzer_rng.cloned(), experimental_oracles_enabled: runtime_config.experimental_oracles, oracle_hint_service: OracleHintService::default(), },