From 936d258a0fda8adee8568bf6a1f9d5b78f6a8a9c Mon Sep 17 00:00:00 2001 From: Julian Gonzalez Calderon Date: Fri, 7 Jun 2024 16:41:07 -0300 Subject: [PATCH] Migrate Cairo-VM test contracts (#677) * Move cairo vm programs to separate folder * Add cairo vm contracts * Add test contract cases structure * Update fib.cairo to latest version * Implement load cairo program with CairoRunner * Implement run_vm_contract * Add commented cases * Add other cases * Migrate all other tests * Improve code legibility * Fix clippy * Add comment * Add comment * Add assert on failure flag * Update to new corelib * Reorder cases * Ignore failing test * Add better expect messages --- Cargo.lock | 291 +++++++++++++++++- Cargo.toml | 1 + .../contracts/alloc_constant_size.cairo | 24 ++ .../cairo_vm/contracts/alloc_segment.cairo | 23 ++ .../contracts/assert_le_find_small_arcs.cairo | 16 + .../cases/cairo_vm/contracts/dict_test.cairo | 38 +++ tests/cases/cairo_vm/contracts/divmod.cairo | 11 + .../cases/cairo_vm/contracts/factorial.cairo | 13 + .../contracts/felt252_dict_entry_init.cairo | 24 ++ .../contracts/felt252_dict_entry_update.cairo | 18 ++ .../cairo_vm/contracts/felt_252_dict.cairo | 15 + tests/cases/cairo_vm/contracts/fib.cairo | 13 + .../cases/cairo_vm/contracts/field_sqrt.cairo | 20 ++ .../contracts/get_segment_arena_index.cairo | 14 + .../cairo_vm/contracts/init_squash_data.cairo | 20 ++ .../cairo_vm/contracts/linear_split.cairo | 12 + .../cairo_vm/contracts/random_ec_point.cairo | 28 ++ .../contracts/should_skip_squash_loop.cairo | 13 + .../cairo_vm/contracts/test_less_than.cairo | 20 ++ .../cases/cairo_vm/contracts/u128_sqrt.cairo | 19 ++ tests/cases/cairo_vm/contracts/u16_sqrt.cairo | 19 ++ .../cases/cairo_vm/contracts/u256_sqrt.cairo | 27 ++ tests/cases/cairo_vm/contracts/u32_sqrt.cairo | 19 ++ tests/cases/cairo_vm/contracts/u64_sqrt.cairo | 19 ++ tests/cases/cairo_vm/contracts/u8_sqrt.cairo | 19 ++ .../cairo_vm/contracts/uint512_div_mod.cairo | 29 ++ .../cases/cairo_vm/contracts/widemul128.cairo | 17 + .../{ => programs}/array_append.cairo | 0 .../cairo_vm/{ => programs}/array_get.cairo | 0 .../{ => programs}/array_integer_tuple.cairo | 0 .../cairo_vm/{ => programs}/bitwise.cairo | 0 .../cairo_vm/{ => programs}/bytes31_ret.cairo | 0 .../{ => programs}/dict_with_struct.cairo | 0 .../{ => programs}/dictionaries.cairo | 0 .../{ => programs}/ecdsa_recover.cairo | 0 .../cairo_vm/{ => programs}/enum_flow.cairo | 0 .../cairo_vm/{ => programs}/enum_match.cairo | 0 .../cairo_vm/{ => programs}/factorial.cairo | 0 .../cairo_vm/{ => programs}/felt_dict.cairo | 0 .../{ => programs}/felt_dict_squash.cairo | 0 .../cairo_vm/{ => programs}/felt_span.cairo | 0 .../cairo_vm/{ => programs}/fibonacci.cairo | 0 .../cases/cairo_vm/{ => programs}/hello.cairo | 0 .../{ => programs}/my_rectangle.cairo | 0 .../cairo_vm/{ => programs}/null_ret.cairo | 0 .../{ => programs}/nullable_box_vec.cairo | 0 .../{ => programs}/nullable_dict.cairo | 0 tests/cases/cairo_vm/{ => programs}/ops.cairo | 0 .../{ => programs}/pedersen_example.cairo | 0 .../cairo_vm/{ => programs}/poseidon.cairo | 0 .../{ => programs}/poseidon_pedersen.cairo | 0 .../{ => programs}/primitive_types2.cairo | 0 .../cases/cairo_vm/{ => programs}/print.cairo | 0 .../cairo_vm/{ => programs}/recursion.cairo | 0 .../cairo_vm/{ => programs}/sample.cairo | 0 .../{ => programs}/short_string.cairo | 0 .../cairo_vm/{ => programs}/simple.cairo | 0 .../{ => programs}/simple_struct.cairo | 0 .../{ => programs}/struct_span_return.cairo | 0 .../cairo_vm/{ => programs}/tensor_new.cairo | 0 tests/common.rs | 164 +++++++++- tests/tests/cases.rs | 133 +++++--- 62 files changed, 1042 insertions(+), 37 deletions(-) create mode 100644 tests/cases/cairo_vm/contracts/alloc_constant_size.cairo create mode 100644 tests/cases/cairo_vm/contracts/alloc_segment.cairo create mode 100644 tests/cases/cairo_vm/contracts/assert_le_find_small_arcs.cairo create mode 100644 tests/cases/cairo_vm/contracts/dict_test.cairo create mode 100644 tests/cases/cairo_vm/contracts/divmod.cairo create mode 100644 tests/cases/cairo_vm/contracts/factorial.cairo create mode 100644 tests/cases/cairo_vm/contracts/felt252_dict_entry_init.cairo create mode 100644 tests/cases/cairo_vm/contracts/felt252_dict_entry_update.cairo create mode 100644 tests/cases/cairo_vm/contracts/felt_252_dict.cairo create mode 100644 tests/cases/cairo_vm/contracts/fib.cairo create mode 100644 tests/cases/cairo_vm/contracts/field_sqrt.cairo create mode 100644 tests/cases/cairo_vm/contracts/get_segment_arena_index.cairo create mode 100644 tests/cases/cairo_vm/contracts/init_squash_data.cairo create mode 100644 tests/cases/cairo_vm/contracts/linear_split.cairo create mode 100644 tests/cases/cairo_vm/contracts/random_ec_point.cairo create mode 100644 tests/cases/cairo_vm/contracts/should_skip_squash_loop.cairo create mode 100644 tests/cases/cairo_vm/contracts/test_less_than.cairo create mode 100644 tests/cases/cairo_vm/contracts/u128_sqrt.cairo create mode 100644 tests/cases/cairo_vm/contracts/u16_sqrt.cairo create mode 100644 tests/cases/cairo_vm/contracts/u256_sqrt.cairo create mode 100644 tests/cases/cairo_vm/contracts/u32_sqrt.cairo create mode 100644 tests/cases/cairo_vm/contracts/u64_sqrt.cairo create mode 100644 tests/cases/cairo_vm/contracts/u8_sqrt.cairo create mode 100644 tests/cases/cairo_vm/contracts/uint512_div_mod.cairo create mode 100644 tests/cases/cairo_vm/contracts/widemul128.cairo rename tests/cases/cairo_vm/{ => programs}/array_append.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/array_get.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/array_integer_tuple.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/bitwise.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/bytes31_ret.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/dict_with_struct.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/dictionaries.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/ecdsa_recover.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/enum_flow.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/enum_match.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/factorial.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/felt_dict.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/felt_dict_squash.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/felt_span.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/fibonacci.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/hello.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/my_rectangle.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/null_ret.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/nullable_box_vec.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/nullable_dict.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/ops.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/pedersen_example.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/poseidon.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/poseidon_pedersen.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/primitive_types2.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/print.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/recursion.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/sample.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/short_string.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/simple.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/simple_struct.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/struct_span_return.cairo (100%) rename tests/cases/cairo_vm/{ => programs}/tensor_new.cairo (100%) diff --git a/Cargo.lock b/Cargo.lock index 89667766d..7cbc7276e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,23 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "ahash" version = "0.8.11" @@ -349,6 +366,33 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "cairo-felt" version = "0.9.1" @@ -570,7 +614,7 @@ dependencies = [ "cairo-lang-sierra-type-size", "cairo-lang-starknet", "cairo-lang-utils", - "cairo-vm", + "cairo-vm 0.9.2", "itertools 0.11.0", "keccak", "num-bigint", @@ -878,6 +922,7 @@ dependencies = [ "cairo-lang-test-plugin", "cairo-lang-utils", "cairo-native-runtime", + "cairo-vm 1.0.0-rc3", "cc", "clap", "colored", @@ -959,6 +1004,41 @@ dependencies = [ "thiserror-no-std", ] +[[package]] +name = "cairo-vm" +version = "1.0.0-rc3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0fa4c74b86c0f17b58ced4fdab5c1da0a41fb12725ad7601e12bb27d8d90435" +dependencies = [ + "anyhow", + "ark-ff", + "ark-std", + "bincode", + "bitvec", + "cairo-lang-casm", + "cairo-lang-starknet", + "cairo-lang-starknet-classes", + "generic-array", + "hashbrown 0.14.5", + "hex", + "keccak", + "lazy_static", + "nom", + "num-bigint", + "num-integer", + "num-prime", + "num-traits 0.2.19", + "rand", + "serde", + "serde_json", + "sha2", + "sha3", + "starknet-crypto", + "starknet-types-core", + "thiserror-no-std", + "zip", +] + [[package]] name = "camino" version = "1.1.7" @@ -979,6 +1059,11 @@ name = "cc" version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +dependencies = [ + "jobserver", + "libc", + "once_cell", +] [[package]] name = "cexpr" @@ -1022,6 +1107,16 @@ dependencies = [ "half", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -1150,6 +1245,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "convert_case" version = "0.6.0" @@ -1168,6 +1269,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "criterion" version = "0.5.1" @@ -1328,6 +1438,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "derivative" version = "2.2.0" @@ -1552,6 +1671,16 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1892,6 +2021,15 @@ version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.13" @@ -1960,6 +2098,15 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.69" @@ -2023,6 +2170,18 @@ dependencies = [ "regex-automata 0.4.6", ] +[[package]] +name = "lambdaworks-crypto" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb5d4f22241504f7c7b8d2c3a7d7835d7c07117f10bff2a7d96a9ef6ef217c3" +dependencies = [ + "lambdaworks-math", + "serde", + "sha2", + "sha3", +] + [[package]] name = "lambdaworks-math" version = "0.7.0" @@ -2214,6 +2373,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +dependencies = [ + "adler", +] + [[package]] name = "mlir-sys" version = "0.2.2" @@ -2284,6 +2452,12 @@ dependencies = [ "num-traits 0.2.19", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.46" @@ -2458,6 +2632,17 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + [[package]] name = "paste" version = "1.0.15" @@ -2470,6 +2655,18 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -2526,6 +2723,12 @@ dependencies = [ "spki", ] +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + [[package]] name = "plotters" version = "0.3.6" @@ -2560,6 +2763,12 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -3082,6 +3291,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.8" @@ -3253,6 +3473,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4098ac4ad57621cc7ec133b80fe72814d2cc4bee63ca8e7be4450ba6f42a07e8" dependencies = [ + "lambdaworks-crypto", "lambdaworks-math", "num-bigint", "num-integer", @@ -3431,6 +3652,25 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -4001,3 +4241,52 @@ dependencies = [ "quote", "syn 2.0.66", ] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.10+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 8b9522144..d423771dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,6 +109,7 @@ sec1 = { version = "0.7.3", optional = true } serde_json = { version = "1.0.117", optional = true } [dev-dependencies] +cairo-vm = { version = "1.0.0-rc3", features = ["cairo-1-hints"] } cairo-felt = "0.9.1" cairo-lang-runner = "2.6.3" cairo-lang-semantic = { version = "2.6.3", features = ["testing"] } diff --git a/tests/cases/cairo_vm/contracts/alloc_constant_size.cairo b/tests/cases/cairo_vm/contracts/alloc_constant_size.cairo new file mode 100644 index 000000000..b736c1c66 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/alloc_constant_size.cairo @@ -0,0 +1,24 @@ +#[starknet::contract] +mod AllocConstantSizeContract { + use box::BoxTrait; + + + #[storage] + struct Storage {} + + // Calculates fib, but all variables are boxes. + #[external(v0)] + fn fib(self: @ContractState, a: felt252, b: felt252, n: felt252) -> felt252 { + let a = BoxTrait::new(a); + let b = BoxTrait::new(b); + let n = BoxTrait::new(n); + + + let unboxed_n = n.unbox(); + if unboxed_n == 0 { + a.unbox() + } else { + fib(self, b.unbox(), a.unbox() + b.unbox(), unboxed_n - 1, ) + } + } +} diff --git a/tests/cases/cairo_vm/contracts/alloc_segment.cairo b/tests/cases/cairo_vm/contracts/alloc_segment.cairo new file mode 100644 index 000000000..5fef14266 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/alloc_segment.cairo @@ -0,0 +1,23 @@ +#[starknet::contract] +mod AllocSegment { + use dict::{Felt252DictTrait, Felt252DictEntryTrait}; + use traits::Index; + use array::{ArrayTrait, SpanTrait}; + + #[storage] + struct Storage {} + + #[external(v0)] + fn alloc_segment(self: @ContractState) { + // generates hint AllocSegment for felt252 dict when compiled to casm + let mut dict: Felt252Dict = Default::default(); + dict.squash(); + + // generates hint AllocSegment for array + let mut arr: Array = ArrayTrait::new(); + + arr.append(10); + assert(*arr[0] == 10, 'array[0] == 10'); + } +} + diff --git a/tests/cases/cairo_vm/contracts/assert_le_find_small_arcs.cairo b/tests/cases/cairo_vm/contracts/assert_le_find_small_arcs.cairo new file mode 100644 index 000000000..4a45bec38 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/assert_le_find_small_arcs.cairo @@ -0,0 +1,16 @@ +#[starknet::contract] +mod Felt252Dict { + use dict::{felt252_dict_entry_finalize, Felt252DictTrait}; + + #[storage] + struct Storage {} + + #[external(v0)] + fn update_dict(self: @ContractState) { + let mut dict = felt252_dict_new::(); + dict.insert(1, 64); + dict.insert(2, 75); + dict.insert(3, 75); + dict.squash(); + } +} diff --git a/tests/cases/cairo_vm/contracts/dict_test.cairo b/tests/cases/cairo_vm/contracts/dict_test.cairo new file mode 100644 index 000000000..2bb9c8f46 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/dict_test.cairo @@ -0,0 +1,38 @@ +#[starknet::contract] +mod DictTest { + use dict::Felt252DictTrait; + use traits::Index; + + const KEY1: felt252 = 10; + const KEY2: felt252 = 21; + // KEY3 is ~37% * PRIME. + const KEY3: felt252 = + 1343531647004637707094910297222796970954128321746173119103571679493202324940; + // KEY4 and KEY5 are ~92% * PRIME. + const KEY4: felt252 = + 3334603141101959564751596861783084684819726025596122159217101666076094555684; + const KEY5: felt252 = + 3334603141101959564751596861783084684819726025596122159217101666076094555685; + + #[storage] + struct Storage {} + + #[external(v0)] + fn test_dict_big_keys(self: @ContractState) -> felt252 { + let mut dict: Felt252Dict = Default::default(); + + dict.insert(KEY1, 1); + dict.insert(KEY2, 2); + dict.insert(KEY3, 3); + dict.insert(KEY4, 4); + dict.insert(KEY5, 5); + + assert(dict.index(KEY1) == 1, 'KEY1'); + assert(dict.index(KEY2) == 2, 'KEY2'); + assert(dict.index(KEY3) == 3, 'KEY3'); + assert(dict.index(KEY4) == 4, 'KEY4'); + assert(dict.index(KEY5) == 5, 'KEY5'); + + return dict.index(KEY5); + } +} diff --git a/tests/cases/cairo_vm/contracts/divmod.cairo b/tests/cases/cairo_vm/contracts/divmod.cairo new file mode 100644 index 000000000..7c902f060 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/divmod.cairo @@ -0,0 +1,11 @@ +#[starknet::contract] +mod DivModTestContract { + #[storage] + struct Storage {} + + #[external(v0)] + fn div_mod_test(self: @ContractState, x: u8, y: u8) -> u8 { + let (res, _) = integer::u8_safe_divmod(x, integer::u8_as_non_zero(y)); + res + } +} diff --git a/tests/cases/cairo_vm/contracts/factorial.cairo b/tests/cases/cairo_vm/contracts/factorial.cairo new file mode 100644 index 000000000..58579bffd --- /dev/null +++ b/tests/cases/cairo_vm/contracts/factorial.cairo @@ -0,0 +1,13 @@ +#[starknet::contract] +mod Factorial { + #[storage] + struct Storage {} + + #[external(v0)] + fn factorial(self: @ContractState, n: felt252) -> felt252 { + if (n == 0) { + return 1; + } + n * factorial(self, n - 1) + } +} diff --git a/tests/cases/cairo_vm/contracts/felt252_dict_entry_init.cairo b/tests/cases/cairo_vm/contracts/felt252_dict_entry_init.cairo new file mode 100644 index 000000000..69e14f0cc --- /dev/null +++ b/tests/cases/cairo_vm/contracts/felt252_dict_entry_init.cairo @@ -0,0 +1,24 @@ +#[starknet::contract] +mod DictEntryInitTest { + use dict::{Felt252DictTrait, Felt252DictEntryTrait}; + use traits::Index; + use array::{ArrayTrait, SpanTrait}; + + #[storage] + struct Storage {} + + #[external(v0)] + fn felt252_dict_entry_init(self: @ContractState) { + let mut dict: Felt252Dict = Default::default(); + + // Generates hint Felt252DictEntryInit by creating a new dict entry + dict.insert(10, 110); + dict.insert(11, 111); + let val10 = dict.index(10); + let val11 = dict.index(11); + assert(val10 == 110, 'dict[10] == 110'); + assert(val11 == 111, 'dict[11] == 111'); + + dict.squash(); + } +} diff --git a/tests/cases/cairo_vm/contracts/felt252_dict_entry_update.cairo b/tests/cases/cairo_vm/contracts/felt252_dict_entry_update.cairo new file mode 100644 index 000000000..7c840ffce --- /dev/null +++ b/tests/cases/cairo_vm/contracts/felt252_dict_entry_update.cairo @@ -0,0 +1,18 @@ +#[starknet::contract] +mod Felt252Dict { + use dict::{felt252_dict_entry_finalize, Felt252DictTrait}; + + #[storage] + struct Storage {} + + #[external(v0)] + fn update_dict(self: @ContractState) -> (felt252, felt252) { + let mut dict = felt252_dict_new::(); + dict.insert(1, 64); + let val = dict.get(1); + dict.insert(1, 75); + let val2 = dict.get(1); + dict.squash(); + return (val, val2); + } +} diff --git a/tests/cases/cairo_vm/contracts/felt_252_dict.cairo b/tests/cases/cairo_vm/contracts/felt_252_dict.cairo new file mode 100644 index 000000000..1294bfb57 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/felt_252_dict.cairo @@ -0,0 +1,15 @@ +#[starknet::contract] +mod Felt252Dict { + #[storage] + struct Storage {} + + use dict::{felt252_dict_entry_finalize, Felt252DictTrait}; + + /// An external method that requires the `segment_arena` builtin. + #[external(v0)] + fn squash_empty_dict(self: @ContractState) -> bool { + let x = felt252_dict_new::(); + x.squash(); + return true; + } +} diff --git a/tests/cases/cairo_vm/contracts/fib.cairo b/tests/cases/cairo_vm/contracts/fib.cairo new file mode 100644 index 000000000..a0339f686 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/fib.cairo @@ -0,0 +1,13 @@ +#[starknet::contract] +mod Fibonacci { + #[storage] + struct Storage {} + + #[external(v0)] + fn fib(self: @ContractState, a: felt252, b: felt252, n: felt252) -> felt252 { + match n { + 0 => a, + _ => fib(self, b, a + b, n - 1), + } + } +} diff --git a/tests/cases/cairo_vm/contracts/field_sqrt.cairo b/tests/cases/cairo_vm/contracts/field_sqrt.cairo new file mode 100644 index 000000000..ebdd2cfd0 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/field_sqrt.cairo @@ -0,0 +1,20 @@ +#[starknet::contract] +mod FieldSqrt { + #[storage] + struct Storage {} + + use core::traits::Into; + use option::OptionTrait; + use ec::ec_point_from_x_nz; + use ec::ec_point_unwrap; + + #[external(v0)] + fn field_sqrt(self: @ContractState) -> felt252 { + let p_nz = ec_point_from_x_nz(10).unwrap(); + + let (qx, _) = ec_point_unwrap(p_nz); + + assert(qx == 10, 'bad finalize x'); + qx + } +} diff --git a/tests/cases/cairo_vm/contracts/get_segment_arena_index.cairo b/tests/cases/cairo_vm/contracts/get_segment_arena_index.cairo new file mode 100644 index 000000000..d2feae6ca --- /dev/null +++ b/tests/cases/cairo_vm/contracts/get_segment_arena_index.cairo @@ -0,0 +1,14 @@ +#[starknet::contract] +mod SegmentArenaIndex { + #[storage] + struct Storage {} + + use dict::Felt252DictTrait; + + #[external(v0)] + fn test_arena_index(self: @ContractState) -> bool { + let mut dict: Felt252Dict = Default::default(); + dict.squash(); + return true; + } +} diff --git a/tests/cases/cairo_vm/contracts/init_squash_data.cairo b/tests/cases/cairo_vm/contracts/init_squash_data.cairo new file mode 100644 index 000000000..a9fcabe82 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/init_squash_data.cairo @@ -0,0 +1,20 @@ +#[starknet::contract] +mod TestDict { + #[storage] + struct Storage {} + + use dict::Felt252DictTrait; + use nullable::NullableTrait; + use traits::Index; + + #[external(v0)] + fn test_dict_init(self: @ContractState, test_value: felt252) -> felt252 { + let mut dict: Felt252Dict = Default::default(); + + dict.insert(10, test_value); + let (_entry, value) = dict.entry(10); + assert(value == test_value, 'dict[10] == test_value'); + + return test_value; + } +} diff --git a/tests/cases/cairo_vm/contracts/linear_split.cairo b/tests/cases/cairo_vm/contracts/linear_split.cairo new file mode 100644 index 000000000..5ff435b88 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/linear_split.cairo @@ -0,0 +1,12 @@ +#[starknet::contract] +mod LinearSplit { + #[storage] + struct Storage {} + + use integer::u16_try_from_felt252; + + #[external(v0)] + fn cast(self: @ContractState, a: felt252) -> Option { + u16_try_from_felt252(a) + } +} diff --git a/tests/cases/cairo_vm/contracts/random_ec_point.cairo b/tests/cases/cairo_vm/contracts/random_ec_point.cairo new file mode 100644 index 000000000..aa3549a98 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/random_ec_point.cairo @@ -0,0 +1,28 @@ +#[starknet::contract] +mod RandomEcPoint{ + #[storage] + struct Storage {} + + use option::OptionTrait; + use ec::ec_state_init; + use ec::ec_state_add; + use ec::ec_state_try_finalize_nz; + use ec::ec_point_from_x_nz; + use ec::ec_point_unwrap; + + // Test taken from https://github.com/starkware-libs/cairo/blob/a0ead7c0b8e297d281c7213151cd43ac11de5042/corelib/src/test/ec_test.cairo#L17 + #[external(v0)] + fn random_ec_point(self: @ContractState) -> felt252{ + let p_nz = ec_point_from_x_nz(1).unwrap(); + + let mut state = ec_state_init(); + ec_state_add(ref state, p_nz); + + let q = ec_state_try_finalize_nz(state).expect('zero point'); + let (qx, _qy) = ec_point_unwrap(q); + + assert(qx == 1, 'bad finalize x'); + qx + } + +} diff --git a/tests/cases/cairo_vm/contracts/should_skip_squash_loop.cairo b/tests/cases/cairo_vm/contracts/should_skip_squash_loop.cairo new file mode 100644 index 000000000..53554bce5 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/should_skip_squash_loop.cairo @@ -0,0 +1,13 @@ +#[starknet::contract] +mod ShouldSkipSquashLoop { + #[storage] + struct Storage {} + + use dict::Felt252DictTrait; + + #[external(v0)] + fn should_skip_squash_loop(self: @ContractState) { + let x = felt252_dict_new::(); + x.squash(); + } +} diff --git a/tests/cases/cairo_vm/contracts/test_less_than.cairo b/tests/cases/cairo_vm/contracts/test_less_than.cairo new file mode 100644 index 000000000..e391e1070 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/test_less_than.cairo @@ -0,0 +1,20 @@ +#[starknet::contract] +mod TestLessThan { + #[storage] + struct Storage {} + + use integer::upcast; + use integer::downcast; + use option::OptionTrait; + + // tests whether the input (u128) can be downcast to an u8 + #[external(v0)] + fn test_less_than_with_downcast(self: @ContractState, number: u128) -> bool { + let downcast_test: Option = downcast(number); + + match downcast_test { + Option::Some(_) => { return true; }, + Option::None(_) => { return false; } + } + } +} diff --git a/tests/cases/cairo_vm/contracts/u128_sqrt.cairo b/tests/cases/cairo_vm/contracts/u128_sqrt.cairo new file mode 100644 index 000000000..35e2dc089 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/u128_sqrt.cairo @@ -0,0 +1,19 @@ +#[starknet::contract] +mod U128Sqrt { + #[storage] + struct Storage {} + + use integer::u128_sqrt; + use core::traits::Into; + use traits::TryInto; + use option::OptionTrait; + + + #[external(v0)] + fn sqrt(self: @ContractState, num: felt252) -> felt252 { + let num_in_u128: u128 = num.try_into().unwrap(); + let a: u64 = u128_sqrt(num_in_u128); + let to_return: felt252 = a.into(); + to_return + } +} diff --git a/tests/cases/cairo_vm/contracts/u16_sqrt.cairo b/tests/cases/cairo_vm/contracts/u16_sqrt.cairo new file mode 100644 index 000000000..582df5167 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/u16_sqrt.cairo @@ -0,0 +1,19 @@ +#[starknet::contract] +mod U16Sqrt { + #[storage] + struct Storage {} + + use integer::u16_sqrt; + use core::traits::Into; + use traits::TryInto; + use option::OptionTrait; + + + #[external(v0)] + fn sqrt(self: @ContractState, num: felt252) -> felt252 { + let num_in_u16: u16 = num.try_into().unwrap(); + let a: u8 = u16_sqrt(num_in_u16); + let to_return: felt252 = a.into(); + to_return + } +} diff --git a/tests/cases/cairo_vm/contracts/u256_sqrt.cairo b/tests/cases/cairo_vm/contracts/u256_sqrt.cairo new file mode 100644 index 000000000..5bb704260 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/u256_sqrt.cairo @@ -0,0 +1,27 @@ +#[starknet::contract] +mod U256Sqrt { + #[storage] + struct Storage {} + + use integer::u256_sqrt; + use core::traits::Into; + use traits::TryInto; + use option::OptionTrait; + use integer::BoundedInt; + + fn as_u256(a: u128, b: u128) -> u256{ + u256{ + low: a, + high: b + } + } + + #[external(v0)] + fn sqrt(self: @ContractState, num: felt252) -> felt252 { + let num_in_u128: u128 = num.try_into().unwrap(); + let num_in_u256: u256 = as_u256(num_in_u128, 0); + let a: u128 = u256_sqrt(num_in_u256); + let to_return: felt252 = a.into(); + to_return + } +} diff --git a/tests/cases/cairo_vm/contracts/u32_sqrt.cairo b/tests/cases/cairo_vm/contracts/u32_sqrt.cairo new file mode 100644 index 000000000..1778c6ed7 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/u32_sqrt.cairo @@ -0,0 +1,19 @@ +#[starknet::contract] +mod U32Sqrt { + #[storage] + struct Storage {} + + use integer::u32_sqrt; + use core::traits::Into; + use traits::TryInto; + use option::OptionTrait; + + + #[external(v0)] + fn sqrt(self: @ContractState, num: felt252) -> felt252 { + let num_in_u32: u32 = num.try_into().unwrap(); + let a: u16 = u32_sqrt(num_in_u32); + let to_return: felt252 = a.into(); + to_return + } +} diff --git a/tests/cases/cairo_vm/contracts/u64_sqrt.cairo b/tests/cases/cairo_vm/contracts/u64_sqrt.cairo new file mode 100644 index 000000000..fbceac225 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/u64_sqrt.cairo @@ -0,0 +1,19 @@ +#[starknet::contract] +mod U64Sqrt { + #[storage] + struct Storage {} + + use integer::u64_sqrt; + use core::traits::Into; + use traits::TryInto; + use option::OptionTrait; + + + #[external(v0)] + fn sqrt(self: @ContractState, num: felt252) -> felt252 { + let num_in_u64: u64 = num.try_into().unwrap(); + let a: u32 = u64_sqrt(num_in_u64); + let to_return: felt252 = a.into(); + to_return + } +} diff --git a/tests/cases/cairo_vm/contracts/u8_sqrt.cairo b/tests/cases/cairo_vm/contracts/u8_sqrt.cairo new file mode 100644 index 000000000..ec083041e --- /dev/null +++ b/tests/cases/cairo_vm/contracts/u8_sqrt.cairo @@ -0,0 +1,19 @@ +#[starknet::contract] +mod U8Sqrt { + #[storage] + struct Storage {} + + use integer::u8_sqrt; + use core::traits::Into; + use traits::TryInto; + use option::OptionTrait; + + + #[external(v0)] + fn sqrt(self: @ContractState, num: felt252) -> felt252 { + let num_in_u8: u8 = num.try_into().unwrap(); + let a: u8 = u8_sqrt(num_in_u8); + let to_return: felt252 = a.into(); + to_return + } +} diff --git a/tests/cases/cairo_vm/contracts/uint512_div_mod.cairo b/tests/cases/cairo_vm/contracts/uint512_div_mod.cairo new file mode 100644 index 000000000..e68b3525b --- /dev/null +++ b/tests/cases/cairo_vm/contracts/uint512_div_mod.cairo @@ -0,0 +1,29 @@ +#[starknet::contract] +mod UintDivMod { + #[storage] + struct Storage {} + + + use integer::{u512, u512_safe_div_rem_by_u256}; + + #[external(v0)] + fn div_mod(self: @ContractState) -> () { + let zero = u512 { limb0: 0, limb1: 0, limb2: 0, limb3: 0 }; + let one = u512 { limb0: 1, limb1: 0, limb2: 0, limb3: 0 }; + + let (q, r) = u512_safe_div_rem_by_u256(zero, integer::u256_as_non_zero(1)); + assert(q == zero, '0 / 1 != 0'); + assert(r == 0, '0 % 1 != 0'); + + let (q, r) = u512_safe_div_rem_by_u256(one, integer::u256_as_non_zero(1)); + assert(q == one, '1 / 1 != 1'); + assert(r == 0, '1 % 1 != 0'); + + let two = u512 { limb0: 0, limb1: 0, limb2: 0, limb3: 2 }; + let (q, r) = u512_safe_div_rem_by_u256(two, integer::u256_as_non_zero(1)); + assert(q == two, '2/1 != 2'); + assert(r == 0, '2/1 != 0'); + + return (); + } +} diff --git a/tests/cases/cairo_vm/contracts/widemul128.cairo b/tests/cases/cairo_vm/contracts/widemul128.cairo new file mode 100644 index 000000000..918025906 --- /dev/null +++ b/tests/cases/cairo_vm/contracts/widemul128.cairo @@ -0,0 +1,17 @@ +#[starknet::contract] +mod WideMul128TestContract { + #[storage] + struct Storage {} + + + #[external(v0)] + fn wide_mul_128_test(self: @ContractState, a: u128, b: u128) -> bool { + let (res_high, res_low, _) = integer::u128_guarantee_mul(a, b); + // verify that: `a * b = 2**128 * res_high + res_low` + let a_256: u256 = integer::u256 { low: a, high: 0 }; + let b_256: u256 = integer::u256 { low: b, high: 0 }; + let res_high_256: u256 = integer::u256 { low: res_high, high: 0 }; + let res_low_256: u256 = integer::u256 { low: res_low, high: 0 }; + a_256 * b_256 == 0x100000000000000000000000000000000_u256 * res_high_256 + res_low_256 + } +} diff --git a/tests/cases/cairo_vm/array_append.cairo b/tests/cases/cairo_vm/programs/array_append.cairo similarity index 100% rename from tests/cases/cairo_vm/array_append.cairo rename to tests/cases/cairo_vm/programs/array_append.cairo diff --git a/tests/cases/cairo_vm/array_get.cairo b/tests/cases/cairo_vm/programs/array_get.cairo similarity index 100% rename from tests/cases/cairo_vm/array_get.cairo rename to tests/cases/cairo_vm/programs/array_get.cairo diff --git a/tests/cases/cairo_vm/array_integer_tuple.cairo b/tests/cases/cairo_vm/programs/array_integer_tuple.cairo similarity index 100% rename from tests/cases/cairo_vm/array_integer_tuple.cairo rename to tests/cases/cairo_vm/programs/array_integer_tuple.cairo diff --git a/tests/cases/cairo_vm/bitwise.cairo b/tests/cases/cairo_vm/programs/bitwise.cairo similarity index 100% rename from tests/cases/cairo_vm/bitwise.cairo rename to tests/cases/cairo_vm/programs/bitwise.cairo diff --git a/tests/cases/cairo_vm/bytes31_ret.cairo b/tests/cases/cairo_vm/programs/bytes31_ret.cairo similarity index 100% rename from tests/cases/cairo_vm/bytes31_ret.cairo rename to tests/cases/cairo_vm/programs/bytes31_ret.cairo diff --git a/tests/cases/cairo_vm/dict_with_struct.cairo b/tests/cases/cairo_vm/programs/dict_with_struct.cairo similarity index 100% rename from tests/cases/cairo_vm/dict_with_struct.cairo rename to tests/cases/cairo_vm/programs/dict_with_struct.cairo diff --git a/tests/cases/cairo_vm/dictionaries.cairo b/tests/cases/cairo_vm/programs/dictionaries.cairo similarity index 100% rename from tests/cases/cairo_vm/dictionaries.cairo rename to tests/cases/cairo_vm/programs/dictionaries.cairo diff --git a/tests/cases/cairo_vm/ecdsa_recover.cairo b/tests/cases/cairo_vm/programs/ecdsa_recover.cairo similarity index 100% rename from tests/cases/cairo_vm/ecdsa_recover.cairo rename to tests/cases/cairo_vm/programs/ecdsa_recover.cairo diff --git a/tests/cases/cairo_vm/enum_flow.cairo b/tests/cases/cairo_vm/programs/enum_flow.cairo similarity index 100% rename from tests/cases/cairo_vm/enum_flow.cairo rename to tests/cases/cairo_vm/programs/enum_flow.cairo diff --git a/tests/cases/cairo_vm/enum_match.cairo b/tests/cases/cairo_vm/programs/enum_match.cairo similarity index 100% rename from tests/cases/cairo_vm/enum_match.cairo rename to tests/cases/cairo_vm/programs/enum_match.cairo diff --git a/tests/cases/cairo_vm/factorial.cairo b/tests/cases/cairo_vm/programs/factorial.cairo similarity index 100% rename from tests/cases/cairo_vm/factorial.cairo rename to tests/cases/cairo_vm/programs/factorial.cairo diff --git a/tests/cases/cairo_vm/felt_dict.cairo b/tests/cases/cairo_vm/programs/felt_dict.cairo similarity index 100% rename from tests/cases/cairo_vm/felt_dict.cairo rename to tests/cases/cairo_vm/programs/felt_dict.cairo diff --git a/tests/cases/cairo_vm/felt_dict_squash.cairo b/tests/cases/cairo_vm/programs/felt_dict_squash.cairo similarity index 100% rename from tests/cases/cairo_vm/felt_dict_squash.cairo rename to tests/cases/cairo_vm/programs/felt_dict_squash.cairo diff --git a/tests/cases/cairo_vm/felt_span.cairo b/tests/cases/cairo_vm/programs/felt_span.cairo similarity index 100% rename from tests/cases/cairo_vm/felt_span.cairo rename to tests/cases/cairo_vm/programs/felt_span.cairo diff --git a/tests/cases/cairo_vm/fibonacci.cairo b/tests/cases/cairo_vm/programs/fibonacci.cairo similarity index 100% rename from tests/cases/cairo_vm/fibonacci.cairo rename to tests/cases/cairo_vm/programs/fibonacci.cairo diff --git a/tests/cases/cairo_vm/hello.cairo b/tests/cases/cairo_vm/programs/hello.cairo similarity index 100% rename from tests/cases/cairo_vm/hello.cairo rename to tests/cases/cairo_vm/programs/hello.cairo diff --git a/tests/cases/cairo_vm/my_rectangle.cairo b/tests/cases/cairo_vm/programs/my_rectangle.cairo similarity index 100% rename from tests/cases/cairo_vm/my_rectangle.cairo rename to tests/cases/cairo_vm/programs/my_rectangle.cairo diff --git a/tests/cases/cairo_vm/null_ret.cairo b/tests/cases/cairo_vm/programs/null_ret.cairo similarity index 100% rename from tests/cases/cairo_vm/null_ret.cairo rename to tests/cases/cairo_vm/programs/null_ret.cairo diff --git a/tests/cases/cairo_vm/nullable_box_vec.cairo b/tests/cases/cairo_vm/programs/nullable_box_vec.cairo similarity index 100% rename from tests/cases/cairo_vm/nullable_box_vec.cairo rename to tests/cases/cairo_vm/programs/nullable_box_vec.cairo diff --git a/tests/cases/cairo_vm/nullable_dict.cairo b/tests/cases/cairo_vm/programs/nullable_dict.cairo similarity index 100% rename from tests/cases/cairo_vm/nullable_dict.cairo rename to tests/cases/cairo_vm/programs/nullable_dict.cairo diff --git a/tests/cases/cairo_vm/ops.cairo b/tests/cases/cairo_vm/programs/ops.cairo similarity index 100% rename from tests/cases/cairo_vm/ops.cairo rename to tests/cases/cairo_vm/programs/ops.cairo diff --git a/tests/cases/cairo_vm/pedersen_example.cairo b/tests/cases/cairo_vm/programs/pedersen_example.cairo similarity index 100% rename from tests/cases/cairo_vm/pedersen_example.cairo rename to tests/cases/cairo_vm/programs/pedersen_example.cairo diff --git a/tests/cases/cairo_vm/poseidon.cairo b/tests/cases/cairo_vm/programs/poseidon.cairo similarity index 100% rename from tests/cases/cairo_vm/poseidon.cairo rename to tests/cases/cairo_vm/programs/poseidon.cairo diff --git a/tests/cases/cairo_vm/poseidon_pedersen.cairo b/tests/cases/cairo_vm/programs/poseidon_pedersen.cairo similarity index 100% rename from tests/cases/cairo_vm/poseidon_pedersen.cairo rename to tests/cases/cairo_vm/programs/poseidon_pedersen.cairo diff --git a/tests/cases/cairo_vm/primitive_types2.cairo b/tests/cases/cairo_vm/programs/primitive_types2.cairo similarity index 100% rename from tests/cases/cairo_vm/primitive_types2.cairo rename to tests/cases/cairo_vm/programs/primitive_types2.cairo diff --git a/tests/cases/cairo_vm/print.cairo b/tests/cases/cairo_vm/programs/print.cairo similarity index 100% rename from tests/cases/cairo_vm/print.cairo rename to tests/cases/cairo_vm/programs/print.cairo diff --git a/tests/cases/cairo_vm/recursion.cairo b/tests/cases/cairo_vm/programs/recursion.cairo similarity index 100% rename from tests/cases/cairo_vm/recursion.cairo rename to tests/cases/cairo_vm/programs/recursion.cairo diff --git a/tests/cases/cairo_vm/sample.cairo b/tests/cases/cairo_vm/programs/sample.cairo similarity index 100% rename from tests/cases/cairo_vm/sample.cairo rename to tests/cases/cairo_vm/programs/sample.cairo diff --git a/tests/cases/cairo_vm/short_string.cairo b/tests/cases/cairo_vm/programs/short_string.cairo similarity index 100% rename from tests/cases/cairo_vm/short_string.cairo rename to tests/cases/cairo_vm/programs/short_string.cairo diff --git a/tests/cases/cairo_vm/simple.cairo b/tests/cases/cairo_vm/programs/simple.cairo similarity index 100% rename from tests/cases/cairo_vm/simple.cairo rename to tests/cases/cairo_vm/programs/simple.cairo diff --git a/tests/cases/cairo_vm/simple_struct.cairo b/tests/cases/cairo_vm/programs/simple_struct.cairo similarity index 100% rename from tests/cases/cairo_vm/simple_struct.cairo rename to tests/cases/cairo_vm/programs/simple_struct.cairo diff --git a/tests/cases/cairo_vm/struct_span_return.cairo b/tests/cases/cairo_vm/programs/struct_span_return.cairo similarity index 100% rename from tests/cases/cairo_vm/struct_span_return.cairo rename to tests/cases/cairo_vm/programs/struct_span_return.cairo diff --git a/tests/cases/cairo_vm/tensor_new.cairo b/tests/cases/cairo_vm/programs/tensor_new.cairo similarity index 100% rename from tests/cases/cairo_vm/tensor_new.cairo rename to tests/cases/cairo_vm/programs/tensor_new.cairo diff --git a/tests/common.rs b/tests/common.rs index 93c7a5dd2..faedd0b39 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -20,7 +20,12 @@ use cairo_lang_sierra::{ program_registry::ProgramRegistry, }; use cairo_lang_sierra_generator::replace_ids::DebugReplacer; -use cairo_lang_starknet::contract::get_contracts_info; +use cairo_lang_starknet::{ + compile::compile_contract_in_prepared_db, contract::get_contracts_info, starknet_plugin_suite, +}; +use cairo_lang_starknet_classes::{ + casm_contract_class::CasmContractClass, contract_class::ContractClass, +}; use cairo_native::{ context::NativeContext, execution_result::{ContractExecutionResult, ExecutionResult}, @@ -34,6 +39,12 @@ use cairo_native::{ values::JitValue, OptLevel, }; +use cairo_vm::{ + hint_processor::cairo_1_hint_processor::hint_processor::Cairo1HintProcessor, + types::{builtin_name::BuiltinName, layout_name::LayoutName, relocatable::MaybeRelocatable}, + vm::runners::cairo_runner::{CairoArg, CairoRunner, RunResources}, +}; +use itertools::Itertools; use lambdaworks_math::{ field::{ element::FieldElement, fields::montgomery_backed_prime_fields::MontgomeryBackendPrimeField, @@ -175,6 +186,29 @@ pub fn load_cairo_path(program_path: &str) -> (String, Program, SierraCasmRunner (module_name.to_string(), program, runner) } +/// Compiles a cairo starknet contract from the given path +pub fn load_cairo_contract_path(path: &str) -> ContractClass { + let mut db = RootDatabase::builder() + .detect_corelib() + .with_plugin_suite(starknet_plugin_suite()) + .build() + .expect("failed to build database"); + + let main_crate_ids = setup_project(&mut db, Path::new(&path)) + .expect("path should be a valid cairo project or file"); + + compile_contract_in_prepared_db( + &db, + None, + main_crate_ids.clone(), + CompilerConfig { + replace_ids: true, + ..Default::default() + }, + ) + .expect("path should contain a single valid contract") +} + pub fn run_native_program( program: &(String, Program, SierraCasmRunner), entry_point: &str, @@ -230,6 +264,134 @@ pub fn run_vm_program( ) } +/// Runs the contract on the cairo-vm +pub fn run_vm_contract( + cairo_contract: &ContractClass, + entrypoint: usize, + args: &[Felt], +) -> Vec { + let args = args + .iter() + .map(|arg| MaybeRelocatable::Int(*arg)) + .collect_vec(); + + let contract = + CasmContractClass::from_contract_class(cairo_contract.clone(), false, usize::MAX) + .expect("failed to compile sierra contract to casm"); + + let program = contract + .clone() + .try_into() + .expect("failed to extract program from casm contract"); + + // Initialize runner and builtins + let mut runner = CairoRunner::new(&program, LayoutName::all_cairo, false, false) + .expect("failed to build runner"); + + let program_builtins = contract + .entry_points_by_type + .external + .iter() + .find(|e| e.offset == entrypoint) + .expect("given entrypoint index should exist") + .builtins + .iter() + .map(|s| BuiltinName::from_str(s).expect("invalid builtin name")) + .collect_vec(); + runner + .initialize_function_runner_cairo_1(&program_builtins) + .expect("failed to initialize runner"); + + // Initialize implicit Args + let builtins = runner.get_program_builtins(); + let mut implicit_args: Vec = runner + .vm + .get_builtin_runners() + .iter() + .filter(|b| builtins.contains(&b.name())) + .flat_map(|b| b.initial_stack()) + .collect(); + let initial_gas = MaybeRelocatable::from(usize::MAX); + implicit_args.extend([initial_gas]); + let syscall_segment = MaybeRelocatable::from(runner.vm.add_memory_segment()); + implicit_args.extend([syscall_segment]); + + // Load builtin costs + let builtin_costs: Vec = + vec![0.into(), 0.into(), 0.into(), 0.into(), 0.into()]; + let builtin_costs_ptr = runner.vm.add_memory_segment(); + + runner + .vm + .load_data(builtin_costs_ptr, &builtin_costs) + .expect("failed to load builtin costs data to vm"); + + // Load extra data + let core_program_end_ptr = (runner.program_base.expect("program base is missing") + + runner.get_program().data_len()) + .expect("memory pointer overflowed"); + + let program_extra_data: Vec = + vec![0x208B7FFF7FFF7FFE.into(), builtin_costs_ptr.into()]; + runner + .vm + .load_data(core_program_end_ptr, &program_extra_data) + .expect("failed to load extra data to vm"); + + // Load calldata + let calldata_start = runner.vm.add_memory_segment(); + let calldata_end = runner + .vm + .load_data(calldata_start, &args.to_vec()) + .expect("failed to load calldata to vm"); + + // Create entrypoint_args + let mut entrypoint_args: Vec = implicit_args + .iter() + .map(|m| CairoArg::from(m.clone())) + .collect(); + entrypoint_args.extend([ + MaybeRelocatable::from(calldata_start).into(), + MaybeRelocatable::from(calldata_end).into(), + ]); + let entrypoint_args: Vec<&CairoArg> = entrypoint_args.iter().collect(); + + // Run contract entrypoint + let mut hint_processor = Cairo1HintProcessor::new(&contract.hints, RunResources::default()); + runner + .run_from_entrypoint( + entrypoint, + &entrypoint_args, + true, + Some(runner.get_program().data_len() + program_extra_data.len()), + &mut hint_processor, + ) + .expect("failed to execute contract"); + + // Extract return values + let return_values = runner + .vm + .get_return_values(5) + .expect("failed to extract return values"); + let retdata_start = return_values[3] + .get_relocatable() + .expect("failed to get return data start"); + let retdata_end = return_values[4] + .get_relocatable() + .expect("failed to get return data end"); + + runner + .vm + .get_integer_range( + retdata_start, + (retdata_end - retdata_start).expect("return data length should not be negative"), + ) + .expect("failed to access vm memory") + .iter() + .map(|c| c.clone().into_owned()) + .collect_vec() +} + #[track_caller] pub fn compare_inputless_program(program_path: &str) { let program: (String, Program, SierraCasmRunner) = load_cairo_path(program_path); diff --git a/tests/tests/cases.rs b/tests/tests/cases.rs index ff85fbe3a..a5193ea0a 100644 --- a/tests/tests/cases.rs +++ b/tests/tests/cases.rs @@ -1,4 +1,10 @@ -use crate::common::compare_inputless_program; +use crate::common::{ + compare_inputless_program, load_cairo_contract_path, run_native_starknet_contract, + run_vm_contract, +}; +use cairo_native::starknet::DummySyscallHandler; +use itertools::Itertools; +use pretty_assertions_sorted::assert_eq_sorted; use test_case::test_case; // Test cases for programs without input, it checks the outputs are correct automatically. @@ -105,40 +111,97 @@ use test_case::test_case; #[test_case("tests/cases/nullable/test_nullable.cairo")] // Programs copied from the cairo-vm // https://github.com/lambdaclass/cairo-vm/tree/main/cairo_programs/cairo-1-programs -#[test_case("tests/cases/cairo_vm/array_append.cairo")] -#[test_case("tests/cases/cairo_vm/array_get.cairo")] -#[test_case("tests/cases/cairo_vm/array_integer_tuple.cairo")] -#[test_case("tests/cases/cairo_vm/bitwise.cairo")] -#[test_case("tests/cases/cairo_vm/bytes31_ret.cairo")] -#[test_case("tests/cases/cairo_vm/dict_with_struct.cairo")] -#[test_case("tests/cases/cairo_vm/dictionaries.cairo")] -#[test_case("tests/cases/cairo_vm/ecdsa_recover.cairo")] -#[test_case("tests/cases/cairo_vm/enum_flow.cairo")] -#[test_case("tests/cases/cairo_vm/enum_match.cairo")] -#[test_case("tests/cases/cairo_vm/factorial.cairo")] -#[test_case("tests/cases/cairo_vm/felt_dict.cairo")] -#[test_case("tests/cases/cairo_vm/felt_dict_squash.cairo")] -#[test_case("tests/cases/cairo_vm/felt_span.cairo")] -#[test_case("tests/cases/cairo_vm/fibonacci.cairo")] -#[test_case("tests/cases/cairo_vm/hello.cairo")] -#[test_case("tests/cases/cairo_vm/my_rectangle.cairo")] -#[test_case("tests/cases/cairo_vm/null_ret.cairo")] -#[test_case("tests/cases/cairo_vm/nullable_box_vec.cairo")] -#[test_case("tests/cases/cairo_vm/nullable_dict.cairo")] -#[test_case("tests/cases/cairo_vm/ops.cairo")] -#[test_case("tests/cases/cairo_vm/pedersen_example.cairo")] -#[test_case("tests/cases/cairo_vm/poseidon.cairo")] -#[test_case("tests/cases/cairo_vm/poseidon_pedersen.cairo")] -#[test_case("tests/cases/cairo_vm/primitive_types2.cairo")] -#[test_case("tests/cases/cairo_vm/print.cairo")] -#[test_case("tests/cases/cairo_vm/recursion.cairo")] -#[test_case("tests/cases/cairo_vm/sample.cairo")] -#[test_case("tests/cases/cairo_vm/short_string.cairo")] -#[test_case("tests/cases/cairo_vm/simple.cairo")] -#[test_case("tests/cases/cairo_vm/simple_struct.cairo")] -#[test_case("tests/cases/cairo_vm/struct_span_return.cairo")] -#[test_case("tests/cases/cairo_vm/tensor_new.cairo")] +#[test_case("tests/cases/cairo_vm/programs/array_append.cairo")] +#[test_case("tests/cases/cairo_vm/programs/array_get.cairo")] +#[test_case("tests/cases/cairo_vm/programs/array_integer_tuple.cairo")] +#[test_case("tests/cases/cairo_vm/programs/bitwise.cairo")] +#[test_case("tests/cases/cairo_vm/programs/bytes31_ret.cairo")] +#[test_case("tests/cases/cairo_vm/programs/dict_with_struct.cairo")] +#[test_case("tests/cases/cairo_vm/programs/dictionaries.cairo")] +#[test_case("tests/cases/cairo_vm/programs/ecdsa_recover.cairo")] +#[test_case("tests/cases/cairo_vm/programs/enum_flow.cairo")] +#[test_case("tests/cases/cairo_vm/programs/enum_match.cairo")] +#[test_case("tests/cases/cairo_vm/programs/factorial.cairo")] +#[test_case("tests/cases/cairo_vm/programs/felt_dict.cairo")] +#[test_case("tests/cases/cairo_vm/programs/felt_dict_squash.cairo")] +#[test_case("tests/cases/cairo_vm/programs/felt_span.cairo")] +#[test_case("tests/cases/cairo_vm/programs/fibonacci.cairo")] +#[test_case("tests/cases/cairo_vm/programs/hello.cairo")] +#[test_case("tests/cases/cairo_vm/programs/my_rectangle.cairo")] +#[test_case("tests/cases/cairo_vm/programs/null_ret.cairo")] +#[test_case("tests/cases/cairo_vm/programs/nullable_box_vec.cairo")] +#[test_case("tests/cases/cairo_vm/programs/nullable_dict.cairo")] +#[test_case("tests/cases/cairo_vm/programs/ops.cairo")] +#[test_case("tests/cases/cairo_vm/programs/pedersen_example.cairo")] +#[test_case("tests/cases/cairo_vm/programs/poseidon.cairo")] +#[test_case("tests/cases/cairo_vm/programs/poseidon_pedersen.cairo")] +#[test_case("tests/cases/cairo_vm/programs/primitive_types2.cairo")] +#[test_case("tests/cases/cairo_vm/programs/print.cairo")] +#[test_case("tests/cases/cairo_vm/programs/recursion.cairo")] +#[test_case("tests/cases/cairo_vm/programs/sample.cairo")] +#[test_case("tests/cases/cairo_vm/programs/short_string.cairo")] +#[test_case("tests/cases/cairo_vm/programs/simple.cairo")] +#[test_case("tests/cases/cairo_vm/programs/simple_struct.cairo")] +#[test_case("tests/cases/cairo_vm/programs/struct_span_return.cairo")] +#[test_case("tests/cases/cairo_vm/programs/tensor_new.cairo")] #[test_case("tests/cases/brainfuck.cairo")] -fn test_cases(program_path: &str) { +fn test_program_cases(program_path: &str) { compare_inputless_program(program_path) } + +// Contracts copied from the cairo-vm +// https://github.com/lambdaclass/cairo-vm/tree/main/cairo_programs/cairo-1-contracts +#[test_case("tests/cases/cairo_vm/contracts/alloc_segment.cairo", &[])] +#[test_case("tests/cases/cairo_vm/contracts/assert_le_find_small_arcs.cairo", &[])] +#[test_case("tests/cases/cairo_vm/contracts/dict_test.cairo", &[])] +#[test_case("tests/cases/cairo_vm/contracts/divmod.cairo", &[100, 10])] +#[test_case("tests/cases/cairo_vm/contracts/factorial.cairo", &[10])] +#[test_case("tests/cases/cairo_vm/contracts/felt252_dict_entry_init.cairo", &[])] +#[test_case("tests/cases/cairo_vm/contracts/felt252_dict_entry_update.cairo", &[])] +#[test_case("tests/cases/cairo_vm/contracts/felt_252_dict.cairo", &[])] +#[test_case("tests/cases/cairo_vm/contracts/fib.cairo", &[10, 10, 10])] +#[test_case("tests/cases/cairo_vm/contracts/get_segment_arena_index.cairo", &[])] +#[test_case("tests/cases/cairo_vm/contracts/init_squash_data.cairo", &[10])] +#[test_case("tests/cases/cairo_vm/contracts/linear_split.cairo", &[10])] +#[test_case("tests/cases/cairo_vm/contracts/should_skip_squash_loop.cairo", &[])] +#[test_case("tests/cases/cairo_vm/contracts/test_less_than.cairo", &[10])] +#[test_case("tests/cases/cairo_vm/contracts/u128_sqrt.cairo", &[100])] +#[test_case("tests/cases/cairo_vm/contracts/u16_sqrt.cairo", &[100])] +#[test_case("tests/cases/cairo_vm/contracts/u256_sqrt.cairo", &[100])] +#[test_case("tests/cases/cairo_vm/contracts/u32_sqrt.cairo", &[100])] +#[test_case("tests/cases/cairo_vm/contracts/u64_sqrt.cairo", &[100])] +#[test_case("tests/cases/cairo_vm/contracts/u8_sqrt.cairo", &[100])] +#[test_case("tests/cases/cairo_vm/contracts/uint512_div_mod.cairo", &[])] +#[test_case("tests/cases/cairo_vm/contracts/widemul128.cairo", &[100, 100])] +#[test_case("tests/cases/cairo_vm/contracts/field_sqrt.cairo", &[])] +#[test_case("tests/cases/cairo_vm/contracts/random_ec_point.cairo", &[])] +// #[test_case("tests/cases/cairo_vm/contracts/alloc_constant_size.cairo", &[10, 10, 10])] +fn test_contract_cases(program_path: &str, args: &[u128]) { + let args = args.iter().map(|&arg| arg.into()).collect_vec(); + + let contract = load_cairo_contract_path(program_path); + let entrypoint = contract + .entry_points_by_type + .external + .first() + .expect("contract should have at least one external entrypoint") + .function_idx; + + let program = contract + .extract_sierra_program() + .expect("contract bytes should be a valid sierra program"); + + let native_result = + run_native_starknet_contract(&program, entrypoint, &args, DummySyscallHandler); + + assert!( + !native_result.failure_flag, + "native contract execution failed" + ); + + let native_output = native_result.return_values; + + let vm_output = run_vm_contract(&contract, entrypoint, &args); + + assert_eq_sorted!(vm_output, native_output); +}