From ec43b7b472a23e1e8e417d783bf77460512c5304 Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 14 Jan 2025 08:18:23 +0100 Subject: [PATCH 01/18] first version - dirty --- Cargo.lock | 394 ++++++++++++++++- Cargo.toml | 8 + crates/core/Cargo.toml | 16 + crates/core/src/lib.rs | 2 + crates/core/src/node/debug.rs | 2 +- crates/core/src/node/eth.rs | 8 +- crates/core/src/node/in_memory.rs | 142 ++++-- crates/core/src/node/in_memory_ext.rs | 2 + crates/core/src/node/mod.rs | 1 + crates/core/src/node/zkos.rs | 597 ++++++++++++++++++++++++++ rust-toolchain.toml | 2 +- 11 files changed, 1128 insertions(+), 46 deletions(-) create mode 100644 crates/core/src/node/zkos.rs diff --git a/Cargo.lock b/Cargo.lock index 42ae4c5f..454b40ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,12 @@ dependencies = [ "gimli", ] +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "adler2" version = "2.0.0" @@ -38,6 +44,18 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -47,6 +65,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "alloy-consensus" version = "0.5.4" @@ -468,12 +492,14 @@ dependencies = [ "anvil_zksync_config", "anvil_zksync_types", "anyhow", + "basic_system", "chrono", "colored", "ethabi 16.0.0", "ethers", "eyre", "flate2", + "forward_system", "futures 0.3.31", "hex", "httptest", @@ -483,9 +509,11 @@ dependencies = [ "maplit", "once_cell", "reqwest 0.11.27", + "ruint", "rustc-hash 1.1.0", "serde", "serde_json", + "system_hooks", "tempdir", "test-case", "thiserror", @@ -493,7 +521,9 @@ dependencies = [ "tokio", "tracing", "tracing-subscriber", + "zk_ee", "zksync-web3-rs", + "zksync_basic_types", "zksync_contracts", "zksync_multivm", "zksync_types", @@ -517,6 +547,38 @@ version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-poly", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.2", + "itertools 0.13.0", + "num-bigint", + "num-integer", + "num-traits", + "zeroize", +] + [[package]] name = "ark-ff" version = "0.3.0" @@ -555,6 +617,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec 0.7.6", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "zeroize", +] + [[package]] name = "ark-ff-asm" version = "0.3.0" @@ -575,6 +657,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.89", +] + [[package]] name = "ark-ff-macros" version = "0.3.0" @@ -600,6 +692,34 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.2", +] + [[package]] name = "ark-serialize" version = "0.3.0" @@ -621,6 +741,30 @@ dependencies = [ "num-bigint", ] +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive", + "ark-std 0.5.0", + "arrayvec 0.7.6", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "ark-std" version = "0.3.0" @@ -641,6 +785,16 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -859,6 +1013,51 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "basic_bootloader" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +dependencies = [ + "arrayvec 0.7.6", + "crypto", + "either", + "evm_interpreter", + "hex", + "iwasm_ee", + "iwasm_interpreter", + "ruint", + "seq-macro", + "system_hooks", + "zk_ee", +] + +[[package]] +name = "basic_system" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "arrayvec 0.7.6", + "cfg-if", + "const_for", + "crypto", + "either", + "evm_interpreter", + "hex", + "iwasm_ee", + "iwasm_interpreter", + "miniz_nostd_compression", + "ruint", + "secp256k1 0.1.0", + "serde", + "storage_models", + "system_hooks", + "zk_ee", +] + [[package]] name = "bech32" version = "0.9.1" @@ -887,6 +1086,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bindgen" version = "0.69.5" @@ -1439,6 +1647,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const_for" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c50fcfdf972929aff202c16b80086aa3cfc6a3a820af714096c58c7c1d0582" + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -1541,6 +1755,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +dependencies = [ + "blake2", + "k256 0.13.4", + "p256", + "sha2 0.10.8", + "sha3 0.10.8", +] + [[package]] name = "crypto-bigint" version = "0.4.9" @@ -1825,6 +2051,18 @@ dependencies = [ "spki 0.7.3", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "either" version = "1.13.0" @@ -1916,6 +2154,26 @@ dependencies = [ "zeroize", ] +[[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.89", +] + [[package]] name = "enum_dispatch" version = "0.3.13" @@ -2326,6 +2584,19 @@ dependencies = [ "yansi 0.5.1", ] +[[package]] +name = "evm_interpreter" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +dependencies = [ + "arrayvec 0.7.6", + "crypto", + "either", + "hex", + "ruint", + "zk_ee", +] + [[package]] name = "eyre" version = "0.6.12" @@ -2461,6 +2732,26 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "forward_system" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +dependencies = [ + "arrayvec 0.7.6", + "basic_bootloader", + "basic_system", + "bincode", + "crypto", + "either", + "evm_interpreter", + "hex", + "ruint", + "seq-macro", + "serde", + "system_hooks", + "zk_ee", +] + [[package]] name = "fs2" version = "0.4.3" @@ -2779,6 +3070,7 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ + "allocator-api2", "foldhash", "serde", ] @@ -3422,6 +3714,36 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +[[package]] +name = "iwasm_ee" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +dependencies = [ + "arrayvec 0.7.6", + "crypto", + "iwasm_interpreter", + "iwasm_specification", + "ruint", + "zk_ee", +] + +[[package]] +name = "iwasm_interpreter" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +dependencies = [ + "arrayvec 0.7.6", +] + +[[package]] +name = "iwasm_specification" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +dependencies = [ + "num-derive", + "num-traits", +] + [[package]] name = "jni" version = "0.19.0" @@ -3906,6 +4228,14 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_nostd_compression" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +dependencies = [ + "adler", +] + [[package]] name = "miniz_oxide" version = "0.8.0" @@ -4017,6 +4347,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "num-integer" version = "0.1.46" @@ -5638,6 +5979,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "secp256k1" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +dependencies = [ + "cfg-if", + "const_for", + "crypto", +] + [[package]] name = "secp256k1" version = "0.27.0" @@ -5836,6 +6187,12 @@ dependencies = [ "uuid 1.11.0", ] +[[package]] +name = "seq-macro" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" + [[package]] name = "serde" version = "1.0.215" @@ -6184,6 +6541,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "storage_models" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +dependencies = [ + "arrayvec 0.7.6", + "either", + "ruint", + "zk_ee", +] + [[package]] name = "string_cache" version = "0.8.7" @@ -6359,6 +6727,16 @@ dependencies = [ "libc", ] +[[package]] +name = "system_hooks" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +dependencies = [ + "crypto", + "ruint", + "zk_ee", +] + [[package]] name = "tap" version = "1.0.1" @@ -7702,6 +8080,20 @@ dependencies = [ "zstd", ] +[[package]] +name = "zk_ee" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +dependencies = [ + "arrayvec 0.7.6", + "bitflags 2.6.0", + "cfg-if", + "crypto", + "derivative", + "ruint", + "serde", +] + [[package]] name = "zk_evm" version = "0.131.0-rc.2" @@ -8016,7 +8408,7 @@ dependencies = [ "blake2", "hex", "rand 0.8.5", - "secp256k1", + "secp256k1 0.27.0", "serde", "serde_json", "sha2 0.10.8", diff --git a/Cargo.toml b/Cargo.toml index 536e335f..fbb67e7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,12 +28,20 @@ categories = ["cryptography"] ######################### zksync_multivm = { git = "https://github.com/matter-labs/zksync-era.git", rev = "core-v25.4.0" } zksync_contracts = { git = "https://github.com/matter-labs/zksync-era.git", rev = "core-v25.4.0" } +zksync_basic_types = { git = "https://github.com/matter-labs/zksync-era.git", rev = "core-v25.4.0" } zksync_types = { git = "https://github.com/matter-labs/zksync-era.git", rev = "core-v25.4.0" } zksync_vm_interface = { git = "https://github.com/matter-labs/zksync-era.git", rev = "core-v25.4.0" } zksync_web3_decl = { git = "https://github.com/matter-labs/zksync-era.git", rev = "core-v25.4.0", features = [ "server", ] } + +forward_system = { git = "https://github.com/matter-labs/zk_ee.git", branch = "mmzk_1217_zkee_for_test_node" } +basic_system = { git = "https://github.com/matter-labs/zk_ee.git", branch = "mmzk_1217_zkee_for_test_node" } +zk_ee = { git = "https://github.com/matter-labs/zk_ee.git", branch = "mmzk_1217_zkee_for_test_node" } +system_hooks = { git = "https://github.com/matter-labs/zk_ee.git", branch = "mmzk_1217_zkee_for_test_node" } +ruint = { version = "1.12.3", default-features = false, features = ["alloc"] } + ######################### # External dependencies # ######################### diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index ae05d588..1ff92c66 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -17,6 +17,7 @@ zksync_multivm.workspace = true zksync_contracts.workspace = true zksync_types.workspace = true zksync_web3_decl.workspace = true +zksync_basic_types.workspace = true anyhow.workspace = true tokio.workspace = true @@ -41,6 +42,13 @@ time.workspace = true flate2.workspace = true thiserror.workspace = true + +forward_system.workspace = true +basic_system.workspace = true +zk_ee.workspace = true +system_hooks.workspace = true +ruint.workspace = true + [dev-dependencies] maplit.workspace = true ethers.workspace = true @@ -48,3 +56,11 @@ httptest.workspace = true tempdir.workspace = true zksync-web3-rs.workspace = true test-case.workspace = true + + + +[features] + +zkos = [] + +default = ["zkos"] \ No newline at end of file diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index f1549d44..201359af 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(allocator_api)] + //! anvil-zksync //! //! The `anvil-zksync` crate provides an in-memory node designed primarily for local testing. diff --git a/crates/core/src/node/debug.rs b/crates/core/src/node/debug.rs index 2fe812b1..298bcc27 100644 --- a/crates/core/src/node/debug.rs +++ b/crates/core/src/node/debug.rs @@ -87,7 +87,7 @@ impl InMemoryNode { ))); } - let allow_no_target = system_contracts.evm_emulator.is_some(); + let allow_no_target = true; //system_contracts.evm_emulator.is_some(); let mut l2_tx = L2Tx::from_request(request.into(), MAX_TX_SIZE, allow_no_target) .map_err(Web3Error::SerializationError)?; let execution_mode = zksync_multivm::interface::TxExecutionMode::EthCall; diff --git a/crates/core/src/node/eth.rs b/crates/core/src/node/eth.rs index a1bb4690..97bffa15 100644 --- a/crates/core/src/node/eth.rs +++ b/crates/core/src/node/eth.rs @@ -35,7 +35,7 @@ impl InMemoryNode { req: zksync_types::transaction_request::CallRequest, ) -> Result { let system_contracts = self.system_contracts.contracts_for_l2_call().clone(); - let allow_no_target = system_contracts.evm_emulator.is_some(); + let allow_no_target = true; //system_contracts.evm_emulator.is_some(); let mut tx = L2Tx::from_request(req.into(), MAX_TX_SIZE, allow_no_target)?; tx.common_data.fee.gas_limit = ETH_CALL_GAS_LIMIT.into(); @@ -87,7 +87,7 @@ impl InMemoryNode { let system_contracts = self .system_contracts .contracts(TxExecutionMode::VerifyExecute, false); - let allow_no_target = system_contracts.evm_emulator.is_some(); + let allow_no_target = true; //system_contracts.evm_emulator.is_some(); let mut l2_tx = L2Tx::from_request(tx_req, MAX_TX_SIZE, allow_no_target)?; l2_tx.set_input(tx_bytes.0, hash); @@ -153,7 +153,7 @@ impl InMemoryNode { let system_contracts = self .system_contracts .contracts(TxExecutionMode::VerifyExecute, false); - let allow_no_target = system_contracts.evm_emulator.is_some(); + let allow_no_target = true; //system_contracts.evm_emulator.is_some(); let mut l2_tx: L2Tx = L2Tx::from_request(tx_req, MAX_TX_SIZE, allow_no_target)?; // `v` was overwritten with 0 during converting into l2 tx @@ -187,6 +187,7 @@ impl InMemoryNode { // TODO: Support _block: Option, ) -> anyhow::Result { + // FIXHERE let balance_key = storage_key_for_standard_token_balance( AccountTreeId::new(L2_BASE_TOKEN_ADDRESS), &address, @@ -298,6 +299,7 @@ impl InMemoryNode { _block: Option, ) -> anyhow::Result { let inner = self.read_inner()?; + // FIXHERE let nonce_key = get_nonce_key(&address); match inner.fork_storage.read_value_internal(&nonce_key) { diff --git a/crates/core/src/node/in_memory.rs b/crates/core/src/node/in_memory.rs index e01e4961..2847ba9a 100644 --- a/crates/core/src/node/in_memory.rs +++ b/crates/core/src/node/in_memory.rs @@ -4,6 +4,7 @@ use crate::node::error::LoadStateError; use crate::node::impersonate::{ImpersonationManager, ImpersonationState}; use crate::node::state::{StateV1, VersionedState}; use crate::node::time::{AdvanceTime, ReadTime, TimestampManager}; +use crate::node::zkos::add_elem_to_tree; use crate::node::{BlockSealer, BlockSealerMode, TxPool}; use crate::{ bootloader_debug::{BootloaderDebug, BootloaderDebugTracer}, @@ -83,6 +84,8 @@ use zksync_types::{ use zksync_types::{h256_to_address, h256_to_u256, u256_to_h256}; use zksync_web3_decl::error::Web3Error; +use super::zkos::{zkos_get_nonce_key, zkos_storage_key_for_eth_balance, ZKOsVM}; + /// Max possible size of an ABI encoded tx (in bytes). pub const MAX_TX_SIZE: usize = 1_000_000; /// Acceptable gas overestimation limit. @@ -274,7 +277,8 @@ pub struct InMemoryNodeInner { pub struct TxExecutionOutput { result: VmExecutionResultAndLogs, call_traces: Vec, - bytecodes: HashMap>, + bytecodes: HashMap>, + //bytecodes: HashMap>, } impl InMemoryNodeInner { @@ -498,7 +502,7 @@ impl InMemoryNodeInner { .system_contracts .contracts_for_fee_estimate(impersonating) .clone(); - let allow_no_target = system_contracts.evm_emulator.is_some(); + let allow_no_target = true; // system_contracts.evm_emulator.is_some(); let mut l2_tx = L2Tx::from_request( request_with_gas_per_pubdata_overridden.into(), @@ -773,7 +777,11 @@ impl InMemoryNodeInner { // The nonce needs to be updated let nonce = l2_tx.nonce(); + //let nonce_key = get_nonce_key(&l2_tx.initiator_account()); + #[cfg(not(feature = "zkos"))] let nonce_key = get_nonce_key(&l2_tx.initiator_account()); + #[cfg(feature = "zkos")] + let nonce_key = zkos_get_nonce_key(&l2_tx.initiator_account()); let full_nonce = storage.borrow_mut().read_value(&nonce_key); let (_, deployment_nonce) = decompose_full_nonce(h256_to_u256(full_nonce)); let enforced_full_nonce = nonces_to_full_nonce(U256::from(nonce.0), deployment_nonce); @@ -783,7 +791,11 @@ impl InMemoryNodeInner { // We need to explicitly put enough balance into the account of the users let payer = l2_tx.payer(); + + #[cfg(not(feature = "zkos"))] let balance_key = storage_key_for_eth_balance(&payer); + #[cfg(feature = "zkos")] + let balance_key = zkos_storage_key_for_eth_balance(&payer); let mut current_balance = h256_to_u256(storage.borrow_mut().read_value(&balance_key)); let added_balance = l2_tx.common_data.fee.gas_limit * l2_tx.common_data.fee.max_fee_per_gas; current_balance += added_balance; @@ -791,7 +803,23 @@ impl InMemoryNodeInner { .borrow_mut() .set_value(balance_key, u256_to_h256(current_balance)); + //let mut vm: Vm<_, HistoryDisabled> = Vm::new(batch_env, system_env, storage.clone()); + + #[cfg(not(feature = "zkos"))] let mut vm: Vm<_, HistoryDisabled> = Vm::new(batch_env, system_env, storage.clone()); + #[cfg(feature = "zkos")] + let mut vm = ZKOsVM::new( + storage.clone(), + &fork_storage.inner.read().unwrap().raw_storage, + system_env.execution_mode, + ); + #[cfg(feature = "zkos")] + { + // Temporary hack - as we update the 'storage' just above, but zkos loads its full + // state from fork_storage (that is not updated). + add_elem_to_tree(&mut vm.tree, &nonce_key, &u256_to_h256(enforced_full_nonce)); + add_elem_to_tree(&mut vm.tree, &balance_key, &u256_to_h256(current_balance)); + } let tx: Transaction = l2_tx.into(); vm.push_transaction(tx); @@ -1313,7 +1341,10 @@ impl InMemoryNode { /// Adds a lot of tokens to a given account with a specified balance. pub fn set_rich_account(&self, address: H160, balance: U256) { + #[cfg(not(feature = "zkos"))] let key = storage_key_for_eth_balance(&address); + #[cfg(feature = "zkos")] + let key = zkos_storage_key_for_eth_balance(&address); let mut inner = match self.inner.write() { Ok(guard) => guard, @@ -1369,10 +1400,17 @@ impl InMemoryNode { // init vm - let (batch_env, _) = inner.create_l1_batch_env(&self.time, storage.clone()); + // let (batch_env, _) = inner.create_l1_batch_env(&self.time, storage.clone()); let system_env = inner.create_system_env(base_contracts, execution_mode); + #[cfg(not(feature = "zkos"))] let mut vm: Vm<_, HistoryDisabled> = Vm::new(batch_env, system_env, storage.clone()); + #[cfg(feature = "zkos")] + let mut vm = ZKOsVM::new( + storage.clone(), + &inner.fork_storage.inner.read().unwrap().raw_storage, + execution_mode, + ); // We must inject *some* signature (otherwise bootloader code fails to generate hash). if l2_tx.common_data.signature.is_empty() { @@ -1384,11 +1422,15 @@ impl InMemoryNode { let call_tracer_result = Arc::new(OnceCell::default()); + #[cfg(not(feature = "zkos"))] let tracers = vec![ CallErrorTracer::new().into_tracer_pointer(), CallTracer::new(call_tracer_result.clone()).into_tracer_pointer(), ]; + #[cfg(not(feature = "zkos"))] let tx_result = vm.inspect(&mut tracers.into(), InspectExecutionMode::OneTx); + #[cfg(feature = "zkos")] + let tx_result = vm.inspect(&mut Default::default(), InspectExecutionMode::OneTx); let call_traces = Arc::try_unwrap(call_tracer_result) .unwrap() @@ -1527,10 +1569,10 @@ impl InMemoryNode { /// This is because external users of the library may call this function to perform an isolated /// VM operation (optionally without bootloader execution) with an external storage and get the results back. /// So any data populated in [Self::run_l2_tx] will not be available for the next invocation. - pub fn run_l2_tx_raw( + pub fn run_l2_tx_raw( &self, l2_tx: L2Tx, - vm: &mut Vm, + vm: &mut VM, ) -> anyhow::Result { let inner = self .inner @@ -1542,7 +1584,8 @@ impl InMemoryNode { let call_tracer_result = Arc::new(OnceCell::default()); let bootloader_debug_result = Arc::new(OnceCell::default()); - let tracers = vec![ + #[cfg(not(feature = "zkos"))] + let tracers: Vec>> = vec![ CallErrorTracer::new().into_tracer_pointer(), CallTracer::new(call_tracer_result.clone()).into_tracer_pointer(), BootloaderDebugTracer { @@ -1554,9 +1597,13 @@ impl InMemoryNode { .push_transaction(tx.clone()) .compressed_bytecodes .into_owned(); + + #[cfg(not(feature = "zkos"))] let tx_result = vm.inspect(&mut tracers.into(), InspectExecutionMode::OneTx); + #[cfg(feature = "zkos")] + let tx_result = vm.inspect(&mut Default::default(), InspectExecutionMode::OneTx); - let call_traces = call_tracer_result.get().unwrap(); + let call_traces = call_tracer_result.get(); let spent_on_pubdata = tx_result.statistics.gas_used - tx_result.statistics.computational_gas_used as u64; @@ -1595,31 +1642,33 @@ impl InMemoryNode { formatter.print_vm_details(&tx_result); } - if !inner.config.disable_console_log { - inner - .console_log_handler - .handle_calls_recursive(call_traces); - } + if let Some(call_traces) = call_traces { + if !inner.config.disable_console_log { + inner + .console_log_handler + .handle_calls_recursive(call_traces); + } - if inner.config.show_calls != ShowCalls::None { - tracing::info!(""); - tracing::info!( - "[Transaction Execution] ({} calls)", - call_traces[0].calls.len() - ); - let num_calls = call_traces.len(); - for (i, call) in call_traces.iter().enumerate() { - let is_last_sibling = i == num_calls - 1; - let mut formatter = formatter::Formatter::new(); - formatter.print_call( - tx.initiator_account(), - tx.execute.contract_address, - call, - is_last_sibling, - &inner.config.show_calls, - inner.config.show_outputs, - inner.config.resolve_hashes, + if inner.config.show_calls != ShowCalls::None { + tracing::info!(""); + tracing::info!( + "[Transaction Execution] ({} calls)", + call_traces[0].calls.len() ); + let num_calls = call_traces.len(); + for (i, call) in call_traces.iter().enumerate() { + let is_last_sibling = i == num_calls - 1; + let mut formatter = formatter::Formatter::new(); + formatter.print_call( + tx.initiator_account(), + tx.execute.contract_address, + call, + is_last_sibling, + &inner.config.show_calls, + inner.config.show_outputs, + inner.config.resolve_hashes, + ); + } } } // Print event logs if enabled @@ -1634,30 +1683,31 @@ impl InMemoryNode { tracing::info!(""); } - let mut bytecodes = HashMap::new(); - for b in &*compressed_bytecodes { + //let bytecodes = HashMap::new(); + // HERE + /*for b in &*compressed_bytecodes { let (hash, bytecode) = bytecode_to_factory_dep(b.original.clone()).map_err(|err| { tracing::error!("{}", format!("cannot convert bytecode: {err}").on_red()); err })?; bytecodes.insert(hash, bytecode); - } + }*/ Ok(TxExecutionOutput { - result: tx_result, - call_traces: call_traces.clone(), - bytecodes, + result: tx_result.clone(), + call_traces: call_traces.cloned().unwrap_or_default(), + bytecodes: tx_result.dynamic_factory_deps.clone(), }) } /// Runs L2 transaction and commits it to a new block. - pub fn run_l2_tx( + pub fn run_l2_tx( &self, l2_tx: L2Tx, l2_tx_index: U64, block_ctx: &BlockContext, batch_env: &L1BatchEnv, - vm: &mut Vm, + vm: &mut VM, ) -> anyhow::Result<()> { let tx_hash = l2_tx.hash(); let transaction_type = l2_tx.common_data.transaction_type; @@ -1705,7 +1755,10 @@ impl InMemoryNode { .write() .map_err(|_| anyhow::anyhow!("Failed to acquire write lock"))?; for (hash, code) in bytecodes.iter() { - inner.fork_storage.store_factory_dep( + inner + .fork_storage + .store_factory_dep(hash.clone(), code.clone()); + /*inner.fork_storage.store_factory_dep( u256_to_h256(*hash), code.iter() .flat_map(|entry| { @@ -1714,7 +1767,7 @@ impl InMemoryNode { bytes.to_vec() }) .collect(), - ) + )*/ } let logs = result @@ -1800,8 +1853,17 @@ impl InMemoryNode { let storage = StorageView::new(inner.fork_storage.clone()).into_rc_ptr(); let system_env = inner.create_system_env(system_contracts, TxExecutionMode::VerifyExecute); let (batch_env, mut block_ctx) = inner.create_l1_batch_env(time, storage.clone()); + + #[cfg(feature = "zkos")] + let mut vm = ZKOsVM::new( + storage.clone(), + &inner.fork_storage.inner.read().unwrap().raw_storage, + TxExecutionMode::VerifyExecute, + ); + drop(inner); + #[cfg(not(feature = "zkos"))] let mut vm: Vm<_, HistoryEnabled> = Vm::new(batch_env.clone(), system_env, storage.clone()); // Compute block hash. Note that the computed block hash here will be different than that in production. diff --git a/crates/core/src/node/in_memory_ext.rs b/crates/core/src/node/in_memory_ext.rs index 2cd59dea..271fcf08 100644 --- a/crates/core/src/node/in_memory_ext.rs +++ b/crates/core/src/node/in_memory_ext.rs @@ -192,6 +192,7 @@ impl InMemoryNode { pub fn set_balance(&self, address: Address, balance: U256) -> Result { self.write_inner().map(|mut writer| { + // FIXHERE let balance_key = storage_key_for_eth_balance(&address); writer .fork_storage @@ -207,6 +208,7 @@ impl InMemoryNode { pub fn set_nonce(&self, address: Address, nonce: U256) -> Result { self.write_inner().map(|mut writer| { + // FIXHERE let nonce_key = get_nonce_key(&address); let enforced_full_nonce = nonces_to_full_nonce(nonce, nonce); tracing::info!( diff --git a/crates/core/src/node/mod.rs b/crates/core/src/node/mod.rs index 08bcc01e..8f62f100 100644 --- a/crates/core/src/node/mod.rs +++ b/crates/core/src/node/mod.rs @@ -14,6 +14,7 @@ mod sealer; mod state; mod storage_logs; mod time; +mod zkos; mod zks; pub use self::{ diff --git a/crates/core/src/node/zkos.rs b/crates/core/src/node/zkos.rs new file mode 100644 index 00000000..ee683b23 --- /dev/null +++ b/crates/core/src/node/zkos.rs @@ -0,0 +1,597 @@ +use std::{alloc::Global, collections::HashMap, vec}; + +use basic_system::basic_system::simple_growable_storage::TestingTree; +use forward_system::run::{ + test_impl::{InMemoryPreimageSource, InMemoryTree, TxListSource}, + PreimageType, StorageCommitment, +}; +use hex::ToHex; +use ruint::aliases::B160; +use system_hooks::addresses_constants::{ + NOMINAL_TOKEN_BALANCE_STORAGE_ADDRESS, NONCE_HOLDER_HOOK_ADDRESS, +}; +use zk_ee::{common_structs::derive_flat_storage_key, utils::Bytes32}; +use zksync_multivm::interface::{ + storage::{StoragePtr, WriteStorage}, + ExecutionResult, InspectExecutionMode, PushTransactionResult, TxExecutionMode, VmExecutionLogs, + VmExecutionResultAndLogs, VmInterface, VmInterfaceHistoryEnabled, VmRevertReason, +}; +use zksync_types::{ + address_to_h256, + block::{pack_block_info, unpack_block_info}, + h256_to_u256, + web3::keccak256, + AccountTreeId, Address, StorageKey, StorageLog, StorageLogWithPreviousValue, Transaction, H160, + H256, SYSTEM_CONTEXT_ADDRESS, SYSTEM_CONTEXT_BLOCK_INFO_POSITION, +}; +//use zksync_utils::{address_to_h256, h256_to_u256, u256_to_h256}; + +use crate::deps::InMemoryStorage; + +pub fn bytes32_to_h256(data: Bytes32) -> H256 { + H256::from(data.as_u8_array_ref()) +} + +pub fn h256_to_bytes32(data: &H256) -> Bytes32 { + Bytes32::from(data.as_fixed_bytes().clone()) +} + +pub fn b160_to_h160(data: B160) -> H160 { + H160::from_slice(&data.to_be_bytes_vec()) +} + +pub fn pad_to_word(input: &Vec) -> Vec { + let mut data = input.clone(); + let remainder = input.len().div_ceil(32) * 32 - input.len(); + for _ in 0..remainder { + data.push(0u8); + } + data +} + +// TODO: check endinanness +pub fn h160_to_b160(data: &H160) -> B160 { + B160::from_be_bytes(data.as_fixed_bytes().clone()) +} + +pub fn append_address(data: &mut Vec, address: &H160) { + let mut pp = vec![0u8; 32]; + let ap1 = address.as_fixed_bytes(); + for i in 0..20 { + pp[i + 12] = ap1[i]; + } + data.append(&mut pp); +} + +pub fn append_u256(data: &mut Vec, payload: &zksync_types::U256) { + let mut pp = [0u8; 32]; + payload.to_big_endian(&mut pp); + + data.append(&mut pp.to_vec()); +} +pub fn append_u64(data: &mut Vec, payload: u64) { + let mut pp = [0u8; 32]; + let pp1 = payload.to_be_bytes(); + for i in 0..8 { + pp[24 + i] = pp1[i]; + } + data.append(&mut pp.to_vec()); +} + +pub fn append_usize(data: &mut Vec, payload: usize) { + let mut pp = [0u8; 32]; + let pp1 = payload.to_be_bytes(); + for i in 0..8 { + pp[24 + i] = pp1[i]; + } + data.append(&mut pp.to_vec()); +} + +pub fn create_tree_from_full_state( + raw_storage: &InMemoryStorage, +) -> (InMemoryTree, InMemoryPreimageSource) { + let original_state = &raw_storage.state; + let mut tree = InMemoryTree { + storage_tree: TestingTree::new_in(Global), + cold_storage: HashMap::new(), + }; + let mut preimage_source = InMemoryPreimageSource { + inner: HashMap::new(), + }; + + for entry in original_state { + let kk = derive_flat_storage_key( + &h160_to_b160(entry.0.address()), + &h256_to_bytes32(entry.0.key()), + ); + let vv = h256_to_bytes32(entry.1); + + tree.storage_tree.insert(&kk, &vv); + tree.cold_storage.insert(kk, vv); + } + + for entry in &raw_storage.factory_deps { + preimage_source.inner.insert( + ( + PreimageType::Bytecode(zk_ee::system::ExecutionEnvironmentType::EVM), + h256_to_bytes32(entry.0), + ), + entry.1.clone(), + ); + } + println!("Tree size is: {}", tree.cold_storage.len()); + println!("Preimage size is: {}", preimage_source.inner.len()); + + (tree, preimage_source) +} + +pub fn add_elem_to_tree(tree: &mut InMemoryTree, k: &StorageKey, v: &H256) { + let kk = derive_flat_storage_key(&h160_to_b160(k.address()), &h256_to_bytes32(k.key())); + let vv = h256_to_bytes32(v); + + tree.storage_tree.insert(&kk, &vv); + tree.cold_storage.insert(kk, vv); +} + +// Serialize Transaction to ZKOS format. +// Should match the code in basic_bootlaoder/src/bootloader/transaction/mod.rs +pub fn transaction_to_zkos_vec(tx: &Transaction) -> Vec { + let mut tx_raw: Vec = vec![]; + let tx_type_id = match tx.tx_format() { + zksync_types::l2::TransactionType::LegacyTransaction => 0u8, + zksync_types::l2::TransactionType::EIP2930Transaction => 1u8, + zksync_types::l2::TransactionType::EIP1559Transaction => 2u8, + zksync_types::l2::TransactionType::EIP712Transaction => todo!(), + zksync_types::l2::TransactionType::PriorityOpTransaction => todo!(), + zksync_types::l2::TransactionType::ProtocolUpgradeTransaction => todo!(), + }; + let common_data = match &tx.common_data { + zksync_types::ExecuteTransactionCommon::L1(_) => todo!(), + zksync_types::ExecuteTransactionCommon::L2(l2_tx_common_data) => l2_tx_common_data, + zksync_types::ExecuteTransactionCommon::ProtocolUpgrade(_) => todo!(), + }; + // tx_type + tx_raw.append(&mut vec![0u8; 31]); + + tx_raw.append(&mut vec![tx_type_id; 1]); + + // from + append_address(&mut tx_raw, &common_data.initiator_address); + // to + append_address( + &mut tx_raw, + &tx.execute.contract_address.unwrap_or(H160::zero()), + ); + + let gas_limit = common_data.fee.gas_limit; + // gas limit + append_u256(&mut tx_raw, &gas_limit); + // gas per pubdata limit + append_u256(&mut tx_raw, &common_data.fee.gas_per_pubdata_limit); + + let fee_per_gas = common_data.fee.max_fee_per_gas; + + // max fee per gas + append_u256(&mut tx_raw, &fee_per_gas); + // max priority fee per gas. + // hack for legacy tx (verify!!) + append_u256(&mut tx_raw, &common_data.fee.max_priority_fee_per_gas); + + // paymaster + append_u64(&mut tx_raw, 0); + + // nonce + append_u64(&mut tx_raw, common_data.nonce.0.into()); + + append_u256(&mut tx_raw, &tx.execute.value); + + let mut reserved = [0u64; 4]; + + // Should check chain_id + if tx_type_id == 0 { + reserved[0] = 1; + } + + if tx.execute.contract_address.is_none() { + reserved[1] = 1; + } + + for i in 0..4 { + // reserved + append_u64(&mut tx_raw, reserved[i]); + } + + let signature_u256 = common_data.signature.len().div_ceil(32) as u64; + + let execute_calldata_words = tx.execute.calldata.len().div_ceil(32) as u64; + + let mut current_offset = 19; + + // data offset + append_u64(&mut tx_raw, current_offset * 32); + // lent + current_offset += 1 + execute_calldata_words; + // signature offset (stupid -- this doesn't include the padding!!) + append_u64(&mut tx_raw, current_offset * 32); + current_offset += 1 + signature_u256; + + // factory deps + append_u64(&mut tx_raw, current_offset * 32); + current_offset += 1; + // paymater + append_u64(&mut tx_raw, current_offset * 32); + current_offset += 1; + // reserved + append_u64(&mut tx_raw, current_offset * 32); + current_offset += 1; + + // len - data. + append_usize(&mut tx_raw, tx.execute.calldata.len()); + tx_raw.append(&mut pad_to_word(&tx.execute.calldata)); + + // len - signature. + append_usize(&mut tx_raw, common_data.signature.len()); + tx_raw.append(&mut pad_to_word(&common_data.signature)); + + // factory deps + append_u64(&mut tx_raw, 0); + // paymater + append_u64(&mut tx_raw, 0); + // reserved + append_u64(&mut tx_raw, 0); + tx_raw +} + +pub fn execute_tx_in_zkos( + tx: &Transaction, + tree: &InMemoryTree, + preimage_source: &InMemoryPreimageSource, + storage: &mut StoragePtr, + simulate_only: bool, +) -> VmExecutionResultAndLogs { + let batch_context = basic_system::basic_system::BasicBlockMetadataFromOracle { + eip1559_basefee: ruint::aliases::U256::from(if simulate_only { 0u64 } else { 1000u64 }), + ergs_price: ruint::aliases::U256::from(1u64), + // FIXME + block_number: 1, + timestamp: 42, + gas_per_pubdata: ruint::aliases::U256::from(1u64), + }; + + println!("Tree size is: {}", tree.cold_storage.len()); + + let storage_commitment = StorageCommitment { + root: *tree.storage_tree.root(), + next_free_slot: tree.storage_tree.next_free_slot, + }; + + let tx_raw = transaction_to_zkos_vec(tx); + + let (output, dynamic_factory_deps, storage_logs) = if simulate_only { + ( + forward_system::run::simulate_tx( + tx_raw, + storage_commitment, + batch_context, + tree.clone(), + preimage_source.clone(), + ) + .unwrap(), + Default::default(), // dynamic factory deps + vec![], // storage logs + ) + } else { + let tx_source = TxListSource { + // transactions: vec![encoded_iwasm_tx].into(), + transactions: vec![tx_raw].into(), + }; + let batch_output = forward_system::run::run_batch( + batch_context, + storage_commitment, + // FIXME + tree.clone(), + preimage_source.clone(), + tx_source, + ) + .unwrap(); + + let mut storage_ptr = storage.borrow_mut(); + + let mut storage_logs = vec![]; + + // apply storage writes.. + for write in batch_output.storage_writes { + //let ab = write.key.as_u8_array_ref(); + //let ac = H256::from(ab); + + let storage_key = StorageKey::new( + AccountTreeId::new(Address::from_slice(&write.account.to_be_bytes_vec())), + H256::from(write.account_key.as_u8_array_ref()), + ); + dbg!(&storage_key); + let storage_value = H256::from(write.value.as_u8_array_ref()); + let prev_value = storage_ptr.set_value(storage_key, storage_value); + + let storage_log = StorageLog { + // FIXME - should distinguish between initial write and repeated write. + kind: zksync_types::StorageLogKind::InitialWrite, + key: storage_key, + value: storage_value, + }; + storage_logs.push(StorageLogWithPreviousValue { + log: storage_log, + previous_value: prev_value, + }); + } + let mut f_deps = HashMap::new(); + + println!( + "Adding {} preimages:", + batch_output.published_preimages.len() + ); + + for factory_dep in batch_output.published_preimages { + println!(" {:?}", factory_dep.0); + f_deps.insert(bytes32_to_h256(factory_dep.0), factory_dep.1); + } + + (batch_output.tx_results[0].clone(), f_deps, storage_logs) + }; + + let tx_output = match output.as_ref() { + Ok(tx_output) => { + match &tx_output.execution_result { + forward_system::run::ExecutionResult::Success(output) => match &output { + forward_system::run::ExecutionOutput::Call(data) => data, + forward_system::run::ExecutionOutput::Create(data, address) => { + // TODO - pass it to the output somehow. + println!( + "Deployed to {}", + address.to_be_bytes_vec().encode_hex::() + ); + data + } + }, + forward_system::run::ExecutionResult::Revert(data) => { + return VmExecutionResultAndLogs { + result: ExecutionResult::Revert { + output: VmRevertReason::General { + msg: "Transaction reverted".to_string(), + data: data.clone(), + }, + }, + logs: Default::default(), + statistics: Default::default(), + refunds: Default::default(), + dynamic_factory_deps: Default::default(), + } + } + } + } + Err(invalid_tx) => { + return VmExecutionResultAndLogs { + result: ExecutionResult::Revert { + output: VmRevertReason::General { + msg: format!("{:?}", invalid_tx), + data: vec![], + }, + }, + logs: Default::default(), + statistics: Default::default(), + refunds: Default::default(), + dynamic_factory_deps: Default::default(), + } + } + }; + + VmExecutionResultAndLogs { + result: ExecutionResult::Success { + output: tx_output.clone(), + }, + logs: VmExecutionLogs { + storage_logs, + events: Default::default(), + user_l2_to_l1_logs: Default::default(), + system_l2_to_l1_logs: Default::default(), + total_log_queries_count: Default::default(), + }, + statistics: Default::default(), + refunds: Default::default(), + dynamic_factory_deps, + } +} + +pub fn zkos_get_nonce_key(account: &Address) -> StorageKey { + let nonce_manager = AccountTreeId::new(b160_to_h160(NONCE_HOLDER_HOOK_ADDRESS)); + + // The `minNonce` (used as nonce for EOAs) is stored in a mapping inside the `NONCE_HOLDER` system contract + //let key = get_address_mapping_key(account, H256::zero()); + let key = address_to_h256(account); + + StorageKey::new(nonce_manager, key) +} + +pub fn zkos_key_for_eth_balance(address: &Address) -> H256 { + address_to_h256(address) +} + +/// Create a `key` part of `StorageKey` to access the balance from ERC20 contract balances +fn zkos_key_for_erc20_balance(address: &Address) -> H256 { + let address_h256 = address_to_h256(address); + + // 20 bytes address first gets aligned to 32 bytes with index of `balanceOf` storage slot + // of default ERC20 contract and to then to 64 bytes. + let slot_index = H256::from_low_u64_be(51); + let mut bytes = [0_u8; 64]; + bytes[..32].copy_from_slice(address_h256.as_bytes()); + bytes[32..].copy_from_slice(slot_index.as_bytes()); + H256(keccak256(&bytes)) +} + +pub fn zkos_storage_key_for_standard_token_balance( + token_contract: AccountTreeId, + address: &Address, +) -> StorageKey { + // We have different implementation of the standard ERC20 contract and native + // eth contract. The key for the balance is different for each. + let key = if token_contract.address() == &b160_to_h160(NOMINAL_TOKEN_BALANCE_STORAGE_ADDRESS) { + zkos_key_for_eth_balance(address) + } else { + zkos_key_for_erc20_balance(address) + }; + + StorageKey::new(token_contract, key) +} + +pub fn zkos_storage_key_for_eth_balance(address: &Address) -> StorageKey { + zkos_storage_key_for_standard_token_balance( + AccountTreeId::new(b160_to_h160(NOMINAL_TOKEN_BALANCE_STORAGE_ADDRESS)), + address, + ) +} + +pub struct ZKOsVM { + pub storage: StoragePtr, + pub tree: InMemoryTree, + preimage: InMemoryPreimageSource, + transactions: Vec, + execution_mode: TxExecutionMode, +} + +impl ZKOsVM { + pub fn new( + storage: StoragePtr, + raw_storage: &InMemoryStorage, + execution_mode: TxExecutionMode, + ) -> Self { + let (tree, preimage) = { create_tree_from_full_state(raw_storage) }; + ZKOsVM { + storage, + tree, + preimage, + transactions: vec![], + execution_mode, + } + } +} +/* +impl TestNodeVMInterface for ZKOsVM { + fn execute_tx(&mut self, tx: Transaction) -> VmExecutionResultAndLogs { + { + let mut storage_ptr = self.storage.borrow_mut(); + let current_l1_batch_info_key = StorageKey::new( + AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), + SYSTEM_CONTEXT_BLOCK_INFO_POSITION, + ); + let current_l1_batch_info = storage_ptr.read_value(¤t_l1_batch_info_key); + let (batch_number, batch_timestamp) = + unpack_block_info(h256_to_u256(current_l1_batch_info)); + + dbg!(batch_number); + dbg!(batch_timestamp); + + // TODO: move this somewhere + let aa = pack_block_info(batch_number + 1, batch_timestamp + 1); + storage_ptr.set_value(current_l1_batch_info_key, u256_to_h256(aa)); + } + + let simulate_only = match self.execution_mode { + TxExecutionMode::VerifyExecute => false, + TxExecutionMode::EstimateFee => true, + TxExecutionMode::EthCall => true, + }; + let tx_result = { + execute_tx_in_zkos( + &tx, + &self.tree, + &self.preimage, + &mut self.storage, + simulate_only, + ) + }; + tx_result + } +}*/ + +#[derive(Default)] +pub struct ZkOsTracerDispatcher {} + +impl VmInterface for ZKOsVM { + type TracerDispatcher = ZkOsTracerDispatcher; + + fn push_transaction( + &mut self, + tx: Transaction, + ) -> zksync_multivm::interface::PushTransactionResult<'_> { + self.transactions.push(tx); + PushTransactionResult { + compressed_bytecodes: Default::default(), + } + } + + fn inspect( + &mut self, + dispatcher: &mut Self::TracerDispatcher, + execution_mode: zksync_multivm::interface::InspectExecutionMode, + ) -> VmExecutionResultAndLogs { + if let InspectExecutionMode::Bootloader = execution_mode { + return VmExecutionResultAndLogs { + result: ExecutionResult::Success { output: vec![] }, + logs: Default::default(), + statistics: Default::default(), + refunds: Default::default(), + dynamic_factory_deps: Default::default(), + }; + } + let simulate_only = match self.execution_mode { + TxExecutionMode::VerifyExecute => false, + TxExecutionMode::EstimateFee => true, + TxExecutionMode::EthCall => true, + }; + + assert_eq!(1, self.transactions.len()); + + // FIXME. + let tx = self.transactions[0].clone(); + execute_tx_in_zkos( + &tx, + &self.tree, + &self.preimage, + &mut self.storage, + simulate_only, + ) + } + + fn start_new_l2_block(&mut self, l2_block_env: zksync_multivm::interface::L2BlockEnv) { + todo!() + } + + fn inspect_transaction_with_bytecode_compression( + &mut self, + tracer: &mut Self::TracerDispatcher, + tx: Transaction, + with_compression: bool, + ) -> ( + zksync_multivm::interface::BytecodeCompressionResult<'_>, + VmExecutionResultAndLogs, + ) { + todo!() + } + + fn finish_batch( + &mut self, + pubdata_builder: std::rc::Rc, + ) -> zksync_multivm::interface::FinishedL1Batch { + todo!() + } +} + +impl VmInterfaceHistoryEnabled for ZKOsVM { + fn make_snapshot(&mut self) {} + + fn rollback_to_the_latest_snapshot(&mut self) { + panic!("Not implemented for zkos"); + } + + fn pop_snapshot_no_rollback(&mut self) {} +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 73cb934d..d456bdf6 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "stable" +channel = "nightly-2024-11-12" components = ["rustfmt", "clippy"] From 335e5172b46d775fc87b6cf5008ff1de54107080 Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 14 Jan 2025 08:36:17 +0100 Subject: [PATCH 02/18] moved nonce key and base token key to separate file --- crates/core/src/node/eth.rs | 18 +++++++----------- crates/core/src/node/in_memory.rs | 18 ++++-------------- crates/core/src/node/in_memory_ext.rs | 13 ++++--------- crates/core/src/node/keys.rs | 22 ++++++++++++++++++++++ crates/core/src/node/mod.rs | 1 + 5 files changed, 38 insertions(+), 34 deletions(-) create mode 100644 crates/core/src/node/keys.rs diff --git a/crates/core/src/node/eth.rs b/crates/core/src/node/eth.rs index 97bffa15..04a1fec1 100644 --- a/crates/core/src/node/eth.rs +++ b/crates/core/src/node/eth.rs @@ -7,11 +7,10 @@ use zksync_multivm::interface::{ExecutionResult, TxExecutionMode}; use zksync_multivm::vm_latest::constants::ETH_CALL_GAS_LIMIT; use zksync_types::{ api::{Block, BlockIdVariant, BlockNumber, TransactionVariant}, - get_code_key, get_nonce_key, + get_code_key, l2::L2Tx, transaction_request::TransactionRequest, - utils::storage_key_for_standard_token_balance, - PackedEthSignature, StorageKey, L2_BASE_TOKEN_ADDRESS, MAX_L1_TRANSACTION_GAS_LIMIT, + PackedEthSignature, StorageKey, MAX_L1_TRANSACTION_GAS_LIMIT, }; use zksync_types::{h256_to_u256, u256_to_h256}; use zksync_types::{ @@ -25,7 +24,9 @@ use zksync_web3_decl::{ use crate::{ filters::{FilterType, LogFilter}, - node::{InMemoryNode, TransactionResult, MAX_TX_SIZE, PROTOCOL_VERSION}, + node::{ + keys::StorageKeyLayout, InMemoryNode, TransactionResult, MAX_TX_SIZE, PROTOCOL_VERSION, + }, utils::{self, h256_to_u64, TransparentError}, }; @@ -187,11 +188,7 @@ impl InMemoryNode { // TODO: Support _block: Option, ) -> anyhow::Result { - // FIXHERE - let balance_key = storage_key_for_standard_token_balance( - AccountTreeId::new(L2_BASE_TOKEN_ADDRESS), - &address, - ); + let balance_key = StorageKeyLayout::get_storage_key_for_base_token(&address); let inner_guard = self.read_inner()?; match inner_guard.fork_storage.read_value_internal(&balance_key) { @@ -299,8 +296,7 @@ impl InMemoryNode { _block: Option, ) -> anyhow::Result { let inner = self.read_inner()?; - // FIXHERE - let nonce_key = get_nonce_key(&address); + let nonce_key = StorageKeyLayout::get_nonce_key(&address); match inner.fork_storage.read_value_internal(&nonce_key) { Ok(result) => Ok(h256_to_u64(result).into()), diff --git a/crates/core/src/node/in_memory.rs b/crates/core/src/node/in_memory.rs index 2847ba9a..74be2781 100644 --- a/crates/core/src/node/in_memory.rs +++ b/crates/core/src/node/in_memory.rs @@ -84,6 +84,7 @@ use zksync_types::{ use zksync_types::{h256_to_address, h256_to_u256, u256_to_h256}; use zksync_web3_decl::error::Web3Error; +use super::keys::StorageKeyLayout; use super::zkos::{zkos_get_nonce_key, zkos_storage_key_for_eth_balance, ZKOsVM}; /// Max possible size of an ABI encoded tx (in bytes). @@ -777,11 +778,7 @@ impl InMemoryNodeInner { // The nonce needs to be updated let nonce = l2_tx.nonce(); - //let nonce_key = get_nonce_key(&l2_tx.initiator_account()); - #[cfg(not(feature = "zkos"))] - let nonce_key = get_nonce_key(&l2_tx.initiator_account()); - #[cfg(feature = "zkos")] - let nonce_key = zkos_get_nonce_key(&l2_tx.initiator_account()); + let nonce_key = StorageKeyLayout::get_nonce_key(&l2_tx.initiator_account()); let full_nonce = storage.borrow_mut().read_value(&nonce_key); let (_, deployment_nonce) = decompose_full_nonce(h256_to_u256(full_nonce)); let enforced_full_nonce = nonces_to_full_nonce(U256::from(nonce.0), deployment_nonce); @@ -791,11 +788,7 @@ impl InMemoryNodeInner { // We need to explicitly put enough balance into the account of the users let payer = l2_tx.payer(); - - #[cfg(not(feature = "zkos"))] - let balance_key = storage_key_for_eth_balance(&payer); - #[cfg(feature = "zkos")] - let balance_key = zkos_storage_key_for_eth_balance(&payer); + let balance_key = StorageKeyLayout::get_storage_key_for_base_token(&payer); let mut current_balance = h256_to_u256(storage.borrow_mut().read_value(&balance_key)); let added_balance = l2_tx.common_data.fee.gas_limit * l2_tx.common_data.fee.max_fee_per_gas; current_balance += added_balance; @@ -1341,10 +1334,7 @@ impl InMemoryNode { /// Adds a lot of tokens to a given account with a specified balance. pub fn set_rich_account(&self, address: H160, balance: U256) { - #[cfg(not(feature = "zkos"))] - let key = storage_key_for_eth_balance(&address); - #[cfg(feature = "zkos")] - let key = zkos_storage_key_for_eth_balance(&address); + let key = StorageKeyLayout::get_storage_key_for_base_token(&address) let mut inner = match self.inner.write() { Ok(guard) => guard, diff --git a/crates/core/src/node/in_memory_ext.rs b/crates/core/src/node/in_memory_ext.rs index 271fcf08..61f7fb59 100644 --- a/crates/core/src/node/in_memory_ext.rs +++ b/crates/core/src/node/in_memory_ext.rs @@ -1,3 +1,4 @@ +use crate::node::keys::StorageKeyLayout; use crate::node::pool::TxBatch; use crate::node::sealer::BlockSealerMode; use crate::{fork::ForkDetails, node::InMemoryNode, utils::bytecode_to_factory_dep}; @@ -7,11 +8,7 @@ use std::time::Duration; use zksync_multivm::interface::TxExecutionMode; use zksync_types::api::{Block, TransactionVariant}; use zksync_types::u256_to_h256; -use zksync_types::{ - get_code_key, get_nonce_key, - utils::{nonces_to_full_nonce, storage_key_for_eth_balance}, - L2BlockNumber, StorageKey, -}; +use zksync_types::{get_code_key, utils::nonces_to_full_nonce, L2BlockNumber, StorageKey}; use zksync_types::{AccountTreeId, Address, H256, U256, U64}; type Result = anyhow::Result; @@ -192,8 +189,7 @@ impl InMemoryNode { pub fn set_balance(&self, address: Address, balance: U256) -> Result { self.write_inner().map(|mut writer| { - // FIXHERE - let balance_key = storage_key_for_eth_balance(&address); + let balance_key = StorageKeyLayout::get_storage_key_for_base_token(&address); writer .fork_storage .set_value(balance_key, u256_to_h256(balance)); @@ -208,8 +204,7 @@ impl InMemoryNode { pub fn set_nonce(&self, address: Address, nonce: U256) -> Result { self.write_inner().map(|mut writer| { - // FIXHERE - let nonce_key = get_nonce_key(&address); + let nonce_key = StorageKeyLayout::get_nonce_key(&address); let enforced_full_nonce = nonces_to_full_nonce(nonce, nonce); tracing::info!( "👷 Nonces for address {:?} have been set to {}", diff --git a/crates/core/src/node/keys.rs b/crates/core/src/node/keys.rs new file mode 100644 index 00000000..baa4f64f --- /dev/null +++ b/crates/core/src/node/keys.rs @@ -0,0 +1,22 @@ +use zksync_types::{Address, StorageKey}; + +pub struct StorageKeyLayout {} + +impl StorageKeyLayout { + pub fn get_nonce_key(account: &Address) -> StorageKey { + #[cfg(not(feature = "zkos"))] + return zksync_types::get_nonce_key(account); + #[cfg(feature = "zkos")] + return crate::node::zkos::zkos_get_nonce_key(account); + } + + pub fn get_storage_key_for_base_token(address: &Address) -> StorageKey { + #[cfg(not(feature = "zkos"))] + return zksync_types::utils::storage_key_for_standard_token_balance( + zksync_types::AccountTreeId::new(zksync_types::L2_BASE_TOKEN_ADDRESS), + &address, + ); + #[cfg(feature = "zkos")] + return crate::node::zkos::zkos_storage_key_for_eth_balance(address); + } +} diff --git a/crates/core/src/node/mod.rs b/crates/core/src/node/mod.rs index 8f62f100..9715eec0 100644 --- a/crates/core/src/node/mod.rs +++ b/crates/core/src/node/mod.rs @@ -9,6 +9,7 @@ mod fee_model; mod impersonate; mod in_memory; mod in_memory_ext; +mod keys; mod pool; mod sealer; mod state; From 43ea95370cbc6ac7fa613a0c260c655e644a0995 Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 14 Jan 2025 08:46:07 +0100 Subject: [PATCH 03/18] moved allow_no_target to separate method --- crates/core/src/node/debug.rs | 3 +-- crates/core/src/node/eth.rs | 16 ++-------------- crates/core/src/node/in_memory.rs | 11 ++++++++++- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/crates/core/src/node/debug.rs b/crates/core/src/node/debug.rs index 298bcc27..8eaa0702 100644 --- a/crates/core/src/node/debug.rs +++ b/crates/core/src/node/debug.rs @@ -87,8 +87,7 @@ impl InMemoryNode { ))); } - let allow_no_target = true; //system_contracts.evm_emulator.is_some(); - let mut l2_tx = L2Tx::from_request(request.into(), MAX_TX_SIZE, allow_no_target) + let mut l2_tx = L2Tx::from_request(request.into(), MAX_TX_SIZE, self.allow_no_target()) .map_err(Web3Error::SerializationError)?; let execution_mode = zksync_multivm::interface::TxExecutionMode::EthCall; let storage = StorageView::new(&inner.fork_storage).into_rc_ptr(); diff --git a/crates/core/src/node/eth.rs b/crates/core/src/node/eth.rs index 04a1fec1..94ac0219 100644 --- a/crates/core/src/node/eth.rs +++ b/crates/core/src/node/eth.rs @@ -83,13 +83,7 @@ impl InMemoryNode { .chain_id; let (tx_req, hash) = TransactionRequest::from_bytes(&tx_bytes.0, chain_id)?; - // Impersonation does not matter in this context so we assume the tx is not impersonated: - // system contracts here are fetched solely to check for EVM emulator. - let system_contracts = self - .system_contracts - .contracts(TxExecutionMode::VerifyExecute, false); - let allow_no_target = true; //system_contracts.evm_emulator.is_some(); - let mut l2_tx = L2Tx::from_request(tx_req, MAX_TX_SIZE, allow_no_target)?; + let mut l2_tx = L2Tx::from_request(tx_req, MAX_TX_SIZE, self.allow_no_target())?; l2_tx.set_input(tx_bytes.0, hash); if hash != l2_tx.hash() { @@ -149,13 +143,7 @@ impl InMemoryNode { 27, ))?; - // Impersonation does not matter in this context so we assume the tx is not impersonated: - // system contracts here are fetched solely to check for EVM emulator. - let system_contracts = self - .system_contracts - .contracts(TxExecutionMode::VerifyExecute, false); - let allow_no_target = true; //system_contracts.evm_emulator.is_some(); - let mut l2_tx: L2Tx = L2Tx::from_request(tx_req, MAX_TX_SIZE, allow_no_target)?; + let mut l2_tx: L2Tx = L2Tx::from_request(tx_req, MAX_TX_SIZE, self.allow_no_target())?; // `v` was overwritten with 0 during converting into l2 tx let mut signature = vec![0u8; 65]; diff --git a/crates/core/src/node/in_memory.rs b/crates/core/src/node/in_memory.rs index 74be2781..b2cdfca9 100644 --- a/crates/core/src/node/in_memory.rs +++ b/crates/core/src/node/in_memory.rs @@ -1232,6 +1232,15 @@ impl InMemoryNode { Ok(inner.config.clone()) } + /// Whether it accepts the transactions that have 'null' as target. + /// This is used only when EVM emulator is enabled, or we're running in zkos mode. + pub fn allow_no_target(&self) -> bool { + #[cfg(feature = "zkos")] + return true; + #[cfg(not(feature = "zkos"))] + self.system_contracts.evm_emulator.is_some() + } + pub fn reset(&self, fork: Option) -> Result<(), String> { let config = self.get_config()?; let inner = InMemoryNodeInner::new( @@ -1334,7 +1343,7 @@ impl InMemoryNode { /// Adds a lot of tokens to a given account with a specified balance. pub fn set_rich_account(&self, address: H160, balance: U256) { - let key = StorageKeyLayout::get_storage_key_for_base_token(&address) + let key = StorageKeyLayout::get_storage_key_for_base_token(&address); let mut inner = match self.inner.write() { Ok(guard) => guard, From fe9ba561cf97d41de169a12338038d758648985a Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 14 Jan 2025 09:24:51 +0100 Subject: [PATCH 04/18] cleanup inconsistent keys, align arguments --- crates/core/src/node/in_memory.rs | 15 +++++++++------ crates/core/src/node/zkos.rs | 17 ++++++++++++++--- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/crates/core/src/node/in_memory.rs b/crates/core/src/node/in_memory.rs index b2cdfca9..7c7f542f 100644 --- a/crates/core/src/node/in_memory.rs +++ b/crates/core/src/node/in_memory.rs @@ -802,16 +802,16 @@ impl InMemoryNodeInner { let mut vm: Vm<_, HistoryDisabled> = Vm::new(batch_env, system_env, storage.clone()); #[cfg(feature = "zkos")] let mut vm = ZKOsVM::new( + batch_env, + system_env, storage.clone(), &fork_storage.inner.read().unwrap().raw_storage, - system_env.execution_mode, ); #[cfg(feature = "zkos")] { // Temporary hack - as we update the 'storage' just above, but zkos loads its full // state from fork_storage (that is not updated). - add_elem_to_tree(&mut vm.tree, &nonce_key, &u256_to_h256(enforced_full_nonce)); - add_elem_to_tree(&mut vm.tree, &balance_key, &u256_to_h256(current_balance)); + vm.update_inconsistent_keys(&[&nonce_key, &balance_key]); } let tx: Transaction = l2_tx.into(); @@ -1399,16 +1399,18 @@ impl InMemoryNode { // init vm - // let (batch_env, _) = inner.create_l1_batch_env(&self.time, storage.clone()); + let (batch_env, _) = inner.create_l1_batch_env(&self.time, storage.clone()); let system_env = inner.create_system_env(base_contracts, execution_mode); #[cfg(not(feature = "zkos"))] let mut vm: Vm<_, HistoryDisabled> = Vm::new(batch_env, system_env, storage.clone()); #[cfg(feature = "zkos")] let mut vm = ZKOsVM::new( + batch_env, + system_env, storage.clone(), + // TODO: this might be causing a deadlock.. check.. &inner.fork_storage.inner.read().unwrap().raw_storage, - execution_mode, ); // We must inject *some* signature (otherwise bootloader code fails to generate hash). @@ -1855,9 +1857,10 @@ impl InMemoryNode { #[cfg(feature = "zkos")] let mut vm = ZKOsVM::new( + batch_env.clone(), + system_env, storage.clone(), &inner.fork_storage.inner.read().unwrap().raw_storage, - TxExecutionMode::VerifyExecute, ); drop(inner); diff --git a/crates/core/src/node/zkos.rs b/crates/core/src/node/zkos.rs index ee683b23..d83da7fc 100644 --- a/crates/core/src/node/zkos.rs +++ b/crates/core/src/node/zkos.rs @@ -13,8 +13,9 @@ use system_hooks::addresses_constants::{ use zk_ee::{common_structs::derive_flat_storage_key, utils::Bytes32}; use zksync_multivm::interface::{ storage::{StoragePtr, WriteStorage}, - ExecutionResult, InspectExecutionMode, PushTransactionResult, TxExecutionMode, VmExecutionLogs, - VmExecutionResultAndLogs, VmInterface, VmInterfaceHistoryEnabled, VmRevertReason, + ExecutionResult, InspectExecutionMode, L1BatchEnv, PushTransactionResult, SystemEnv, + TxExecutionMode, VmExecutionLogs, VmExecutionResultAndLogs, VmInterface, + VmInterfaceHistoryEnabled, VmRevertReason, }; use zksync_types::{ address_to_h256, @@ -460,10 +461,12 @@ pub struct ZKOsVM { impl ZKOsVM { pub fn new( + _batch_env: L1BatchEnv, + system_env: SystemEnv, storage: StoragePtr, raw_storage: &InMemoryStorage, - execution_mode: TxExecutionMode, ) -> Self { + let execution_mode = system_env.execution_mode; let (tree, preimage) = { create_tree_from_full_state(raw_storage) }; ZKOsVM { storage, @@ -473,6 +476,14 @@ impl ZKOsVM { execution_mode, } } + + /// If any keys are updated in storage externally, but not reflected in internal tree. + pub fn update_inconsistent_keys(&mut self, inconsistent_nodes: &[&StorageKey]) { + for key in inconsistent_nodes { + let value = self.storage.borrow_mut().read_value(key); + add_elem_to_tree(&mut self.tree, key, &value); + } + } } /* impl TestNodeVMInterface for ZKOsVM { From a5fe9700ebb60009945c8dd2e7f21262ceddc44e Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 14 Jan 2025 10:19:23 +0100 Subject: [PATCH 05/18] compiles but dirty --- crates/cli/Cargo.toml | 6 ++++ crates/core/Cargo.toml | 4 +-- crates/core/src/node/in_memory.rs | 46 +++++++++++++++++++++---------- crates/core/src/node/zkos.rs | 44 ++++++++++++++++++++++------- 4 files changed, 72 insertions(+), 28 deletions(-) diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index ca38223c..1850c8f0 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -37,3 +37,9 @@ flate2.workspace = true [dev-dependencies] tempdir.workspace = true + +[features] + +zkos = ["anvil_zksync_core/zkos"] + +default = ["zkos"] \ No newline at end of file diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 1ff92c66..56eb1f42 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -60,7 +60,5 @@ test-case.workspace = true [features] - zkos = [] - -default = ["zkos"] \ No newline at end of file +default = [] \ No newline at end of file diff --git a/crates/core/src/node/in_memory.rs b/crates/core/src/node/in_memory.rs index 7c7f542f..9c864bd7 100644 --- a/crates/core/src/node/in_memory.rs +++ b/crates/core/src/node/in_memory.rs @@ -45,7 +45,7 @@ use std::{ sync::{Arc, RwLock}, }; use zksync_contracts::BaseSystemContracts; -use zksync_multivm::vm_latest::HistoryEnabled; +use zksync_multivm::vm_latest::{HistoryEnabled, TracerPointer, VmTracer}; use zksync_multivm::{ interface::{ storage::{ReadStorage, StoragePtr, WriteStorage}, @@ -85,7 +85,9 @@ use zksync_types::{h256_to_address, h256_to_u256, u256_to_h256}; use zksync_web3_decl::error::Web3Error; use super::keys::StorageKeyLayout; -use super::zkos::{zkos_get_nonce_key, zkos_storage_key_for_eth_balance, ZKOsVM}; +use super::zkos::{ + zkos_get_nonce_key, zkos_storage_key_for_eth_balance, ZKOsVM, ZkOsTracerDispatcher, +}; /// Max possible size of an ABI encoded tx (in bytes). pub const MAX_TX_SIZE: usize = 1_000_000; @@ -1238,7 +1240,10 @@ impl InMemoryNode { #[cfg(feature = "zkos")] return true; #[cfg(not(feature = "zkos"))] - self.system_contracts.evm_emulator.is_some() + self.system_contracts + .contracts_for_l2_call() + .evm_emulator + .is_some() } pub fn reset(&self, fork: Option) -> Result<(), String> { @@ -1423,15 +1428,15 @@ impl InMemoryNode { let call_tracer_result = Arc::new(OnceCell::default()); - #[cfg(not(feature = "zkos"))] - let tracers = vec![ + //#[cfg(not(feature = "zkos"))] + let tracers: Vec>> = vec![ CallErrorTracer::new().into_tracer_pointer(), CallTracer::new(call_tracer_result.clone()).into_tracer_pointer(), ]; - #[cfg(not(feature = "zkos"))] + //#[cfg(feature = "zkos")] + //let tracers: Vec = vec![]; + let tx_result = vm.inspect(&mut tracers.into(), InspectExecutionMode::OneTx); - #[cfg(feature = "zkos")] - let tx_result = vm.inspect(&mut Default::default(), InspectExecutionMode::OneTx); let call_traces = Arc::try_unwrap(call_tracer_result) .unwrap() @@ -1570,11 +1575,14 @@ impl InMemoryNode { /// This is because external users of the library may call this function to perform an isolated /// VM operation (optionally without bootloader execution) with an external storage and get the results back. /// So any data populated in [Self::run_l2_tx] will not be available for the next invocation. - pub fn run_l2_tx_raw( + pub fn run_l2_tx_raw( &self, l2_tx: L2Tx, vm: &mut VM, - ) -> anyhow::Result { + ) -> anyhow::Result + where + ::TracerDispatcher: From>>, + { let inner = self .inner .read() @@ -1586,7 +1594,8 @@ impl InMemoryNode { let bootloader_debug_result = Arc::new(OnceCell::default()); #[cfg(not(feature = "zkos"))] - let tracers: Vec>> = vec![ + //let tracers: Vec>> = vec![ + let tracers = vec![ CallErrorTracer::new().into_tracer_pointer(), CallTracer::new(call_tracer_result.clone()).into_tracer_pointer(), BootloaderDebugTracer { @@ -1594,6 +1603,8 @@ impl InMemoryNode { } .into_tracer_pointer(), ]; + //#[cfg(feature = "zkos")] + //let tracers: Vec = vec![]; let compressed_bytecodes = vm .push_transaction(tx.clone()) .compressed_bytecodes @@ -1601,6 +1612,8 @@ impl InMemoryNode { #[cfg(not(feature = "zkos"))] let tx_result = vm.inspect(&mut tracers.into(), InspectExecutionMode::OneTx); + //let tx_result = vm.inspect(&mut Default::default(), InspectExecutionMode::OneTx); + #[cfg(feature = "zkos")] let tx_result = vm.inspect(&mut Default::default(), InspectExecutionMode::OneTx); @@ -1702,14 +1715,17 @@ impl InMemoryNode { } /// Runs L2 transaction and commits it to a new block. - pub fn run_l2_tx( + pub fn run_l2_tx( &self, l2_tx: L2Tx, l2_tx_index: U64, block_ctx: &BlockContext, batch_env: &L1BatchEnv, vm: &mut VM, - ) -> anyhow::Result<()> { + ) -> anyhow::Result<()> + where + ::TracerDispatcher: From>>, + { let tx_hash = l2_tx.hash(); let transaction_type = l2_tx.common_data.transaction_type; @@ -2204,13 +2220,13 @@ mod tests { ) -> ( BlockContext, L1BatchEnv, - Vm, HistoryDisabled>, + Vm, HistoryEnabled>, ) { let inner = node.inner.read().unwrap(); let storage = StorageView::new(inner.fork_storage.clone()).into_rc_ptr(); let system_env = inner.create_system_env(system_contracts, TxExecutionMode::VerifyExecute); let (batch_env, block_ctx) = inner.create_l1_batch_env(&node.time, storage.clone()); - let vm: Vm<_, HistoryDisabled> = Vm::new(batch_env.clone(), system_env, storage); + let vm: Vm<_, HistoryEnabled> = Vm::new(batch_env.clone(), system_env, storage); (block_ctx, batch_env, vm) } diff --git a/crates/core/src/node/zkos.rs b/crates/core/src/node/zkos.rs index d83da7fc..1d11231c 100644 --- a/crates/core/src/node/zkos.rs +++ b/crates/core/src/node/zkos.rs @@ -1,9 +1,9 @@ -use std::{alloc::Global, collections::HashMap, vec}; +use std::{alloc::Global, collections::HashMap, fmt::Write, vec}; use basic_system::basic_system::simple_growable_storage::TestingTree; use forward_system::run::{ test_impl::{InMemoryPreimageSource, InMemoryTree, TxListSource}, - PreimageType, StorageCommitment, + PreimageType, ReadStorage, StorageCommitment, }; use hex::ToHex; use ruint::aliases::B160; @@ -11,11 +11,15 @@ use system_hooks::addresses_constants::{ NOMINAL_TOKEN_BALANCE_STORAGE_ADDRESS, NONCE_HOLDER_HOOK_ADDRESS, }; use zk_ee::{common_structs::derive_flat_storage_key, utils::Bytes32}; -use zksync_multivm::interface::{ - storage::{StoragePtr, WriteStorage}, - ExecutionResult, InspectExecutionMode, L1BatchEnv, PushTransactionResult, SystemEnv, - TxExecutionMode, VmExecutionLogs, VmExecutionResultAndLogs, VmInterface, - VmInterfaceHistoryEnabled, VmRevertReason, +use zksync_multivm::{ + interface::{ + storage::{StoragePtr, WriteStorage}, + ExecutionResult, InspectExecutionMode, L1BatchEnv, PushTransactionResult, SystemEnv, + TxExecutionMode, VmExecutionLogs, VmExecutionResultAndLogs, VmInterface, + VmInterfaceHistoryEnabled, VmRevertReason, + }, + vm_latest::{TracerDispatcher, TracerPointer}, + HistoryMode, }; use zksync_types::{ address_to_h256, @@ -524,11 +528,31 @@ impl TestNodeVMInterface for ZKOsVM { } }*/ -#[derive(Default)] -pub struct ZkOsTracerDispatcher {} +pub struct ZkOsTracerDispatcher { + tracers: Vec, + //_marker: PhantomData, +} + +impl Default for ZkOsTracerDispatcher { + fn default() -> Self { + Self { + tracers: Default::default(), + //_marker: Default::default(), + } + } +} + +impl From>> for ZkOsTracerDispatcher { + fn from(_value: Vec>) -> Self { + Self { + tracers: Default::default(), + //_marker: Default::default(), + } + } +} impl VmInterface for ZKOsVM { - type TracerDispatcher = ZkOsTracerDispatcher; + type TracerDispatcher = ZkOsTracerDispatcher; fn push_transaction( &mut self, From 0135ab33c040c328e8efc043e69b4b8e6a90e3d1 Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 14 Jan 2025 10:39:43 +0100 Subject: [PATCH 06/18] tracers are fixed now --- crates/core/src/node/in_memory.rs | 46 +++++++++++-------------------- crates/core/src/node/zkos.rs | 29 ++++++++++--------- 2 files changed, 32 insertions(+), 43 deletions(-) diff --git a/crates/core/src/node/in_memory.rs b/crates/core/src/node/in_memory.rs index 9c864bd7..b68e1ed6 100644 --- a/crates/core/src/node/in_memory.rs +++ b/crates/core/src/node/in_memory.rs @@ -4,7 +4,6 @@ use crate::node::error::LoadStateError; use crate::node::impersonate::{ImpersonationManager, ImpersonationState}; use crate::node::state::{StateV1, VersionedState}; use crate::node::time::{AdvanceTime, ReadTime, TimestampManager}; -use crate::node::zkos::add_elem_to_tree; use crate::node::{BlockSealer, BlockSealerMode, TxPool}; use crate::{ bootloader_debug::{BootloaderDebug, BootloaderDebugTracer}, @@ -45,7 +44,7 @@ use std::{ sync::{Arc, RwLock}, }; use zksync_contracts::BaseSystemContracts; -use zksync_multivm::vm_latest::{HistoryEnabled, TracerPointer, VmTracer}; +use zksync_multivm::vm_latest::{HistoryEnabled, HistoryMode, TracerPointer, VmTracer}; use zksync_multivm::{ interface::{ storage::{ReadStorage, StoragePtr, WriteStorage}, @@ -63,7 +62,7 @@ use zksync_multivm::{ utils::l2_blocks::load_last_l2_block, HistoryDisabled, ToTracerPointer, Vm, }, - HistoryMode, VmVersion, + VmVersion, }; use zksync_types::bytecode::BytecodeHash; use zksync_types::transaction_request::CallRequest; @@ -505,7 +504,10 @@ impl InMemoryNodeInner { .system_contracts .contracts_for_fee_estimate(impersonating) .clone(); - let allow_no_target = true; // system_contracts.evm_emulator.is_some(); + #[cfg(feature = "zkos")] + let allow_no_target = true; + #[cfg(not(feature = "zkos"))] + let allow_no_target = system_contracts.evm_emulator.is_some(); let mut l2_tx = L2Tx::from_request( request_with_gas_per_pubdata_overridden.into(), @@ -798,12 +800,10 @@ impl InMemoryNodeInner { .borrow_mut() .set_value(balance_key, u256_to_h256(current_balance)); - //let mut vm: Vm<_, HistoryDisabled> = Vm::new(batch_env, system_env, storage.clone()); - #[cfg(not(feature = "zkos"))] let mut vm: Vm<_, HistoryDisabled> = Vm::new(batch_env, system_env, storage.clone()); #[cfg(feature = "zkos")] - let mut vm = ZKOsVM::new( + let mut vm: ZKOsVM<_, HistoryDisabled> = ZKOsVM::new( batch_env, system_env, storage.clone(), @@ -1410,7 +1410,7 @@ impl InMemoryNode { #[cfg(not(feature = "zkos"))] let mut vm: Vm<_, HistoryDisabled> = Vm::new(batch_env, system_env, storage.clone()); #[cfg(feature = "zkos")] - let mut vm = ZKOsVM::new( + let mut vm: ZKOsVM<_, HistoryDisabled> = ZKOsVM::new( batch_env, system_env, storage.clone(), @@ -1428,14 +1428,10 @@ impl InMemoryNode { let call_tracer_result = Arc::new(OnceCell::default()); - //#[cfg(not(feature = "zkos"))] - let tracers: Vec>> = vec![ + let tracers = vec![ CallErrorTracer::new().into_tracer_pointer(), CallTracer::new(call_tracer_result.clone()).into_tracer_pointer(), ]; - //#[cfg(feature = "zkos")] - //let tracers: Vec = vec![]; - let tx_result = vm.inspect(&mut tracers.into(), InspectExecutionMode::OneTx); let call_traces = Arc::try_unwrap(call_tracer_result) @@ -1575,13 +1571,13 @@ impl InMemoryNode { /// This is because external users of the library may call this function to perform an isolated /// VM operation (optionally without bootloader execution) with an external storage and get the results back. /// So any data populated in [Self::run_l2_tx] will not be available for the next invocation. - pub fn run_l2_tx_raw( + pub fn run_l2_tx_raw( &self, l2_tx: L2Tx, vm: &mut VM, ) -> anyhow::Result where - ::TracerDispatcher: From>>, + ::TracerDispatcher: From>>, { let inner = self .inner @@ -1593,8 +1589,6 @@ impl InMemoryNode { let call_tracer_result = Arc::new(OnceCell::default()); let bootloader_debug_result = Arc::new(OnceCell::default()); - #[cfg(not(feature = "zkos"))] - //let tracers: Vec>> = vec![ let tracers = vec![ CallErrorTracer::new().into_tracer_pointer(), CallTracer::new(call_tracer_result.clone()).into_tracer_pointer(), @@ -1603,19 +1597,11 @@ impl InMemoryNode { } .into_tracer_pointer(), ]; - //#[cfg(feature = "zkos")] - //let tracers: Vec = vec![]; let compressed_bytecodes = vm .push_transaction(tx.clone()) .compressed_bytecodes .into_owned(); - - #[cfg(not(feature = "zkos"))] let tx_result = vm.inspect(&mut tracers.into(), InspectExecutionMode::OneTx); - //let tx_result = vm.inspect(&mut Default::default(), InspectExecutionMode::OneTx); - - #[cfg(feature = "zkos")] - let tx_result = vm.inspect(&mut Default::default(), InspectExecutionMode::OneTx); let call_traces = call_tracer_result.get(); @@ -1715,7 +1701,7 @@ impl InMemoryNode { } /// Runs L2 transaction and commits it to a new block. - pub fn run_l2_tx( + pub fn run_l2_tx( &self, l2_tx: L2Tx, l2_tx_index: U64, @@ -1724,7 +1710,7 @@ impl InMemoryNode { vm: &mut VM, ) -> anyhow::Result<()> where - ::TracerDispatcher: From>>, + ::TracerDispatcher: From>>, { let tx_hash = l2_tx.hash(); let transaction_type = l2_tx.common_data.transaction_type; @@ -1872,7 +1858,7 @@ impl InMemoryNode { let (batch_env, mut block_ctx) = inner.create_l1_batch_env(time, storage.clone()); #[cfg(feature = "zkos")] - let mut vm = ZKOsVM::new( + let mut vm: ZKOsVM, HistoryEnabled> = ZKOsVM::new( batch_env.clone(), system_env, storage.clone(), @@ -2220,13 +2206,13 @@ mod tests { ) -> ( BlockContext, L1BatchEnv, - Vm, HistoryEnabled>, + Vm, HistoryDisabled>, ) { let inner = node.inner.read().unwrap(); let storage = StorageView::new(inner.fork_storage.clone()).into_rc_ptr(); let system_env = inner.create_system_env(system_contracts, TxExecutionMode::VerifyExecute); let (batch_env, block_ctx) = inner.create_l1_batch_env(&node.time, storage.clone()); - let vm: Vm<_, HistoryEnabled> = Vm::new(batch_env.clone(), system_env, storage); + let vm: Vm<_, HistoryDisabled> = Vm::new(batch_env.clone(), system_env, storage); (block_ctx, batch_env, vm) } diff --git a/crates/core/src/node/zkos.rs b/crates/core/src/node/zkos.rs index 1d11231c..fdf4d185 100644 --- a/crates/core/src/node/zkos.rs +++ b/crates/core/src/node/zkos.rs @@ -18,8 +18,7 @@ use zksync_multivm::{ TxExecutionMode, VmExecutionLogs, VmExecutionResultAndLogs, VmInterface, VmInterfaceHistoryEnabled, VmRevertReason, }, - vm_latest::{TracerDispatcher, TracerPointer}, - HistoryMode, + vm_latest::{HistoryMode, TracerDispatcher, TracerPointer}, }; use zksync_types::{ address_to_h256, @@ -455,15 +454,16 @@ pub fn zkos_storage_key_for_eth_balance(address: &Address) -> StorageKey { ) } -pub struct ZKOsVM { +pub struct ZKOsVM { pub storage: StoragePtr, pub tree: InMemoryTree, preimage: InMemoryPreimageSource, transactions: Vec, execution_mode: TxExecutionMode, + _phantom: std::marker::PhantomData, } -impl ZKOsVM { +impl ZKOsVM { pub fn new( _batch_env: L1BatchEnv, system_env: SystemEnv, @@ -478,6 +478,7 @@ impl ZKOsVM { preimage, transactions: vec![], execution_mode, + _phantom: Default::default(), } } @@ -528,31 +529,33 @@ impl TestNodeVMInterface for ZKOsVM { } }*/ -pub struct ZkOsTracerDispatcher { +pub struct ZkOsTracerDispatcher { tracers: Vec, - //_marker: PhantomData, + _marker: std::marker::PhantomData, } -impl Default for ZkOsTracerDispatcher { +impl Default for ZkOsTracerDispatcher { fn default() -> Self { Self { tracers: Default::default(), - //_marker: Default::default(), + _marker: Default::default(), } } } -impl From>> for ZkOsTracerDispatcher { +impl From>> + for ZkOsTracerDispatcher +{ fn from(_value: Vec>) -> Self { Self { tracers: Default::default(), - //_marker: Default::default(), + _marker: Default::default(), } } } -impl VmInterface for ZKOsVM { - type TracerDispatcher = ZkOsTracerDispatcher; +impl VmInterface for ZKOsVM { + type TracerDispatcher = ZkOsTracerDispatcher; fn push_transaction( &mut self, @@ -621,7 +624,7 @@ impl VmInterface for ZKOsVM { } } -impl VmInterfaceHistoryEnabled for ZKOsVM { +impl VmInterfaceHistoryEnabled for ZKOsVM { fn make_snapshot(&mut self) {} fn rollback_to_the_latest_snapshot(&mut self) { From 950bd163c19031a8f58682de10a25b0e44e56ca3 Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 14 Jan 2025 10:42:20 +0100 Subject: [PATCH 07/18] cleanup warnings --- crates/core/src/node/zkos.rs | 52 ++++-------------------------------- 1 file changed, 5 insertions(+), 47 deletions(-) diff --git a/crates/core/src/node/zkos.rs b/crates/core/src/node/zkos.rs index fdf4d185..bfbc3884 100644 --- a/crates/core/src/node/zkos.rs +++ b/crates/core/src/node/zkos.rs @@ -1,9 +1,9 @@ -use std::{alloc::Global, collections::HashMap, fmt::Write, vec}; +use std::{alloc::Global, collections::HashMap, vec}; use basic_system::basic_system::simple_growable_storage::TestingTree; use forward_system::run::{ test_impl::{InMemoryPreimageSource, InMemoryTree, TxListSource}, - PreimageType, ReadStorage, StorageCommitment, + PreimageType, StorageCommitment, }; use hex::ToHex; use ruint::aliases::B160; @@ -18,15 +18,11 @@ use zksync_multivm::{ TxExecutionMode, VmExecutionLogs, VmExecutionResultAndLogs, VmInterface, VmInterfaceHistoryEnabled, VmRevertReason, }, - vm_latest::{HistoryMode, TracerDispatcher, TracerPointer}, + vm_latest::{HistoryMode, TracerPointer}, }; use zksync_types::{ - address_to_h256, - block::{pack_block_info, unpack_block_info}, - h256_to_u256, - web3::keccak256, - AccountTreeId, Address, StorageKey, StorageLog, StorageLogWithPreviousValue, Transaction, H160, - H256, SYSTEM_CONTEXT_ADDRESS, SYSTEM_CONTEXT_BLOCK_INFO_POSITION, + address_to_h256, web3::keccak256, AccountTreeId, Address, StorageKey, StorageLog, + StorageLogWithPreviousValue, Transaction, H160, H256, }; //use zksync_utils::{address_to_h256, h256_to_u256, u256_to_h256}; @@ -490,44 +486,6 @@ impl ZKOsVM { } } } -/* -impl TestNodeVMInterface for ZKOsVM { - fn execute_tx(&mut self, tx: Transaction) -> VmExecutionResultAndLogs { - { - let mut storage_ptr = self.storage.borrow_mut(); - let current_l1_batch_info_key = StorageKey::new( - AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), - SYSTEM_CONTEXT_BLOCK_INFO_POSITION, - ); - let current_l1_batch_info = storage_ptr.read_value(¤t_l1_batch_info_key); - let (batch_number, batch_timestamp) = - unpack_block_info(h256_to_u256(current_l1_batch_info)); - - dbg!(batch_number); - dbg!(batch_timestamp); - - // TODO: move this somewhere - let aa = pack_block_info(batch_number + 1, batch_timestamp + 1); - storage_ptr.set_value(current_l1_batch_info_key, u256_to_h256(aa)); - } - - let simulate_only = match self.execution_mode { - TxExecutionMode::VerifyExecute => false, - TxExecutionMode::EstimateFee => true, - TxExecutionMode::EthCall => true, - }; - let tx_result = { - execute_tx_in_zkos( - &tx, - &self.tree, - &self.preimage, - &mut self.storage, - simulate_only, - ) - }; - tx_result - } -}*/ pub struct ZkOsTracerDispatcher { tracers: Vec, From c056f79584b4e07c53c25d7af02eb21f61c04aa4 Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 14 Jan 2025 15:59:40 +0100 Subject: [PATCH 08/18] cleanup warnings and factory deps --- crates/cli/Cargo.toml | 2 +- crates/core/src/node/eth.rs | 6 +-- crates/core/src/node/in_memory.rs | 60 +++++++++++++-------------- crates/core/src/node/in_memory_ext.rs | 12 +----- crates/core/src/node/mod.rs | 1 + crates/core/src/node/zkos.rs | 20 ++++----- crates/core/src/utils.rs | 20 +-------- 7 files changed, 45 insertions(+), 76 deletions(-) diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 1850c8f0..550804ec 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -42,4 +42,4 @@ tempdir.workspace = true zkos = ["anvil_zksync_core/zkos"] -default = ["zkos"] \ No newline at end of file +default = [] \ No newline at end of file diff --git a/crates/core/src/node/eth.rs b/crates/core/src/node/eth.rs index 94ac0219..6a6716bc 100644 --- a/crates/core/src/node/eth.rs +++ b/crates/core/src/node/eth.rs @@ -3,7 +3,7 @@ use std::collections::HashSet; use anyhow::Context as _; use colored::Colorize; use itertools::Itertools; -use zksync_multivm::interface::{ExecutionResult, TxExecutionMode}; +use zksync_multivm::interface::ExecutionResult; use zksync_multivm::vm_latest::constants::ETH_CALL_GAS_LIMIT; use zksync_types::{ api::{Block, BlockIdVariant, BlockNumber, TransactionVariant}, @@ -36,9 +36,7 @@ impl InMemoryNode { req: zksync_types::transaction_request::CallRequest, ) -> Result { let system_contracts = self.system_contracts.contracts_for_l2_call().clone(); - let allow_no_target = true; //system_contracts.evm_emulator.is_some(); - - let mut tx = L2Tx::from_request(req.into(), MAX_TX_SIZE, allow_no_target)?; + let mut tx = L2Tx::from_request(req.into(), MAX_TX_SIZE, self.allow_no_target())?; tx.common_data.fee.gas_limit = ETH_CALL_GAS_LIMIT.into(); let call_result = self .run_l2_call(tx, system_contracts) diff --git a/crates/core/src/node/in_memory.rs b/crates/core/src/node/in_memory.rs index b68e1ed6..99475577 100644 --- a/crates/core/src/node/in_memory.rs +++ b/crates/core/src/node/in_memory.rs @@ -44,12 +44,14 @@ use std::{ sync::{Arc, RwLock}, }; use zksync_contracts::BaseSystemContracts; -use zksync_multivm::vm_latest::{HistoryEnabled, HistoryMode, TracerPointer, VmTracer}; +#[cfg(not(feature = "zkos"))] +use zksync_multivm::interface::VmFactory; +use zksync_multivm::vm_latest::{HistoryEnabled, HistoryMode, TracerPointer}; use zksync_multivm::{ interface::{ storage::{ReadStorage, StoragePtr, WriteStorage}, Call, ExecutionResult, InspectExecutionMode, L1BatchEnv, L2Block, L2BlockEnv, SystemEnv, - TxExecutionMode, VmExecutionResultAndLogs, VmFactory, VmInterface, VmInterfaceExt, + TxExecutionMode, VmExecutionResultAndLogs, VmInterface, VmInterfaceExt, VmInterfaceHistoryEnabled, }, tracers::CallTracer, @@ -60,7 +62,7 @@ use zksync_multivm::{ vm_latest::{ constants::{BATCH_COMPUTATIONAL_GAS_LIMIT, BATCH_GAS_LIMIT, MAX_VM_PUBDATA_PER_BATCH}, utils::l2_blocks::load_last_l2_block, - HistoryDisabled, ToTracerPointer, Vm, + HistoryDisabled, ToTracerPointer, }, VmVersion, }; @@ -71,9 +73,9 @@ use zksync_types::{ block::{build_bloom, unpack_block_info, L2BlockHasher}, fee::Fee, fee_model::{BatchFeeInput, PubdataIndependentBatchFeeModelInput}, - get_code_key, get_nonce_key, + get_code_key, l2::{L2Tx, TransactionType}, - utils::{decompose_full_nonce, nonces_to_full_nonce, storage_key_for_eth_balance}, + utils::{decompose_full_nonce, nonces_to_full_nonce}, web3::{keccak256, Bytes, Index}, AccountTreeId, Address, Bloom, BloomInput, L1BatchNumber, L2BlockNumber, PackedEthSignature, StorageKey, StorageValue, Transaction, ACCOUNT_CODE_STORAGE_ADDRESS, EMPTY_UNCLES_HASH, H160, @@ -84,9 +86,6 @@ use zksync_types::{h256_to_address, h256_to_u256, u256_to_h256}; use zksync_web3_decl::error::Web3Error; use super::keys::StorageKeyLayout; -use super::zkos::{ - zkos_get_nonce_key, zkos_storage_key_for_eth_balance, ZKOsVM, ZkOsTracerDispatcher, -}; /// Max possible size of an ABI encoded tx (in bytes). pub const MAX_TX_SIZE: usize = 1_000_000; @@ -280,7 +279,6 @@ pub struct TxExecutionOutput { result: VmExecutionResultAndLogs, call_traces: Vec, bytecodes: HashMap>, - //bytecodes: HashMap>, } impl InMemoryNodeInner { @@ -801,9 +799,11 @@ impl InMemoryNodeInner { .set_value(balance_key, u256_to_h256(current_balance)); #[cfg(not(feature = "zkos"))] - let mut vm: Vm<_, HistoryDisabled> = Vm::new(batch_env, system_env, storage.clone()); + let mut vm: zksync_multivm::vm_latest::Vm<_, HistoryDisabled> = + zksync_multivm::vm_latest::Vm::new(batch_env, system_env, storage.clone()); + #[cfg(feature = "zkos")] - let mut vm: ZKOsVM<_, HistoryDisabled> = ZKOsVM::new( + let mut vm: super::zkos::ZKOsVM<_, HistoryDisabled> = super::zkos::ZKOsVM::new( batch_env, system_env, storage.clone(), @@ -1408,9 +1408,10 @@ impl InMemoryNode { let system_env = inner.create_system_env(base_contracts, execution_mode); #[cfg(not(feature = "zkos"))] - let mut vm: Vm<_, HistoryDisabled> = Vm::new(batch_env, system_env, storage.clone()); + let mut vm: zksync_multivm::vm_latest::Vm<_, HistoryDisabled> = + zksync_multivm::vm_latest::Vm::new(batch_env, system_env, storage.clone()); #[cfg(feature = "zkos")] - let mut vm: ZKOsVM<_, HistoryDisabled> = ZKOsVM::new( + let mut vm: super::zkos::ZKOsVM<_, HistoryDisabled> = super::zkos::ZKOsVM::new( batch_env, system_env, storage.clone(), @@ -1683,20 +1684,24 @@ impl InMemoryNode { tracing::info!(""); } - //let bytecodes = HashMap::new(); - // HERE - /*for b in &*compressed_bytecodes { + let mut bytecodes = HashMap::new(); + for b in &*compressed_bytecodes { let (hash, bytecode) = bytecode_to_factory_dep(b.original.clone()).map_err(|err| { tracing::error!("{}", format!("cannot convert bytecode: {err}").on_red()); err })?; bytecodes.insert(hash, bytecode); - }*/ + } + + // Also add bytecodes that were created by EVM. + for entry in &tx_result.dynamic_factory_deps { + bytecodes.insert(entry.0.clone(), entry.1.clone()); + } Ok(TxExecutionOutput { - result: tx_result.clone(), + result: tx_result, call_traces: call_traces.cloned().unwrap_or_default(), - bytecodes: tx_result.dynamic_factory_deps.clone(), + bytecodes, }) } @@ -1761,16 +1766,6 @@ impl InMemoryNode { inner .fork_storage .store_factory_dep(hash.clone(), code.clone()); - /*inner.fork_storage.store_factory_dep( - u256_to_h256(*hash), - code.iter() - .flat_map(|entry| { - let mut bytes = vec![0u8; 32]; - entry.to_big_endian(&mut bytes); - bytes.to_vec() - }) - .collect(), - )*/ } let logs = result @@ -1858,7 +1853,7 @@ impl InMemoryNode { let (batch_env, mut block_ctx) = inner.create_l1_batch_env(time, storage.clone()); #[cfg(feature = "zkos")] - let mut vm: ZKOsVM, HistoryEnabled> = ZKOsVM::new( + let mut vm: super::zkos::ZKOsVM<_, HistoryEnabled> = super::zkos::ZKOsVM::new( batch_env.clone(), system_env, storage.clone(), @@ -1868,7 +1863,8 @@ impl InMemoryNode { drop(inner); #[cfg(not(feature = "zkos"))] - let mut vm: Vm<_, HistoryEnabled> = Vm::new(batch_env.clone(), system_env, storage.clone()); + let mut vm: zksync_multivm::vm_latest::Vm<_, HistoryEnabled> = + zksync_multivm::vm_latest::Vm::new(batch_env.clone(), system_env, storage.clone()); // Compute block hash. Note that the computed block hash here will be different than that in production. let tx_hashes = txs.iter().map(|t| t.hash()).collect::>(); @@ -2195,6 +2191,8 @@ mod tests { use anvil_zksync_config::TestNodeConfig; use anvil_zksync_types::TransactionOrder; use ethabi::{Token, Uint}; + use zksync_multivm::interface::VmFactory; + use zksync_multivm::vm_latest::Vm; use zksync_types::{utils::deployed_address_create, K256PrivateKey, Nonce}; use super::*; diff --git a/crates/core/src/node/in_memory_ext.rs b/crates/core/src/node/in_memory_ext.rs index 61f7fb59..c11c214e 100644 --- a/crates/core/src/node/in_memory_ext.rs +++ b/crates/core/src/node/in_memory_ext.rs @@ -342,17 +342,7 @@ impl InMemoryNode { .strip_prefix("0x") .ok_or_else(|| anyhow!("code must be 0x-prefixed"))?; let code_bytes = hex::decode(code_slice)?; - let hashcode = bytecode_to_factory_dep(code_bytes)?; - let hash = u256_to_h256(hashcode.0); - let code = hashcode - .1 - .iter() - .flat_map(|entry| { - let mut bytes = vec![0u8; 32]; - entry.to_big_endian(&mut bytes); - bytes.to_vec() - }) - .collect(); + let (hash, code) = bytecode_to_factory_dep(code_bytes)?; writer.fork_storage.store_factory_dep(hash, code); writer.fork_storage.set_value(code_key, hash); Ok(()) diff --git a/crates/core/src/node/mod.rs b/crates/core/src/node/mod.rs index 9715eec0..90b32647 100644 --- a/crates/core/src/node/mod.rs +++ b/crates/core/src/node/mod.rs @@ -15,6 +15,7 @@ mod sealer; mod state; mod storage_logs; mod time; +#[cfg(feature = "zkos")] mod zkos; mod zks; diff --git a/crates/core/src/node/zkos.rs b/crates/core/src/node/zkos.rs index bfbc3884..17de5aa8 100644 --- a/crates/core/src/node/zkos.rs +++ b/crates/core/src/node/zkos.rs @@ -24,7 +24,6 @@ use zksync_types::{ address_to_h256, web3::keccak256, AccountTreeId, Address, StorageKey, StorageLog, StorageLogWithPreviousValue, Transaction, H160, H256, }; -//use zksync_utils::{address_to_h256, h256_to_u256, u256_to_h256}; use crate::deps::InMemoryStorage; @@ -223,7 +222,6 @@ pub fn transaction_to_zkos_vec(tx: &Transaction) -> Vec { current_offset += 1; // reserved append_u64(&mut tx_raw, current_offset * 32); - current_offset += 1; // len - data. append_usize(&mut tx_raw, tx.execute.calldata.len()); @@ -488,14 +486,14 @@ impl ZKOsVM { } pub struct ZkOsTracerDispatcher { - tracers: Vec, + _tracers: Vec, _marker: std::marker::PhantomData, } impl Default for ZkOsTracerDispatcher { fn default() -> Self { Self { - tracers: Default::default(), + _tracers: Default::default(), _marker: Default::default(), } } @@ -506,7 +504,7 @@ impl From>> { fn from(_value: Vec>) -> Self { Self { - tracers: Default::default(), + _tracers: Default::default(), _marker: Default::default(), } } @@ -527,7 +525,7 @@ impl VmInterface for ZKOsVM { fn inspect( &mut self, - dispatcher: &mut Self::TracerDispatcher, + _dispatcher: &mut Self::TracerDispatcher, execution_mode: zksync_multivm::interface::InspectExecutionMode, ) -> VmExecutionResultAndLogs { if let InspectExecutionMode::Bootloader = execution_mode { @@ -558,15 +556,15 @@ impl VmInterface for ZKOsVM { ) } - fn start_new_l2_block(&mut self, l2_block_env: zksync_multivm::interface::L2BlockEnv) { + fn start_new_l2_block(&mut self, _l2_block_env: zksync_multivm::interface::L2BlockEnv) { todo!() } fn inspect_transaction_with_bytecode_compression( &mut self, - tracer: &mut Self::TracerDispatcher, - tx: Transaction, - with_compression: bool, + _tracer: &mut Self::TracerDispatcher, + _tx: Transaction, + _with_compression: bool, ) -> ( zksync_multivm::interface::BytecodeCompressionResult<'_>, VmExecutionResultAndLogs, @@ -576,7 +574,7 @@ impl VmInterface for ZKOsVM { fn finish_batch( &mut self, - pubdata_builder: std::rc::Rc, + _pubdata_builder: std::rc::Rc, ) -> zksync_multivm::interface::FinishedL1Batch { todo!() } diff --git a/crates/core/src/utils.rs b/crates/core/src/utils.rs index ba04a5e3..efef6e75 100644 --- a/crates/core/src/utils.rs +++ b/crates/core/src/utils.rs @@ -16,15 +16,6 @@ use zksync_types::{ }; use zksync_web3_decl::error::Web3Error; -pub(crate) fn bytes_to_be_words(bytes: &[u8]) -> Vec { - assert_eq!( - bytes.len() % 32, - 0, - "Bytes must be divisible by 32 to split into chunks" - ); - bytes.chunks(32).map(U256::from_big_endian).collect() -} - /// Takes long integers and returns them in human friendly format with "_". /// For example: 12_334_093 pub fn to_human_size(input: U256) -> String { @@ -46,17 +37,10 @@ pub fn to_human_size(input: U256) -> String { // TODO: Approach to encoding bytecode has changed in the core, so this function is likely no // longer needed. See `zksync_contracts::SystemContractCode` for general approach. -// -// Use of `bytecode_to_factory_dep` needs to be refactored and vendored `bytes_to_be_words` -// should be removed. -pub fn bytecode_to_factory_dep(bytecode: Vec) -> Result<(U256, Vec), anyhow::Error> { +pub fn bytecode_to_factory_dep(bytecode: Vec) -> Result<(H256, Vec), anyhow::Error> { zksync_types::bytecode::validate_bytecode(&bytecode).context("Invalid bytecode")?; let bytecode_hash = zksync_types::bytecode::BytecodeHash::for_bytecode(&bytecode).value(); - let bytecode_hash = U256::from_big_endian(bytecode_hash.as_bytes()); - - let bytecode_words = bytes_to_be_words(&bytecode); - - Ok((bytecode_hash, bytecode_words)) + Ok((bytecode_hash, bytecode)) } /// Returns the actual [U64] block number from [BlockNumber]. From 4c7e85d76f159de6c308d08cf131533dedb89727 Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 14 Jan 2025 16:18:12 +0100 Subject: [PATCH 09/18] cleanup prints & logs --- crates/core/src/node/zkos.rs | 91 +++++++++++++++--------------------- 1 file changed, 38 insertions(+), 53 deletions(-) diff --git a/crates/core/src/node/zkos.rs b/crates/core/src/node/zkos.rs index 17de5aa8..71edcd37 100644 --- a/crates/core/src/node/zkos.rs +++ b/crates/core/src/node/zkos.rs @@ -1,3 +1,5 @@ +//! Interfaces that use zkos for VM execution. +//! This is still experimental code. use std::{alloc::Global, collections::HashMap, vec}; use basic_system::basic_system::simple_growable_storage::TestingTree; @@ -5,7 +7,6 @@ use forward_system::run::{ test_impl::{InMemoryPreimageSource, InMemoryTree, TxListSource}, PreimageType, StorageCommitment, }; -use hex::ToHex; use ruint::aliases::B160; use system_hooks::addresses_constants::{ NOMINAL_TOKEN_BALANCE_STORAGE_ADDRESS, NONCE_HOLDER_HOOK_ADDRESS, @@ -27,6 +28,7 @@ use zksync_types::{ use crate::deps::InMemoryStorage; +// Helper methods for different convertions. pub fn bytes32_to_h256(data: Bytes32) -> H256 { H256::from(data.as_u8_array_ref()) } @@ -48,11 +50,11 @@ pub fn pad_to_word(input: &Vec) -> Vec { data } -// TODO: check endinanness pub fn h160_to_b160(data: &H160) -> B160 { B160::from_be_bytes(data.as_fixed_bytes().clone()) } +// Helper methods to add data to the Vec in the format expected by ZKOS. pub fn append_address(data: &mut Vec, address: &H160) { let mut pp = vec![0u8; 32]; let ap1 = address.as_fixed_bytes(); @@ -86,6 +88,7 @@ pub fn append_usize(data: &mut Vec, payload: usize) { data.append(&mut pp.to_vec()); } +/// Iterates over raw storage and creates a tree from it. pub fn create_tree_from_full_state( raw_storage: &InMemoryStorage, ) -> (InMemoryTree, InMemoryPreimageSource) { @@ -118,9 +121,6 @@ pub fn create_tree_from_full_state( entry.1.clone(), ); } - println!("Tree size is: {}", tree.cold_storage.len()); - println!("Preimage size is: {}", preimage_source.inner.len()); - (tree, preimage_source) } @@ -133,7 +133,7 @@ pub fn add_elem_to_tree(tree: &mut InMemoryTree, k: &StorageKey, v: &H256) { } // Serialize Transaction to ZKOS format. -// Should match the code in basic_bootlaoder/src/bootloader/transaction/mod.rs +// Should match the code in basic_bootloader/src/bootloader/transaction/mod.rs pub fn transaction_to_zkos_vec(tx: &Transaction) -> Vec { let mut tx_raw: Vec = vec![]; let tx_type_id = match tx.tx_format() { @@ -151,7 +151,6 @@ pub fn transaction_to_zkos_vec(tx: &Transaction) -> Vec { }; // tx_type tx_raw.append(&mut vec![0u8; 31]); - tx_raw.append(&mut vec![tx_type_id; 1]); // from @@ -246,18 +245,17 @@ pub fn execute_tx_in_zkos( preimage_source: &InMemoryPreimageSource, storage: &mut StoragePtr, simulate_only: bool, + batch_env: &L1BatchEnv, ) -> VmExecutionResultAndLogs { let batch_context = basic_system::basic_system::BasicBlockMetadataFromOracle { + // TODO: get fee from batch_env. eip1559_basefee: ruint::aliases::U256::from(if simulate_only { 0u64 } else { 1000u64 }), ergs_price: ruint::aliases::U256::from(1u64), - // FIXME - block_number: 1, - timestamp: 42, + block_number: batch_env.number.0 as u64, + timestamp: batch_env.timestamp, gas_per_pubdata: ruint::aliases::U256::from(1u64), }; - println!("Tree size is: {}", tree.cold_storage.len()); - let storage_commitment = StorageCommitment { root: *tree.storage_tree.root(), next_free_slot: tree.storage_tree.next_free_slot, @@ -280,7 +278,6 @@ pub fn execute_tx_in_zkos( ) } else { let tx_source = TxListSource { - // transactions: vec![encoded_iwasm_tx].into(), transactions: vec![tx_raw].into(), }; let batch_output = forward_system::run::run_batch( @@ -299,14 +296,10 @@ pub fn execute_tx_in_zkos( // apply storage writes.. for write in batch_output.storage_writes { - //let ab = write.key.as_u8_array_ref(); - //let ac = H256::from(ab); - let storage_key = StorageKey::new( AccountTreeId::new(Address::from_slice(&write.account.to_be_bytes_vec())), H256::from(write.account_key.as_u8_array_ref()), ); - dbg!(&storage_key); let storage_value = H256::from(write.value.as_u8_array_ref()); let prev_value = storage_ptr.set_value(storage_key, storage_value); @@ -323,13 +316,7 @@ pub fn execute_tx_in_zkos( } let mut f_deps = HashMap::new(); - println!( - "Adding {} preimages:", - batch_output.published_preimages.len() - ); - for factory_dep in batch_output.published_preimages { - println!(" {:?}", factory_dep.0); f_deps.insert(bytes32_to_h256(factory_dep.0), factory_dep.1); } @@ -337,35 +324,26 @@ pub fn execute_tx_in_zkos( }; let tx_output = match output.as_ref() { - Ok(tx_output) => { - match &tx_output.execution_result { - forward_system::run::ExecutionResult::Success(output) => match &output { - forward_system::run::ExecutionOutput::Call(data) => data, - forward_system::run::ExecutionOutput::Create(data, address) => { - // TODO - pass it to the output somehow. - println!( - "Deployed to {}", - address.to_be_bytes_vec().encode_hex::() - ); - data - } - }, - forward_system::run::ExecutionResult::Revert(data) => { - return VmExecutionResultAndLogs { - result: ExecutionResult::Revert { - output: VmRevertReason::General { - msg: "Transaction reverted".to_string(), - data: data.clone(), - }, + Ok(tx_output) => match &tx_output.execution_result { + forward_system::run::ExecutionResult::Success(output) => match &output { + forward_system::run::ExecutionOutput::Call(data) => data, + forward_system::run::ExecutionOutput::Create(data, _) => data, + }, + forward_system::run::ExecutionResult::Revert(data) => { + return VmExecutionResultAndLogs { + result: ExecutionResult::Revert { + output: VmRevertReason::General { + msg: "Transaction reverted".to_string(), + data: data.clone(), }, - logs: Default::default(), - statistics: Default::default(), - refunds: Default::default(), - dynamic_factory_deps: Default::default(), - } + }, + logs: Default::default(), + statistics: Default::default(), + refunds: Default::default(), + dynamic_factory_deps: Default::default(), } } - } + }, Err(invalid_tx) => { return VmExecutionResultAndLogs { result: ExecutionResult::Revert { @@ -403,7 +381,6 @@ pub fn zkos_get_nonce_key(account: &Address) -> StorageKey { let nonce_manager = AccountTreeId::new(b160_to_h160(NONCE_HOLDER_HOOK_ADDRESS)); // The `minNonce` (used as nonce for EOAs) is stored in a mapping inside the `NONCE_HOLDER` system contract - //let key = get_address_mapping_key(account, H256::zero()); let key = address_to_h256(account); StorageKey::new(nonce_manager, key) @@ -454,12 +431,13 @@ pub struct ZKOsVM { preimage: InMemoryPreimageSource, transactions: Vec, execution_mode: TxExecutionMode, + batch_env: L1BatchEnv, _phantom: std::marker::PhantomData, } impl ZKOsVM { pub fn new( - _batch_env: L1BatchEnv, + batch_env: L1BatchEnv, system_env: SystemEnv, storage: StoragePtr, raw_storage: &InMemoryStorage, @@ -472,6 +450,7 @@ impl ZKOsVM { preimage, transactions: vec![], execution_mode, + batch_env, _phantom: Default::default(), } } @@ -543,9 +522,14 @@ impl VmInterface for ZKOsVM { TxExecutionMode::EthCall => true, }; - assert_eq!(1, self.transactions.len()); + // For now we only support one transaction. + assert_eq!( + 1, + self.transactions.len(), + "only one tx per batch supported for now" + ); - // FIXME. + // TODO: add support for multiple transactions. let tx = self.transactions[0].clone(); execute_tx_in_zkos( &tx, @@ -553,6 +537,7 @@ impl VmInterface for ZKOsVM { &self.preimage, &mut self.storage, simulate_only, + &self.batch_env, ) } From 75abde36fe0c635e0342d6615eac8f488497e232 Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 14 Jan 2025 17:56:58 +0100 Subject: [PATCH 10/18] small cleanups --- Cargo.lock | 26 +++++++++++++------------- Cargo.toml | 9 +++++---- crates/config/Cargo.toml | 3 +++ crates/config/src/config.rs | 3 +++ crates/core/Cargo.toml | 12 ++++++------ crates/core/src/node/zkos.rs | 1 + 6 files changed, 31 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 454b40ea..e281c86e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1016,7 +1016,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "basic_bootloader" version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" dependencies = [ "arrayvec 0.7.6", "crypto", @@ -1034,7 +1034,7 @@ dependencies = [ [[package]] name = "basic_system" version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" dependencies = [ "ark-bn254", "ark-ec", @@ -1758,7 +1758,7 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto" version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" dependencies = [ "blake2", "k256 0.13.4", @@ -2587,7 +2587,7 @@ dependencies = [ [[package]] name = "evm_interpreter" version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" dependencies = [ "arrayvec 0.7.6", "crypto", @@ -2735,7 +2735,7 @@ dependencies = [ [[package]] name = "forward_system" version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" dependencies = [ "arrayvec 0.7.6", "basic_bootloader", @@ -3717,7 +3717,7 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "iwasm_ee" version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" dependencies = [ "arrayvec 0.7.6", "crypto", @@ -3730,7 +3730,7 @@ dependencies = [ [[package]] name = "iwasm_interpreter" version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" dependencies = [ "arrayvec 0.7.6", ] @@ -3738,7 +3738,7 @@ dependencies = [ [[package]] name = "iwasm_specification" version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" dependencies = [ "num-derive", "num-traits", @@ -4231,7 +4231,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_nostd_compression" version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" dependencies = [ "adler", ] @@ -5982,7 +5982,7 @@ dependencies = [ [[package]] name = "secp256k1" version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" dependencies = [ "cfg-if", "const_for", @@ -6544,7 +6544,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "storage_models" version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" dependencies = [ "arrayvec 0.7.6", "either", @@ -6730,7 +6730,7 @@ dependencies = [ [[package]] name = "system_hooks" version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" dependencies = [ "crypto", "ruint", @@ -8083,7 +8083,7 @@ dependencies = [ [[package]] name = "zk_ee" version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=mmzk_1217_zkee_for_test_node#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" +source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" dependencies = [ "arrayvec 0.7.6", "bitflags 2.6.0", diff --git a/Cargo.toml b/Cargo.toml index fbb67e7e..94ef40d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,11 +35,12 @@ zksync_web3_decl = { git = "https://github.com/matter-labs/zksync-era.git", rev "server", ] } +# ZK os dependencies -forward_system = { git = "https://github.com/matter-labs/zk_ee.git", branch = "mmzk_1217_zkee_for_test_node" } -basic_system = { git = "https://github.com/matter-labs/zk_ee.git", branch = "mmzk_1217_zkee_for_test_node" } -zk_ee = { git = "https://github.com/matter-labs/zk_ee.git", branch = "mmzk_1217_zkee_for_test_node" } -system_hooks = { git = "https://github.com/matter-labs/zk_ee.git", branch = "mmzk_1217_zkee_for_test_node" } +forward_system = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217" } +basic_system = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217" } +zk_ee = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217" } +system_hooks = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217" } ruint = { version = "1.12.3", default-features = false, features = ["alloc"] } ######################### diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml index cf360257..3ee98c3d 100644 --- a/crates/config/Cargo.toml +++ b/crates/config/Cargo.toml @@ -25,3 +25,6 @@ rand.workspace = true serde.workspace = true serde_json.workspace = true tracing.workspace = true + +[features] +zkos = [] diff --git a/crates/config/src/config.rs b/crates/config/src/config.rs index 0cc553da..2035a20c 100644 --- a/crates/config/src/config.rs +++ b/crates/config/src/config.rs @@ -362,6 +362,9 @@ impl TestNodeConfig { "Disabled".red() } ); + #[cfg(feature = "zkos")] + tracing::info!("ZK OS: {}", "Enabled".green()); + println!("\n"); tracing::info!("========================================"); for host in &self.host { diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 56eb1f42..b28e3559 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -43,11 +43,11 @@ flate2.workspace = true thiserror.workspace = true -forward_system.workspace = true -basic_system.workspace = true -zk_ee.workspace = true -system_hooks.workspace = true -ruint.workspace = true +forward_system = { workspace = true, optional = true } +basic_system = { workspace = true, optional = true } +zk_ee = { workspace = true, optional = true } +system_hooks = { workspace = true, optional = true } +ruint = { workspace = true, optional = true } [dev-dependencies] maplit.workspace = true @@ -60,5 +60,5 @@ test-case.workspace = true [features] -zkos = [] +zkos = ["forward_system", "basic_system", "zk_ee", "system_hooks", "ruint", "anvil_zksync_config/zkos"] default = [] \ No newline at end of file diff --git a/crates/core/src/node/zkos.rs b/crates/core/src/node/zkos.rs index 71edcd37..fb0bc2fc 100644 --- a/crates/core/src/node/zkos.rs +++ b/crates/core/src/node/zkos.rs @@ -444,6 +444,7 @@ impl ZKOsVM { ) -> Self { let execution_mode = system_env.execution_mode; let (tree, preimage) = { create_tree_from_full_state(raw_storage) }; + // TODO: get chain_id from system_env and pass to ZKOS. ZKOsVM { storage, tree, From b660e2388186faf3fe2900c6311bd2dfb5ad5c04 Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 14 Jan 2025 18:07:41 +0100 Subject: [PATCH 11/18] cleaning up rust version --- crates/core/src/lib.rs | 3 +-- docs/rustbook/src/usage/experimental-zkos.md | 24 ++++++++++++++++++++ rust-toolchain.toml | 2 +- 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 docs/rustbook/src/usage/experimental-zkos.md diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 201359af..57103028 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -1,5 +1,4 @@ -#![feature(allocator_api)] - +#![cfg_attr(feature = "zkos", feature(allocator_api))] //! anvil-zksync //! //! The `anvil-zksync` crate provides an in-memory node designed primarily for local testing. diff --git a/docs/rustbook/src/usage/experimental-zkos.md b/docs/rustbook/src/usage/experimental-zkos.md new file mode 100644 index 00000000..8b12262f --- /dev/null +++ b/docs/rustbook/src/usage/experimental-zkos.md @@ -0,0 +1,24 @@ +# ZKOS (experimental) + +ZKOS is the new backend for proving. The features below are still experimental and might break without warning. + + +## Usage + +``` +RUSTUP_TOOLCHAIN=nightly-2024-11-12 cargo run --features zkos -- --chain-id 31337 +``` + +Afterwards, any regular forge script should work: + +``` +forge script script/Counter.s.sol --rpc-url http://localhost:8011 --private-key 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6 --broadcast --slow -g 400 +``` + +## Caveats + +There is still no gas equivalency -- that's why this `-g` option that is increasing the gas limits. + +Currently chain_id is hardcoded inside zkos to 31337, soon it will be passed as argument. + +Many things will not work yet, but basic things like deploying contracts & calling them should work. \ No newline at end of file diff --git a/rust-toolchain.toml b/rust-toolchain.toml index d456bdf6..73cb934d 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-11-12" +channel = "stable" components = ["rustfmt", "clippy"] From 73e04c9f10706296c3acdd71ca39b0adf05d3f09 Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 14 Jan 2025 18:44:42 +0100 Subject: [PATCH 12/18] cleanups after merge --- crates/core/src/node/eth.rs | 11 +- crates/core/src/node/in_memory.rs | 15 +- crates/core/src/node/in_memory_ext.rs | 1 + crates/core/src/node/inner/in_memory_inner.rs | 146 +++++++++++------- crates/core/src/node/mod.rs | 1 - 5 files changed, 109 insertions(+), 65 deletions(-) diff --git a/crates/core/src/node/eth.rs b/crates/core/src/node/eth.rs index 352007ae..6057a020 100644 --- a/crates/core/src/node/eth.rs +++ b/crates/core/src/node/eth.rs @@ -2,7 +2,7 @@ use std::collections::HashSet; use anyhow::Context as _; use colored::Colorize; -use zksync_multivm::interface::{ExecutionResult, TxExecutionMode}; +use zksync_multivm::interface::ExecutionResult; use zksync_multivm::vm_latest::constants::ETH_CALL_GAS_LIMIT; use zksync_types::h256_to_u256; use zksync_types::{ @@ -11,12 +11,11 @@ use zksync_types::{ get_code_key, l2::L2Tx, transaction_request::TransactionRequest, - utils::storage_key_for_standard_token_balance, - PackedEthSignature, L2_BASE_TOKEN_ADDRESS, MAX_L1_TRANSACTION_GAS_LIMIT, + PackedEthSignature, MAX_L1_TRANSACTION_GAS_LIMIT, }; use zksync_types::{ web3::{self, Bytes}, - AccountTreeId, Address, H160, H256, U256, U64, + Address, H160, H256, U256, U64, }; use zksync_web3_decl::{ error::Web3Error, @@ -29,6 +28,8 @@ use crate::{ utils::{h256_to_u64, TransparentError}, }; +use super::keys::StorageKeyLayout; + impl InMemoryNode { pub async fn call_impl( &self, @@ -602,7 +603,7 @@ mod tests { utils::deployed_address_create, Bloom, K256PrivateKey, L2BlockNumber, StorageKey, EMPTY_UNCLES_HASH, }; - use zksync_types::{u256_to_h256, web3, Nonce}; + use zksync_types::{u256_to_h256, web3, AccountTreeId, Nonce}; use zksync_web3_decl::types::{SyncState, ValueOrArray}; async fn test_node(url: &str) -> InMemoryNode { diff --git a/crates/core/src/node/in_memory.rs b/crates/core/src/node/in_memory.rs index 3202967d..5ca77f88 100644 --- a/crates/core/src/node/in_memory.rs +++ b/crates/core/src/node/in_memory.rs @@ -36,13 +36,17 @@ use std::sync::Arc; use tokio::sync::RwLock; use zksync_contracts::BaseSystemContracts; use zksync_multivm::interface::storage::{ReadStorage, StoragePtr}; +#[cfg(not(feature = "zkos"))] +use zksync_multivm::interface::VmFactory; use zksync_multivm::interface::{ - ExecutionResult, InspectExecutionMode, L1BatchEnv, L2BlockEnv, TxExecutionMode, VmFactory, - VmInterface, + ExecutionResult, InspectExecutionMode, L1BatchEnv, L2BlockEnv, TxExecutionMode, VmInterface, }; use zksync_multivm::tracers::CallTracer; use zksync_multivm::utils::{get_batch_base_fee, get_max_batch_gas_limit}; -use zksync_multivm::vm_latest::{HistoryDisabled, ToTracerPointer, Vm}; +#[cfg(not(feature = "zkos"))] +use zksync_multivm::vm_latest::Vm; + +use zksync_multivm::vm_latest::{HistoryDisabled, ToTracerPointer}; use zksync_multivm::VmVersion; use zksync_types::api::{Block, DebugCall, TransactionReceipt, TransactionVariant}; use zksync_types::block::unpack_block_info; @@ -59,8 +63,6 @@ use zksync_types::{ StorageValue, Transaction, H160, H256, H64, U256, U64, }; -use super::keys::StorageKeyLayout; - /// Max possible size of an ABI encoded tx (in bytes). pub const MAX_TX_SIZE: usize = 1_000_000; /// Acceptable gas overestimation limit. @@ -397,8 +399,7 @@ impl InMemoryNode { let storage = StorageView::new(&inner.fork_storage).into_rc_ptr(); #[cfg(not(feature = "zkos"))] - let mut vm: zksync_multivm::vm_latest::Vm<_, HistoryDisabled> = - zksync_multivm::vm_latest::Vm::new(batch_env, system_env, storage); + let mut vm: Vm<_, HistoryDisabled> = Vm::new(batch_env, system_env, storage); #[cfg(feature = "zkos")] let mut vm: super::zkos::ZKOsVM<_, HistoryDisabled> = super::zkos::ZKOsVM::new( batch_env, diff --git a/crates/core/src/node/in_memory_ext.rs b/crates/core/src/node/in_memory_ext.rs index 74e25465..8f9a8654 100644 --- a/crates/core/src/node/in_memory_ext.rs +++ b/crates/core/src/node/in_memory_ext.rs @@ -2,6 +2,7 @@ use super::inner::fork::ForkDetails; use super::pool::TxBatch; use super::sealer::BlockSealerMode; use super::InMemoryNode; +use crate::node::keys::StorageKeyLayout; use crate::utils::bytecode_to_factory_dep; use anvil_zksync_types::api::{DetailedTransaction, ResetRequest}; use anyhow::anyhow; diff --git a/crates/core/src/node/inner/in_memory_inner.rs b/crates/core/src/node/inner/in_memory_inner.rs index 55daf3ea..252e7bd5 100644 --- a/crates/core/src/node/inner/in_memory_inner.rs +++ b/crates/core/src/node/inner/in_memory_inner.rs @@ -7,13 +7,17 @@ use crate::deps::storage_view::StorageView; use crate::filters::EthFilters; use crate::node::call_error_tracer::CallErrorTracer; use crate::node::error::LoadStateError; +use crate::node::keys::StorageKeyLayout; use crate::node::state::StateV1; use crate::node::storage_logs::print_storage_logs_details; +#[cfg(feature = "zkos")] +use crate::node::zkos::ZKOsVM; use crate::node::{ compute_hash, create_block, ImpersonationManager, Snapshot, TestNodeFeeInputProvider, TransactionResult, TxExecutionInfo, VersionedState, ESTIMATE_GAS_ACCEPTABLE_OVERESTIMATION, MAX_PREVIOUS_STATES, MAX_TX_SIZE, }; + use crate::system_contracts::SystemContracts; use crate::utils::{bytecode_to_factory_dep, create_debug_output}; use crate::{formatter, utils}; @@ -28,11 +32,16 @@ use std::sync::Arc; use tokio::sync::RwLock; use zksync_contracts::BaseSystemContracts; use zksync_multivm::interface::storage::{ReadStorage, WriteStorage}; +#[cfg(not(feature = "zkos"))] +use zksync_multivm::interface::VmFactory; use zksync_multivm::interface::{ Call, ExecutionResult, InspectExecutionMode, L1BatchEnv, L2BlockEnv, SystemEnv, - TxExecutionMode, VmExecutionResultAndLogs, VmFactory, VmInterface, VmInterfaceExt, + TxExecutionMode, VmExecutionResultAndLogs, VmInterface, VmInterfaceExt, VmInterfaceHistoryEnabled, }; +#[cfg(not(feature = "zkos"))] +use zksync_multivm::vm_latest::Vm; + use zksync_multivm::tracers::CallTracer; use zksync_multivm::utils::{ adjust_pubdata_price_for_tx, derive_base_fee_and_gas_per_pubdata, derive_overhead, @@ -41,21 +50,21 @@ use zksync_multivm::utils::{ use zksync_multivm::vm_latest::constants::{ BATCH_COMPUTATIONAL_GAS_LIMIT, BATCH_GAS_LIMIT, MAX_VM_PUBDATA_PER_BATCH, }; -use zksync_multivm::vm_latest::{HistoryDisabled, HistoryEnabled, ToTracerPointer, Vm}; -use zksync_multivm::{HistoryMode, VmVersion}; +use zksync_multivm::vm_latest::{ + HistoryDisabled, HistoryEnabled, HistoryMode, ToTracerPointer, TracerPointer, +}; +use zksync_multivm::VmVersion; use zksync_types::api::{BlockIdVariant, TransactionVariant}; use zksync_types::block::build_bloom; use zksync_types::fee::Fee; use zksync_types::fee_model::{BatchFeeInput, PubdataIndependentBatchFeeModelInput}; use zksync_types::l2::{L2Tx, TransactionType}; use zksync_types::transaction_request::CallRequest; -use zksync_types::utils::{ - decompose_full_nonce, nonces_to_full_nonce, storage_key_for_eth_balance, -}; +use zksync_types::utils::{decompose_full_nonce, nonces_to_full_nonce}; use zksync_types::web3::{Bytes, Index}; use zksync_types::{ - api, get_nonce_key, h256_to_address, h256_to_u256, u256_to_h256, AccountTreeId, Address, Bloom, - BloomInput, L1BatchNumber, L2BlockNumber, StorageKey, StorageValue, Transaction, + api, h256_to_address, h256_to_u256, u256_to_h256, AccountTreeId, Address, Bloom, BloomInput, + L1BatchNumber, L2BlockNumber, StorageKey, StorageValue, Transaction, ACCOUNT_CODE_STORAGE_ADDRESS, H160, H256, MAX_L2_TX_GAS_LIMIT, U256, U64, }; use zksync_web3_decl::error::Web3Error; @@ -313,11 +322,14 @@ impl InMemoryNodeInner { /// This is because external users of the library may call this function to perform an isolated /// VM operation (optionally without bootloader execution) with an external storage and get the results back. /// So any data populated in [Self::run_l2_tx] will not be available for the next invocation. - fn run_l2_tx_raw( + fn run_l2_tx_raw( &self, l2_tx: L2Tx, - vm: &mut Vm, - ) -> anyhow::Result { + vm: &mut VM, + ) -> anyhow::Result + where + ::TracerDispatcher: From>>, + { let tx: Transaction = l2_tx.into(); let call_tracer_result = Arc::new(OnceCell::default()); @@ -337,7 +349,7 @@ impl InMemoryNodeInner { .into_owned(); let tx_result = vm.inspect(&mut tracers.into(), InspectExecutionMode::OneTx); - let call_traces = call_tracer_result.get().unwrap(); + let call_traces = call_tracer_result.get(); let spent_on_pubdata = tx_result.statistics.gas_used - tx_result.statistics.computational_gas_used as u64; @@ -376,29 +388,31 @@ impl InMemoryNodeInner { formatter.print_vm_details(&tx_result); } - if !self.config.disable_console_log { - self.console_log_handler.handle_calls_recursive(call_traces); - } + if let Some(call_traces) = call_traces { + if !self.config.disable_console_log { + self.console_log_handler.handle_calls_recursive(call_traces); + } - if self.config.show_calls != ShowCalls::None { - tracing::info!(""); - tracing::info!( - "[Transaction Execution] ({} calls)", - call_traces[0].calls.len() - ); - let num_calls = call_traces.len(); - for (i, call) in call_traces.iter().enumerate() { - let is_last_sibling = i == num_calls - 1; - let mut formatter = formatter::Formatter::new(); - formatter.print_call( - tx.initiator_account(), - tx.execute.contract_address, - call, - is_last_sibling, - self.config.show_calls, - self.config.show_outputs, - self.config.resolve_hashes, + if self.config.show_calls != ShowCalls::None { + tracing::info!(""); + tracing::info!( + "[Transaction Execution] ({} calls)", + call_traces[0].calls.len() ); + let num_calls = call_traces.len(); + for (i, call) in call_traces.iter().enumerate() { + let is_last_sibling = i == num_calls - 1; + let mut formatter = formatter::Formatter::new(); + formatter.print_call( + tx.initiator_account(), + tx.execute.contract_address, + call, + is_last_sibling, + self.config.show_calls, + self.config.show_outputs, + self.config.resolve_hashes, + ); + } } } // Print event logs if enabled @@ -421,23 +435,30 @@ impl InMemoryNodeInner { })?; bytecodes.insert(hash, bytecode); } + // Also add bytecodes that were created by EVM. + for entry in &tx_result.dynamic_factory_deps { + bytecodes.insert(entry.0.clone(), entry.1.clone()); + } Ok(TxExecutionOutput { result: tx_result, - call_traces: call_traces.clone(), + call_traces: call_traces.cloned().unwrap_or_default(), bytecodes, }) } /// Runs L2 transaction and commits it to a new block. - fn run_l2_tx( + fn run_l2_tx( &mut self, l2_tx: L2Tx, l2_tx_index: u64, block_ctx: &BlockContext, batch_env: &L1BatchEnv, - vm: &mut Vm, - ) -> anyhow::Result { + vm: &mut VM, + ) -> anyhow::Result + where + ::TracerDispatcher: From>>, + { let tx_hash = l2_tx.hash(); let transaction_type = l2_tx.common_data.transaction_type; @@ -467,16 +488,8 @@ impl InMemoryNodeInner { // Write all the factory deps. for (hash, code) in bytecodes.iter() { - self.fork_storage.store_factory_dep( - u256_to_h256(*hash), - code.iter() - .flat_map(|entry| { - let mut bytes = vec![0u8; 32]; - entry.to_big_endian(&mut bytes); - bytes.to_vec() - }) - .collect(), - ) + self.fork_storage + .store_factory_dep(hash.clone(), code.clone()) } let logs = result @@ -544,6 +557,16 @@ impl InMemoryNodeInner { block_ctx: &mut BlockContext, ) -> Vec { let storage = StorageView::new(self.fork_storage.clone()).into_rc_ptr(); + + #[cfg(feature = "zkos")] + let mut vm: ZKOsVM<_, HistoryEnabled> = ZKOsVM::new( + batch_env.clone(), + system_env, + storage.clone(), + &self.fork_storage.inner.read().unwrap().raw_storage, + ); + + #[cfg(not(feature = "zkos"))] let mut vm: Vm<_, HistoryEnabled> = Vm::new(batch_env.clone(), system_env, storage.clone()); // Compute block hash. Note that the computed block hash here will be different than that in production. @@ -725,6 +748,9 @@ impl InMemoryNodeInner { .system_contracts .contracts_for_fee_estimate(impersonating) .clone(); + #[cfg(feature = "zkos")] + let allow_no_target = true; + #[cfg(not(feature = "zkos"))] let allow_no_target = system_contracts.evm_emulator.is_some(); let mut l2_tx = L2Tx::from_request( @@ -997,7 +1023,7 @@ impl InMemoryNodeInner { // The nonce needs to be updated let nonce = l2_tx.nonce(); - let nonce_key = get_nonce_key(&l2_tx.initiator_account()); + let nonce_key = StorageKeyLayout::get_nonce_key(&l2_tx.initiator_account()); let full_nonce = storage.borrow_mut().read_value(&nonce_key); let (_, deployment_nonce) = decompose_full_nonce(h256_to_u256(full_nonce)); let enforced_full_nonce = nonces_to_full_nonce(U256::from(nonce.0), deployment_nonce); @@ -1007,7 +1033,7 @@ impl InMemoryNodeInner { // We need to explicitly put enough balance into the account of the users let payer = l2_tx.payer(); - let balance_key = storage_key_for_eth_balance(&payer); + let balance_key = StorageKeyLayout::get_storage_key_for_base_token(&payer); let mut current_balance = h256_to_u256(storage.borrow_mut().read_value(&balance_key)); let added_balance = l2_tx.common_data.fee.gas_limit * l2_tx.common_data.fee.max_fee_per_gas; current_balance += added_balance; @@ -1015,7 +1041,23 @@ impl InMemoryNodeInner { .borrow_mut() .set_value(balance_key, u256_to_h256(current_balance)); - let mut vm: Vm<_, HistoryDisabled> = Vm::new(batch_env, system_env, storage.clone()); + #[cfg(not(feature = "zkos"))] + let mut vm: zksync_multivm::vm_latest::Vm<_, HistoryDisabled> = + zksync_multivm::vm_latest::Vm::new(batch_env, system_env, storage.clone()); + + #[cfg(feature = "zkos")] + let mut vm: ZKOsVM<_, HistoryDisabled> = ZKOsVM::new( + batch_env, + system_env, + storage.clone(), + &fork_storage.inner.read().unwrap().raw_storage, + ); + #[cfg(feature = "zkos")] + { + // Temporary hack - as we update the 'storage' just above, but zkos loads its full + // state from fork_storage (that is not updated). + vm.update_inconsistent_keys(&[&nonce_key, &balance_key]); + } let tx: Transaction = l2_tx.into(); vm.push_transaction(tx); @@ -1268,7 +1310,7 @@ impl InMemoryNodeInner { /// Adds a lot of tokens to a given account with a specified balance. pub fn set_rich_account(&mut self, address: H160, balance: U256) { - let key = storage_key_for_eth_balance(&address); + let key = StorageKeyLayout::get_storage_key_for_base_token(&address); let keys = { let mut storage_view = StorageView::new(&self.fork_storage); @@ -1288,7 +1330,7 @@ impl InMemoryNodeInner { pub struct TxExecutionOutput { result: VmExecutionResultAndLogs, call_traces: Vec, - bytecodes: HashMap>, + bytecodes: HashMap>, } /// Keeps track of a block's batch number, miniblock number and timestamp. diff --git a/crates/core/src/node/mod.rs b/crates/core/src/node/mod.rs index f37e02fc..e0a0e3ef 100644 --- a/crates/core/src/node/mod.rs +++ b/crates/core/src/node/mod.rs @@ -14,7 +14,6 @@ mod pool; mod sealer; mod state; mod storage_logs; -mod time; #[cfg(feature = "zkos")] mod zkos; mod zks; From a53b3b3e4cf755a3bbb5bbbcfefc4c5a9942de40 Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 14 Jan 2025 18:53:12 +0100 Subject: [PATCH 13/18] move deps to optional --- Cargo.toml | 7 ------- crates/core/Cargo.toml | 13 ++++++++----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 82f33734..536362a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,13 +35,6 @@ zksync_web3_decl = { git = "https://github.com/matter-labs/zksync-era.git", rev "server", ] } -# ZK os dependencies - -forward_system = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217" } -basic_system = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217" } -zk_ee = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217" } -system_hooks = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217" } -ruint = { version = "1.12.3", default-features = false, features = ["alloc"] } ######################### # External dependencies # diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 8b2f7ed6..29753a5f 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -44,11 +44,14 @@ thiserror.workspace = true async-trait.workspace = true -forward_system = { workspace = true, optional = true } -basic_system = { workspace = true, optional = true } -zk_ee = { workspace = true, optional = true } -system_hooks = { workspace = true, optional = true } -ruint = { workspace = true, optional = true } +# ZK os dependencies + +forward_system = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217" , optional = true} +basic_system = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217", optional = true } +zk_ee = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217", optional = true } +system_hooks = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217", optional = true } +ruint = { version = "1.12.3", default-features = false, features = ["alloc"] } + [dev-dependencies] maplit.workspace = true From cb8bdbfbbcf442c8e676ed21aedc33dc9758d5b6 Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 14 Jan 2025 18:55:07 +0100 Subject: [PATCH 14/18] fixed toml typo --- crates/core/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 29753a5f..1ca4c7d6 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -50,8 +50,7 @@ forward_system = { git = "https://github.com/matter-labs/zk_ee.git", branch = "z basic_system = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217", optional = true } zk_ee = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217", optional = true } system_hooks = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217", optional = true } -ruint = { version = "1.12.3", default-features = false, features = ["alloc"] } - +ruint = { version = "1.12.3", default-features = false, features = ["alloc"], optional = true } [dev-dependencies] maplit.workspace = true From 7214f8741818ca4fcf240014add8c8f31a94916a Mon Sep 17 00:00:00 2001 From: mm Date: Wed, 15 Jan 2025 07:26:07 +0100 Subject: [PATCH 15/18] marked zkos implemetnation as 'todo' until we finish opensourcing --- Cargo.lock | 393 +--------------------------- crates/core/Cargo.toml | 10 +- crates/core/src/node/zkos.rs | 479 +---------------------------------- 3 files changed, 14 insertions(+), 868 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03035ffb..46a5b29e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,12 +21,6 @@ dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -44,18 +38,6 @@ dependencies = [ "cpufeatures", ] -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -65,12 +47,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - [[package]] name = "alloy-consensus" version = "0.5.4" @@ -495,14 +471,12 @@ dependencies = [ "anyhow", "async-trait", "backon", - "basic_system", "chrono", "colored", "ethabi 16.0.0", "ethers", "eyre", "flate2", - "forward_system", "futures 0.3.31", "hex", "httptest", @@ -512,11 +486,9 @@ dependencies = [ "maplit", "once_cell", "reqwest 0.11.27", - "ruint", "rustc-hash 1.1.0", "serde", "serde_json", - "system_hooks", "tempdir", "test-case", "thiserror", @@ -524,7 +496,6 @@ dependencies = [ "tokio", "tracing", "tracing-subscriber", - "zk_ee", "zksync-web3-rs", "zksync_basic_types", "zksync_contracts", @@ -550,38 +521,6 @@ version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" -[[package]] -name = "ark-bn254" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" -dependencies = [ - "ark-ec", - "ark-ff 0.5.0", - "ark-std 0.5.0", -] - -[[package]] -name = "ark-ec" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" -dependencies = [ - "ahash", - "ark-ff 0.5.0", - "ark-poly", - "ark-serialize 0.5.0", - "ark-std 0.5.0", - "educe", - "fnv", - "hashbrown 0.15.2", - "itertools 0.13.0", - "num-bigint", - "num-integer", - "num-traits", - "zeroize", -] - [[package]] name = "ark-ff" version = "0.3.0" @@ -620,26 +559,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ark-ff" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" -dependencies = [ - "ark-ff-asm 0.5.0", - "ark-ff-macros 0.5.0", - "ark-serialize 0.5.0", - "ark-std 0.5.0", - "arrayvec 0.7.6", - "digest 0.10.7", - "educe", - "itertools 0.13.0", - "num-bigint", - "num-traits", - "paste", - "zeroize", -] - [[package]] name = "ark-ff-asm" version = "0.3.0" @@ -660,16 +579,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "ark-ff-asm" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" -dependencies = [ - "quote", - "syn 2.0.89", -] - [[package]] name = "ark-ff-macros" version = "0.3.0" @@ -695,34 +604,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "ark-ff-macros" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" -dependencies = [ - "num-bigint", - "num-traits", - "proc-macro2", - "quote", - "syn 2.0.89", -] - -[[package]] -name = "ark-poly" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" -dependencies = [ - "ahash", - "ark-ff 0.5.0", - "ark-serialize 0.5.0", - "ark-std 0.5.0", - "educe", - "fnv", - "hashbrown 0.15.2", -] - [[package]] name = "ark-serialize" version = "0.3.0" @@ -744,30 +625,6 @@ dependencies = [ "num-bigint", ] -[[package]] -name = "ark-serialize" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" -dependencies = [ - "ark-serialize-derive", - "ark-std 0.5.0", - "arrayvec 0.7.6", - "digest 0.10.7", - "num-bigint", -] - -[[package]] -name = "ark-serialize-derive" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.89", -] - [[package]] name = "ark-std" version = "0.3.0" @@ -788,16 +645,6 @@ dependencies = [ "rand 0.8.5", ] -[[package]] -name = "ark-std" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" -dependencies = [ - "num-traits", - "rand 0.8.5", -] - [[package]] name = "arrayref" version = "0.3.9" @@ -1027,51 +874,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "basic_bootloader" -version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" -dependencies = [ - "arrayvec 0.7.6", - "crypto", - "either", - "evm_interpreter", - "hex", - "iwasm_ee", - "iwasm_interpreter", - "ruint", - "seq-macro", - "system_hooks", - "zk_ee", -] - -[[package]] -name = "basic_system" -version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" -dependencies = [ - "ark-bn254", - "ark-ec", - "ark-ff 0.5.0", - "ark-serialize 0.5.0", - "arrayvec 0.7.6", - "cfg-if", - "const_for", - "crypto", - "either", - "evm_interpreter", - "hex", - "iwasm_ee", - "iwasm_interpreter", - "miniz_nostd_compression", - "ruint", - "secp256k1 0.1.0", - "serde", - "storage_models", - "system_hooks", - "zk_ee", -] - [[package]] name = "bech32" version = "0.9.1" @@ -1100,15 +902,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - [[package]] name = "bindgen" version = "0.69.5" @@ -1661,12 +1454,6 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[package]] -name = "const_for" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c50fcfdf972929aff202c16b80086aa3cfc6a3a820af714096c58c7c1d0582" - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -1769,18 +1556,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "crypto" -version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" -dependencies = [ - "blake2", - "k256 0.13.4", - "p256", - "sha2 0.10.8", - "sha3 0.10.8", -] - [[package]] name = "crypto-bigint" version = "0.4.9" @@ -2065,18 +1840,6 @@ dependencies = [ "spki 0.7.3", ] -[[package]] -name = "educe" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" -dependencies = [ - "enum-ordinalize", - "proc-macro2", - "quote", - "syn 2.0.89", -] - [[package]] name = "either" version = "1.13.0" @@ -2168,26 +1931,6 @@ dependencies = [ "zeroize", ] -[[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.89", -] - [[package]] name = "enum_dispatch" version = "0.3.13" @@ -2598,19 +2341,6 @@ dependencies = [ "yansi 0.5.1", ] -[[package]] -name = "evm_interpreter" -version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" -dependencies = [ - "arrayvec 0.7.6", - "crypto", - "either", - "hex", - "ruint", - "zk_ee", -] - [[package]] name = "eyre" version = "0.6.12" @@ -2746,26 +2476,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "forward_system" -version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" -dependencies = [ - "arrayvec 0.7.6", - "basic_bootloader", - "basic_system", - "bincode", - "crypto", - "either", - "evm_interpreter", - "hex", - "ruint", - "seq-macro", - "serde", - "system_hooks", - "zk_ee", -] - [[package]] name = "fs2" version = "0.4.3" @@ -3096,7 +2806,6 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ - "allocator-api2", "foldhash", "serde", ] @@ -3740,36 +3449,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" -[[package]] -name = "iwasm_ee" -version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" -dependencies = [ - "arrayvec 0.7.6", - "crypto", - "iwasm_interpreter", - "iwasm_specification", - "ruint", - "zk_ee", -] - -[[package]] -name = "iwasm_interpreter" -version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" -dependencies = [ - "arrayvec 0.7.6", -] - -[[package]] -name = "iwasm_specification" -version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" -dependencies = [ - "num-derive", - "num-traits", -] - [[package]] name = "jni" version = "0.19.0" @@ -4254,14 +3933,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_nostd_compression" -version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -4373,17 +4044,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[package]] -name = "num-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.89", -] - [[package]] name = "num-integer" version = "0.1.46" @@ -6005,16 +5665,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "secp256k1" -version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" -dependencies = [ - "cfg-if", - "const_for", - "crypto", -] - [[package]] name = "secp256k1" version = "0.27.0" @@ -6213,12 +5863,6 @@ dependencies = [ "uuid 1.11.0", ] -[[package]] -name = "seq-macro" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" - [[package]] name = "serde" version = "1.0.215" @@ -6567,17 +6211,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "storage_models" -version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" -dependencies = [ - "arrayvec 0.7.6", - "either", - "ruint", - "zk_ee", -] - [[package]] name = "string_cache" version = "0.8.7" @@ -6753,16 +6386,6 @@ dependencies = [ "libc", ] -[[package]] -name = "system_hooks" -version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" -dependencies = [ - "crypto", - "ruint", - "zk_ee", -] - [[package]] name = "tap" version = "1.0.1" @@ -8106,20 +7729,6 @@ dependencies = [ "zstd", ] -[[package]] -name = "zk_ee" -version = "0.1.0" -source = "git+https://github.com/matter-labs/zk_ee.git?branch=zkos_anvil_v241217#5aa07d27ab201ee6bbcfbfc39991737acc2dbd8b" -dependencies = [ - "arrayvec 0.7.6", - "bitflags 2.6.0", - "cfg-if", - "crypto", - "derivative", - "ruint", - "serde", -] - [[package]] name = "zk_evm" version = "0.131.0-rc.2" @@ -8434,7 +8043,7 @@ dependencies = [ "blake2", "hex", "rand 0.8.5", - "secp256k1 0.27.0", + "secp256k1", "serde", "serde_json", "sha2 0.10.8", diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 1ca4c7d6..67222e9f 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -44,14 +44,6 @@ thiserror.workspace = true async-trait.workspace = true -# ZK os dependencies - -forward_system = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217" , optional = true} -basic_system = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217", optional = true } -zk_ee = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217", optional = true } -system_hooks = { git = "https://github.com/matter-labs/zk_ee.git", branch = "zkos_anvil_v241217", optional = true } -ruint = { version = "1.12.3", default-features = false, features = ["alloc"], optional = true } - [dev-dependencies] maplit.workspace = true ethers.workspace = true @@ -63,5 +55,5 @@ backon.workspace = true [features] -zkos = ["forward_system", "basic_system", "zk_ee", "system_hooks", "ruint", "anvil_zksync_config/zkos"] +zkos = [] default = [] diff --git a/crates/core/src/node/zkos.rs b/crates/core/src/node/zkos.rs index fb0bc2fc..2d778486 100644 --- a/crates/core/src/node/zkos.rs +++ b/crates/core/src/node/zkos.rs @@ -1,437 +1,30 @@ +#![allow(dead_code)] +#![allow(unused_variables)] + //! Interfaces that use zkos for VM execution. //! This is still experimental code. -use std::{alloc::Global, collections::HashMap, vec}; - -use basic_system::basic_system::simple_growable_storage::TestingTree; -use forward_system::run::{ - test_impl::{InMemoryPreimageSource, InMemoryTree, TxListSource}, - PreimageType, StorageCommitment, -}; -use ruint::aliases::B160; -use system_hooks::addresses_constants::{ - NOMINAL_TOKEN_BALANCE_STORAGE_ADDRESS, NONCE_HOLDER_HOOK_ADDRESS, -}; -use zk_ee::{common_structs::derive_flat_storage_key, utils::Bytes32}; use zksync_multivm::{ interface::{ storage::{StoragePtr, WriteStorage}, - ExecutionResult, InspectExecutionMode, L1BatchEnv, PushTransactionResult, SystemEnv, - TxExecutionMode, VmExecutionLogs, VmExecutionResultAndLogs, VmInterface, - VmInterfaceHistoryEnabled, VmRevertReason, + L1BatchEnv, SystemEnv, VmExecutionResultAndLogs, VmInterface, VmInterfaceHistoryEnabled, }, vm_latest::{HistoryMode, TracerPointer}, }; -use zksync_types::{ - address_to_h256, web3::keccak256, AccountTreeId, Address, StorageKey, StorageLog, - StorageLogWithPreviousValue, Transaction, H160, H256, -}; +use zksync_types::{Address, StorageKey, Transaction}; use crate::deps::InMemoryStorage; -// Helper methods for different convertions. -pub fn bytes32_to_h256(data: Bytes32) -> H256 { - H256::from(data.as_u8_array_ref()) -} - -pub fn h256_to_bytes32(data: &H256) -> Bytes32 { - Bytes32::from(data.as_fixed_bytes().clone()) -} - -pub fn b160_to_h160(data: B160) -> H160 { - H160::from_slice(&data.to_be_bytes_vec()) -} - -pub fn pad_to_word(input: &Vec) -> Vec { - let mut data = input.clone(); - let remainder = input.len().div_ceil(32) * 32 - input.len(); - for _ in 0..remainder { - data.push(0u8); - } - data -} - -pub fn h160_to_b160(data: &H160) -> B160 { - B160::from_be_bytes(data.as_fixed_bytes().clone()) -} - -// Helper methods to add data to the Vec in the format expected by ZKOS. -pub fn append_address(data: &mut Vec, address: &H160) { - let mut pp = vec![0u8; 32]; - let ap1 = address.as_fixed_bytes(); - for i in 0..20 { - pp[i + 12] = ap1[i]; - } - data.append(&mut pp); -} - -pub fn append_u256(data: &mut Vec, payload: &zksync_types::U256) { - let mut pp = [0u8; 32]; - payload.to_big_endian(&mut pp); - - data.append(&mut pp.to_vec()); -} -pub fn append_u64(data: &mut Vec, payload: u64) { - let mut pp = [0u8; 32]; - let pp1 = payload.to_be_bytes(); - for i in 0..8 { - pp[24 + i] = pp1[i]; - } - data.append(&mut pp.to_vec()); -} - -pub fn append_usize(data: &mut Vec, payload: usize) { - let mut pp = [0u8; 32]; - let pp1 = payload.to_be_bytes(); - for i in 0..8 { - pp[24 + i] = pp1[i]; - } - data.append(&mut pp.to_vec()); -} - -/// Iterates over raw storage and creates a tree from it. -pub fn create_tree_from_full_state( - raw_storage: &InMemoryStorage, -) -> (InMemoryTree, InMemoryPreimageSource) { - let original_state = &raw_storage.state; - let mut tree = InMemoryTree { - storage_tree: TestingTree::new_in(Global), - cold_storage: HashMap::new(), - }; - let mut preimage_source = InMemoryPreimageSource { - inner: HashMap::new(), - }; - - for entry in original_state { - let kk = derive_flat_storage_key( - &h160_to_b160(entry.0.address()), - &h256_to_bytes32(entry.0.key()), - ); - let vv = h256_to_bytes32(entry.1); - - tree.storage_tree.insert(&kk, &vv); - tree.cold_storage.insert(kk, vv); - } - - for entry in &raw_storage.factory_deps { - preimage_source.inner.insert( - ( - PreimageType::Bytecode(zk_ee::system::ExecutionEnvironmentType::EVM), - h256_to_bytes32(entry.0), - ), - entry.1.clone(), - ); - } - (tree, preimage_source) -} - -pub fn add_elem_to_tree(tree: &mut InMemoryTree, k: &StorageKey, v: &H256) { - let kk = derive_flat_storage_key(&h160_to_b160(k.address()), &h256_to_bytes32(k.key())); - let vv = h256_to_bytes32(v); - - tree.storage_tree.insert(&kk, &vv); - tree.cold_storage.insert(kk, vv); -} - -// Serialize Transaction to ZKOS format. -// Should match the code in basic_bootloader/src/bootloader/transaction/mod.rs -pub fn transaction_to_zkos_vec(tx: &Transaction) -> Vec { - let mut tx_raw: Vec = vec![]; - let tx_type_id = match tx.tx_format() { - zksync_types::l2::TransactionType::LegacyTransaction => 0u8, - zksync_types::l2::TransactionType::EIP2930Transaction => 1u8, - zksync_types::l2::TransactionType::EIP1559Transaction => 2u8, - zksync_types::l2::TransactionType::EIP712Transaction => todo!(), - zksync_types::l2::TransactionType::PriorityOpTransaction => todo!(), - zksync_types::l2::TransactionType::ProtocolUpgradeTransaction => todo!(), - }; - let common_data = match &tx.common_data { - zksync_types::ExecuteTransactionCommon::L1(_) => todo!(), - zksync_types::ExecuteTransactionCommon::L2(l2_tx_common_data) => l2_tx_common_data, - zksync_types::ExecuteTransactionCommon::ProtocolUpgrade(_) => todo!(), - }; - // tx_type - tx_raw.append(&mut vec![0u8; 31]); - tx_raw.append(&mut vec![tx_type_id; 1]); - - // from - append_address(&mut tx_raw, &common_data.initiator_address); - // to - append_address( - &mut tx_raw, - &tx.execute.contract_address.unwrap_or(H160::zero()), - ); - - let gas_limit = common_data.fee.gas_limit; - // gas limit - append_u256(&mut tx_raw, &gas_limit); - // gas per pubdata limit - append_u256(&mut tx_raw, &common_data.fee.gas_per_pubdata_limit); - - let fee_per_gas = common_data.fee.max_fee_per_gas; - - // max fee per gas - append_u256(&mut tx_raw, &fee_per_gas); - // max priority fee per gas. - // hack for legacy tx (verify!!) - append_u256(&mut tx_raw, &common_data.fee.max_priority_fee_per_gas); - - // paymaster - append_u64(&mut tx_raw, 0); - - // nonce - append_u64(&mut tx_raw, common_data.nonce.0.into()); - - append_u256(&mut tx_raw, &tx.execute.value); - - let mut reserved = [0u64; 4]; - - // Should check chain_id - if tx_type_id == 0 { - reserved[0] = 1; - } - - if tx.execute.contract_address.is_none() { - reserved[1] = 1; - } - - for i in 0..4 { - // reserved - append_u64(&mut tx_raw, reserved[i]); - } - - let signature_u256 = common_data.signature.len().div_ceil(32) as u64; - - let execute_calldata_words = tx.execute.calldata.len().div_ceil(32) as u64; - - let mut current_offset = 19; - - // data offset - append_u64(&mut tx_raw, current_offset * 32); - // lent - current_offset += 1 + execute_calldata_words; - // signature offset (stupid -- this doesn't include the padding!!) - append_u64(&mut tx_raw, current_offset * 32); - current_offset += 1 + signature_u256; - - // factory deps - append_u64(&mut tx_raw, current_offset * 32); - current_offset += 1; - // paymater - append_u64(&mut tx_raw, current_offset * 32); - current_offset += 1; - // reserved - append_u64(&mut tx_raw, current_offset * 32); - - // len - data. - append_usize(&mut tx_raw, tx.execute.calldata.len()); - tx_raw.append(&mut pad_to_word(&tx.execute.calldata)); - - // len - signature. - append_usize(&mut tx_raw, common_data.signature.len()); - tx_raw.append(&mut pad_to_word(&common_data.signature)); - - // factory deps - append_u64(&mut tx_raw, 0); - // paymater - append_u64(&mut tx_raw, 0); - // reserved - append_u64(&mut tx_raw, 0); - tx_raw -} - -pub fn execute_tx_in_zkos( - tx: &Transaction, - tree: &InMemoryTree, - preimage_source: &InMemoryPreimageSource, - storage: &mut StoragePtr, - simulate_only: bool, - batch_env: &L1BatchEnv, -) -> VmExecutionResultAndLogs { - let batch_context = basic_system::basic_system::BasicBlockMetadataFromOracle { - // TODO: get fee from batch_env. - eip1559_basefee: ruint::aliases::U256::from(if simulate_only { 0u64 } else { 1000u64 }), - ergs_price: ruint::aliases::U256::from(1u64), - block_number: batch_env.number.0 as u64, - timestamp: batch_env.timestamp, - gas_per_pubdata: ruint::aliases::U256::from(1u64), - }; - - let storage_commitment = StorageCommitment { - root: *tree.storage_tree.root(), - next_free_slot: tree.storage_tree.next_free_slot, - }; - - let tx_raw = transaction_to_zkos_vec(tx); - - let (output, dynamic_factory_deps, storage_logs) = if simulate_only { - ( - forward_system::run::simulate_tx( - tx_raw, - storage_commitment, - batch_context, - tree.clone(), - preimage_source.clone(), - ) - .unwrap(), - Default::default(), // dynamic factory deps - vec![], // storage logs - ) - } else { - let tx_source = TxListSource { - transactions: vec![tx_raw].into(), - }; - let batch_output = forward_system::run::run_batch( - batch_context, - storage_commitment, - // FIXME - tree.clone(), - preimage_source.clone(), - tx_source, - ) - .unwrap(); - - let mut storage_ptr = storage.borrow_mut(); - - let mut storage_logs = vec![]; - - // apply storage writes.. - for write in batch_output.storage_writes { - let storage_key = StorageKey::new( - AccountTreeId::new(Address::from_slice(&write.account.to_be_bytes_vec())), - H256::from(write.account_key.as_u8_array_ref()), - ); - let storage_value = H256::from(write.value.as_u8_array_ref()); - let prev_value = storage_ptr.set_value(storage_key, storage_value); - - let storage_log = StorageLog { - // FIXME - should distinguish between initial write and repeated write. - kind: zksync_types::StorageLogKind::InitialWrite, - key: storage_key, - value: storage_value, - }; - storage_logs.push(StorageLogWithPreviousValue { - log: storage_log, - previous_value: prev_value, - }); - } - let mut f_deps = HashMap::new(); - - for factory_dep in batch_output.published_preimages { - f_deps.insert(bytes32_to_h256(factory_dep.0), factory_dep.1); - } - - (batch_output.tx_results[0].clone(), f_deps, storage_logs) - }; - - let tx_output = match output.as_ref() { - Ok(tx_output) => match &tx_output.execution_result { - forward_system::run::ExecutionResult::Success(output) => match &output { - forward_system::run::ExecutionOutput::Call(data) => data, - forward_system::run::ExecutionOutput::Create(data, _) => data, - }, - forward_system::run::ExecutionResult::Revert(data) => { - return VmExecutionResultAndLogs { - result: ExecutionResult::Revert { - output: VmRevertReason::General { - msg: "Transaction reverted".to_string(), - data: data.clone(), - }, - }, - logs: Default::default(), - statistics: Default::default(), - refunds: Default::default(), - dynamic_factory_deps: Default::default(), - } - } - }, - Err(invalid_tx) => { - return VmExecutionResultAndLogs { - result: ExecutionResult::Revert { - output: VmRevertReason::General { - msg: format!("{:?}", invalid_tx), - data: vec![], - }, - }, - logs: Default::default(), - statistics: Default::default(), - refunds: Default::default(), - dynamic_factory_deps: Default::default(), - } - } - }; - - VmExecutionResultAndLogs { - result: ExecutionResult::Success { - output: tx_output.clone(), - }, - logs: VmExecutionLogs { - storage_logs, - events: Default::default(), - user_l2_to_l1_logs: Default::default(), - system_l2_to_l1_logs: Default::default(), - total_log_queries_count: Default::default(), - }, - statistics: Default::default(), - refunds: Default::default(), - dynamic_factory_deps, - } -} - pub fn zkos_get_nonce_key(account: &Address) -> StorageKey { - let nonce_manager = AccountTreeId::new(b160_to_h160(NONCE_HOLDER_HOOK_ADDRESS)); - - // The `minNonce` (used as nonce for EOAs) is stored in a mapping inside the `NONCE_HOLDER` system contract - let key = address_to_h256(account); - - StorageKey::new(nonce_manager, key) -} - -pub fn zkos_key_for_eth_balance(address: &Address) -> H256 { - address_to_h256(address) -} - -/// Create a `key` part of `StorageKey` to access the balance from ERC20 contract balances -fn zkos_key_for_erc20_balance(address: &Address) -> H256 { - let address_h256 = address_to_h256(address); - - // 20 bytes address first gets aligned to 32 bytes with index of `balanceOf` storage slot - // of default ERC20 contract and to then to 64 bytes. - let slot_index = H256::from_low_u64_be(51); - let mut bytes = [0_u8; 64]; - bytes[..32].copy_from_slice(address_h256.as_bytes()); - bytes[32..].copy_from_slice(slot_index.as_bytes()); - H256(keccak256(&bytes)) -} - -pub fn zkos_storage_key_for_standard_token_balance( - token_contract: AccountTreeId, - address: &Address, -) -> StorageKey { - // We have different implementation of the standard ERC20 contract and native - // eth contract. The key for the balance is different for each. - let key = if token_contract.address() == &b160_to_h160(NOMINAL_TOKEN_BALANCE_STORAGE_ADDRESS) { - zkos_key_for_eth_balance(address) - } else { - zkos_key_for_erc20_balance(address) - }; - - StorageKey::new(token_contract, key) + todo!() } pub fn zkos_storage_key_for_eth_balance(address: &Address) -> StorageKey { - zkos_storage_key_for_standard_token_balance( - AccountTreeId::new(b160_to_h160(NOMINAL_TOKEN_BALANCE_STORAGE_ADDRESS)), - address, - ) + todo!(); } pub struct ZKOsVM { pub storage: StoragePtr, - pub tree: InMemoryTree, - preimage: InMemoryPreimageSource, - transactions: Vec, - execution_mode: TxExecutionMode, - batch_env: L1BatchEnv, + _phantom: std::marker::PhantomData, } @@ -442,26 +35,12 @@ impl ZKOsVM { storage: StoragePtr, raw_storage: &InMemoryStorage, ) -> Self { - let execution_mode = system_env.execution_mode; - let (tree, preimage) = { create_tree_from_full_state(raw_storage) }; - // TODO: get chain_id from system_env and pass to ZKOS. - ZKOsVM { - storage, - tree, - preimage, - transactions: vec![], - execution_mode, - batch_env, - _phantom: Default::default(), - } + todo!() } /// If any keys are updated in storage externally, but not reflected in internal tree. pub fn update_inconsistent_keys(&mut self, inconsistent_nodes: &[&StorageKey]) { - for key in inconsistent_nodes { - let value = self.storage.borrow_mut().read_value(key); - add_elem_to_tree(&mut self.tree, key, &value); - } + todo!() } } @@ -497,10 +76,7 @@ impl VmInterface for ZKOsVM { &mut self, tx: Transaction, ) -> zksync_multivm::interface::PushTransactionResult<'_> { - self.transactions.push(tx); - PushTransactionResult { - compressed_bytecodes: Default::default(), - } + todo!() } fn inspect( @@ -508,38 +84,7 @@ impl VmInterface for ZKOsVM { _dispatcher: &mut Self::TracerDispatcher, execution_mode: zksync_multivm::interface::InspectExecutionMode, ) -> VmExecutionResultAndLogs { - if let InspectExecutionMode::Bootloader = execution_mode { - return VmExecutionResultAndLogs { - result: ExecutionResult::Success { output: vec![] }, - logs: Default::default(), - statistics: Default::default(), - refunds: Default::default(), - dynamic_factory_deps: Default::default(), - }; - } - let simulate_only = match self.execution_mode { - TxExecutionMode::VerifyExecute => false, - TxExecutionMode::EstimateFee => true, - TxExecutionMode::EthCall => true, - }; - - // For now we only support one transaction. - assert_eq!( - 1, - self.transactions.len(), - "only one tx per batch supported for now" - ); - - // TODO: add support for multiple transactions. - let tx = self.transactions[0].clone(); - execute_tx_in_zkos( - &tx, - &self.tree, - &self.preimage, - &mut self.storage, - simulate_only, - &self.batch_env, - ) + todo!() } fn start_new_l2_block(&mut self, _l2_block_env: zksync_multivm::interface::L2BlockEnv) { From 0cd8a0d8d217c65f4eb60879905fc49007565d80 Mon Sep 17 00:00:00 2001 From: mm Date: Wed, 15 Jan 2025 07:36:29 +0100 Subject: [PATCH 16/18] clippy --- crates/core/src/node/inner/in_memory_inner.rs | 5 ++--- crates/core/src/node/keys.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/core/src/node/inner/in_memory_inner.rs b/crates/core/src/node/inner/in_memory_inner.rs index 252e7bd5..cd4079b8 100644 --- a/crates/core/src/node/inner/in_memory_inner.rs +++ b/crates/core/src/node/inner/in_memory_inner.rs @@ -437,7 +437,7 @@ impl InMemoryNodeInner { } // Also add bytecodes that were created by EVM. for entry in &tx_result.dynamic_factory_deps { - bytecodes.insert(entry.0.clone(), entry.1.clone()); + bytecodes.insert(*entry.0, entry.1.clone()); } Ok(TxExecutionOutput { @@ -488,8 +488,7 @@ impl InMemoryNodeInner { // Write all the factory deps. for (hash, code) in bytecodes.iter() { - self.fork_storage - .store_factory_dep(hash.clone(), code.clone()) + self.fork_storage.store_factory_dep(*hash, code.clone()) } let logs = result diff --git a/crates/core/src/node/keys.rs b/crates/core/src/node/keys.rs index baa4f64f..265c0ff0 100644 --- a/crates/core/src/node/keys.rs +++ b/crates/core/src/node/keys.rs @@ -14,7 +14,7 @@ impl StorageKeyLayout { #[cfg(not(feature = "zkos"))] return zksync_types::utils::storage_key_for_standard_token_balance( zksync_types::AccountTreeId::new(zksync_types::L2_BASE_TOKEN_ADDRESS), - &address, + address, ); #[cfg(feature = "zkos")] return crate::node::zkos::zkos_storage_key_for_eth_balance(address); From d9ec694028fa7ff5ccaee2cbadc5f78ed9503f0d Mon Sep 17 00:00:00 2001 From: mm Date: Wed, 15 Jan 2025 09:42:15 +0100 Subject: [PATCH 17/18] revert basic types --- Cargo.lock | 1 - Cargo.toml | 1 - crates/core/Cargo.toml | 1 - 3 files changed, 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 46a5b29e..6f1e8f29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -497,7 +497,6 @@ dependencies = [ "tracing", "tracing-subscriber", "zksync-web3-rs", - "zksync_basic_types", "zksync_contracts", "zksync_multivm", "zksync_types", diff --git a/Cargo.toml b/Cargo.toml index 536362a9..7c627f39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,6 @@ categories = ["cryptography"] ######################### zksync_multivm = { git = "https://github.com/matter-labs/zksync-era.git", rev = "core-v25.4.0" } zksync_contracts = { git = "https://github.com/matter-labs/zksync-era.git", rev = "core-v25.4.0" } -zksync_basic_types = { git = "https://github.com/matter-labs/zksync-era.git", rev = "core-v25.4.0" } zksync_types = { git = "https://github.com/matter-labs/zksync-era.git", rev = "core-v25.4.0" } zksync_vm_interface = { git = "https://github.com/matter-labs/zksync-era.git", rev = "core-v25.4.0" } zksync_web3_decl = { git = "https://github.com/matter-labs/zksync-era.git", rev = "core-v25.4.0", features = [ diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 67222e9f..4c5d3606 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -17,7 +17,6 @@ zksync_multivm.workspace = true zksync_contracts.workspace = true zksync_types.workspace = true zksync_web3_decl.workspace = true -zksync_basic_types.workspace = true anyhow.workspace = true tokio.workspace = true From 0f947ccd89137b523ea0985dfc71e1fb01fcbc23 Mon Sep 17 00:00:00 2001 From: mm Date: Wed, 15 Jan 2025 10:53:18 +0100 Subject: [PATCH 18/18] got rid of feature flag. --- Cargo.toml | 1 - crates/cli/Cargo.toml | 6 -- crates/cli/src/main.rs | 7 +- crates/config/Cargo.toml | 3 - crates/config/src/config.rs | 13 ++- crates/core/Cargo.toml | 8 +- crates/core/src/lib.rs | 1 - crates/core/src/node/debug.rs | 8 +- crates/core/src/node/eth.rs | 19 +++- crates/core/src/node/in_memory.rs | 46 ++++----- crates/core/src/node/in_memory_ext.rs | 7 +- crates/core/src/node/inner/in_memory_inner.rs | 97 +++++++++++-------- crates/core/src/node/keys.rs | 28 +++--- crates/core/src/node/mod.rs | 2 +- crates/core/src/node/vm.rs | 18 ++++ crates/core/src/node/zkos.rs | 3 +- crates/core/src/system_contracts.rs | 21 +++- 17 files changed, 170 insertions(+), 118 deletions(-) create mode 100644 crates/core/src/node/vm.rs diff --git a/Cargo.toml b/Cargo.toml index 7c627f39..ca9c3040 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,6 @@ zksync_web3_decl = { git = "https://github.com/matter-labs/zksync-era.git", rev "server", ] } - ######################### # External dependencies # ######################### diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 550804ec..ca38223c 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -37,9 +37,3 @@ flate2.workspace = true [dev-dependencies] tempdir.workspace = true - -[features] - -zkos = ["anvil_zksync_core/zkos"] - -default = [] \ No newline at end of file diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 1f804c6a..94ff9847 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -218,8 +218,11 @@ async fn main() -> anyhow::Result<()> { let fee_input_provider = TestNodeFeeInputProvider::from_fork(fork_details.as_ref()); let filters = Arc::new(RwLock::new(EthFilters::default())); - let system_contracts = - SystemContracts::from_options(&config.system_contracts_options, config.use_evm_emulator); + let system_contracts = SystemContracts::from_options( + &config.system_contracts_options, + config.use_evm_emulator, + config.use_zkos, + ); let (node_inner, _fork_storage, blockchain, time) = InMemoryNodeInner::init( fork_details, diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml index 3ee98c3d..cf360257 100644 --- a/crates/config/Cargo.toml +++ b/crates/config/Cargo.toml @@ -25,6 +25,3 @@ rand.workspace = true serde.workspace = true serde_json.workspace = true tracing.workspace = true - -[features] -zkos = [] diff --git a/crates/config/src/config.rs b/crates/config/src/config.rs index 2035a20c..e7ceafdb 100644 --- a/crates/config/src/config.rs +++ b/crates/config/src/config.rs @@ -70,6 +70,8 @@ pub struct TestNodeConfig { pub override_bytecodes_dir: Option, /// Enables EVM emulation mode pub use_evm_emulator: bool, + /// Enables ZKOS mode (experimental) + pub use_zkos: bool, /// Optional chain ID for the node pub chain_id: Option, /// L1 gas price (optional override) @@ -155,6 +157,7 @@ impl Default for TestNodeConfig { system_contracts_options: Default::default(), override_bytecodes_dir: None, use_evm_emulator: false, + use_zkos: false, chain_id: None, // Gas configuration defaults @@ -362,8 +365,14 @@ impl TestNodeConfig { "Disabled".red() } ); - #[cfg(feature = "zkos")] - tracing::info!("ZK OS: {}", "Enabled".green()); + tracing::info!( + "ZK OS: {}", + if self.use_zkos { + "Enabled".green() + } else { + "Disabled".red() + } + ); println!("\n"); tracing::info!("========================================"); diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 4c5d3606..75bbb313 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -42,7 +42,6 @@ flate2.workspace = true thiserror.workspace = true async-trait.workspace = true - [dev-dependencies] maplit.workspace = true ethers.workspace = true @@ -50,9 +49,4 @@ httptest.workspace = true tempdir.workspace = true zksync-web3-rs.workspace = true test-case.workspace = true -backon.workspace = true - - -[features] -zkos = [] -default = [] +backon.workspace = true \ No newline at end of file diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 9b539ca6..674fdf15 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -1,4 +1,3 @@ -#![cfg_attr(feature = "zkos", feature(allocator_api))] //! anvil-zksync //! //! The `anvil-zksync` crate provides an in-memory node designed primarily for local testing. diff --git a/crates/core/src/node/debug.rs b/crates/core/src/node/debug.rs index ca57e6ff..214d80e3 100644 --- a/crates/core/src/node/debug.rs +++ b/crates/core/src/node/debug.rs @@ -57,8 +57,12 @@ impl InMemoryNode { ))); } - let mut l2_tx = L2Tx::from_request(request.into(), MAX_TX_SIZE, self.allow_no_target()) - .map_err(Web3Error::SerializationError)?; + let mut l2_tx = L2Tx::from_request( + request.into(), + MAX_TX_SIZE, + self.system_contracts.allow_no_target(), + ) + .map_err(Web3Error::SerializationError)?; let execution_mode = zksync_multivm::interface::TxExecutionMode::EthCall; // init vm diff --git a/crates/core/src/node/eth.rs b/crates/core/src/node/eth.rs index 6057a020..9de40a91 100644 --- a/crates/core/src/node/eth.rs +++ b/crates/core/src/node/eth.rs @@ -36,7 +36,11 @@ impl InMemoryNode { req: zksync_types::transaction_request::CallRequest, ) -> Result { let system_contracts = self.system_contracts.contracts_for_l2_call().clone(); - let mut tx = L2Tx::from_request(req.into(), MAX_TX_SIZE, self.allow_no_target())?; + let mut tx = L2Tx::from_request( + req.into(), + MAX_TX_SIZE, + self.system_contracts.allow_no_target(), + )?; tx.common_data.fee.gas_limit = ETH_CALL_GAS_LIMIT.into(); let call_result = self .run_l2_call(tx, system_contracts) @@ -77,7 +81,8 @@ impl InMemoryNode { let chain_id = self.inner.read().await.fork_storage.chain_id; let (tx_req, hash) = TransactionRequest::from_bytes(&tx_bytes.0, chain_id)?; - let mut l2_tx = L2Tx::from_request(tx_req, MAX_TX_SIZE, self.allow_no_target())?; + let mut l2_tx = + L2Tx::from_request(tx_req, MAX_TX_SIZE, self.system_contracts.allow_no_target())?; l2_tx.set_input(tx_bytes.0, hash); if hash != l2_tx.hash() { @@ -137,7 +142,8 @@ impl InMemoryNode { 27, ))?; - let mut l2_tx: L2Tx = L2Tx::from_request(tx_req, MAX_TX_SIZE, self.allow_no_target())?; + let mut l2_tx: L2Tx = + L2Tx::from_request(tx_req, MAX_TX_SIZE, self.system_contracts.allow_no_target())?; // `v` was overwritten with 0 during converting into l2 tx let mut signature = vec![0u8; 65]; @@ -170,7 +176,10 @@ impl InMemoryNode { // TODO: Support _block: Option, ) -> anyhow::Result { - let balance_key = StorageKeyLayout::get_storage_key_for_base_token(&address); + let balance_key = StorageKeyLayout::get_storage_key_for_base_token( + self.system_contracts.use_zkos, + &address, + ); let inner_guard = self.inner.read().await; match inner_guard.fork_storage.read_value_internal(&balance_key) { @@ -265,7 +274,7 @@ impl InMemoryNode { _block: Option, ) -> anyhow::Result { let inner = self.inner.read().await; - let nonce_key = StorageKeyLayout::get_nonce_key(&address); + let nonce_key = StorageKeyLayout::get_nonce_key(self.system_contracts.use_zkos, &address); match inner.fork_storage.read_value_internal(&nonce_key) { Ok(result) => Ok(h256_to_u64(result).into()), diff --git a/crates/core/src/node/in_memory.rs b/crates/core/src/node/in_memory.rs index 5ca77f88..30ced093 100644 --- a/crates/core/src/node/in_memory.rs +++ b/crates/core/src/node/in_memory.rs @@ -2,9 +2,9 @@ use super::inner::fork::ForkDetails; use super::inner::node_executor::NodeExecutorHandle; use super::inner::InMemoryNodeInner; +use super::vm::AnvilVM; use crate::deps::{storage_view::StorageView, InMemoryStorage}; use crate::filters::EthFilters; -use crate::formatter; use crate::node::call_error_tracer::CallErrorTracer; use crate::node::error::LoadStateError; use crate::node::fee_model::TestNodeFeeInputProvider; @@ -16,6 +16,7 @@ use crate::node::state::VersionedState; use crate::node::{BlockSealer, BlockSealerMode, NodeExecutor, TxPool}; use crate::observability::Observability; use crate::system_contracts::SystemContracts; +use crate::{delegate_vm, formatter}; use anvil_zksync_config::constants::{ LEGACY_RICH_WALLETS, NON_FORK_FIRST_BLOCK_TIMESTAMP, RICH_WALLETS, TEST_NODE_NETWORK_ID, }; @@ -36,14 +37,12 @@ use std::sync::Arc; use tokio::sync::RwLock; use zksync_contracts::BaseSystemContracts; use zksync_multivm::interface::storage::{ReadStorage, StoragePtr}; -#[cfg(not(feature = "zkos"))] use zksync_multivm::interface::VmFactory; use zksync_multivm::interface::{ ExecutionResult, InspectExecutionMode, L1BatchEnv, L2BlockEnv, TxExecutionMode, VmInterface, }; use zksync_multivm::tracers::CallTracer; use zksync_multivm::utils::{get_batch_base_fee, get_max_batch_gas_limit}; -#[cfg(not(feature = "zkos"))] use zksync_multivm::vm_latest::Vm; use zksync_multivm::vm_latest::{HistoryDisabled, ToTracerPointer}; @@ -310,18 +309,6 @@ impl InMemoryNode { Ok(()) } - /// Whether it accepts the transactions that have 'null' as target. - /// This is used only when EVM emulator is enabled, or we're running in zkos mode. - pub fn allow_no_target(&self) -> bool { - #[cfg(feature = "zkos")] - return true; - #[cfg(not(feature = "zkos"))] - self.system_contracts - .contracts_for_l2_call() - .evm_emulator - .is_some() - } - /// Applies multiple transactions across multiple blocks. All transactions are expected to be /// executable. Note that on error this method may leave node in partially applied state (i.e. /// some txs have been applied while others have not). @@ -398,16 +385,17 @@ impl InMemoryNode { let storage = StorageView::new(&inner.fork_storage).into_rc_ptr(); - #[cfg(not(feature = "zkos"))] - let mut vm: Vm<_, HistoryDisabled> = Vm::new(batch_env, system_env, storage); - #[cfg(feature = "zkos")] - let mut vm: super::zkos::ZKOsVM<_, HistoryDisabled> = super::zkos::ZKOsVM::new( - batch_env, - system_env, - storage, - // TODO: this might be causing a deadlock.. check.. - &inner.fork_storage.inner.read().unwrap().raw_storage, - ); + let mut vm = if self.system_contracts.use_zkos { + AnvilVM::ZKOs(super::zkos::ZKOsVM::<_, HistoryDisabled>::new( + batch_env, + system_env, + storage, + // TODO: this might be causing a deadlock.. check.. + &inner.fork_storage.inner.read().unwrap().raw_storage, + )) + } else { + AnvilVM::ZKSync(Vm::new(batch_env, system_env, storage)) + }; // We must inject *some* signature (otherwise bootloader code fails to generate hash). if l2_tx.common_data.signature.is_empty() { @@ -415,7 +403,7 @@ impl InMemoryNode { } let tx: Transaction = l2_tx.into(); - vm.push_transaction(tx.clone()); + delegate_vm!(vm, push_transaction(tx.clone())); let call_tracer_result = Arc::new(OnceCell::default()); @@ -423,7 +411,10 @@ impl InMemoryNode { CallErrorTracer::new().into_tracer_pointer(), CallTracer::new(call_tracer_result.clone()).into_tracer_pointer(), ]; - let tx_result = vm.inspect(&mut tracers.into(), InspectExecutionMode::OneTx); + let tx_result = delegate_vm!( + vm, + inspect(&mut tracers.into(), InspectExecutionMode::OneTx) + ); let call_traces = Arc::try_unwrap(call_tracer_result) .unwrap() @@ -661,6 +652,7 @@ impl InMemoryNode { let system_contracts = SystemContracts::from_options( &config.system_contracts_options, config.use_evm_emulator, + config.use_zkos, ); let (inner, _, blockchain, time) = InMemoryNodeInner::init( fork, diff --git a/crates/core/src/node/in_memory_ext.rs b/crates/core/src/node/in_memory_ext.rs index 8f9a8654..d1193ccc 100644 --- a/crates/core/src/node/in_memory_ext.rs +++ b/crates/core/src/node/in_memory_ext.rs @@ -167,7 +167,10 @@ impl InMemoryNode { pub async fn set_balance(&self, address: Address, balance: U256) -> bool { let writer = self.inner.write().await; - let balance_key = StorageKeyLayout::get_storage_key_for_base_token(&address); + let balance_key = StorageKeyLayout::get_storage_key_for_base_token( + self.system_contracts.use_zkos, + &address, + ); writer .fork_storage .set_value(balance_key, u256_to_h256(balance)); @@ -181,7 +184,7 @@ impl InMemoryNode { pub async fn set_nonce(&self, address: Address, nonce: U256) -> bool { let writer = self.inner.write().await; - let nonce_key = StorageKeyLayout::get_nonce_key(&address); + let nonce_key = StorageKeyLayout::get_nonce_key(self.system_contracts.use_zkos, &address); let enforced_full_nonce = nonces_to_full_nonce(nonce, nonce); tracing::info!( "👷 Nonces for address {:?} have been set to {}", diff --git a/crates/core/src/node/inner/in_memory_inner.rs b/crates/core/src/node/inner/in_memory_inner.rs index cd4079b8..73d947e4 100644 --- a/crates/core/src/node/inner/in_memory_inner.rs +++ b/crates/core/src/node/inner/in_memory_inner.rs @@ -10,7 +10,7 @@ use crate::node::error::LoadStateError; use crate::node::keys::StorageKeyLayout; use crate::node::state::StateV1; use crate::node::storage_logs::print_storage_logs_details; -#[cfg(feature = "zkos")] +use crate::node::vm::AnvilVM; use crate::node::zkos::ZKOsVM; use crate::node::{ compute_hash, create_block, ImpersonationManager, Snapshot, TestNodeFeeInputProvider, @@ -20,7 +20,7 @@ use crate::node::{ use crate::system_contracts::SystemContracts; use crate::utils::{bytecode_to_factory_dep, create_debug_output}; -use crate::{formatter, utils}; +use crate::{delegate_vm, formatter, utils}; use anvil_zksync_config::constants::NON_FORK_FIRST_BLOCK_TIMESTAMP; use anvil_zksync_config::TestNodeConfig; use anvil_zksync_types::{ShowCalls, ShowGasDetails, ShowStorageLogs, ShowVMDetails}; @@ -32,14 +32,12 @@ use std::sync::Arc; use tokio::sync::RwLock; use zksync_contracts::BaseSystemContracts; use zksync_multivm::interface::storage::{ReadStorage, WriteStorage}; -#[cfg(not(feature = "zkos"))] use zksync_multivm::interface::VmFactory; use zksync_multivm::interface::{ Call, ExecutionResult, InspectExecutionMode, L1BatchEnv, L2BlockEnv, SystemEnv, TxExecutionMode, VmExecutionResultAndLogs, VmInterface, VmInterfaceExt, VmInterfaceHistoryEnabled, }; -#[cfg(not(feature = "zkos"))] use zksync_multivm::vm_latest::Vm; use zksync_multivm::tracers::CallTracer; @@ -557,16 +555,17 @@ impl InMemoryNodeInner { ) -> Vec { let storage = StorageView::new(self.fork_storage.clone()).into_rc_ptr(); - #[cfg(feature = "zkos")] - let mut vm: ZKOsVM<_, HistoryEnabled> = ZKOsVM::new( - batch_env.clone(), - system_env, - storage.clone(), - &self.fork_storage.inner.read().unwrap().raw_storage, - ); - - #[cfg(not(feature = "zkos"))] - let mut vm: Vm<_, HistoryEnabled> = Vm::new(batch_env.clone(), system_env, storage.clone()); + let mut vm = if self.system_contracts.use_zkos { + AnvilVM::ZKOs(ZKOsVM::<_, HistoryEnabled>::new( + batch_env.clone(), + system_env, + storage.clone(), + // TODO: this might be causing a deadlock.. check.. + &self.fork_storage.inner.read().unwrap().raw_storage, + )) + } else { + AnvilVM::ZKSync(Vm::new(batch_env.clone(), system_env, storage.clone())) + }; // Compute block hash. Note that the computed block hash here will be different than that in production. let tx_hashes = txs.iter().map(|t| t.hash()).collect::>(); @@ -579,21 +578,31 @@ impl InMemoryNodeInner { for tx in txs { // Executing a next transaction means that a previous transaction was either rolled back (in which case its snapshot // was already removed), or that we build on top of it (in which case, it can be removed now). - vm.pop_snapshot_no_rollback(); + delegate_vm!(vm, pop_snapshot_no_rollback()); // Save pre-execution VM snapshot. - vm.make_snapshot(); - match self.run_l2_tx(tx, tx_index, block_ctx, &batch_env, &mut vm) { + delegate_vm!(vm, make_snapshot()); + let result = match vm { + AnvilVM::ZKSync(ref mut vm) => { + self.run_l2_tx(tx, tx_index, block_ctx, &batch_env, vm) + } + AnvilVM::ZKOs(ref mut vm) => { + self.run_l2_tx(tx, tx_index, block_ctx, &batch_env, vm) + } + }; + + match result { + //self.run_l2_tx(tx, tx_index, block_ctx, &batch_env, &mut vm) { Ok(tx_result) => { tx_results.push(tx_result); tx_index += 1; } Err(e) => { tracing::error!("Error while executing transaction: {e}"); - vm.rollback_to_the_latest_snapshot(); + delegate_vm!(vm, rollback_to_the_latest_snapshot()); } } } - vm.execute(InspectExecutionMode::Bootloader); + delegate_vm!(vm, execute(InspectExecutionMode::Bootloader)); // Write all the mutated keys (storage slots). for (key, value) in storage.borrow().modified_storage_keys() { @@ -747,15 +756,11 @@ impl InMemoryNodeInner { .system_contracts .contracts_for_fee_estimate(impersonating) .clone(); - #[cfg(feature = "zkos")] - let allow_no_target = true; - #[cfg(not(feature = "zkos"))] - let allow_no_target = system_contracts.evm_emulator.is_some(); let mut l2_tx = L2Tx::from_request( request_with_gas_per_pubdata_overridden.into(), MAX_TX_SIZE, - allow_no_target, + self.system_contracts.allow_no_target(), ) .map_err(Web3Error::SerializationError)?; @@ -822,6 +827,7 @@ impl InMemoryNodeInner { batch_env.clone(), system_env.clone(), &self.fork_storage, + self.system_contracts.use_zkos, ); if result.statistics.pubdata_published > MAX_VM_PUBDATA_PER_BATCH.try_into().unwrap() { @@ -859,6 +865,7 @@ impl InMemoryNodeInner { batch_env.clone(), system_env.clone(), &self.fork_storage, + self.system_contracts.use_zkos, ); if estimate_gas_result.result.is_failed() { @@ -890,6 +897,7 @@ impl InMemoryNodeInner { batch_env, system_env, &self.fork_storage, + self.system_contracts.use_zkos, ); let overhead = derive_overhead( @@ -1004,6 +1012,7 @@ impl InMemoryNodeInner { batch_env: L1BatchEnv, system_env: SystemEnv, fork_storage: &ForkStorage, + is_zkos: bool, ) -> VmExecutionResultAndLogs { let tx: Transaction = l2_tx.clone().into(); @@ -1022,7 +1031,7 @@ impl InMemoryNodeInner { // The nonce needs to be updated let nonce = l2_tx.nonce(); - let nonce_key = StorageKeyLayout::get_nonce_key(&l2_tx.initiator_account()); + let nonce_key = StorageKeyLayout::get_nonce_key(is_zkos, &l2_tx.initiator_account()); let full_nonce = storage.borrow_mut().read_value(&nonce_key); let (_, deployment_nonce) = decompose_full_nonce(h256_to_u256(full_nonce)); let enforced_full_nonce = nonces_to_full_nonce(U256::from(nonce.0), deployment_nonce); @@ -1032,7 +1041,7 @@ impl InMemoryNodeInner { // We need to explicitly put enough balance into the account of the users let payer = l2_tx.payer(); - let balance_key = StorageKeyLayout::get_storage_key_for_base_token(&payer); + let balance_key = StorageKeyLayout::get_storage_key_for_base_token(is_zkos, &payer); let mut current_balance = h256_to_u256(storage.borrow_mut().read_value(&balance_key)); let added_balance = l2_tx.common_data.fee.gas_limit * l2_tx.common_data.fee.max_fee_per_gas; current_balance += added_balance; @@ -1040,28 +1049,26 @@ impl InMemoryNodeInner { .borrow_mut() .set_value(balance_key, u256_to_h256(current_balance)); - #[cfg(not(feature = "zkos"))] - let mut vm: zksync_multivm::vm_latest::Vm<_, HistoryDisabled> = - zksync_multivm::vm_latest::Vm::new(batch_env, system_env, storage.clone()); - - #[cfg(feature = "zkos")] - let mut vm: ZKOsVM<_, HistoryDisabled> = ZKOsVM::new( - batch_env, - system_env, - storage.clone(), - &fork_storage.inner.read().unwrap().raw_storage, - ); - #[cfg(feature = "zkos")] - { + let mut vm = if is_zkos { + let mut vm = ZKOsVM::<_, HistoryDisabled>::new( + batch_env, + system_env, + storage, + // TODO: this might be causing a deadlock.. check.. + &fork_storage.inner.read().unwrap().raw_storage, + ); // Temporary hack - as we update the 'storage' just above, but zkos loads its full // state from fork_storage (that is not updated). vm.update_inconsistent_keys(&[&nonce_key, &balance_key]); - } + AnvilVM::ZKOs(vm) + } else { + AnvilVM::ZKSync(Vm::new(batch_env, system_env, storage)) + }; let tx: Transaction = l2_tx.into(); - vm.push_transaction(tx); + delegate_vm!(vm, push_transaction(tx)); - vm.execute(InspectExecutionMode::OneTx) + delegate_vm!(vm, execute(InspectExecutionMode::OneTx)) } /// Creates a [Snapshot] of the current state of the node. @@ -1309,7 +1316,10 @@ impl InMemoryNodeInner { /// Adds a lot of tokens to a given account with a specified balance. pub fn set_rich_account(&mut self, address: H160, balance: U256) { - let key = StorageKeyLayout::get_storage_key_for_base_token(&address); + let key = StorageKeyLayout::get_storage_key_for_base_token( + self.system_contracts.use_zkos, + &address, + ); let keys = { let mut storage_view = StorageView::new(&self.fork_storage); @@ -1372,6 +1382,7 @@ impl InMemoryNodeInner { let system_contracts = SystemContracts::from_options( &config.system_contracts_options, config.use_evm_emulator, + config.use_zkos, ); let (inner, _, _, _) = InMemoryNodeInner::init( None, diff --git a/crates/core/src/node/keys.rs b/crates/core/src/node/keys.rs index 265c0ff0..776a459b 100644 --- a/crates/core/src/node/keys.rs +++ b/crates/core/src/node/keys.rs @@ -3,20 +3,22 @@ use zksync_types::{Address, StorageKey}; pub struct StorageKeyLayout {} impl StorageKeyLayout { - pub fn get_nonce_key(account: &Address) -> StorageKey { - #[cfg(not(feature = "zkos"))] - return zksync_types::get_nonce_key(account); - #[cfg(feature = "zkos")] - return crate::node::zkos::zkos_get_nonce_key(account); + pub fn get_nonce_key(is_zkos: bool, account: &Address) -> StorageKey { + if is_zkos { + crate::node::zkos::zkos_get_nonce_key(account) + } else { + zksync_types::get_nonce_key(account) + } } - pub fn get_storage_key_for_base_token(address: &Address) -> StorageKey { - #[cfg(not(feature = "zkos"))] - return zksync_types::utils::storage_key_for_standard_token_balance( - zksync_types::AccountTreeId::new(zksync_types::L2_BASE_TOKEN_ADDRESS), - address, - ); - #[cfg(feature = "zkos")] - return crate::node::zkos::zkos_storage_key_for_eth_balance(address); + pub fn get_storage_key_for_base_token(is_zkos: bool, address: &Address) -> StorageKey { + if is_zkos { + crate::node::zkos::zkos_storage_key_for_eth_balance(address) + } else { + zksync_types::utils::storage_key_for_standard_token_balance( + zksync_types::AccountTreeId::new(zksync_types::L2_BASE_TOKEN_ADDRESS), + address, + ) + } } } diff --git a/crates/core/src/node/mod.rs b/crates/core/src/node/mod.rs index e0a0e3ef..d435e438 100644 --- a/crates/core/src/node/mod.rs +++ b/crates/core/src/node/mod.rs @@ -14,7 +14,7 @@ mod pool; mod sealer; mod state; mod storage_logs; -#[cfg(feature = "zkos")] +mod vm; mod zkos; mod zks; diff --git a/crates/core/src/node/vm.rs b/crates/core/src/node/vm.rs new file mode 100644 index 00000000..293cf04e --- /dev/null +++ b/crates/core/src/node/vm.rs @@ -0,0 +1,18 @@ +use zksync_multivm::{interface::storage::WriteStorage, vm_latest::Vm, HistoryMode}; + +use super::zkos::ZKOsVM; + +pub enum AnvilVM { + ZKOs(ZKOsVM), + ZKSync(Vm), +} + +#[macro_export] +macro_rules! delegate_vm { + ($variable:expr, $function:ident($($params:tt)*)) => { + match &mut $variable { + AnvilVM::ZKOs(vm) => vm.$function($($params)*), + AnvilVM::ZKSync(vm) => vm.$function($($params)*), + } + }; +} diff --git a/crates/core/src/node/zkos.rs b/crates/core/src/node/zkos.rs index 2d778486..6f53ce98 100644 --- a/crates/core/src/node/zkos.rs +++ b/crates/core/src/node/zkos.rs @@ -8,7 +8,8 @@ use zksync_multivm::{ storage::{StoragePtr, WriteStorage}, L1BatchEnv, SystemEnv, VmExecutionResultAndLogs, VmInterface, VmInterfaceHistoryEnabled, }, - vm_latest::{HistoryMode, TracerPointer}, + vm_latest::TracerPointer, + HistoryMode, }; use zksync_types::{Address, StorageKey, Transaction}; diff --git a/crates/core/src/system_contracts.rs b/crates/core/src/system_contracts.rs index 3e6fb6ad..3bb9295d 100644 --- a/crates/core/src/system_contracts.rs +++ b/crates/core/src/system_contracts.rs @@ -17,19 +17,28 @@ pub struct SystemContracts { fee_estimate_contracts: BaseSystemContracts, baseline_impersonating_contracts: BaseSystemContracts, fee_estimate_impersonating_contracts: BaseSystemContracts, + use_evm_emulator: bool, + // For now, store the zkos switch flag here. + // Long term, we should probably refactor this code, and add another struct ('System') + // that would hold separate things for ZKOS and for EraVM. (but that's too early for now). + pub use_zkos: bool, } impl Default for SystemContracts { /// Creates SystemContracts that use compiled-in contracts. fn default() -> Self { - SystemContracts::from_options(&SystemContractsOptions::BuiltIn, false) + SystemContracts::from_options(&SystemContractsOptions::BuiltIn, false, false) } } impl SystemContracts { /// Creates the SystemContracts that use the complied contracts from ZKSYNC_HOME path. /// These are loaded at binary runtime. - pub fn from_options(options: &SystemContractsOptions, use_evm_emulator: bool) -> Self { + pub fn from_options( + options: &SystemContractsOptions, + use_evm_emulator: bool, + use_zkos: bool, + ) -> Self { Self { baseline_contracts: baseline_contracts(options, use_evm_emulator), playground_contracts: playground(options, use_evm_emulator), @@ -42,9 +51,17 @@ impl SystemContracts { options, use_evm_emulator, ), + use_evm_emulator, + use_zkos, } } + /// Whether it accepts the transactions that have 'null' as target. + /// This is used only when EVM emulator is enabled, or we're running in zkos mode. + pub fn allow_no_target(&self) -> bool { + self.use_zkos || self.use_evm_emulator + } + pub fn contracts_for_l2_call(&self) -> &BaseSystemContracts { self.contracts(TxExecutionMode::EthCall, false) }