From 39a6a6f79ed317dd1f60c6ae00a7a0e12433459d Mon Sep 17 00:00:00 2001 From: Guy Nir Date: Sun, 29 Sep 2024 11:41:01 +0300 Subject: [PATCH] feat: broadcast stream messages --- Cargo.lock | 145 +++++++++ config/mempool/default_config.json | 5 + .../cairo1/compiled/test_contract.casm.json | 274 +++++++++++++++++- .../cairo1/test_contract.cairo | 35 +++ .../blockifier/transaction_executor_test.rs | 1 + crates/blockifier/src/fee/fee_utils.rs | 3 +- crates/blockifier/src/fee/resources.rs | 24 ++ .../blockifier/src/test_utils/struct_impls.rs | 8 +- .../src/transaction/execution_flavors_test.rs | 8 +- .../src/transaction/post_execution_test.rs | 1 + .../blockifier/src/transaction/test_utils.rs | 19 ++ .../block_700000/tx_hashes_block_700000.json | 12 + .../raw_rpc_json_objects/block_header.json | 35 +++ .../deprecated_contract_class.json | 122 ++++++++ .../raw_rpc_json_objects/transactions.json | 73 +++++ .../src/state_reader.rs | 8 + .../src/state_reader/compile.rs | 105 +++++++ .../src/state_reader/raw_rpc_json_test.rs | 67 +++++ .../src/state_reader/rpc_https_test.rs | 90 ++++++ .../src/state_reader/test_state_reader.rs | 181 ++++++++++++ .../src/state_reader/utils.rs | 94 ++++++ crates/gateway/src/rpc_state_reader_test.rs | 4 + crates/mempool/src/mempool_test.rs | 2 + crates/papyrus_network/src/lib.rs | 2 +- crates/papyrus_network/src/utils.rs | 2 +- .../papyrus_consensus/src/stream_handler.rs | 68 ++++- .../src/stream_handler_test.rs | 25 +- crates/starknet_api/src/transaction.rs | 6 + .../src/integration_test_utils.rs | 2 + crates/tests-integration/src/state_reader.rs | 4 + 30 files changed, 1388 insertions(+), 37 deletions(-) create mode 100644 crates/blockifier_regression_test/resources/block_700000/tx_hashes_block_700000.json create mode 100644 crates/blockifier_regression_test/resources/raw_rpc_json_objects/block_header.json create mode 100644 crates/blockifier_regression_test/resources/raw_rpc_json_objects/deprecated_contract_class.json create mode 100644 crates/blockifier_regression_test/resources/raw_rpc_json_objects/transactions.json create mode 100644 crates/blockifier_regression_test/src/state_reader.rs create mode 100644 crates/blockifier_regression_test/src/state_reader/compile.rs create mode 100644 crates/blockifier_regression_test/src/state_reader/raw_rpc_json_test.rs create mode 100644 crates/blockifier_regression_test/src/state_reader/rpc_https_test.rs create mode 100644 crates/blockifier_regression_test/src/state_reader/test_state_reader.rs create mode 100644 crates/blockifier_regression_test/src/state_reader/utils.rs diff --git a/Cargo.lock b/Cargo.lock index f07ae46094..0a2a648df5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -596,6 +596,20 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "aquamarine" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21cc1548309245035eb18aa7f0967da6bc65587005170c56e6ef2788a4cf3f4e" +dependencies = [ + "include_dir", + "itertools 0.10.5", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "arc-swap" version = "1.7.1" @@ -3513,6 +3527,26 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "env_filter" version = "0.1.2" @@ -6178,6 +6212,20 @@ dependencies = [ "semver 1.0.23", ] +[[package]] +name = "llvm-sys" +version = "181.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320f9d2723c97d4b78f9190a61ed25cc7cfbe456668c08e6e7dd8e50ceb8500" +dependencies = [ + "anyhow", + "cc", + "lazy_static", + "libc", + "regex-lite", + "semver 1.0.23", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -6487,6 +6535,15 @@ dependencies = [ "bindgen 0.69.4", ] +[[package]] +name = "mlir-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1b5806a63bc959cd5c4e5db8cadd20e40045d41969d325132748db8af11b7f" +dependencies = [ + "bindgen 0.69.4", +] + [[package]] name = "mockall" version = "0.12.1" @@ -8159,6 +8216,15 @@ dependencies = [ "elliptic-curve", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "primitive-types" version = "0.12.2" @@ -9847,6 +9913,16 @@ dependencies = [ "wasm-bindgen", ] +[[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.13.2" @@ -10774,6 +10850,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "tblgen-alt" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ae726d43658a13a9cd479de814be1311fea69236cd821e931a4fb9ca4d70e50" +dependencies = [ + "bindgen 0.69.4", + "cc", + "paste", + "thiserror", +] + [[package]] name = "tempfile" version = "3.13.0" @@ -11466,6 +11554,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[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.1.11" @@ -11958,6 +12052,21 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -12040,6 +12149,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -12058,6 +12173,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -12082,6 +12203,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -12100,6 +12227,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -12118,6 +12251,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -12136,6 +12275,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" diff --git a/config/mempool/default_config.json b/config/mempool/default_config.json index ce15f1730c..3141c4b023 100644 --- a/config/mempool/default_config.json +++ b/config/mempool/default_config.json @@ -139,6 +139,11 @@ "privacy": "Public", "value": "Local" }, + "components.consensus_manager.execution_mode": { + "description": "The component execution mode.", + "privacy": "Public", + "value": "Local" + }, "components.consensus_manager.local_config.#is_none": { "description": "Flag for an optional field.", "privacy": "TemporaryValue", diff --git a/crates/blockifier/feature_contracts/cairo1/compiled/test_contract.casm.json b/crates/blockifier/feature_contracts/cairo1/compiled/test_contract.casm.json index 8ae97e8bc4..36c44aa19a 100644 --- a/crates/blockifier/feature_contracts/cairo1/compiled/test_contract.casm.json +++ b/crates/blockifier/feature_contracts/cairo1/compiled/test_contract.casm.json @@ -7349,6 +7349,274 @@ "0x482480017ff78000", "0x1", "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x43616c6c436f6e7472616374", + "0x400280007ff97fff", + "0x400380017ff97ff8", + "0x400380027ff97ffa", + "0x400380037ff97ffb", + "0x400380047ff97ffc", + "0x400380057ff97ffd", + "0x480280077ff98000", + "0x20680017fff7fff", + "0x1c", + "0x40780017fff7fff", + "0xc", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3", + "0x400080007ffe7fff", + "0x480680017fff8000", + "0x0", + "0x400080017ffd7fff", + "0x480680017fff8000", + "0x457870656374656420726576657274", + "0x400080027ffc7fff", + "0x480680017fff8000", + "0xf", + "0x400080037ffb7fff", + "0x480a7ff77fff8000", + "0x480280067ff98000", + "0x482680017ff98000", + "0xa", + "0x480680017fff8000", + "0x1", + "0x48127ff77fff8000", + "0x482480017ff68000", + "0x4", + "0x208b7fff7fff7ffe", + "0x480280087ff98000", + "0x480280097ff98000", + "0x480280067ff98000", + "0x482680017ff98000", + "0xa", + "0x48307ffc80007ffd", + "0x20680017fff7fff", + "0x4", + "0x10780017fff7fff", + "0x51", + "0x4824800180007ffc", + "0x1", + "0x480080007fff8000", + "0x4824800180007fff", + "0x454e545259504f494e545f4641494c4544", + "0x20680017fff7fff", + "0x3a", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1275130f95dda36bcbb6e9d28796c1d7e10b6e9fd5ed083e0ede4b12f613528", + "0x480680017fff8000", + "0x53746f7261676552656164", + "0x400080007ff87fff", + "0x400080017ff87ff7", + "0x400080027ff87ffd", + "0x400080037ff87ffe", + "0x480080057ff88000", + "0x20680017fff7fff", + "0x22", + "0x480080067ff78000", + "0x480080047ff68000", + "0x482480017ff58000", + "0x7", + "0x20680017fff7ffd", + "0xe", + "0x40780017fff7fff", + "0x2", + "0x480a7ff77fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x76616c7565732073686f756c64206e6f74206368616e67652e", + "0x400080007ffe7fff", + "0x480a7ff77fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x5", + "0x480a7ff77fff8000", + "0x480080047ff18000", + "0x482480017ff08000", + "0x8", + "0x480680017fff8000", + "0x1", + "0x480080067fee8000", + "0x480080077fed8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x7", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x556e6578706563746564206572726f72", + "0x400080007ffe7fff", + "0x480a7ff77fff8000", + "0x48127ff07fff8000", + "0x48127ff07fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xa", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x4f7074696f6e3a3a756e77726170206661696c65642e", + "0x400080007ffe7fff", + "0x480a7ff77fff8000", + "0x48127ff07fff8000", + "0x48127ff07fff8000", + "0x480680017fff8000", + "0x1", + "0x48127ffa7fff8000", + "0x482480017ff98000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x0", + "0x400080007ffe7fff", + "0x48127ffe7fff8000", + "0x482480017ffd8000", + "0x1", + "0x480680017fff8000", + "0x456d69744576656e74", + "0x400280007ffc7fff", + "0x400380017ffc7ffb", + "0x400280027ffc7ffd", + "0x400280037ffc7ffe", + "0x400280047ffc7ffd", + "0x400280057ffc7ffe", + "0x480280077ffc8000", + "0x20680017fff7fff", + "0x62", + "0x480280067ffc8000", + "0x480680017fff8000", + "0x5265706c616365436c617373", + "0x400280087ffc7fff", + "0x400280097ffc7ffe", + "0x4003800a7ffc7ffd", + "0x4802800c7ffc8000", + "0x20680017fff7fff", + "0x4e", + "0x4802800b7ffc8000", + "0x480680017fff8000", + "0x11", + "0x480680017fff8000", + "0x53656e644d657373616765546f4c31", + "0x4002800d7ffc7fff", + "0x4002800e7ffc7ffd", + "0x4002800f7ffc7ffe", + "0x400280107ffc7ff6", + "0x400280117ffc7ff7", + "0x480280137ffc8000", + "0x20680017fff7fff", + "0x36", + "0x480280127ffc8000", + "0x480680017fff8000", + "0x0", + "0x480680017fff8000", + "0x1275130f95dda36bcbb6e9d28796c1d7e10b6e9fd5ed083e0ede4b12f613528", + "0x480680017fff8000", + "0x11", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400280147ffc7fff", + "0x400280157ffc7ffb", + "0x400280167ffc7ffc", + "0x400280177ffc7ffd", + "0x400280187ffc7ffe", + "0x4802801a7ffc8000", + "0x20680017fff7fff", + "0x1a", + "0x40780017fff7fff", + "0x1", + "0x480680017fff8000", + "0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3", + "0x400080007ffe7fff", + "0x480680017fff8000", + "0x0", + "0x400080017ffd7fff", + "0x480680017fff8000", + "0x746573745f7265766572745f68656c706572", + "0x400080027ffc7fff", + "0x480680017fff8000", + "0x12", + "0x400080037ffb7fff", + "0x480a7ffa7fff8000", + "0x480280197ffc8000", + "0x482680017ffc8000", + "0x1b", + "0x480680017fff8000", + "0x1", + "0x48127ff77fff8000", + "0x482480017ff68000", + "0x4", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x5", + "0x480a7ffa7fff8000", + "0x480280197ffc8000", + "0x482680017ffc8000", + "0x1d", + "0x480680017fff8000", + "0x1", + "0x4802801b7ffc8000", + "0x4802801c7ffc8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xb", + "0x480a7ffa7fff8000", + "0x480280127ffc8000", + "0x482680017ffc8000", + "0x16", + "0x480680017fff8000", + "0x1", + "0x480280147ffc8000", + "0x480280157ffc8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0xf", + "0x480a7ffa7fff8000", + "0x4802800b7ffc8000", + "0x482680017ffc8000", + "0xf", + "0x480680017fff8000", + "0x1", + "0x4802800d7ffc8000", + "0x4802800e7ffc8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x12", + "0x480a7ffa7fff8000", + "0x480280067ffc8000", + "0x482680017ffc8000", + "0xa", + "0x480680017fff8000", + "0x1", + "0x480280087ffc8000", + "0x480280097ffc8000", + "0x208b7fff7fff7ffe", "0xa0680017fff8000", "0x7", "0x482680017ff98000", @@ -21817,8 +22085,8 @@ "TestLessThan": { "lhs": { "Deref": { - "register": "FP", - "offset": 1 + "register": "AP", + "offset": -1 } }, "rhs": { @@ -24406,7 +24674,7 @@ ] ], [ - 5475, + 5936, [ { "AllocSegment": { diff --git a/crates/blockifier/feature_contracts/cairo1/test_contract.cairo b/crates/blockifier/feature_contracts/cairo1/test_contract.cairo index d87a76efda..0b625642a8 100644 --- a/crates/blockifier/feature_contracts/cairo1/test_contract.cairo +++ b/crates/blockifier/feature_contracts/cairo1/test_contract.cairo @@ -71,6 +71,41 @@ mod TestContract { .span() } + + #[external(v0)] + fn test_call_contract_revert( + ref self: ContractState, + contract_address: ContractAddress, + entry_point_selector: felt252, + calldata: Array:: + ) { + match syscalls::call_contract_syscall( + contract_address, entry_point_selector, calldata.span()) + { + Result::Ok(_) => panic!("Expected revert"), + Result::Err(errors) => { + let mut error_span = errors.span(); + assert( + *error_span.pop_back().unwrap() == 'ENTRYPOINT_FAILED', + 'Unexpected error', + ); + }, + }; + // TODO(Yoni, 1/12/2024): test replace class once get_class_hash_at syscall is supported. + assert(self.my_storage_var.read() == 0, 'values should not change.'); + } + + + #[external(v0)] + fn test_revert_helper(ref self: ContractState, class_hash: ClassHash) { + let dummy_span = array![0].span(); + syscalls::emit_event_syscall(dummy_span, dummy_span).unwrap_syscall(); + syscalls::replace_class_syscall(class_hash).unwrap_syscall(); + syscalls::send_message_to_l1_syscall(17.try_into().unwrap(), dummy_span).unwrap_syscall(); + self.my_storage_var.write(17); + panic!("test_revert_helper"); + } + #[external(v0)] fn test_call_two_contracts( self: @ContractState, diff --git a/crates/blockifier/src/blockifier/transaction_executor_test.rs b/crates/blockifier/src/blockifier/transaction_executor_test.rs index 014b7a5e7f..8fc3e7137f 100644 --- a/crates/blockifier/src/blockifier/transaction_executor_test.rs +++ b/crates/blockifier/src/blockifier/transaction_executor_test.rs @@ -1,6 +1,7 @@ use assert_matches::assert_matches; use pretty_assertions::assert_eq; use rstest::rstest; +use starknet_api::execution_resources::GasAmount; use starknet_api::test_utils::NonceManager; use starknet_api::transaction::{Fee, TransactionVersion}; use starknet_api::{declare_tx_args, deploy_account_tx_args, felt, invoke_tx_args, nonce}; diff --git a/crates/blockifier/src/fee/fee_utils.rs b/crates/blockifier/src/fee/fee_utils.rs index 37cb1cb4e6..944ba08ada 100644 --- a/crates/blockifier/src/fee/fee_utils.rs +++ b/crates/blockifier/src/fee/fee_utils.rs @@ -51,7 +51,8 @@ pub fn get_vm_resources_cost( // Convert Cairo resource usage to L1 gas usage. // Do so by taking the maximum of the usage of each builtin + step usage. - let vm_l1_gas_usage = vm_resource_fee_costs + let vm_l1_gas_usage = GasAmount( + vm_resource_fee_costs .builtins .iter() // Builtin costs and usage. diff --git a/crates/blockifier/src/fee/resources.rs b/crates/blockifier/src/fee/resources.rs index 9944a736b9..01df739d7d 100644 --- a/crates/blockifier/src/fee/resources.rs +++ b/crates/blockifier/src/fee/resources.rs @@ -145,6 +145,30 @@ pub struct StateResources { state_changes_for_fee: StateChangesCount, } +impl StateResources { + pub fn new( + state_changes: &StateChanges, + sender_address: Option, + fee_token_address: ContractAddress, + ) -> Self { + Self { + state_changes_for_fee: state_changes + .count_for_fee_charge(sender_address, fee_token_address), + } + } + + #[cfg(any(test, feature = "testing"))] + pub fn new_for_testing(state_changes_for_fee: StateChangesCount) -> Self { + Self { state_changes_for_fee } + } +} + +#[cfg_attr(feature = "transaction_serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, Default, PartialEq)] +pub struct StateResources { + state_changes_for_fee: StateChangesCount, +} + impl StateResources { pub fn new( state_changes: &StateChanges, diff --git a/crates/blockifier/src/test_utils/struct_impls.rs b/crates/blockifier/src/test_utils/struct_impls.rs index a54c0ea027..12c644a48c 100644 --- a/crates/blockifier/src/test_utils/struct_impls.rs +++ b/crates/blockifier/src/test_utils/struct_impls.rs @@ -5,7 +5,13 @@ use serde_json::Value; use starknet_api::block::{BlockHash, BlockNumber, BlockTimestamp, NonzeroGasPrice}; use starknet_api::core::{ChainId, ClassHash, ContractAddress, Nonce, PatriciaKey}; use starknet_api::hash::StarkHash; -use starknet_api::transaction::{Calldata, Fee, TransactionHash, TransactionVersion}; +use starknet_api::transaction::{ + Calldata, + Fee, + GasVectorComputationMode, + TransactionHash, + TransactionVersion, +}; use starknet_api::{calldata, contract_address, felt, patricia_key}; use starknet_types_core::felt::Felt; diff --git a/crates/blockifier/src/transaction/execution_flavors_test.rs b/crates/blockifier/src/transaction/execution_flavors_test.rs index cf11789626..dd284eddbd 100644 --- a/crates/blockifier/src/transaction/execution_flavors_test.rs +++ b/crates/blockifier/src/transaction/execution_flavors_test.rs @@ -375,7 +375,7 @@ fn test_simulate_validate_pre_validate_not_charge_fee( let base_gas = calculate_actual_gas(&tx_execution_info, &block_context, false); assert!( base_gas - > u64_from_usize( + > u128_from_usize( get_syscall_resources(SyscallSelector::CallContract).n_steps + get_tx_resources(TransactionType::InvokeFunction).n_steps ) @@ -611,7 +611,7 @@ fn test_simulate_validate_charge_fee_mid_execution( // used. Otherwise, execution is limited by block bounds, so more resources will be used. let (limited_gas_used, limited_fee) = gas_and_fee(7763_u32.into(), validate, &fee_type); let (unlimited_gas_used, unlimited_fee) = gas_and_fee( - u64_from_usize( + u128_from_usize( get_syscall_resources(SyscallSelector::CallContract).n_steps + get_tx_resources(TransactionType::InvokeFunction).n_steps + 5730, @@ -739,7 +739,7 @@ fn test_simulate_validate_charge_fee_post_execution( &fee_type, ); let (unlimited_gas_used, unlimited_fee) = gas_and_fee( - u64_from_usize( + u128_from_usize( get_syscall_resources(SyscallSelector::CallContract).n_steps + get_tx_resources(TransactionType::InvokeFunction).n_steps + 5730, @@ -784,7 +784,7 @@ fn test_simulate_validate_charge_fee_post_execution( // Second scenario: balance too low. // Execute a transfer, and make sure we get the expected result. let (success_actual_gas, actual_fee) = gas_and_fee( - u64_from_usize( + u128_from_usize( get_syscall_resources(SyscallSelector::CallContract).n_steps + get_tx_resources(TransactionType::InvokeFunction).n_steps + 4260, diff --git a/crates/blockifier/src/transaction/post_execution_test.rs b/crates/blockifier/src/transaction/post_execution_test.rs index 59f4fb3910..9b3fe27f29 100644 --- a/crates/blockifier/src/transaction/post_execution_test.rs +++ b/crates/blockifier/src/transaction/post_execution_test.rs @@ -1,6 +1,7 @@ use assert_matches::assert_matches; use rstest::rstest; use starknet_api::core::{ContractAddress, PatriciaKey}; +use starknet_api::execution_resources::GasAmount; use starknet_api::state::StorageKey; use starknet_api::transaction::{ Calldata, diff --git a/crates/blockifier/src/transaction/test_utils.rs b/crates/blockifier/src/transaction/test_utils.rs index 85a8fed075..9870ee7bc0 100644 --- a/crates/blockifier/src/transaction/test_utils.rs +++ b/crates/blockifier/src/transaction/test_utils.rs @@ -96,6 +96,7 @@ pub fn max_l1_resource_bounds() -> ValidResourceBounds { create_resource_bounds(&GasVectorComputationMode::NoL2Gas) } +// TODO(Amos, 1/10/2024): Delete this fixture and use `create_resource_bounds` #[fixture] pub fn default_all_resource_bounds() -> ValidResourceBounds { create_resource_bounds(&GasVectorComputationMode::All) @@ -365,6 +366,24 @@ pub fn create_all_resource_bounds( l2_max_price: GasPrice, l1_data_max_amount: GasAmount, l1_data_max_price: GasPrice, +) -> ValidResourceBounds { + create_all_resource_bounds( + l1_max_amount, + l1_max_price, + l2_max_amount, + l2_max_price, + l1_data_max_amount, + l1_data_max_price, + ) +} + +fn create_all_resource_bounds( + l1_max_amount: u64, + l1_max_price: u128, + l2_max_amount: u64, + l2_max_price: u128, + l1_data_max_amount: u64, + l1_data_max_price: u128, ) -> ValidResourceBounds { ValidResourceBounds::AllResources(AllResourceBounds { l1_gas: ResourceBounds { max_amount: l1_max_amount, max_price_per_unit: l1_max_price }, diff --git a/crates/blockifier_regression_test/resources/block_700000/tx_hashes_block_700000.json b/crates/blockifier_regression_test/resources/block_700000/tx_hashes_block_700000.json new file mode 100644 index 0000000000..a9192a1c92 --- /dev/null +++ b/crates/blockifier_regression_test/resources/block_700000/tx_hashes_block_700000.json @@ -0,0 +1,12 @@ +[ + "0x47165a9a9c97e8829a4778f2a4b6fae4366aefc35b51d484bf04c458168351b", + "0x57c0b8578fc39ae6ddadfec8973861f0481f9b056c2c6cbf682c8388ccf70e0", + "0x518d8ad0393e8895fefc0f05660f57208c3b743a7ca55e94729f21f4f182c34", + "0x7c593acf831585f0d1a5c318ab4d5c0ed75c2fbd6d253bf211029a8e6ecf7d1", + "0x2583a7ef17ac289e4e64bf3bf20aab7725dbfcc19d709af08c8306cf2037970", + "0x1c23a4eb97bd0539b0d15e9483fc34b9021d15139d954ec2dfea098abc9f48c", + "0x60c6cfe335697fbad3fb2b04edecc946e114d3e6fe1447fe6445f9fc7dc9998", + "0x15006aeeddec46275565f6d0bf344130bee1b5774b1424d024c1c907dead80", + "0x797cbf65f46fa84e738e99d56a938a344414166e30091a9bf0dbaba01f71b32", + "0xa7c7db686c7f756ceb7ca85a759caef879d425d156da83d6a836f86851983" +] \ No newline at end of file diff --git a/crates/blockifier_regression_test/resources/raw_rpc_json_objects/block_header.json b/crates/blockifier_regression_test/resources/raw_rpc_json_objects/block_header.json new file mode 100644 index 0000000000..120b7ff2b7 --- /dev/null +++ b/crates/blockifier_regression_test/resources/raw_rpc_json_objects/block_header.json @@ -0,0 +1,35 @@ +{ + "block_hash": "0x29851b3a78e95b3c9469ea53c0ca902f4df92be129f1929fdb4dde0eb0cda4c", + "block_number": 700000, + "l1_da_mode": "BLOB", + "l1_data_gas_price": { + "price_in_fri": "0x1459", + "price_in_wei": "0x1" + }, + "l1_gas_price": { + "price_in_fri": "0xd28710bbc88", + "price_in_wei": "0xa5883d4c" + }, + "l2_gas_price": { + "price_in_fri": "0x1", + "price_in_wei": "0x1" + }, + "new_root": "0x2c82376b7e0d7cddec192d51198bb74b96ee5aaf94268cbc15ae7551adf502", + "parent_hash": "0x7f1f233dee2c50193842d0f6af87695d7d8b26292d0e70e349df4d71b2f9398", + "sequencer_address": "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "starknet_version": "0.13.2.1", + "status": "ACCEPTED_ON_L1", + "timestamp": 1725724084, + "transactions": [ + "0x47165a9a9c97e8829a4778f2a4b6fae4366aefc35b51d484bf04c458168351b", + "0x57c0b8578fc39ae6ddadfec8973861f0481f9b056c2c6cbf682c8388ccf70e0", + "0x518d8ad0393e8895fefc0f05660f57208c3b743a7ca55e94729f21f4f182c34", + "0x7c593acf831585f0d1a5c318ab4d5c0ed75c2fbd6d253bf211029a8e6ecf7d1", + "0x2583a7ef17ac289e4e64bf3bf20aab7725dbfcc19d709af08c8306cf2037970", + "0x1c23a4eb97bd0539b0d15e9483fc34b9021d15139d954ec2dfea098abc9f48c", + "0x60c6cfe335697fbad3fb2b04edecc946e114d3e6fe1447fe6445f9fc7dc9998", + "0x15006aeeddec46275565f6d0bf344130bee1b5774b1424d024c1c907dead80", + "0x797cbf65f46fa84e738e99d56a938a344414166e30091a9bf0dbaba01f71b32", + "0xa7c7db686c7f756ceb7ca85a759caef879d425d156da83d6a836f86851983" + ] +} \ No newline at end of file diff --git a/crates/blockifier_regression_test/resources/raw_rpc_json_objects/deprecated_contract_class.json b/crates/blockifier_regression_test/resources/raw_rpc_json_objects/deprecated_contract_class.json new file mode 100644 index 0000000000..cd04db42da --- /dev/null +++ b/crates/blockifier_regression_test/resources/raw_rpc_json_objects/deprecated_contract_class.json @@ -0,0 +1,122 @@ +{ + "abi": [ + { + "data": [ + { + "name": "implementation", + "type": "felt" + } + ], + "keys": [], + "name": "Upgraded", + "type": "event" + }, + { + "inputs": [ + { + "name": "implementation_address", + "type": "felt" + }, + { + "name": "initializer_selector", + "type": "felt" + }, + { + "name": "calldata_len", + "type": "felt" + }, + { + "name": "calldata", + "type": "felt*" + } + ], + "name": "constructor", + "outputs": [], + "type": "constructor" + }, + { + "inputs": [], + "name": "get_implementation", + "outputs": [ + { + "name": "implementation", + "type": "felt" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "name": "selector", + "type": "felt" + }, + { + "name": "calldata_size", + "type": "felt" + }, + { + "name": "calldata", + "type": "felt*" + } + ], + "name": "__default__", + "outputs": [ + { + "name": "retdata_size", + "type": "felt" + }, + { + "name": "retdata", + "type": "felt*" + } + ], + "type": "function" + }, + { + "inputs": [ + { + "name": "selector", + "type": "felt" + }, + { + "name": "calldata_size", + "type": "felt" + }, + { + "name": "calldata", + "type": "felt*" + } + ], + "name": "__l1_default__", + "outputs": [], + "type": "l1_handler" + } + ], + "entry_points_by_type": { + "CONSTRUCTOR": [ + { + "offset": "0x91", + "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194" + } + ], + "EXTERNAL": [ + { + "offset": "0xde", + "selector": "0x0" + }, + { + "offset": "0xbd", + "selector": "0x21691762da057c1b71f851f9b709e0c143628acf6e0cbc9735411a65663d747" + } + ], + "L1_HANDLER": [ + { + "offset": "0xf7", + "selector": "0x0" + } + ] + }, + "program": "H4sIAAAAAAAA/+x9a2/buLb2XzH8aWZ2dsA7pQLzIW09s4s3bedN0jOzT1EIskSnQm3ZW1LaZA/63w90syWLlEhdnHSmAYLEsrjW4uJ6Hi5eRP0530XBRsyfzebg3gKVHwiB2Q+cn83mbpJEwfIuEfH82ez9h7PZPPBFmASrQETppT/njrNxg9Bxzv/lxh+f3wXrJAizL3wRJ0HoJsE2/TyPEzf69MWNxLnnBtH23NtuNtsw/+As83JxTcjZbJ487LK6uOvAjedfz2YHdb9F2/sHqaLIO7/b3UauL+LzdbCM3OihuLtdouP4YuXerRPHKeR628hNtllF38/FfSKi0F2nUiL3ixOEu7uk/LC9S9JPqYN23vzZDAFSUba6C73MPJW+84voNnfn6m69dkI3b0L1rWezeRz8N70Jn83mG7FZlu0Ri7Xwkm2UfdiuVrFI5s9m4Gw2z129t0msk8wez12vfTdxnUJgpRTsLlUvgKQFfpp//VrxRpxEd16i9sWrzW4deEFi4JNakRbfPMSp3c4u0XLPT5mNO+GLKBZhs1TTPcZBnquI3PBWON5H4X1qapH71MylVyK5i3JY1kX9EIlk3/jPZqnks1lxLf/4049V2KR/U7lBGLQH9PWr/128/cW5fPvi4vI6U/zZXd+JwtelOG8bxg2z17AdiGvofHRDfy2iOhQP4MNQA3xVNd34a97914NgrY7aKFSX+g5EmYvUWDRBWk1kb7Bll1KLi2A9Qlr16z26ILI60VUp2AWtxq2HqCFHURNsdmuxEWGS9fWO6/uRiGNtlGWedNfBf0XkyCGqATZnLUK9sFAiFPdFaNVVmvBUFvmOzYZ/xgBmVV5vVN6KxKnHugycnwPxpYJK3p1wNuV2gVNV4hA9oB49Xf6WCNSM5K6S3wNa5SZ1XNdvzPM9/ViXqOod8sU4zUkbqn30mP0XiqT0ctG6cV1E+0iveqtTSSeHK3bqyanMhi+Ru9uJKB57xImQmgDkOpXob7vdHPoKaV241yk2mjFqjFTYoxgQnc2q5PBsZg7/s9kR9suR16BRmKJq5phUCCq/8J00umRgkU6lGMHAEaG39YUTZe1xvhEbbyef5ZE7PS9QltNRPXy0Sbgm8LRGnB0lBka80RBPs+SYJv3lcDhwnKaWZYTGWpCbouLUmOw1KCVUC4Q6A9O22wfFusn4TafYaMb8xVA3bBCmEGSAt2qEGoX7qZHWa6Bp2VpIMxhsapQaFOo9Bp0Gpcc27S8GxlFGie3yDKApifg+MKkDVQKaClxAT7gckUGvSJXJOMQrOpooiUTilC3ROk2imDjonNRQza/2Q8pR5QZBuk3WyAA/UtWyNCcHZjkLXf08EjKPTFPjFPbB6Ql6N+na/y8Xl9cLAz3L7XZdFNJXcprdDy17G1KlZYE06OOd64mOQgpS6SpgCogWee2g1S04okEDFgFapJr2eC2inFgnaTv0P0A5O2GmxDxWlEIOzQWPeqBQfJHVrXN1z7ydZcb1DsZOYX/vxQlDz00DQZmmEWGpNZSqrKErJ+uNdJiDcqwBlpmK3sj6vurXE1jTrwOaKR8Pao7rb4okyzTfyYsag6ZabDycFFIfO3EszOiLUFnx0X00SY9QyB47MM8/uvFHZNCU6f1FoX5NF26jTbatqbYjSn8dO9lG7q2QiOlnTiHPiYTr91xRr4kYZsWXKEjEQDNyGaZ2tOxWM+YtuSxzImuTMyJqFWoeneoUdvXmPh1507t1GnZUKBuRLhUa0r9tuTPvMaBt0zUaig7Cpm/zTNfYcdsUqp4rVmfKzfx6ikzZcCq5pzPanpuIB+fJraqnB9oJExWFBU8mc1HYV0lhpFRk9RjFt+kajYoOwqanokzX2FTUFPp9pN/Dg7pD/rLUZJSWWTM9pT322KPDrKc2GDmvGiRlOFu5raqnstEoriJNvZ6gtZo9MvByw8YmRInU74zYx4UnHS3lKsfkvf0zbH7PmYSDgB5QPC48ZnZRkf34EwUVY/ojWSVkIq9NFNkVDdME8kkHIhW1T2f0UTHq0TMYiS2PkbbcXL0z3rOTldFX8S6/YEykZTkT/qyXGYUA9iJ7EJS87LhmjU1He8HXi8vFi5u3V/UdaciGNiLEIgBSTqCNMbQpBJRwBCBhAFBsE5sibts2JhRhzC1kEWhByAgHFqbpRYsBTPW57GDTGMy4l+au11vpPlZF9Gf3F6XM4/9cbIKkbRBAsdEgoCa3F0gOBdWp/dTbhOrGDMFYU4B6WrVX5j75RGm9KpMBO5OuRhLqgaRUpCM+izDp2X9VBPRA1sn2uN6KJHv+WEQ9k5myvhJBciu6maiFUZR74rvFqghFs6BxH9ctt4MbDAVMYKAasIcnSbqh263HuBPs3H89TMY+h2zftq43nHweJF+CWFSHpTrt3C7l0Nj0qCO41+vRzmbzBz2+P5vN7x039J0HvWmX7P77bXR8v/z0muL+5u3EsPvR8uLCe7sb2BBVEYdW4MernD2XNoXn7LZBmJwvvN/Sv1nd/tPleBNhGz03p9lB/U7aX+3ANsul6PeFDQNMOqKWyaCeEXM0n6SYep0Ct5GI79bJsNlSrSpeB7ehm9xFQ1muIadlH8Hd0vkkHrS9thFx7N6KYTmuvBJ+4CWO63kijs9fBl5ykf2r7QNFcXWomFR7F4nPsmfzWqImFF9kJcYJnAY2db0kA7UiNEaHklkVs1nGE81Ed04yXrx8eeU8f/vuzctaQvNPCBiHgCObAkg5phzZFkXAIghAm1AMMLIBx5wAQBCl1LIsajEObVJ7jFuWDKlMeX3xh3N98/bq4teF8+pm8dpJ0776QI2ynrLdOBZR4iAKnGVg0lds3OTjcWlTV5dDoBcXl5fOi7dvbq4uXtw40tkmBCyKEceEU4QA4YhYDNqQW8RCXXmqWq+7Xr/Yhknkeq140hOgTmoi8Z87ESf6qY2WwqtCatFh7bZhLPQzD00VhdhuJBuZPNTXpRx1Nm9+ImwhWn7IZQvrl6NpxQmXGodVSg6hbcn55UdcytNR9RGXfQNheMsVgtS9UPWAZO3mKwrptNogp7xcXC5+vbhZOBlnyakKQsapTQCD3MIIMAthaDMOGSS9qWqv9xI6/7p48/JycaXQjhEnAFILIJsji1BEOKXMIsi2GOY2hBZjvP44nKElv12+/bdcOacIIMIsSgCyusb+ag1it94+9Aq1oughuOzJqDhX1U3CbIjw4fRbN7O/T5uUywZT7tqNYyfN+rTJ9pilndjVHaedzaoHWTk9yVciQZOI8wAR0edi/bOll9ZMnnWjZ0ijN9j6eEzV3m+2d7h7V6opvz0WjgXoRMIw+q+PUvVSZfU4tVe2vHj96sZZ/M/ijSJVhsgCHNgYQEoBxpQTmxOrLxkvNkGy2C/nmIbRofSIqdon8RA3TwVviZS0gGZonM3m8kPHW0jhJNnYr4sb5/nl2xf/z3nz7vVzVe8PCbGAZUPALEwpwgBAgi0OECYUIMAt43FiU//Nq9eL65uL178pEhCCbGIDzDFiiDFCLWYhSBGmnFvcRpxyTiGkvROQ1JI0+1pcOekgfXF9LTcktSLNu7gFsY0BtwghiBILYAA5oxYEiBE8yIpyyNpqB0PQJjbFDFiAEhsSDlN/2BxADDhgiEAbWQgAa5Ax14v//27x5kWXVyC1EbSBhTG1oG1DDjCg2ALUQja1CYPpV6k1NA2cIQbd/OG8evPLW4UZGHKAbGwDBAiECAIM0KD63/zhXL/69c3FzburRTs4kMUowgQATjjkkCHEOQDc5v31i+T5eut9enOX0lovpjwS0TY8GiuDravszmTbdiVrKxme0crNHu7zZoZ7vAPGrKcar4YD8jiFKHUdl+ndTngI5BPU8ybYiDhxN7tBVTxIOSV49lonxk9Fz3gQahg/iv+fHpCazhupoppwSmoBPm2FX2R7iS4qo7Ee9awLORGeakqng9ORmlHQJDV9DN8/KSzJPTdONTuRJNlsN3Fti5mNoVA6EnMqMNXVTginY0XjAEpu/jht8LRApfDfWFXtBlavGbxBdb5OGyD0BndTDTknAtex3unQ1dQ0CrxUFRipHZ4UwJQuHK2ynRCLyyInxNjN/atwte1byaL0ifCUa5sORaX8UbBTN3aQf58UTo6cNLBinZhI7p2gDNBhAZSrHDa7nhq+30TZv+4HEeoVs5GRs1c5JXwqSkbCUMPs4T5/Ymhq+myMKnZun4nLe5trWC1ranEt9qfcQXP56vnVxdW/8w00XbtZCGYIY0IRpwTaFqScA8oJQxRwy6aUU2gjZCFCGGSU9V5TqhklX01CmDOAGLcJRhxAyDmyKWSs95aey/xJshflCzhNI6Na/hR7Dyv6vpGthxKLBzp6io2H5rtg/rJbDq8Xb146rxfX1xe/Lpybtyk9KGgBA8htYHFmYYAJtm3Aoc0saiOCOeeg/1peudP6anHxUrGOCIBlA2ZjzAEDkDMACAIWGsAFpdLfr17dKFYvEbWQBSCnAFmcAArSujLGkM1x/8qK0H+dP+Bxs72E1w9xbzpSiDpTvlzeGCnJ1nhz7s59WG9dXxLuLSApCzWe7DZ9j7yO1/J9+Ffl4SPGXq+UP0XKWdHX3Qm0PXCnp2F4HyAxeKCfm31AIwUzjWyjsB7JFwNyUpkcddI9wpFw2ib9vj84p2edfi9PzVEd9DZp057NZN7q/QBZx4i5l58aE0PHCednEcXa54OkDvK87V2YOL0fwNi4985K6NN7ywCpJQdSDJDatvsmkRvGbp6pNfM71bbf9PJHNwid4GifcHMj+dAwaJzVIT06gqgPozFR0XmMhLYMdUoh3xnasZVUc8Sr3BnaEmrNpHmCFKLiHt2DMYxltUypGJ+fM0pNhxyJY6So/xEbOtKPvReJlYhE6IkMgn9WAOjunJQePwXhrdMMq9SW22h7t0uJpdqNzN97bpz8sNrN/jH74Z/8x7P88JGffvyQWlsooKBTAVQqyOS/3yv4MPtHSm3FESdfP2TD1d5BWPWPIp4qrbD3nm5LFIf5ZI9ytFHgEAas6ujPgU0pahZUzSi08GDHjELbUxjqGQWNeYjJybHmt8H0qJb2NAiyZl/bqxQOj9v0fOO0qTET0GhNvhaRmvEoNOZRaMajsItH+TAeVTpoYiZ11tD56Ib+WrS+VgaqTzrvrW8cgm0I/M61Q1w4Ku0qBT89Bq6a+pTIuGrXxLxcVaVF0Rkp6HM0Mubo7MF3fY5GJ+RolbMmoGvJoddSjkbqV3+ZKelPzE0paqSfaHdVzaTB7KaW9jQorWafmscykOi+zsZQ6wQsVZOvRU0ZFvSpCaupicipCUMjasJqaiIZNeFh1KT00IR81Pl6HDwkaaxpGc5I0hfiHK8FmR6LYHDk3HBIa705Z5C4p0Vhw19IY6prQubKFegNfM2yKqKmLiqnLmI28iVq6qJjUlfTRUbclU3hi+XdbblTNbxbrw/T+u/n4J4AbgEA+Wq1Sn9TQeAe5n8QsJblF3y1EvlVYgFWFrEAAMVVj9kMccQgR9wmmEHmMa/4DgCU3slXK/ughACACznpVbd2FRVXl7WruLjq1a6S4qpf2odK++yDfXxvfGoKrX9ZXGX1q8OrTzwMicUgE4wwj1GO/jYOoZgTtkodwjijFDHKICON6nvS6ntS472DdFwzE9W/HGAm54jZnDDaMHQpNXTZ8D0qrjbNXzbMNwowyvzUNEI5Y5QJ3vTlo4USba2OjGAKHEAISPpl8VuIS//b/0CwMvrx9nWFuNRZi2uJb5G/xAQI5jFgYw4BYhzDFeGAAh/bWfh6lr0kq+USQGQTyBi2CPSo7UN3hesNUTTGaroaEmkNYa3dQFHLo3armwH3TnHLCO9yVaVIWdFqEWSVGiqRlN97LGh8xwhcq4931MgqsEnuLa76Oh7Bro/JyvU5RksKVwL40IWYghUk9gpBF3grSFwbW8izPSb4EjHkEQE8y1+uoDWWcRP4c08biviAKZGIyc3Yx7tUYXGVGlw1CYwmKCQtMkUs+zWFro7vTxYYS1Ezg0mNYwZeblRP3/enQwOsVa/BDY/aIh7qxoggUpP9sdFwskr7TMNkLjXOkl61pVfd6cFutYfWN4MRbmtgBOlcVbZpme8vG4OVTGPl6iEXE5XE+JDA+m3DiaogC4PSjKp4VPq0OoZpMxBIr8Ljq4g0DYQNQb5UUPNqozIt9Z8Co22jANjWLZtdlWVm9SLLb5bnyiGNwfiqORioJeT7wQBQDQYa0M0y+z2g2kYBKjPRsoIXvw8yZNiago7FiTPco9RC3k/Lr8qTcq2rrQh4Wh2k62lwgjz3elpQRkKjgzye+Wm7OqylB2KvNTN5LBcL+5sLb1unI/wWwhuuxgrvv1fILr+VJOnD2WxevqQqW0DaCV9EscjeUlV5qXB248cgTPKlUpAv5XlbP1uh2ojNNnp47+4+zH6exeJ2I8IkPnd9P1+/XK23XyQLcft1LSfw9683rSzZqZcDwdfiOS0Rx8FyLZzY2+7y9cXKYlztyPv9m7Hbvi/u+pAt8cGjSpaLduWGqOpGqR/KSv9c/nM2qyzy/Rz4cXXRz8grA3ceg1av1nf/6nhVZcO8xwMOuaMR0nd0ZUfaU/K5elch1HY/OrX7q7ui85bAsL0lqhtwHtv9LdulkLbP8Sl8XtvamDuadHBLbbvAU/G0bHsH1nY1OaWr811bua9ph68PD3c9tqOVj+ERbS/TU3i58pRu0VUyevqEwKLVvqsNyY6zcYPQcVLV9f+/RO5uJ6K4+fm88jKfspbWI6c9sK11e1XyViROsNmtRWp69tYgR4Rp9Zwo35JW9ND0EdqX1rbVt6V8varupN2fL1bu3TpxnLSi+aP7QZiLTqtZFXYwfuOG7q14zKe6Jn8kYfKNxZNv/5voCeUPX7/+XwAAAP//QZpCgmDPAAA=" +} \ No newline at end of file diff --git a/crates/blockifier_regression_test/resources/raw_rpc_json_objects/transactions.json b/crates/blockifier_regression_test/resources/raw_rpc_json_objects/transactions.json new file mode 100644 index 0000000000..fbdfc3e4aa --- /dev/null +++ b/crates/blockifier_regression_test/resources/raw_rpc_json_objects/transactions.json @@ -0,0 +1,73 @@ +{ + "invoke_v1": { + "calldata": [ + "0x1", + "0x422d33a3638dcc4c62e72e1d6942cd31eb643ef596ccac2351e0e21f6cd4bf4", + "0xcaffbd1bd76bd7f24a3fa1d69d1b2588a86d1f9d2359b13f6a84b7e1cbd126", + "0x5", + "0x5265736f6c766552616e646f6d4576656e74", + "0x3", + "0x0", + "0x1", + "0x10c3" + ], + "max_fee": "0x65f2d0057b2", + "nonce": "0x4d8", + "sender_address": "0x4e6989d518d5eb7e516dc5673f855fe7c5cfece1880a1047d6a8e8465be0d69", + "signature": [ + "0x59b7462ea9566750ab7d7d08acbb6d339bfda921b053f1f8a5fd6b96c3656f9", + "0x2f11c36d10a03f21be918a5feeeb9922c11a2713fecd51f5e6bac5167856ecb" + ], + "transaction_hash": "0x47165a9a9c97e8829a4778f2a4b6fae4366aefc35b51d484bf04c458168351b", + "type": "INVOKE", + "version": "0x1" + }, + "invoke_v3": { + "account_deployment_data": [], + "calldata": [ + "0x2", + "0x4878d1148318a31829523ee9c6a5ee563af6cd87f90a30809e5b0d27db8a9b", + "0xa72371689866be053cc37a071de4216af73c9ffff96319b2576f7bf1e15290", + "0x4", + "0x2cb8f1439c83d9856179cbeae626e676bbb9b68e0bdda5423aa1988018acebe", + "0xba43b7400", + "0x2750a0009", + "0x422d33a3638dcc4c62e72e1d6942cd31eb643ef596ccac2351e0e21f6cd4bf4", + "0x422d33a3638dcc4c62e72e1d6942cd31eb643ef596ccac2351e0e21f6cd4bf4", + "0xcaffbd1bd76bd7f24a3fa1d69d1b2588a86d1f9d2359b13f6a84b7e1cbd126", + "0x6", + "0x41636365707444656c6976657279", + "0x4", + "0x9", + "0x2750a", + "0x1", + "0xcf" + ], + "fee_data_availability_mode": "L1", + "nonce": "0x1412", + "nonce_data_availability_mode": "L1", + "paymaster_data": [], + "resource_bounds": { + "l1_gas": { + "max_amount": "0x368", + "max_price_per_unit": "0x13bca990eeea" + }, + "l2_gas": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "sender_address": "0x614872dd2f3324f3e9a047d0cfaab9e9573bbdfa6081877f49f7108116b8ae0", + "signature": [ + "0x1", + "0x0", + "0x61050eb8efaa6db97248c8c987c1a9df82527c26c204681396108cbd5babaf8", + "0x358bc995a221c3aa96cf2a1e6b5b8959b6d626b6fe89381d627f378dc39402a", + "0xf247079c5e0c5be56f4c0f37452304dc63b4b883b89d5a66e3202a855515ef" + ], + "tip": "0x0", + "transaction_hash": "0xa7c7db686c7f756ceb7ca85a759caef879d425d156da83d6a836f86851983", + "type": "INVOKE", + "version": "0x3" + } +} \ No newline at end of file diff --git a/crates/blockifier_regression_test/src/state_reader.rs b/crates/blockifier_regression_test/src/state_reader.rs new file mode 100644 index 0000000000..9ce3f8a8ac --- /dev/null +++ b/crates/blockifier_regression_test/src/state_reader.rs @@ -0,0 +1,8 @@ +pub mod compile; +#[cfg(test)] +pub mod raw_rpc_json_test; +#[cfg(test)] +#[cfg(feature = "blockifier_regression_https_testing")] +pub mod rpc_https_test; +pub mod test_state_reader; +pub mod utils; diff --git a/crates/blockifier_regression_test/src/state_reader/compile.rs b/crates/blockifier_regression_test/src/state_reader/compile.rs new file mode 100644 index 0000000000..b3203c5659 --- /dev/null +++ b/crates/blockifier_regression_test/src/state_reader/compile.rs @@ -0,0 +1,105 @@ +// This module contains code taken from starknet-replay. +// For more information, see the original repository at: +// `` + +use std::collections::HashMap; +use std::io::{self, Read}; +use std::sync::Arc; + +use blockifier::execution::contract_class::{ContractClass, ContractClassV0, ContractClassV0Inner}; +use blockifier::state::state_api::StateResult; +use cairo_lang_starknet_classes::contract_class::ContractEntryPoints; +use cairo_lang_utils::bigint::BigUintAsHex; +use cairo_vm::types::program::Program; +use flate2::bufread; +use serde::Deserialize; +use starknet_api::core::EntryPointSelector; +use starknet_api::deprecated_contract_class::{EntryPoint, EntryPointOffset, EntryPointType}; +use starknet_api::hash::StarkHash; +use starknet_core::types::{ + CompressedLegacyContractClass, + FlattenedSierraClass, + LegacyContractEntryPoint, + LegacyEntryPointsByType, +}; +use starknet_gateway::errors::serde_err_to_state_err; + +#[derive(Debug, Deserialize)] +pub struct MiddleSierraContractClass { + pub sierra_program: Vec, + pub contract_class_version: String, + pub entry_points_by_type: ContractEntryPoints, +} + +/// Maps `LegacyEntryPointsByType` to a `HashMap` where each `EntryPointType` +/// is associated with a vector of `EntryPoint`. Converts selectors and offsets +/// from legacy format to new `EntryPoint` struct. +pub fn map_entry_points_by_type_legacy( + entry_points_by_type: LegacyEntryPointsByType, +) -> HashMap> { + let entry_types_to_points = HashMap::from([ + (EntryPointType::Constructor, entry_points_by_type.constructor), + (EntryPointType::External, entry_points_by_type.external), + (EntryPointType::L1Handler, entry_points_by_type.l1_handler), + ]); + + let to_contract_entry_point = |entrypoint: &LegacyContractEntryPoint| -> EntryPoint { + let felt: StarkHash = StarkHash::from_bytes_be(&entrypoint.selector.to_bytes_be()); + EntryPoint { + offset: EntryPointOffset(usize::try_from(entrypoint.offset).unwrap()), + selector: EntryPointSelector(felt), + } + }; + + let mut entry_points_by_type_map = HashMap::new(); + for (entry_point_type, entry_points) in entry_types_to_points.into_iter() { + let values = entry_points.iter().map(to_contract_entry_point).collect::>(); + entry_points_by_type_map.insert(entry_point_type, values); + } + + entry_points_by_type_map +} + +/// Uncompresses a Gz Encoded vector of bytes and returns a string or error +/// Here &[u8] implements BufRead +pub fn decode_reader(bytes: Vec) -> io::Result { + let mut gz = bufread::GzDecoder::new(&bytes[..]); + let mut s = String::new(); + gz.read_to_string(&mut s)?; + Ok(s) +} + +/// Compile a FlattenedSierraClass to a ContractClass V1 (casm) using cairo_lang_starknet_classes. +pub fn sierra_to_contact_class_v1(sierra: FlattenedSierraClass) -> StateResult { + let middle_sierra: MiddleSierraContractClass = { + let v = serde_json::to_value(sierra).map_err(serde_err_to_state_err); + serde_json::from_value(v?).map_err(serde_err_to_state_err)? + }; + let sierra = cairo_lang_starknet_classes::contract_class::ContractClass { + sierra_program: middle_sierra.sierra_program, + contract_class_version: middle_sierra.contract_class_version, + entry_points_by_type: middle_sierra.entry_points_by_type, + sierra_program_debug_info: None, + abi: None, + }; + + let casm = + cairo_lang_starknet_classes::casm_contract_class::CasmContractClass::from_contract_class( + sierra, + false, + usize::MAX, + ) + .unwrap(); + Ok(ContractClass::V1(casm.try_into().unwrap())) +} + +/// Compile a CompressedLegacyContractClass to a ContractClass V0 using cairo_lang_starknet_classes. +pub fn legacy_to_contract_class_v0( + legacy: CompressedLegacyContractClass, +) -> StateResult { + let as_str = decode_reader(legacy.program).unwrap(); + let program = Program::from_bytes(as_str.as_bytes(), None).unwrap(); + let entry_points_by_type = map_entry_points_by_type_legacy(legacy.entry_points_by_type); + let inner = Arc::new(ContractClassV0Inner { program, entry_points_by_type }); + Ok(ContractClass::V0(ContractClassV0(inner))) +} diff --git a/crates/blockifier_regression_test/src/state_reader/raw_rpc_json_test.rs b/crates/blockifier_regression_test/src/state_reader/raw_rpc_json_test.rs new file mode 100644 index 0000000000..96b6dcfce3 --- /dev/null +++ b/crates/blockifier_regression_test/src/state_reader/raw_rpc_json_test.rs @@ -0,0 +1,67 @@ +use assert_matches::assert_matches; +use blockifier::blockifier::block::BlockInfo; +use pretty_assertions::assert_eq; +use rstest::{fixture, rstest}; +use starknet_api::block::BlockNumber; +use starknet_api::test_utils::read_json_file; +use starknet_api::transaction::{InvokeTransaction, Transaction}; +use starknet_core::types::ContractClass; +use starknet_gateway::rpc_objects::BlockHeader; + +use crate::state_reader::compile::legacy_to_contract_class_v0; +use crate::state_reader::utils::deserialize_transaction_json_to_starknet_api_tx; + +#[fixture] +fn block_header() -> BlockHeader { + serde_json::from_value(read_json_file("raw_rpc_json_objects/block_header.json")) + .expect("Failed to deserialize block header") +} + +#[fixture] +fn deprecated_contract_class() -> ContractClass { + serde_json::from_value(read_json_file("raw_rpc_json_objects/deprecated_contract_class.json")) + .expect("Failed to deserialize deprecated contact class") +} + +/// Test that deserialize block header from JSON file works(in the fixture). +#[rstest] +fn test_deserialize_block_header(block_header: BlockHeader) { + assert_eq!(block_header.block_number, BlockNumber(700000)); +} + +/// Test that converting a block header to block info works. +#[rstest] +fn test_block_header_to_block_info(block_header: BlockHeader) { + let block_info: BlockInfo = + block_header.try_into().expect("Failed to convert BlockHeader to block info"); + // Sanity check. + assert_eq!(block_info.block_number, BlockNumber(700000)); +} + +#[rstest] +fn test_compile_deprecated_contract_class(deprecated_contract_class: ContractClass) { + match deprecated_contract_class { + ContractClass::Legacy(legacy) => { + // Compile the contract class. + assert!(legacy_to_contract_class_v0(legacy).is_ok()); + } + _ => panic!("Expected a legacy contract class"), + } +} + +#[test] +fn deserialize_invoke_txs() { + let invoke_tx_v1 = deserialize_transaction_json_to_starknet_api_tx( + read_json_file("raw_rpc_json_objects/transactions.json")["invoke_v1"].clone(), + ) + .expect("Failed to deserialize invoke v1 tx"); + + assert_matches!(invoke_tx_v1, Transaction::Invoke(InvokeTransaction::V1(..))); + + let invoke_tx_v3 = deserialize_transaction_json_to_starknet_api_tx( + read_json_file("raw_rpc_json_objects/transactions.json")["invoke_v3"].clone(), + ) + .expect("Failed to deserialize invoke v3 tx"); + + assert_matches!(invoke_tx_v3, Transaction::Invoke(InvokeTransaction::V3(..))); +} diff --git a/crates/blockifier_regression_test/src/state_reader/rpc_https_test.rs b/crates/blockifier_regression_test/src/state_reader/rpc_https_test.rs new file mode 100644 index 0000000000..b0144724d7 --- /dev/null +++ b/crates/blockifier_regression_test/src/state_reader/rpc_https_test.rs @@ -0,0 +1,90 @@ +use assert_matches::assert_matches; +use blockifier::blockifier::block::BlockInfo; +use blockifier::versioned_constants::StarknetVersion; +use pretty_assertions::assert_eq; +use rstest::{fixture, rstest}; +use starknet_api::block::BlockNumber; +use starknet_api::core::ClassHash; +use starknet_api::test_utils::read_json_file; +use starknet_api::transaction::Transaction; +use starknet_api::{class_hash, felt}; +use starknet_core::types::ContractClass::{Legacy, Sierra}; + +use crate::state_reader::compile::legacy_to_contract_class_v0; +use crate::state_reader::test_state_reader::TestStateReader; + +const EXAMPLE_INVOKE_TX_HASH: &str = + "0xa7c7db686c7f756ceb7ca85a759caef879d425d156da83d6a836f86851983"; + +const EXAMPLE_BLOCK_NUMBER: u64 = 700000; + +const EXAMPLE_CONTACT_CLASS_HASH: &str = + "0x3131fa018d520a037686ce3efddeab8f28895662f019ca3ca18a626650f7d1e"; + +#[fixture] +pub fn test_block_number() -> BlockNumber { + BlockNumber(EXAMPLE_BLOCK_NUMBER) +} + +#[fixture] +pub fn test_state_reader(test_block_number: BlockNumber) -> TestStateReader { + TestStateReader::new_for_testing(test_block_number) +} + +#[rstest] +pub fn test_get_block_info(test_state_reader: TestStateReader, test_block_number: BlockNumber) { + assert_matches!( + test_state_reader.get_block_info(), + Ok(BlockInfo { block_number, .. }) if block_number == test_block_number + ); +} + +#[rstest] +pub fn test_get_starknet_version(test_state_reader: TestStateReader) { + assert_eq!(test_state_reader.get_starknet_version().unwrap(), StarknetVersion::V0_13_2_1) +} + +#[rstest] +pub fn test_get_contract_class(test_state_reader: TestStateReader, test_block_number: BlockNumber) { + // An example of existing class hash in Mainnet. + let class_hash = class_hash!(EXAMPLE_CONTACT_CLASS_HASH); + + // Test getting the contract class using RPC request. + let deprecated_contract_class = + test_state_reader.get_contract_class(&class_hash).unwrap_or_else(|err| { + panic!( + "Error retrieving deprecated contract class for class hash {}: {} + This class hash exist in Mainnet Block Number: {}", + class_hash, test_block_number, err + ); + }); + + // Test compiling the contract class. + match deprecated_contract_class { + Legacy(legacy) => { + // Test compiling the contract class. + assert!(legacy_to_contract_class_v0(legacy).is_ok()); + } + // This contract class is deprecated. + Sierra(_) => panic!("Expected a legacy contract class"), + } +} + +#[rstest] +pub fn test_get_tx_hashes(test_state_reader: TestStateReader, test_block_number: BlockNumber) { + let block_number_int = test_block_number.0; + let expected_tx_hashes: Vec = serde_json::from_value(read_json_file( + format!("block_{block_number_int}/tx_hashes_block_{block_number_int}.json").as_str(), + )) + .unwrap_or_else(|err| panic!("Failed to deserialize txs hash to Vector of String {}", err)); + let actual_tx_hashes = test_state_reader.get_tx_hashes().unwrap_or_else(|err| { + panic!("Error retrieving txs hash: {}", err); + }); + assert_eq!(actual_tx_hashes, expected_tx_hashes); +} + +#[rstest] +pub fn test_get_tx_by_hash(test_state_reader: TestStateReader) { + let actual_tx = test_state_reader.get_tx_by_hash(EXAMPLE_INVOKE_TX_HASH).unwrap(); + assert_matches!(actual_tx, Transaction::Invoke(..)); +} diff --git a/crates/blockifier_regression_test/src/state_reader/test_state_reader.rs b/crates/blockifier_regression_test/src/state_reader/test_state_reader.rs new file mode 100644 index 0000000000..2bb67ac64e --- /dev/null +++ b/crates/blockifier_regression_test/src/state_reader/test_state_reader.rs @@ -0,0 +1,181 @@ +use blockifier::blockifier::block::BlockInfo; +use blockifier::blockifier::config::TransactionExecutorConfig; +use blockifier::blockifier::transaction_executor::TransactionExecutor; +use blockifier::bouncer::BouncerConfig; +use blockifier::context::BlockContext; +use blockifier::execution::contract_class::ContractClass as BlockifierContractClass; +use blockifier::state::cached_state::CachedState; +use blockifier::state::errors::StateError; +use blockifier::state::state_api::{StateReader, StateResult}; +use blockifier::versioned_constants::{StarknetVersion, VersionedConstants}; +use serde_json::{json, to_value}; +use starknet_api::block::{BlockNumber, GasPrice}; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; +use starknet_api::state::StorageKey; +use starknet_api::transaction::Transaction; +use starknet_core::types::ContractClass as StarknetContractClass; +use starknet_core::types::ContractClass::{Legacy, Sierra}; +use starknet_gateway::config::RpcStateReaderConfig; +use starknet_gateway::errors::serde_err_to_state_err; +use starknet_gateway::rpc_objects::{BlockHeader, GetBlockWithTxHashesParams, ResourcePrice}; +use starknet_gateway::rpc_state_reader::RpcStateReader; +use starknet_types_core::felt::Felt; + +use crate::state_reader::compile::{legacy_to_contract_class_v0, sierra_to_contact_class_v1}; +use crate::state_reader::utils::{ + deserialize_transaction_json_to_starknet_api_tx, + get_chain_info, + get_rpc_state_reader_config, +}; + +pub struct TestStateReader(RpcStateReader); + +impl StateReader for TestStateReader { + fn get_nonce_at(&self, contract_address: ContractAddress) -> StateResult { + self.0.get_nonce_at(contract_address) + } + + fn get_storage_at( + &self, + contract_address: ContractAddress, + key: StorageKey, + ) -> StateResult { + self.0.get_storage_at(contract_address, key) + } + + fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult { + self.0.get_class_hash_at(contract_address) + } + + /// Returns the contract class of the given class hash. + /// Compile the contract class if it is Sierra. + fn get_compiled_contract_class( + &self, + class_hash: ClassHash, + ) -> StateResult { + match self.get_contract_class(&class_hash)? { + Sierra(sierra) => sierra_to_contact_class_v1(sierra), + Legacy(legacy) => legacy_to_contract_class_v0(legacy), + } + } + + fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult { + self.0.get_compiled_class_hash(class_hash) + } +} + +impl TestStateReader { + pub fn new(config: &RpcStateReaderConfig, block_number: BlockNumber) -> Self { + Self(RpcStateReader::from_number(config, block_number)) + } + + pub fn new_for_testing(block_number: BlockNumber) -> Self { + TestStateReader::new(&get_rpc_state_reader_config(), block_number) + } + + /// Get the block info of the current block. + /// If l2_gas_price is not present in the block header, it will be set to 1. + pub fn get_block_info(&self) -> StateResult { + let get_block_params = GetBlockWithTxHashesParams { block_id: self.0.block_id }; + let default_l2_price = + ResourcePrice { price_in_wei: GasPrice(1), price_in_fri: GasPrice(1) }; + + let mut json = + self.0.send_rpc_request("starknet_getBlockWithTxHashes", get_block_params)?; + + let block_header_map = json.as_object_mut().ok_or(StateError::StateReadError( + "starknet_getBlockWithTxHashes should return JSON value of type Object".to_string(), + ))?; + + if block_header_map.get("l2_gas_price").is_none() { + // In old blocks, the l2_gas_price field is not present. + block_header_map.insert( + "l2_gas_price".to_string(), + to_value(default_l2_price).map_err(serde_err_to_state_err)?, + ); + } + + Ok(serde_json::from_value::(json) + .map_err(serde_err_to_state_err)? + .try_into()?) + } + + pub fn get_starknet_version(&self) -> StateResult { + let get_block_params = GetBlockWithTxHashesParams { block_id: self.0.block_id }; + let raw_version: String = serde_json::from_value( + self.0.send_rpc_request("starknet_getBlockWithTxHashes", get_block_params)? + ["starknet_version"] + .clone(), + ) + .map_err(serde_err_to_state_err)?; + StarknetVersion::try_from(raw_version.as_str()).map_err(|err| { + StateError::StateReadError(format!("Failed to match starknet version: {}", err)) + }) + } + + /// Get all transaction hashes in the current block. + pub fn get_tx_hashes(&self) -> StateResult> { + let get_block_params = GetBlockWithTxHashesParams { block_id: self.0.block_id }; + let raw_tx_hashes = serde_json::from_value( + self.0.send_rpc_request("starknet_getBlockWithTxHashes", &get_block_params)? + ["transactions"] + .clone(), + ) + .map_err(serde_err_to_state_err)?; + serde_json::from_value(raw_tx_hashes).map_err(serde_err_to_state_err) + } + + pub fn get_tx_by_hash(&self, tx_hash: &str) -> StateResult { + let method = "starknet_getTransactionByHash"; + let params = json!({ + "transaction_hash": tx_hash, + }); + deserialize_transaction_json_to_starknet_api_tx(self.0.send_rpc_request(method, params)?) + .map_err(serde_err_to_state_err) + } + + pub fn get_contract_class(&self, class_hash: &ClassHash) -> StateResult { + let params = json!({ + "block_id": self.0.block_id, + "class_hash": class_hash.0.to_string(), + }); + let contract_class: StarknetContractClass = + serde_json::from_value(self.0.send_rpc_request("starknet_getClass", params.clone())?) + .map_err(serde_err_to_state_err)?; + Ok(contract_class) + } + + pub fn get_all_txs_in_block(&self) -> StateResult> { + // TODO(Aviv): Use batch request to get all txs in a block. + let txs: Vec<_> = self + .get_tx_hashes()? + .iter() + .map(|tx_hash| self.get_tx_by_hash(tx_hash)) + .collect::>()?; + Ok(txs) + } + + pub fn get_versioned_constants(&self) -> StateResult<&'static VersionedConstants> { + Ok(self.get_starknet_version()?.into()) + } + + pub fn get_block_context(&self) -> StateResult { + Ok(BlockContext::new( + self.get_block_info()?, + get_chain_info(), + self.get_versioned_constants()?.clone(), + BouncerConfig::max(), + )) + } + + pub fn get_transaction_executor( + test_state_reader: TestStateReader, + ) -> StateResult> { + let block_context = test_state_reader.get_block_context()?; + Ok(TransactionExecutor::::new( + CachedState::new(test_state_reader), + block_context, + TransactionExecutorConfig::default(), + )) + } +} diff --git a/crates/blockifier_regression_test/src/state_reader/utils.rs b/crates/blockifier_regression_test/src/state_reader/utils.rs new file mode 100644 index 0000000000..5f94c0b05a --- /dev/null +++ b/crates/blockifier_regression_test/src/state_reader/utils.rs @@ -0,0 +1,94 @@ +use blockifier::context::{ChainInfo, FeeTokenAddresses}; +use papyrus_execution::{ETH_FEE_CONTRACT_ADDRESS, STRK_FEE_CONTRACT_ADDRESS}; +use serde_json::Value; +use starknet_api::core::{ChainId, ContractAddress, PatriciaKey}; +use starknet_api::transaction::{ + DeclareTransaction, + DeployAccountTransaction, + InvokeTransaction, + Transaction, +}; +use starknet_api::{contract_address, felt, patricia_key}; +use starknet_gateway::config::RpcStateReaderConfig; + +pub const RPC_NODE_URL: &str = "https://free-rpc.nethermind.io/mainnet-juno/"; +pub const JSON_RPC_VERSION: &str = "2.0"; + +/// Returns the fee token addresses of mainnet. +pub fn get_fee_token_addresses() -> FeeTokenAddresses { + FeeTokenAddresses { + strk_fee_token_address: contract_address!(STRK_FEE_CONTRACT_ADDRESS), + eth_fee_token_address: contract_address!(ETH_FEE_CONTRACT_ADDRESS), + } +} + +/// Returns the RPC state reader configuration with the constants RPC_NODE_URL and JSON_RPC_VERSION. +pub fn get_rpc_state_reader_config() -> RpcStateReaderConfig { + RpcStateReaderConfig { + url: RPC_NODE_URL.to_string(), + json_rpc_version: JSON_RPC_VERSION.to_string(), + } +} + +/// Returns the chain info of mainnet. +pub fn get_chain_info() -> ChainInfo { + ChainInfo { chain_id: ChainId::Mainnet, fee_token_addresses: get_fee_token_addresses() } +} + +pub fn deserialize_transaction_json_to_starknet_api_tx( + mut raw_transaction: Value, +) -> serde_json::Result { + let tx_type: String = serde_json::from_value(raw_transaction["type"].clone())?; + let tx_version: String = serde_json::from_value(raw_transaction["version"].clone())?; + + match (tx_type.as_str(), tx_version.as_str()) { + ("INVOKE", "0x0") => { + Ok(Transaction::Invoke(InvokeTransaction::V0(serde_json::from_value(raw_transaction)?))) + } + ("INVOKE", "0x1") => { + Ok(Transaction::Invoke(InvokeTransaction::V1(serde_json::from_value(raw_transaction)?))) + } + ("INVOKE", "0x3") => { + let resource_bounds = raw_transaction + .get_mut("resource_bounds") + .expect("Invoke v3 tx should contain resource_bounds field") + .as_object_mut() + .expect("resource_bounds should be an object"); + + // In old invoke v3 transaction, the resource bounds names are lowercase. + // need to convert to uppercase for deserialization to work. + if let Some(l1_gas_value) = resource_bounds.remove("l1_gas") { + resource_bounds.insert("L1_GAS".to_string(), l1_gas_value); + + let l2_gas_value = resource_bounds + .remove("l2_gas") + .expect("If invoke v3 tx contains l1_gas, it should contain l2_gas"); + resource_bounds.insert("L2_GAS".to_string(), l2_gas_value); + } + + Ok(Transaction::Invoke(InvokeTransaction::V3(serde_json::from_value(raw_transaction)?))) + } + ("DEPLOY_ACCOUNT", "0x1") => Ok(Transaction::DeployAccount(DeployAccountTransaction::V1( + serde_json::from_value(raw_transaction)?, + ))), + ("DEPLOY_ACCOUNT", "0x3") => Ok(Transaction::DeployAccount(DeployAccountTransaction::V3( + serde_json::from_value(raw_transaction)?, + ))), + ("DECLARE", "0x0") => Ok(Transaction::Declare(DeclareTransaction::V0( + serde_json::from_value(raw_transaction)?, + ))), + ("DECLARE", "0x1") => Ok(Transaction::Declare(DeclareTransaction::V1( + serde_json::from_value(raw_transaction)?, + ))), + ("DECLARE", "0x2") => Ok(Transaction::Declare(DeclareTransaction::V2( + serde_json::from_value(raw_transaction)?, + ))), + ("DECLARE", "0x3") => Ok(Transaction::Declare(DeclareTransaction::V3( + serde_json::from_value(raw_transaction)?, + ))), + ("L1_HANDLER", _) => Ok(Transaction::L1Handler(serde_json::from_value(raw_transaction)?)), + (tx_type, tx_version) => Err(serde::de::Error::custom(format!( + "unimplemented transaction type: {tx_type} version: {tx_version}" + ))), + } +} diff --git a/crates/gateway/src/rpc_state_reader_test.rs b/crates/gateway/src/rpc_state_reader_test.rs index 4fa099d00a..5269a0b517 100644 --- a/crates/gateway/src/rpc_state_reader_test.rs +++ b/crates/gateway/src/rpc_state_reader_test.rs @@ -78,6 +78,10 @@ async fn test_get_block_info() { price_in_wei: 1_u8.into(), price_in_fri: 1_u8.into(), }, + l2_gas_price: ResourcePrice { + price_in_wei: GasPrice(1), + price_in_fri: GasPrice(1), + }, ..Default::default() }) .unwrap(), diff --git a/crates/mempool/src/mempool_test.rs b/crates/mempool/src/mempool_test.rs index b2ff2bef63..0867a8e68c 100644 --- a/crates/mempool/src/mempool_test.rs +++ b/crates/mempool/src/mempool_test.rs @@ -337,10 +337,12 @@ fn test_add_tx(mut mempool: Mempool) { add_tx_inputs.sort_by_key(|input| std::cmp::Reverse(input.tx.tip().unwrap())); // Assert: transactions are ordered by priority. + let expected_account_nonces = [("0x0", 0), ("0x1", 1), ("0x2", 2)]; let expected_queue_txs: Vec = add_tx_inputs.iter().map(|input| TransactionReference::new(&input.tx)).collect(); let expected_pool_txs = add_tx_inputs.into_iter().map(|input| input.tx); let expected_mempool_content = MempoolContentBuilder::new() + .with_account_nonces(expected_account_nonces) .with_pool(expected_pool_txs) .with_priority_queue(expected_queue_txs) .build(); diff --git a/crates/papyrus_network/src/lib.rs b/crates/papyrus_network/src/lib.rs index 5c0b33a789..ae72a9612a 100644 --- a/crates/papyrus_network/src/lib.rs +++ b/crates/papyrus_network/src/lib.rs @@ -13,7 +13,7 @@ mod peer_manager; mod sqmr; #[cfg(test)] mod test_utils; -mod utils; +pub mod utils; use std::collections::BTreeMap; use std::time::Duration; diff --git a/crates/papyrus_network/src/utils.rs b/crates/papyrus_network/src/utils.rs index bc0a3ab971..015b0d701e 100644 --- a/crates/papyrus_network/src/utils.rs +++ b/crates/papyrus_network/src/utils.rs @@ -66,7 +66,7 @@ impl Stream for StreamHashMap PeerId { @@ -38,8 +40,9 @@ struct StreamData> + TryFrom, Error = ProtobufCo } impl> + TryFrom, Error = ProtobufConversionError>> StreamData { - fn new(sender: mpsc::Sender) -> Self { + fn new(peer_id: PeerId, sender: mpsc::Sender) -> Self { StreamData { + peer_id, next_message_id: 0, fin_message_id: None, max_message_id_received: 0, @@ -54,7 +57,7 @@ pub struct StreamHandler< T: Clone + Into> + TryFrom, Error = ProtobufConversionError>, > { // An end of a channel used to send out receivers, one for each stream. - sender: mpsc::Sender>, + listen_channel_sender: mpsc::Sender>, // An end of a channel used to receive messages. receiver: BroadcastTopicServer>, // A map from stream_id to a struct that contains all the information about the stream. @@ -63,7 +66,7 @@ pub struct StreamHandler< // TODO(guyn): perhaps make input_stream_data and output_stream_data? } -impl> + TryFrom, Error = ProtobufConversionError>> +impl> + TryFrom, Error = ProtobufConversionError>> StreamHandler { /// Create a new StreamHandler. @@ -71,20 +74,57 @@ impl> + TryFrom, Error = ProtobufConversionError sender: mpsc::Sender>, receiver: BroadcastTopicServer>, ) -> Self { - StreamHandler { sender, receiver, stream_data: HashMap::new() } + StreamHandler { + listen_channel_sender, + listen_receiver, + broadcast_sender, + broadcast_channel_receiver, + listen_stream_data: HashMap::new(), + broadcast_stream_receivers: StreamHashMap::new(HashMap::new()), + broadcast_stream_number: HashMap::new(), + } } /// Listen for messages on the receiver channel, buffering them if necessary. /// Guarantees that messages are sent in order. - pub async fn listen(&mut self) { + pub async fn run(&mut self) { loop { - if let Some(message) = self.receiver.next().await { - self.handle_message(message); - } + // The StreamHashMap doesn't report back that some of the channels were closed, + // but the relevant keys are removed when that happens. So check before-after: + let before: HashSet<_> = self.broadcast_stream_receivers.keys().cloned().collect(); + + // Go over the broadcast_channel_receiver to see if there is a new receiver, + // and go over all existing broadcast_receivers to see if there are any messages to + // send. Finally, check if there is an input message from the network. + tokio::select!( + Some((stream_id, receiver)) = self.broadcast_channel_receiver.next() => { + self.broadcast_stream_receivers.insert(stream_id, receiver); + } + output = self.broadcast_stream_receivers.next() => { + match output { + Some((key, message)) => { + println!("Got message! "); + self.broadcast(key, message).await; + } + None => { + let after: HashSet<_> = self.broadcast_stream_receivers.keys().cloned().collect(); + println!("before: {:?} | after: {:?}", before, after); + let diff = before.difference(&after).collect::>(); + for key in diff { + println!("Removing key: {:?}", key); + self.broadcast_fin(*key).await; + } + } + } + } + Some(message) = self.listen_receiver.next() => { + self.handle_message(message); + } + ); } } - fn send(data: &mut StreamData, message: StreamMessage) { + fn internal_send(data: &mut StreamData, message: StreamMessage) { // TODO(guyn): reconsider the "expect" here. let sender = &mut data.sender; if let StreamMessageBody::Content(content) = message.message { @@ -118,9 +158,9 @@ impl> + TryFrom, Error = ProtobufConversionError // we need to create a new receiver for it. let (sender, receiver) = mpsc::channel(CHANNEL_BUFFER_LENGTH); // TODO(guyn): reconsider the "expect" here. - self.sender.try_send(receiver).expect("Send should succeed"); + self.listen_channel_sender.try_send(receiver).expect("Send should succeed"); - let data = StreamData::new(sender); + let data = StreamData::new(peer_id.clone(), sender); e.insert(data) } }; @@ -160,7 +200,7 @@ impl> + TryFrom, Error = ProtobufConversionError // This means we can just send the message without buffering it. if message_id == data.next_message_id { - Self::send(data, message); + Self::internal_send(data, message); Self::process_buffer(data); @@ -201,7 +241,7 @@ impl> + TryFrom, Error = ProtobufConversionError // DOES NOT guarantee that the buffer will be empty after calling this function. fn process_buffer(data: &mut StreamData) { while let Some(message) = data.message_buffer.remove(&data.next_message_id) { - Self::send(data, message); + Self::internal_send(data, message); } } } diff --git a/crates/sequencing/papyrus_consensus/src/stream_handler_test.rs b/crates/sequencing/papyrus_consensus/src/stream_handler_test.rs index 258f965bf4..7b0201cbe6 100644 --- a/crates/sequencing/papyrus_consensus/src/stream_handler_test.rs +++ b/crates/sequencing/papyrus_consensus/src/stream_handler_test.rs @@ -20,6 +20,7 @@ mod tests { use papyrus_network_types::network_types::BroadcastedMessageManager; use super::*; + use crate::stream_handler; fn make_test_message( stream_id: u64, @@ -80,7 +81,7 @@ mod tests { } let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(Duration::from_millis(100), stream_handler.listen()).await; + let _ = tokio::time::timeout(Duration::from_millis(100), stream_handler.run()).await; }); join_handle.await.expect("Task should succeed"); @@ -105,13 +106,13 @@ mod tests { send(&mut network_sender, &metadata, message).await; } let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(Duration::from_millis(100), stream_handler.listen()).await; + let _ = tokio::time::timeout(Duration::from_millis(100), stream_handler.run()).await; stream_handler }); let mut stream_handler = join_handle.await.expect("Task should succeed"); // Get the receiver for the stream. - let mut receiver = rx_output.next().await.unwrap(); + let mut receiver = listen_channel_receiver.next().await.unwrap(); // Check that the channel is empty (no messages were sent yet). assert!(receiver.try_next().is_err()); @@ -131,12 +132,12 @@ mod tests { // Now send the last message: send(&mut network_sender, &metadata, make_test_message(stream_id, 0, false)).await; let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(Duration::from_millis(100), stream_handler.listen()).await; + let _ = tokio::time::timeout(Duration::from_millis(100), stream_handler.run()).await; stream_handler }); let stream_handler = join_handle.await.expect("Task should succeed"); - assert!(stream_handler.stream_data.is_empty()); + assert!(stream_handler.listen_stream_data.is_empty()); for _ in 0..5 { // message number 5 is Fin, so it will not be sent! @@ -175,7 +176,7 @@ mod tests { } let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(Duration::from_millis(100), stream_handler.listen()).await; + let _ = tokio::time::timeout(Duration::from_millis(100), stream_handler.run()).await; stream_handler }); let mut stream_handler = join_handle.await.expect("Task should succeed"); @@ -214,19 +215,19 @@ mod tests { )); // Get the receiver for the first stream. - let mut receiver1 = rx_output.next().await.unwrap(); + let mut receiver1 = listen_channel_receiver.next().await.unwrap(); // Check that the channel is empty (no messages were sent yet). assert!(receiver1.try_next().is_err()); // Get the receiver for the second stream. - let mut receiver2 = rx_output.next().await.unwrap(); + let mut receiver2 = listen_channel_receiver.next().await.unwrap(); // Check that the channel is empty (no messages were sent yet). assert!(receiver2.try_next().is_err()); // Get the receiver for the third stream. - let mut receiver3 = rx_output.next().await.unwrap(); + let mut receiver3 = listen_channel_receiver.next().await.unwrap(); // Check that the channel is empty (no messages were sent yet). assert!(receiver3.try_next().is_err()); @@ -234,7 +235,7 @@ mod tests { // Send the last message on stream_id1: send(&mut network_sender, &metadata, make_test_message(stream_id1, 0, false)).await; let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(Duration::from_millis(100), stream_handler.listen()).await; + let _ = tokio::time::timeout(Duration::from_millis(100), stream_handler.run()).await; stream_handler }); @@ -256,7 +257,7 @@ mod tests { // Send the last message on stream_id2: send(&mut network_sender, &metadata, make_test_message(stream_id2, 0, false)).await; let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(Duration::from_millis(100), stream_handler.listen()).await; + let _ = tokio::time::timeout(Duration::from_millis(100), stream_handler.run()).await; stream_handler }); @@ -279,7 +280,7 @@ mod tests { send(&mut network_sender, &metadata, make_test_message(stream_id3, 0, false)).await; let join_handle = tokio::spawn(async move { - let _ = tokio::time::timeout(Duration::from_millis(100), stream_handler.listen()).await; + let _ = tokio::time::timeout(Duration::from_millis(100), stream_handler.run()).await; stream_handler }); diff --git a/crates/starknet_api/src/transaction.rs b/crates/starknet_api/src/transaction.rs index 0c7bd5e35a..40ad1548de 100644 --- a/crates/starknet_api/src/transaction.rs +++ b/crates/starknet_api/src/transaction.rs @@ -1090,6 +1090,12 @@ pub enum GasVectorComputationMode { NoL2Gas, } +#[derive(Debug, PartialEq)] +pub enum GasVectorComputationMode { + All, + NoL2Gas, +} + /// A mapping from execution resources to their corresponding fee bounds.. #[derive(Clone, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] // TODO(Nimrod): Remove this struct definition. diff --git a/crates/tests-integration/src/integration_test_utils.rs b/crates/tests-integration/src/integration_test_utils.rs index 854910ddfa..715315add7 100644 --- a/crates/tests-integration/src/integration_test_utils.rs +++ b/crates/tests-integration/src/integration_test_utils.rs @@ -1,10 +1,12 @@ use std::net::SocketAddr; +use std::path::Path; use axum::body::Body; use blockifier::context::ChainInfo; use mempool_test_utils::starknet_api_test_utils::rpc_tx_to_json; use papyrus_storage::StorageConfig; use reqwest::{Client, Response}; +use starknet_api::core::ChainId; use starknet_api::rpc_transaction::RpcTransaction; use starknet_api::transaction::TransactionHash; use starknet_batcher::config::BatcherConfig; diff --git a/crates/tests-integration/src/state_reader.rs b/crates/tests-integration/src/state_reader.rs index ba3fa121fe..6c8ea3ef1b 100644 --- a/crates/tests-integration/src/state_reader.rs +++ b/crates/tests-integration/src/state_reader.rs @@ -232,6 +232,10 @@ fn test_block_header(block_number: BlockNumber) -> BlockHeader { price_in_wei: DEFAULT_ETH_L1_GAS_PRICE.into(), price_in_fri: DEFAULT_STRK_L2_GAS_PRICE.into(), }, + l2_gas_price: GasPricePerToken { + price_in_wei: GasPrice(DEFAULT_ETH_L1_GAS_PRICE), + price_in_fri: GasPrice(DEFAULT_STRK_L2_GAS_PRICE), + }, timestamp: BlockTimestamp(CURRENT_BLOCK_TIMESTAMP), ..Default::default() },