From 1cc42fd0d984153cfa9e1e541bf3fb5ee97c2866 Mon Sep 17 00:00:00 2001 From: Javier Chatruc Date: Fri, 9 Aug 2024 11:01:46 -0300 Subject: [PATCH 01/76] [WIP] Initial EVM equivalence changes --- contracts | 2 +- .../system-constants-generator/src/utils.rs | 16 ++++++++++ core/lib/config/src/configs/chain.rs | 3 ++ core/lib/config/src/configs/genesis.rs | 2 ++ core/lib/config/src/testonly.rs | 2 ++ core/lib/contracts/src/lib.rs | 18 ++++++++++- ...0bf5f89e96ab4e6c199fccd17d38eaec77a7.json} | 28 ++++++++++------- ...4a0fe2f0c3bf5f11aec8400c0b6e5b58c62a.json} | 12 ++++++-- ...8ccf0df652f6a8362370563a1073a28a8037.json} | 12 ++++++-- ...927c5f5b88725987e82cf3ec5d499c5addbb.json} | 16 ++++++---- ...e9afe0ead3d435d166a3116551502a730731.json} | 26 +++++++++------- ...6d3bc76cabe8b0c616ed13dd139327c4cc34.json} | 26 +++++++++------- ...87dde392c0efa13ecd42becfd0e5db79f059.json} | 14 ++++++--- ...884ca664431997692e4af804ecf5ff8b819a.json} | 5 ++-- ...dfa954eaf93e6ab5b64bdaa8ef9984ccdf6b.json} | 26 +++++++++------- ...08525bf32965ca06e847082c0fc3c54a1dde.json} | 10 +++++-- ...b7ce70b4aaa5c810c79d5bf854fe30c28fd4.json} | 26 +++++++++------- ...0ff9894b1de204599f4a4fd39cfde1020a3e.json} | 26 +++++++++------- ...686d545c780b37430bdcf70fc55e80588b6b.json} | 30 +++++++++++-------- ...0f877299ff2e7bfdb5de94a07e5556c20144.json} | 16 ++++++---- ...a68e5e5cf16897de4b6e3211d5e1c07e9294.json} | 10 +++++-- ...412e502df24849331486c604fb0d36d99554.json} | 12 ++++++-- ...1bc51d4f949f0941156021a4844ed8c959ca.json} | 26 +++++++++------- ...3c84139791a734ab6d7eafbdb202e6dc32e9.json} | 16 ++++++---- .../20240808160800_evm-simulator.down.sql | 3 ++ .../20240808160800_evm-simulator.up.sql | 3 ++ core/lib/dal/src/blocks_dal.rs | 14 +++++++++ core/lib/dal/src/blocks_web3_dal.rs | 4 ++- core/lib/dal/src/factory_deps_dal.rs | 13 ++++++++ core/lib/dal/src/models/storage_block.rs | 21 +++++++++++++ .../src/models/storage_protocol_version.rs | 12 ++++++++ core/lib/dal/src/models/storage_sync.rs | 3 ++ core/lib/dal/src/protocol_versions_dal.rs | 8 ++++- .../lib/dal/src/protocol_versions_web3_dal.rs | 1 + core/lib/dal/src/sync_dal.rs | 1 + core/lib/dal/src/tests/mod.rs | 1 + core/lib/env_config/src/genesis.rs | 1 + core/lib/protobuf_config/src/chain.rs | 1 + core/lib/protobuf_config/src/genesis.rs | 6 ++++ .../src/proto/config/genesis.proto | 13 ++++---- core/lib/types/src/abi.rs | 5 ++++ core/lib/types/src/api/mod.rs | 14 +++++++++ core/lib/types/src/protocol_upgrade.rs | 8 +++++ core/lib/vm_utils/src/storage.rs | 11 +++++-- .../node/api_server/src/web3/namespaces/en.rs | 6 ++++ core/node/eth_sender/src/eth_tx_aggregator.rs | 14 +++++++++ core/node/eth_watch/src/client.rs | 1 + core/node/genesis/src/lib.rs | 8 +++++ core/node/genesis/src/utils.rs | 12 +++++--- core/node/node_sync/src/external_io.rs | 9 ++++++ core/node/node_sync/src/genesis.rs | 11 +++++++ core/node/test_utils/src/lib.rs | 1 + etc/env/base/chain.toml | 5 ++-- etc/env/base/contracts.toml | 4 +-- 54 files changed, 456 insertions(+), 138 deletions(-) rename core/lib/dal/.sqlx/{query-05b0050aa9d2944542abbcef31af3fe8d35800340d1c6e9d02c15226b699c93b.json => query-08313f09d890c7158bb1ab8158e10bf5f89e96ab4e6c199fccd17d38eaec77a7.json} (83%) rename core/lib/dal/.sqlx/{query-ef70506e90e8add3b95940a7333f8222bd9fbe8ce82d8963f7da03fe6fcf9225.json => query-1ab1ee0657abc6586204dae61cb54a0fe2f0c3bf5f11aec8400c0b6e5b58c62a.json} (74%) rename core/lib/dal/.sqlx/{query-e89e8cc58a2078157d06f3064ccad9773d45ef6d548f03d643007d3bc1072526.json => query-1b039e10a20864e878af005d06378ccf0df652f6a8362370563a1073a28a8037.json} (62%) rename core/lib/dal/.sqlx/{query-778f92b1ac91e1ae279f588053d75a9ac877fdd28bda99661e423405e695223d.json => query-2060d7de5c06f2fd24b43de6eeca927c5f5b88725987e82cf3ec5d499c5addbb.json} (81%) rename core/lib/dal/.sqlx/{query-38dea171e4c49f54bf1db5ac9bfb3be9cf3928755be5f5fcfcdc086e73fb15e2.json => query-2cfcd25a9e0a51c509baafcf8611e9afe0ead3d435d166a3116551502a730731.json} (78%) rename core/lib/dal/.sqlx/{query-2486f8404e8cfcb9c178acd6dccae32e8812becbe5ce85e63694385f015f2cfe.json => query-2f0d3e88282af17374c549e650756d3bc76cabe8b0c616ed13dd139327c4cc34.json} (80%) rename core/lib/dal/.sqlx/{query-454e16ddb5e85285d0c4b9013bcce5d464ecc55c80b54bc16040226df7e297bd.json => query-42ae258b55532b0f814af4e5d39e87dde392c0efa13ecd42becfd0e5db79f059.json} (82%) rename core/lib/dal/.sqlx/{query-9f2c06e6b14434ac4f3b556dc97994cc05ebeb4e5aeeaee50b7c4d8baf58ca44.json => query-49f300dde6f37c283bd99596c290884ca664431997692e4af804ecf5ff8b819a.json} (50%) rename core/lib/dal/.sqlx/{query-659f616d3af4a79f898e84f890e06de9633d1086da972a467d89831e7a07c67e.json => query-535ca6ef0f2b47fe36a6a2c59861dfa954eaf93e6ab5b64bdaa8ef9984ccdf6b.json} (73%) rename core/lib/dal/.sqlx/{query-5556ebdb040428b42c04ea9121b3c2a3d0a09c5ee88bdd671462904d4d27a355.json => query-5b623ec03908aef2f9f4de80ccd108525bf32965ca06e847082c0fc3c54a1dde.json} (71%) rename core/lib/dal/.sqlx/{query-63f95c6cdcfd933e2cf8f62c0d408f2dce89f7b700896fcc0f242e0e15ba058e.json => query-7f5993b00c1270d80e6081c3304fb7ce70b4aaa5c810c79d5bf854fe30c28fd4.json} (69%) rename core/lib/dal/.sqlx/{query-de255be5d2e5ef215428e9a886e7c9dc036873c60b8b916ce8c446e310447b66.json => query-92d3a7d8c32c4575d6a225f0440b0ff9894b1de204599f4a4fd39cfde1020a3e.json} (80%) rename core/lib/dal/.sqlx/{query-52bb6de515e1edf4dcf34a31600edb31cfd855014dfca5041833b9d5d9f7a55e.json => query-acf497b952de2d8f83cf2b96f2eb686d545c780b37430bdcf70fc55e80588b6b.json} (80%) rename core/lib/dal/.sqlx/{query-f35d539db19ed626a2e0b537468bcef1260bd43f7eee2710dfbdeed1a0228318.json => query-c9b576c200570410bedfa54ab36a0f877299ff2e7bfdb5de94a07e5556c20144.json} (81%) rename core/lib/dal/.sqlx/{query-1074d0a2e4a4afb9a92f3822e133db7a71aca15698bafba051a8d9a91a4dbc76.json => query-d7ee8998bdc54b0a68dadb79aae3a68e5e5cf16897de4b6e3211d5e1c07e9294.json} (75%) rename core/lib/dal/.sqlx/{query-5d493cbce749cc5b56d4069423597b16599abaf51df0f19effe1a536376cf6a6.json => query-e4736015a313f552d6763b9a82c3412e502df24849331486c604fb0d36d99554.json} (52%) rename core/lib/dal/.sqlx/{query-b7cd7c40282c2ca2287eef93ee79c69a9e494bf1f873291b4ae7bf68b7e3c549.json => query-ebb6c005f99d144963d487841d6e1bc51d4f949f0941156021a4844ed8c959ca.json} (74%) rename core/lib/dal/.sqlx/{query-8998ddd82cf15feb671b0d4efc6f7496667ce703e30d1bf2e0fb5a66fb0a1d18.json => query-fa4ba80bf19de46f751e0752a1df3c84139791a734ab6d7eafbdb202e6dc32e9.json} (83%) create mode 100644 core/lib/dal/migrations/20240808160800_evm-simulator.down.sql create mode 100644 core/lib/dal/migrations/20240808160800_evm-simulator.up.sql diff --git a/contracts b/contracts index 8670004d6daa..aa30514b6f99 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 8670004d6daa7e8c299087d62f1451a3dec4f899 +Subproject commit aa30514b6f99b4849937fe632abc80dd807e7dc7 diff --git a/core/bin/system-constants-generator/src/utils.rs b/core/bin/system-constants-generator/src/utils.rs index a56c85a7d5b6..926db5124a51 100644 --- a/core/bin/system-constants-generator/src/utils.rs +++ b/core/bin/system-constants-generator/src/utils.rs @@ -69,12 +69,19 @@ pub static GAS_TEST_SYSTEM_CONTRACTS: Lazy = Lazy::new(|| { let bytecode = read_sys_contract_bytecode("", "DefaultAccount", ContractLanguage::Sol); let hash = hash_bytecode(&bytecode); + let evm_simulator_bytecode = + read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); + let evm_simulator_hash = hash_bytecode(&evm_simulator_bytecode); BaseSystemContracts { default_aa: SystemContractCode { code: bytes_to_be_words(bytecode), hash, }, bootloader, + evm_simulator: SystemContractCode { + code: bytes_to_be_words(evm_simulator_bytecode), + hash: evm_simulator_hash, + }, } }); @@ -217,9 +224,18 @@ pub(super) fn execute_internal_transfer_test() -> u32 { hash, }; + let evm_simulator_bytecode = + read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); + let evm_simulator_hash = hash_bytecode(&evm_simulator_bytecode); + let evm_simulator = SystemContractCode { + code: bytes_to_be_words(evm_simulator_bytecode), + hash: evm_simulator_hash, + }; + let base_system_smart_contracts = BaseSystemContracts { bootloader, default_aa, + evm_simulator, }; let system_env = SystemEnv { diff --git a/core/lib/config/src/configs/chain.rs b/core/lib/config/src/configs/chain.rs index 53884c4a7227..31091e9ce1db 100644 --- a/core/lib/config/src/configs/chain.rs +++ b/core/lib/config/src/configs/chain.rs @@ -137,6 +137,8 @@ pub struct StateKeeperConfig { pub bootloader_hash: Option, #[deprecated(note = "Use GenesisConfig::default_aa_hash instead")] pub default_aa_hash: Option, + #[deprecated(note = "Use GenesisConfig::evm_simulator_hash instead")] + pub evm_simulator_hash: Option, #[deprecated(note = "Use GenesisConfig::l1_batch_commit_data_generator_mode instead")] #[serde(default)] pub l1_batch_commit_data_generator_mode: L1BatchCommitmentMode, @@ -181,6 +183,7 @@ impl StateKeeperConfig { protective_reads_persistence_enabled: true, bootloader_hash: None, default_aa_hash: None, + evm_simulator_hash: None, l1_batch_commit_data_generator_mode: L1BatchCommitmentMode::Rollup, } } diff --git a/core/lib/config/src/configs/genesis.rs b/core/lib/config/src/configs/genesis.rs index 2c5c91128431..6b7120c4b527 100644 --- a/core/lib/config/src/configs/genesis.rs +++ b/core/lib/config/src/configs/genesis.rs @@ -17,6 +17,7 @@ pub struct GenesisConfig { pub genesis_commitment: Option, pub bootloader_hash: Option, pub default_aa_hash: Option, + pub evm_simulator_hash: Option, pub l1_chain_id: L1ChainId, pub sl_chain_id: Option, pub l2_chain_id: L2ChainId, @@ -42,6 +43,7 @@ impl GenesisConfig { genesis_commitment: Some(H256::repeat_byte(0x17)), bootloader_hash: Default::default(), default_aa_hash: Default::default(), + evm_simulator_hash: Default::default(), l1_chain_id: L1ChainId(9), sl_chain_id: None, protocol_version: Some(ProtocolSemanticVersion { diff --git a/core/lib/config/src/testonly.rs b/core/lib/config/src/testonly.rs index f31ec9a0acab..6a75e9f6bf1a 100644 --- a/core/lib/config/src/testonly.rs +++ b/core/lib/config/src/testonly.rs @@ -182,6 +182,7 @@ impl Distribution for EncodeDist { fee_account_addr: None, bootloader_hash: None, default_aa_hash: None, + evm_simulator_hash: None, l1_batch_commit_data_generator_mode: Default::default(), } } @@ -701,6 +702,7 @@ impl Distribution for EncodeDist { genesis_commitment: Some(rng.gen()), bootloader_hash: Some(rng.gen()), default_aa_hash: Some(rng.gen()), + evm_simulator_hash: Some(rng.gen()), fee_account: rng.gen(), l1_chain_id: L1ChainId(self.sample(rng)), sl_chain_id: None, diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index bd7fa80b716c..c63f940c3704 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -83,6 +83,7 @@ fn load_contract_if_present + std::fmt::Debug>(path: P) -> Option fn load_contract_for_hardhat(path: (&str, &str)) -> Option { let path = Path::new(HARDHAT_PATH_PREFIX).join(path.0).join(path.1); + println!("PATH: {:?}", path); load_contract_if_present(path) } @@ -96,6 +97,7 @@ fn load_contract_for_both_compilers(path: (&str, &str)) -> Contract { return contract; }; + println!("HARDHAT"); load_contract_for_hardhat(path).unwrap_or_else(|| { panic!("Failed to load contract from {:?}", path); }) @@ -284,7 +286,7 @@ fn read_zbin_bytecode_from_path(bytecode_path: PathBuf) -> Vec { .unwrap_or_else(|err| panic!("Can't read .zbin bytecode at {:?}: {}", bytecode_path, err)) } /// Hash of code and code which consists of 32 bytes words -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct SystemContractCode { pub code: Vec, pub hash: H256, @@ -294,18 +296,21 @@ pub struct SystemContractCode { pub struct BaseSystemContracts { pub bootloader: SystemContractCode, pub default_aa: SystemContractCode, + pub evm_simulator: SystemContractCode, } #[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq)] pub struct BaseSystemContractsHashes { pub bootloader: H256, pub default_aa: H256, + pub evm_simulator: H256, } impl PartialEq for BaseSystemContracts { fn eq(&self, other: &Self) -> bool { self.bootloader.hash == other.bootloader.hash && self.default_aa.hash == other.default_aa.hash + && self.evm_simulator.hash == other.evm_simulator.hash } } @@ -326,9 +331,19 @@ impl BaseSystemContracts { hash, }; + let evm_simulator_bytecode = + read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); + let evm_simulator_hash = hash_bytecode(&evm_simulator_bytecode); + + let evm_simulator = SystemContractCode { + code: bytes_to_be_words(evm_simulator_bytecode), + hash: evm_simulator_hash, + }; + BaseSystemContracts { bootloader, default_aa, + evm_simulator, } } // BaseSystemContracts with proved bootloader - for handling transactions. @@ -465,6 +480,7 @@ impl BaseSystemContracts { BaseSystemContractsHashes { bootloader: self.bootloader.hash, default_aa: self.default_aa.hash, + evm_simulator: self.evm_simulator.hash, } } } diff --git a/core/lib/dal/.sqlx/query-05b0050aa9d2944542abbcef31af3fe8d35800340d1c6e9d02c15226b699c93b.json b/core/lib/dal/.sqlx/query-08313f09d890c7158bb1ab8158e10bf5f89e96ab4e6c199fccd17d38eaec77a7.json similarity index 83% rename from core/lib/dal/.sqlx/query-05b0050aa9d2944542abbcef31af3fe8d35800340d1c6e9d02c15226b699c93b.json rename to core/lib/dal/.sqlx/query-08313f09d890c7158bb1ab8158e10bf5f89e96ab4e6c199fccd17d38eaec77a7.json index b577e7535eb0..abd12214c197 100644 --- a/core/lib/dal/.sqlx/query-05b0050aa9d2944542abbcef31af3fe8d35800340d1c6e9d02c15226b699c93b.json +++ b/core/lib/dal/.sqlx/query-08313f09d890c7158bb1ab8158e10bf5f89e96ab4e6c199fccd17d38eaec77a7.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n eth_commit_tx_id IS NOT NULL\n AND eth_prove_tx_id IS NULL\n ORDER BY\n number\n LIMIT\n $1\n ", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_simulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n system_logs,\n compressed_state_diffs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n number = $1\n ", "describe": { "columns": [ { @@ -90,28 +90,28 @@ }, { "ordinal": 17, - "name": "aux_data_hash", + "name": "evm_simulator_code_hash", "type_info": "Bytea" }, { "ordinal": 18, - "name": "pass_through_data_hash", + "name": "aux_data_hash", "type_info": "Bytea" }, { "ordinal": 19, - "name": "meta_parameters_hash", + "name": "pass_through_data_hash", "type_info": "Bytea" }, { "ordinal": 20, - "name": "protocol_version", - "type_info": "Int4" + "name": "meta_parameters_hash", + "type_info": "Bytea" }, { "ordinal": 21, - "name": "compressed_state_diffs", - "type_info": "Bytea" + "name": "protocol_version", + "type_info": "Int4" }, { "ordinal": 22, @@ -120,16 +120,21 @@ }, { "ordinal": 23, - "name": "events_queue_commitment", + "name": "compressed_state_diffs", "type_info": "Bytea" }, { "ordinal": 24, - "name": "bootloader_initial_content_commitment", + "name": "events_queue_commitment", "type_info": "Bytea" }, { "ordinal": 25, + "name": "bootloader_initial_content_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 26, "name": "pubdata_input", "type_info": "Bytea" } @@ -165,8 +170,9 @@ false, true, true, + true, true ] }, - "hash": "05b0050aa9d2944542abbcef31af3fe8d35800340d1c6e9d02c15226b699c93b" + "hash": "08313f09d890c7158bb1ab8158e10bf5f89e96ab4e6c199fccd17d38eaec77a7" } diff --git a/core/lib/dal/.sqlx/query-ef70506e90e8add3b95940a7333f8222bd9fbe8ce82d8963f7da03fe6fcf9225.json b/core/lib/dal/.sqlx/query-1ab1ee0657abc6586204dae61cb54a0fe2f0c3bf5f11aec8400c0b6e5b58c62a.json similarity index 74% rename from core/lib/dal/.sqlx/query-ef70506e90e8add3b95940a7333f8222bd9fbe8ce82d8963f7da03fe6fcf9225.json rename to core/lib/dal/.sqlx/query-1ab1ee0657abc6586204dae61cb54a0fe2f0c3bf5f11aec8400c0b6e5b58c62a.json index cf102b828aa8..12ddbfbc4211 100644 --- a/core/lib/dal/.sqlx/query-ef70506e90e8add3b95940a7333f8222bd9fbe8ce82d8963f7da03fe6fcf9225.json +++ b/core/lib/dal/.sqlx/query-1ab1ee0657abc6586204dae61cb54a0fe2f0c3bf5f11aec8400c0b6e5b58c62a.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n miniblocks.number,\n COALESCE(\n miniblocks.l1_batch_number,\n (\n SELECT\n (MAX(number) + 1)\n FROM\n l1_batches\n )\n ) AS \"l1_batch_number!\",\n miniblocks.timestamp,\n miniblocks.l1_tx_count,\n miniblocks.l2_tx_count,\n miniblocks.hash AS \"root_hash?\",\n commit_tx.tx_hash AS \"commit_tx_hash?\",\n commit_tx.confirmed_at AS \"committed_at?\",\n prove_tx.tx_hash AS \"prove_tx_hash?\",\n prove_tx.confirmed_at AS \"proven_at?\",\n execute_tx.tx_hash AS \"execute_tx_hash?\",\n execute_tx.confirmed_at AS \"executed_at?\",\n miniblocks.l1_gas_price,\n miniblocks.l2_fair_gas_price,\n miniblocks.fair_pubdata_price,\n miniblocks.bootloader_code_hash,\n miniblocks.default_aa_code_hash,\n miniblocks.protocol_version,\n miniblocks.fee_account_address\n FROM\n miniblocks\n LEFT JOIN l1_batches ON miniblocks.l1_batch_number = l1_batches.number\n LEFT JOIN eth_txs_history AS commit_tx ON (\n l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id\n AND commit_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS prove_tx ON (\n l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id\n AND prove_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS execute_tx ON (\n l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id\n AND execute_tx.confirmed_at IS NOT NULL\n )\n WHERE\n miniblocks.number = $1\n ", + "query": "\n SELECT\n miniblocks.number,\n COALESCE(\n miniblocks.l1_batch_number,\n (\n SELECT\n (MAX(number) + 1)\n FROM\n l1_batches\n )\n ) AS \"l1_batch_number!\",\n miniblocks.timestamp,\n miniblocks.l1_tx_count,\n miniblocks.l2_tx_count,\n miniblocks.hash AS \"root_hash?\",\n commit_tx.tx_hash AS \"commit_tx_hash?\",\n commit_tx.confirmed_at AS \"committed_at?\",\n prove_tx.tx_hash AS \"prove_tx_hash?\",\n prove_tx.confirmed_at AS \"proven_at?\",\n execute_tx.tx_hash AS \"execute_tx_hash?\",\n execute_tx.confirmed_at AS \"executed_at?\",\n miniblocks.l1_gas_price,\n miniblocks.l2_fair_gas_price,\n miniblocks.fair_pubdata_price,\n miniblocks.bootloader_code_hash,\n miniblocks.default_aa_code_hash,\n miniblocks.evm_simulator_code_hash,\n miniblocks.protocol_version,\n miniblocks.fee_account_address\n FROM\n miniblocks\n LEFT JOIN l1_batches ON miniblocks.l1_batch_number = l1_batches.number\n LEFT JOIN eth_txs_history AS commit_tx ON (\n l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id\n AND commit_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS prove_tx ON (\n l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id\n AND prove_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS execute_tx ON (\n l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id\n AND execute_tx.confirmed_at IS NOT NULL\n )\n WHERE\n miniblocks.number = $1\n ", "describe": { "columns": [ { @@ -90,11 +90,16 @@ }, { "ordinal": 17, + "name": "evm_simulator_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 18, "name": "protocol_version", "type_info": "Int4" }, { - "ordinal": 18, + "ordinal": 19, "name": "fee_account_address", "type_info": "Bytea" } @@ -123,8 +128,9 @@ true, true, true, + true, false ] }, - "hash": "ef70506e90e8add3b95940a7333f8222bd9fbe8ce82d8963f7da03fe6fcf9225" + "hash": "1ab1ee0657abc6586204dae61cb54a0fe2f0c3bf5f11aec8400c0b6e5b58c62a" } diff --git a/core/lib/dal/.sqlx/query-e89e8cc58a2078157d06f3064ccad9773d45ef6d548f03d643007d3bc1072526.json b/core/lib/dal/.sqlx/query-1b039e10a20864e878af005d06378ccf0df652f6a8362370563a1073a28a8037.json similarity index 62% rename from core/lib/dal/.sqlx/query-e89e8cc58a2078157d06f3064ccad9773d45ef6d548f03d643007d3bc1072526.json rename to core/lib/dal/.sqlx/query-1b039e10a20864e878af005d06378ccf0df652f6a8362370563a1073a28a8037.json index 68b595b50274..cb63d67becc0 100644 --- a/core/lib/dal/.sqlx/query-e89e8cc58a2078157d06f3064ccad9773d45ef6d548f03d643007d3bc1072526.json +++ b/core/lib/dal/.sqlx/query-1b039e10a20864e878af005d06378ccf0df652f6a8362370563a1073a28a8037.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n protocol_versions.id AS \"minor!\",\n protocol_versions.timestamp,\n protocol_versions.bootloader_code_hash,\n protocol_versions.default_account_code_hash,\n protocol_patches.patch,\n protocol_patches.recursion_scheduler_level_vk_hash\n FROM\n protocol_versions\n JOIN protocol_patches ON protocol_patches.minor = protocol_versions.id\n WHERE\n id = $1\n ORDER BY\n protocol_patches.patch DESC\n LIMIT\n 1\n ", + "query": "\n SELECT\n protocol_versions.id AS \"minor!\",\n protocol_versions.timestamp,\n protocol_versions.bootloader_code_hash,\n protocol_versions.default_account_code_hash,\n protocol_versions.evm_simulator_code_hash,\n protocol_patches.patch,\n protocol_patches.recursion_scheduler_level_vk_hash\n FROM\n protocol_versions\n JOIN protocol_patches ON protocol_patches.minor = protocol_versions.id\n WHERE\n id = $1\n ORDER BY\n protocol_patches.patch DESC\n LIMIT\n 1\n ", "describe": { "columns": [ { @@ -25,11 +25,16 @@ }, { "ordinal": 4, + "name": "evm_simulator_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 5, "name": "patch", "type_info": "Int4" }, { - "ordinal": 5, + "ordinal": 6, "name": "recursion_scheduler_level_vk_hash", "type_info": "Bytea" } @@ -44,9 +49,10 @@ false, false, false, + true, false, false ] }, - "hash": "e89e8cc58a2078157d06f3064ccad9773d45ef6d548f03d643007d3bc1072526" + "hash": "1b039e10a20864e878af005d06378ccf0df652f6a8362370563a1073a28a8037" } diff --git a/core/lib/dal/.sqlx/query-778f92b1ac91e1ae279f588053d75a9ac877fdd28bda99661e423405e695223d.json b/core/lib/dal/.sqlx/query-2060d7de5c06f2fd24b43de6eeca927c5f5b88725987e82cf3ec5d499c5addbb.json similarity index 81% rename from core/lib/dal/.sqlx/query-778f92b1ac91e1ae279f588053d75a9ac877fdd28bda99661e423405e695223d.json rename to core/lib/dal/.sqlx/query-2060d7de5c06f2fd24b43de6eeca927c5f5b88725987e82cf3ec5d499c5addbb.json index aa7d4c65a39d..7b4fa2793dba 100644 --- a/core/lib/dal/.sqlx/query-778f92b1ac91e1ae279f588053d75a9ac877fdd28bda99661e423405e695223d.json +++ b/core/lib/dal/.sqlx/query-2060d7de5c06f2fd24b43de6eeca927c5f5b88725987e82cf3ec5d499c5addbb.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n miniblocks.number,\n COALESCE(\n miniblocks.l1_batch_number,\n (\n SELECT\n (MAX(number) + 1)\n FROM\n l1_batches\n ),\n (\n SELECT\n MAX(l1_batch_number) + 1\n FROM\n snapshot_recovery\n )\n ) AS \"l1_batch_number!\",\n (miniblocks.l1_tx_count + miniblocks.l2_tx_count) AS \"tx_count!\",\n miniblocks.timestamp,\n miniblocks.l1_gas_price,\n miniblocks.l2_fair_gas_price,\n miniblocks.fair_pubdata_price,\n miniblocks.bootloader_code_hash,\n miniblocks.default_aa_code_hash,\n miniblocks.virtual_blocks,\n miniblocks.hash,\n miniblocks.protocol_version AS \"protocol_version!\",\n miniblocks.fee_account_address AS \"fee_account_address!\"\n FROM\n miniblocks\n WHERE\n miniblocks.number BETWEEN $1 AND $2\n ", + "query": "\n SELECT\n miniblocks.number,\n COALESCE(\n miniblocks.l1_batch_number,\n (\n SELECT\n (MAX(number) + 1)\n FROM\n l1_batches\n ),\n (\n SELECT\n MAX(l1_batch_number) + 1\n FROM\n snapshot_recovery\n )\n ) AS \"l1_batch_number!\",\n (miniblocks.l1_tx_count + miniblocks.l2_tx_count) AS \"tx_count!\",\n miniblocks.timestamp,\n miniblocks.l1_gas_price,\n miniblocks.l2_fair_gas_price,\n miniblocks.fair_pubdata_price,\n miniblocks.bootloader_code_hash,\n miniblocks.default_aa_code_hash,\n miniblocks.evm_simulator_code_hash,\n miniblocks.virtual_blocks,\n miniblocks.hash,\n miniblocks.protocol_version AS \"protocol_version!\",\n miniblocks.fee_account_address AS \"fee_account_address!\"\n FROM\n miniblocks\n WHERE\n miniblocks.number BETWEEN $1 AND $2\n ", "describe": { "columns": [ { @@ -50,21 +50,26 @@ }, { "ordinal": 9, + "name": "evm_simulator_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 10, "name": "virtual_blocks", "type_info": "Int8" }, { - "ordinal": 10, + "ordinal": 11, "name": "hash", "type_info": "Bytea" }, { - "ordinal": 11, + "ordinal": 12, "name": "protocol_version!", "type_info": "Int4" }, { - "ordinal": 12, + "ordinal": 13, "name": "fee_account_address!", "type_info": "Bytea" } @@ -85,11 +90,12 @@ true, true, true, + true, false, false, true, false ] }, - "hash": "778f92b1ac91e1ae279f588053d75a9ac877fdd28bda99661e423405e695223d" + "hash": "2060d7de5c06f2fd24b43de6eeca927c5f5b88725987e82cf3ec5d499c5addbb" } diff --git a/core/lib/dal/.sqlx/query-38dea171e4c49f54bf1db5ac9bfb3be9cf3928755be5f5fcfcdc086e73fb15e2.json b/core/lib/dal/.sqlx/query-2cfcd25a9e0a51c509baafcf8611e9afe0ead3d435d166a3116551502a730731.json similarity index 78% rename from core/lib/dal/.sqlx/query-38dea171e4c49f54bf1db5ac9bfb3be9cf3928755be5f5fcfcdc086e73fb15e2.json rename to core/lib/dal/.sqlx/query-2cfcd25a9e0a51c509baafcf8611e9afe0ead3d435d166a3116551502a730731.json index 7ac6785d8e64..5d5785ddc36f 100644 --- a/core/lib/dal/.sqlx/query-38dea171e4c49f54bf1db5ac9bfb3be9cf3928755be5f5fcfcdc086e73fb15e2.json +++ b/core/lib/dal/.sqlx/query-2cfcd25a9e0a51c509baafcf8611e9afe0ead3d435d166a3116551502a730731.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n eth_prove_tx_id IS NOT NULL\n AND eth_execute_tx_id IS NULL\n ORDER BY\n number\n LIMIT\n $1\n ", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_simulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n eth_prove_tx_id IS NOT NULL\n AND eth_execute_tx_id IS NULL\n ORDER BY\n number\n LIMIT\n $1\n ", "describe": { "columns": [ { @@ -90,46 +90,51 @@ }, { "ordinal": 17, - "name": "aux_data_hash", + "name": "evm_simulator_code_hash", "type_info": "Bytea" }, { "ordinal": 18, - "name": "pass_through_data_hash", + "name": "aux_data_hash", "type_info": "Bytea" }, { "ordinal": 19, - "name": "meta_parameters_hash", + "name": "pass_through_data_hash", "type_info": "Bytea" }, { "ordinal": 20, + "name": "meta_parameters_hash", + "type_info": "Bytea" + }, + { + "ordinal": 21, "name": "protocol_version", "type_info": "Int4" }, { - "ordinal": 21, + "ordinal": 22, "name": "compressed_state_diffs", "type_info": "Bytea" }, { - "ordinal": 22, + "ordinal": 23, "name": "system_logs", "type_info": "ByteaArray" }, { - "ordinal": 23, + "ordinal": 24, "name": "events_queue_commitment", "type_info": "Bytea" }, { - "ordinal": 24, + "ordinal": 25, "name": "bootloader_initial_content_commitment", "type_info": "Bytea" }, { - "ordinal": 25, + "ordinal": 26, "name": "pubdata_input", "type_info": "Bytea" } @@ -162,11 +167,12 @@ true, true, true, + true, false, true, true, true ] }, - "hash": "38dea171e4c49f54bf1db5ac9bfb3be9cf3928755be5f5fcfcdc086e73fb15e2" + "hash": "2cfcd25a9e0a51c509baafcf8611e9afe0ead3d435d166a3116551502a730731" } diff --git a/core/lib/dal/.sqlx/query-2486f8404e8cfcb9c178acd6dccae32e8812becbe5ce85e63694385f015f2cfe.json b/core/lib/dal/.sqlx/query-2f0d3e88282af17374c549e650756d3bc76cabe8b0c616ed13dd139327c4cc34.json similarity index 80% rename from core/lib/dal/.sqlx/query-2486f8404e8cfcb9c178acd6dccae32e8812becbe5ce85e63694385f015f2cfe.json rename to core/lib/dal/.sqlx/query-2f0d3e88282af17374c549e650756d3bc76cabe8b0c616ed13dd139327c4cc34.json index f28e3d044ccc..43d5f009cf0b 100644 --- a/core/lib/dal/.sqlx/query-2486f8404e8cfcb9c178acd6dccae32e8812becbe5ce85e63694385f015f2cfe.json +++ b/core/lib/dal/.sqlx/query-2f0d3e88282af17374c549e650756d3bc76cabe8b0c616ed13dd139327c4cc34.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n number BETWEEN $1 AND $2\n ORDER BY\n number\n LIMIT\n $3\n ", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_simulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n number BETWEEN $1 AND $2\n ORDER BY\n number\n LIMIT\n $3\n ", "describe": { "columns": [ { @@ -90,46 +90,51 @@ }, { "ordinal": 17, - "name": "aux_data_hash", + "name": "evm_simulator_code_hash", "type_info": "Bytea" }, { "ordinal": 18, - "name": "pass_through_data_hash", + "name": "aux_data_hash", "type_info": "Bytea" }, { "ordinal": 19, - "name": "meta_parameters_hash", + "name": "pass_through_data_hash", "type_info": "Bytea" }, { "ordinal": 20, + "name": "meta_parameters_hash", + "type_info": "Bytea" + }, + { + "ordinal": 21, "name": "protocol_version", "type_info": "Int4" }, { - "ordinal": 21, + "ordinal": 22, "name": "compressed_state_diffs", "type_info": "Bytea" }, { - "ordinal": 22, + "ordinal": 23, "name": "system_logs", "type_info": "ByteaArray" }, { - "ordinal": 23, + "ordinal": 24, "name": "events_queue_commitment", "type_info": "Bytea" }, { - "ordinal": 24, + "ordinal": 25, "name": "bootloader_initial_content_commitment", "type_info": "Bytea" }, { - "ordinal": 25, + "ordinal": 26, "name": "pubdata_input", "type_info": "Bytea" } @@ -164,11 +169,12 @@ true, true, true, + true, false, true, true, true ] }, - "hash": "2486f8404e8cfcb9c178acd6dccae32e8812becbe5ce85e63694385f015f2cfe" + "hash": "2f0d3e88282af17374c549e650756d3bc76cabe8b0c616ed13dd139327c4cc34" } diff --git a/core/lib/dal/.sqlx/query-454e16ddb5e85285d0c4b9013bcce5d464ecc55c80b54bc16040226df7e297bd.json b/core/lib/dal/.sqlx/query-42ae258b55532b0f814af4e5d39e87dde392c0efa13ecd42becfd0e5db79f059.json similarity index 82% rename from core/lib/dal/.sqlx/query-454e16ddb5e85285d0c4b9013bcce5d464ecc55c80b54bc16040226df7e297bd.json rename to core/lib/dal/.sqlx/query-42ae258b55532b0f814af4e5d39e87dde392c0efa13ecd42becfd0e5db79f059.json index 4a73fde57e29..cff8a75aeb98 100644 --- a/core/lib/dal/.sqlx/query-454e16ddb5e85285d0c4b9013bcce5d464ecc55c80b54bc16040226df7e297bd.json +++ b/core/lib/dal/.sqlx/query-42ae258b55532b0f814af4e5d39e87dde392c0efa13ecd42becfd0e5db79f059.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n l1_tx_count,\n l2_tx_count,\n timestamp,\n l2_to_l1_messages,\n bloom,\n priority_ops_onchain_data,\n used_contract_hashes,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n system_logs,\n pubdata_input\n FROM\n l1_batches\n WHERE\n number = $1\n ", + "query": "\n SELECT\n number,\n l1_tx_count,\n l2_tx_count,\n timestamp,\n l2_to_l1_messages,\n bloom,\n priority_ops_onchain_data,\n used_contract_hashes,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_simulator_code_hash,\n protocol_version,\n system_logs,\n pubdata_input\n FROM\n l1_batches\n WHERE\n number = $1\n ", "describe": { "columns": [ { @@ -55,16 +55,21 @@ }, { "ordinal": 10, + "name": "evm_simulator_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 11, "name": "protocol_version", "type_info": "Int4" }, { - "ordinal": 11, + "ordinal": 12, "name": "system_logs", "type_info": "ByteaArray" }, { - "ordinal": 12, + "ordinal": 13, "name": "pubdata_input", "type_info": "Bytea" } @@ -86,9 +91,10 @@ true, true, true, + true, false, true ] }, - "hash": "454e16ddb5e85285d0c4b9013bcce5d464ecc55c80b54bc16040226df7e297bd" + "hash": "42ae258b55532b0f814af4e5d39e87dde392c0efa13ecd42becfd0e5db79f059" } diff --git a/core/lib/dal/.sqlx/query-9f2c06e6b14434ac4f3b556dc97994cc05ebeb4e5aeeaee50b7c4d8baf58ca44.json b/core/lib/dal/.sqlx/query-49f300dde6f37c283bd99596c290884ca664431997692e4af804ecf5ff8b819a.json similarity index 50% rename from core/lib/dal/.sqlx/query-9f2c06e6b14434ac4f3b556dc97994cc05ebeb4e5aeeaee50b7c4d8baf58ca44.json rename to core/lib/dal/.sqlx/query-49f300dde6f37c283bd99596c290884ca664431997692e4af804ecf5ff8b819a.json index 54f0d27bab26..e5b14af2fedb 100644 --- a/core/lib/dal/.sqlx/query-9f2c06e6b14434ac4f3b556dc97994cc05ebeb4e5aeeaee50b7c4d8baf58ca44.json +++ b/core/lib/dal/.sqlx/query-49f300dde6f37c283bd99596c290884ca664431997692e4af804ecf5ff8b819a.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n l1_batches (\n number,\n l1_tx_count,\n l2_tx_count,\n timestamp,\n l2_to_l1_messages,\n bloom,\n priority_ops_onchain_data,\n predicted_commit_gas_cost,\n predicted_prove_gas_cost,\n predicted_execute_gas_cost,\n initial_bootloader_heap_content,\n used_contract_hashes,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n system_logs,\n storage_refunds,\n pubdata_costs,\n pubdata_input,\n predicted_circuits_by_type,\n created_at,\n updated_at\n )\n VALUES\n (\n $1,\n $2,\n $3,\n $4,\n $5,\n $6,\n $7,\n $8,\n $9,\n $10,\n $11,\n $12,\n $13,\n $14,\n $15,\n $16,\n $17,\n $18,\n $19,\n $20,\n NOW(),\n NOW()\n )\n ", + "query": "\n INSERT INTO\n l1_batches (\n number,\n l1_tx_count,\n l2_tx_count,\n timestamp,\n l2_to_l1_messages,\n bloom,\n priority_ops_onchain_data,\n predicted_commit_gas_cost,\n predicted_prove_gas_cost,\n predicted_execute_gas_cost,\n initial_bootloader_heap_content,\n used_contract_hashes,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_simulator_code_hash,\n protocol_version,\n system_logs,\n storage_refunds,\n pubdata_costs,\n pubdata_input,\n predicted_circuits_by_type,\n created_at,\n updated_at\n )\n VALUES\n (\n $1,\n $2,\n $3,\n $4,\n $5,\n $6,\n $7,\n $8,\n $9,\n $10,\n $11,\n $12,\n $13,\n $14,\n $15,\n $16,\n $17,\n $18,\n $19,\n $20,\n $21,\n NOW(),\n NOW()\n )\n ", "describe": { "columns": [], "parameters": { @@ -19,6 +19,7 @@ "Jsonb", "Bytea", "Bytea", + "Bytea", "Int4", "ByteaArray", "Int8Array", @@ -29,5 +30,5 @@ }, "nullable": [] }, - "hash": "9f2c06e6b14434ac4f3b556dc97994cc05ebeb4e5aeeaee50b7c4d8baf58ca44" + "hash": "49f300dde6f37c283bd99596c290884ca664431997692e4af804ecf5ff8b819a" } diff --git a/core/lib/dal/.sqlx/query-659f616d3af4a79f898e84f890e06de9633d1086da972a467d89831e7a07c67e.json b/core/lib/dal/.sqlx/query-535ca6ef0f2b47fe36a6a2c59861dfa954eaf93e6ab5b64bdaa8ef9984ccdf6b.json similarity index 73% rename from core/lib/dal/.sqlx/query-659f616d3af4a79f898e84f890e06de9633d1086da972a467d89831e7a07c67e.json rename to core/lib/dal/.sqlx/query-535ca6ef0f2b47fe36a6a2c59861dfa954eaf93e6ab5b64bdaa8ef9984ccdf6b.json index 9116a25c1673..6678ad05301f 100644 --- a/core/lib/dal/.sqlx/query-659f616d3af4a79f898e84f890e06de9633d1086da972a467d89831e7a07c67e.json +++ b/core/lib/dal/.sqlx/query-535ca6ef0f2b47fe36a6a2c59861dfa954eaf93e6ab5b64bdaa8ef9984ccdf6b.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n system_logs,\n compressed_state_diffs,\n protocol_version,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n (\n SELECT\n l1_batches.*,\n ROW_NUMBER() OVER (\n ORDER BY\n number ASC\n ) AS ROW_NUMBER\n FROM\n l1_batches\n WHERE\n eth_commit_tx_id IS NOT NULL\n AND l1_batches.skip_proof = TRUE\n AND l1_batches.number > $1\n ORDER BY\n number\n LIMIT\n $2\n ) inn\n LEFT JOIN commitments ON commitments.l1_batch_number = inn.number\n WHERE\n number - ROW_NUMBER = $1\n ", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_simulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n system_logs,\n compressed_state_diffs,\n protocol_version,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n (\n SELECT\n l1_batches.*,\n ROW_NUMBER() OVER (\n ORDER BY\n number ASC\n ) AS ROW_NUMBER\n FROM\n l1_batches\n WHERE\n eth_commit_tx_id IS NOT NULL\n AND l1_batches.skip_proof = TRUE\n AND l1_batches.number > $1\n ORDER BY\n number\n LIMIT\n $2\n ) inn\n LEFT JOIN commitments ON commitments.l1_batch_number = inn.number\n WHERE\n number - ROW_NUMBER = $1\n ", "describe": { "columns": [ { @@ -90,46 +90,51 @@ }, { "ordinal": 17, - "name": "aux_data_hash", + "name": "evm_simulator_code_hash", "type_info": "Bytea" }, { "ordinal": 18, - "name": "pass_through_data_hash", + "name": "aux_data_hash", "type_info": "Bytea" }, { "ordinal": 19, - "name": "meta_parameters_hash", + "name": "pass_through_data_hash", "type_info": "Bytea" }, { "ordinal": 20, + "name": "meta_parameters_hash", + "type_info": "Bytea" + }, + { + "ordinal": 21, "name": "system_logs", "type_info": "ByteaArray" }, { - "ordinal": 21, + "ordinal": 22, "name": "compressed_state_diffs", "type_info": "Bytea" }, { - "ordinal": 22, + "ordinal": 23, "name": "protocol_version", "type_info": "Int4" }, { - "ordinal": 23, + "ordinal": 24, "name": "events_queue_commitment", "type_info": "Bytea" }, { - "ordinal": 24, + "ordinal": 25, "name": "bootloader_initial_content_commitment", "type_info": "Bytea" }, { - "ordinal": 25, + "ordinal": 26, "name": "pubdata_input", "type_info": "Bytea" } @@ -161,6 +166,7 @@ true, true, true, + true, false, true, true, @@ -169,5 +175,5 @@ true ] }, - "hash": "659f616d3af4a79f898e84f890e06de9633d1086da972a467d89831e7a07c67e" + "hash": "535ca6ef0f2b47fe36a6a2c59861dfa954eaf93e6ab5b64bdaa8ef9984ccdf6b" } diff --git a/core/lib/dal/.sqlx/query-5556ebdb040428b42c04ea9121b3c2a3d0a09c5ee88bdd671462904d4d27a355.json b/core/lib/dal/.sqlx/query-5b623ec03908aef2f9f4de80ccd108525bf32965ca06e847082c0fc3c54a1dde.json similarity index 71% rename from core/lib/dal/.sqlx/query-5556ebdb040428b42c04ea9121b3c2a3d0a09c5ee88bdd671462904d4d27a355.json rename to core/lib/dal/.sqlx/query-5b623ec03908aef2f9f4de80ccd108525bf32965ca06e847082c0fc3c54a1dde.json index 5e9051587bb9..56a31f74b835 100644 --- a/core/lib/dal/.sqlx/query-5556ebdb040428b42c04ea9121b3c2a3d0a09c5ee88bdd671462904d4d27a355.json +++ b/core/lib/dal/.sqlx/query-5b623ec03908aef2f9f4de80ccd108525bf32965ca06e847082c0fc3c54a1dde.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n id AS \"minor!\",\n timestamp,\n bootloader_code_hash,\n default_account_code_hash,\n upgrade_tx_hash\n FROM\n protocol_versions\n WHERE\n id = $1\n ", + "query": "\n SELECT\n id AS \"minor!\",\n timestamp,\n bootloader_code_hash,\n default_account_code_hash,\n evm_simulator_code_hash,\n upgrade_tx_hash\n FROM\n protocol_versions\n WHERE\n id = $1\n ", "describe": { "columns": [ { @@ -25,6 +25,11 @@ }, { "ordinal": 4, + "name": "evm_simulator_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 5, "name": "upgrade_tx_hash", "type_info": "Bytea" } @@ -39,8 +44,9 @@ false, false, false, + true, true ] }, - "hash": "5556ebdb040428b42c04ea9121b3c2a3d0a09c5ee88bdd671462904d4d27a355" + "hash": "5b623ec03908aef2f9f4de80ccd108525bf32965ca06e847082c0fc3c54a1dde" } diff --git a/core/lib/dal/.sqlx/query-63f95c6cdcfd933e2cf8f62c0d408f2dce89f7b700896fcc0f242e0e15ba058e.json b/core/lib/dal/.sqlx/query-7f5993b00c1270d80e6081c3304fb7ce70b4aaa5c810c79d5bf854fe30c28fd4.json similarity index 69% rename from core/lib/dal/.sqlx/query-63f95c6cdcfd933e2cf8f62c0d408f2dce89f7b700896fcc0f242e0e15ba058e.json rename to core/lib/dal/.sqlx/query-7f5993b00c1270d80e6081c3304fb7ce70b4aaa5c810c79d5bf854fe30c28fd4.json index cb68e7622524..a2e9f4500961 100644 --- a/core/lib/dal/.sqlx/query-63f95c6cdcfd933e2cf8f62c0d408f2dce89f7b700896fcc0f242e0e15ba058e.json +++ b/core/lib/dal/.sqlx/query-7f5993b00c1270d80e6081c3304fb7ce70b4aaa5c810c79d5bf854fe30c28fd4.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n l1_batches.timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n LEFT JOIN data_availability ON data_availability.l1_batch_number = l1_batches.number\n JOIN protocol_versions ON protocol_versions.id = l1_batches.protocol_version\n WHERE\n eth_commit_tx_id IS NULL\n AND number != 0\n AND protocol_versions.bootloader_code_hash = $1\n AND protocol_versions.default_account_code_hash = $2\n AND commitment IS NOT NULL\n AND (\n protocol_versions.id = $3\n OR protocol_versions.upgrade_tx_hash IS NULL\n )\n AND events_queue_commitment IS NOT NULL\n AND bootloader_initial_content_commitment IS NOT NULL\n AND (\n data_availability.inclusion_data IS NOT NULL\n OR $4 IS FALSE\n )\n ORDER BY\n number\n LIMIT\n $5\n ", + "query": "\n SELECT\n number,\n l1_batches.timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash,\n l1_batches.evm_simulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n LEFT JOIN data_availability ON data_availability.l1_batch_number = l1_batches.number\n JOIN protocol_versions ON protocol_versions.id = l1_batches.protocol_version\n WHERE\n eth_commit_tx_id IS NULL\n AND number != 0\n AND protocol_versions.bootloader_code_hash = $1\n AND protocol_versions.default_account_code_hash = $2\n AND commitment IS NOT NULL\n AND (\n protocol_versions.id = $3\n OR protocol_versions.upgrade_tx_hash IS NULL\n )\n AND events_queue_commitment IS NOT NULL\n AND bootloader_initial_content_commitment IS NOT NULL\n AND (\n data_availability.inclusion_data IS NOT NULL\n OR $4 IS FALSE\n )\n ORDER BY\n number\n LIMIT\n $5\n ", "describe": { "columns": [ { @@ -90,46 +90,51 @@ }, { "ordinal": 17, - "name": "aux_data_hash", + "name": "evm_simulator_code_hash", "type_info": "Bytea" }, { "ordinal": 18, - "name": "pass_through_data_hash", + "name": "aux_data_hash", "type_info": "Bytea" }, { "ordinal": 19, - "name": "meta_parameters_hash", + "name": "pass_through_data_hash", "type_info": "Bytea" }, { "ordinal": 20, + "name": "meta_parameters_hash", + "type_info": "Bytea" + }, + { + "ordinal": 21, "name": "protocol_version", "type_info": "Int4" }, { - "ordinal": 21, + "ordinal": 22, "name": "compressed_state_diffs", "type_info": "Bytea" }, { - "ordinal": 22, + "ordinal": 23, "name": "system_logs", "type_info": "ByteaArray" }, { - "ordinal": 23, + "ordinal": 24, "name": "events_queue_commitment", "type_info": "Bytea" }, { - "ordinal": 24, + "ordinal": 25, "name": "bootloader_initial_content_commitment", "type_info": "Bytea" }, { - "ordinal": 25, + "ordinal": 26, "name": "pubdata_input", "type_info": "Bytea" } @@ -166,11 +171,12 @@ true, true, true, + true, false, true, true, true ] }, - "hash": "63f95c6cdcfd933e2cf8f62c0d408f2dce89f7b700896fcc0f242e0e15ba058e" + "hash": "7f5993b00c1270d80e6081c3304fb7ce70b4aaa5c810c79d5bf854fe30c28fd4" } diff --git a/core/lib/dal/.sqlx/query-de255be5d2e5ef215428e9a886e7c9dc036873c60b8b916ce8c446e310447b66.json b/core/lib/dal/.sqlx/query-92d3a7d8c32c4575d6a225f0440b0ff9894b1de204599f4a4fd39cfde1020a3e.json similarity index 80% rename from core/lib/dal/.sqlx/query-de255be5d2e5ef215428e9a886e7c9dc036873c60b8b916ce8c446e310447b66.json rename to core/lib/dal/.sqlx/query-92d3a7d8c32c4575d6a225f0440b0ff9894b1de204599f4a4fd39cfde1020a3e.json index 8a492376557b..4a0c6ce38596 100644 --- a/core/lib/dal/.sqlx/query-de255be5d2e5ef215428e9a886e7c9dc036873c60b8b916ce8c446e310447b66.json +++ b/core/lib/dal/.sqlx/query-92d3a7d8c32c4575d6a225f0440b0ff9894b1de204599f4a4fd39cfde1020a3e.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n number = 0\n OR eth_commit_tx_id IS NOT NULL\n AND commitment IS NOT NULL\n ORDER BY\n number DESC\n LIMIT\n 1\n ", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_simulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n number = 0\n OR eth_commit_tx_id IS NOT NULL\n AND commitment IS NOT NULL\n ORDER BY\n number DESC\n LIMIT\n 1\n ", "describe": { "columns": [ { @@ -90,46 +90,51 @@ }, { "ordinal": 17, - "name": "aux_data_hash", + "name": "evm_simulator_code_hash", "type_info": "Bytea" }, { "ordinal": 18, - "name": "pass_through_data_hash", + "name": "aux_data_hash", "type_info": "Bytea" }, { "ordinal": 19, - "name": "meta_parameters_hash", + "name": "pass_through_data_hash", "type_info": "Bytea" }, { "ordinal": 20, + "name": "meta_parameters_hash", + "type_info": "Bytea" + }, + { + "ordinal": 21, "name": "protocol_version", "type_info": "Int4" }, { - "ordinal": 21, + "ordinal": 22, "name": "compressed_state_diffs", "type_info": "Bytea" }, { - "ordinal": 22, + "ordinal": 23, "name": "system_logs", "type_info": "ByteaArray" }, { - "ordinal": 23, + "ordinal": 24, "name": "events_queue_commitment", "type_info": "Bytea" }, { - "ordinal": 24, + "ordinal": 25, "name": "bootloader_initial_content_commitment", "type_info": "Bytea" }, { - "ordinal": 25, + "ordinal": 26, "name": "pubdata_input", "type_info": "Bytea" } @@ -160,11 +165,12 @@ true, true, true, + true, false, true, true, true ] }, - "hash": "de255be5d2e5ef215428e9a886e7c9dc036873c60b8b916ce8c446e310447b66" + "hash": "92d3a7d8c32c4575d6a225f0440b0ff9894b1de204599f4a4fd39cfde1020a3e" } diff --git a/core/lib/dal/.sqlx/query-52bb6de515e1edf4dcf34a31600edb31cfd855014dfca5041833b9d5d9f7a55e.json b/core/lib/dal/.sqlx/query-acf497b952de2d8f83cf2b96f2eb686d545c780b37430bdcf70fc55e80588b6b.json similarity index 80% rename from core/lib/dal/.sqlx/query-52bb6de515e1edf4dcf34a31600edb31cfd855014dfca5041833b9d5d9f7a55e.json rename to core/lib/dal/.sqlx/query-acf497b952de2d8f83cf2b96f2eb686d545c780b37430bdcf70fc55e80588b6b.json index b872e2ce6297..bfd2202608f4 100644 --- a/core/lib/dal/.sqlx/query-52bb6de515e1edf4dcf34a31600edb31cfd855014dfca5041833b9d5d9f7a55e.json +++ b/core/lib/dal/.sqlx/query-acf497b952de2d8f83cf2b96f2eb686d545c780b37430bdcf70fc55e80588b6b.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n system_logs,\n compressed_state_diffs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n number = $1\n ", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_simulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n eth_commit_tx_id IS NOT NULL\n AND eth_prove_tx_id IS NULL\n ORDER BY\n number\n LIMIT\n $1\n ", "describe": { "columns": [ { @@ -90,28 +90,28 @@ }, { "ordinal": 17, - "name": "aux_data_hash", + "name": "evm_simulator_code_hash", "type_info": "Bytea" }, { "ordinal": 18, - "name": "pass_through_data_hash", + "name": "aux_data_hash", "type_info": "Bytea" }, { "ordinal": 19, - "name": "meta_parameters_hash", + "name": "pass_through_data_hash", "type_info": "Bytea" }, { "ordinal": 20, - "name": "protocol_version", - "type_info": "Int4" + "name": "meta_parameters_hash", + "type_info": "Bytea" }, { "ordinal": 21, - "name": "system_logs", - "type_info": "ByteaArray" + "name": "protocol_version", + "type_info": "Int4" }, { "ordinal": 22, @@ -120,16 +120,21 @@ }, { "ordinal": 23, + "name": "system_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 24, "name": "events_queue_commitment", "type_info": "Bytea" }, { - "ordinal": 24, + "ordinal": 25, "name": "bootloader_initial_content_commitment", "type_info": "Bytea" }, { - "ordinal": 25, + "ordinal": 26, "name": "pubdata_input", "type_info": "Bytea" } @@ -161,12 +166,13 @@ true, true, true, - false, true, true, + false, + true, true, true ] }, - "hash": "52bb6de515e1edf4dcf34a31600edb31cfd855014dfca5041833b9d5d9f7a55e" + "hash": "acf497b952de2d8f83cf2b96f2eb686d545c780b37430bdcf70fc55e80588b6b" } diff --git a/core/lib/dal/.sqlx/query-f35d539db19ed626a2e0b537468bcef1260bd43f7eee2710dfbdeed1a0228318.json b/core/lib/dal/.sqlx/query-c9b576c200570410bedfa54ab36a0f877299ff2e7bfdb5de94a07e5556c20144.json similarity index 81% rename from core/lib/dal/.sqlx/query-f35d539db19ed626a2e0b537468bcef1260bd43f7eee2710dfbdeed1a0228318.json rename to core/lib/dal/.sqlx/query-c9b576c200570410bedfa54ab36a0f877299ff2e7bfdb5de94a07e5556c20144.json index 8981f7e8a080..43a85969d439 100644 --- a/core/lib/dal/.sqlx/query-f35d539db19ed626a2e0b537468bcef1260bd43f7eee2710dfbdeed1a0228318.json +++ b/core/lib/dal/.sqlx/query-c9b576c200570410bedfa54ab36a0f877299ff2e7bfdb5de94a07e5556c20144.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n timestamp,\n hash,\n l1_tx_count,\n l2_tx_count,\n fee_account_address AS \"fee_account_address!\",\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n gas_per_pubdata_limit,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n virtual_blocks,\n fair_pubdata_price,\n gas_limit\n FROM\n miniblocks\n ORDER BY\n number DESC\n LIMIT\n 1\n ", + "query": "\n SELECT\n number,\n timestamp,\n hash,\n l1_tx_count,\n l2_tx_count,\n fee_account_address AS \"fee_account_address!\",\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n gas_per_pubdata_limit,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_simulator_code_hash,\n protocol_version,\n virtual_blocks,\n fair_pubdata_price,\n gas_limit\n FROM\n miniblocks\n ORDER BY\n number DESC\n LIMIT\n 1\n ", "describe": { "columns": [ { @@ -65,21 +65,26 @@ }, { "ordinal": 12, + "name": "evm_simulator_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 13, "name": "protocol_version", "type_info": "Int4" }, { - "ordinal": 13, + "ordinal": 14, "name": "virtual_blocks", "type_info": "Int8" }, { - "ordinal": 14, + "ordinal": 15, "name": "fair_pubdata_price", "type_info": "Int8" }, { - "ordinal": 15, + "ordinal": 16, "name": "gas_limit", "type_info": "Int8" } @@ -101,10 +106,11 @@ true, true, true, + true, false, true, true ] }, - "hash": "f35d539db19ed626a2e0b537468bcef1260bd43f7eee2710dfbdeed1a0228318" + "hash": "c9b576c200570410bedfa54ab36a0f877299ff2e7bfdb5de94a07e5556c20144" } diff --git a/core/lib/dal/.sqlx/query-1074d0a2e4a4afb9a92f3822e133db7a71aca15698bafba051a8d9a91a4dbc76.json b/core/lib/dal/.sqlx/query-d7ee8998bdc54b0a68dadb79aae3a68e5e5cf16897de4b6e3211d5e1c07e9294.json similarity index 75% rename from core/lib/dal/.sqlx/query-1074d0a2e4a4afb9a92f3822e133db7a71aca15698bafba051a8d9a91a4dbc76.json rename to core/lib/dal/.sqlx/query-d7ee8998bdc54b0a68dadb79aae3a68e5e5cf16897de4b6e3211d5e1c07e9294.json index 13e4cdb9431d..b87cf7e99100 100644 --- a/core/lib/dal/.sqlx/query-1074d0a2e4a4afb9a92f3822e133db7a71aca15698bafba051a8d9a91a4dbc76.json +++ b/core/lib/dal/.sqlx/query-d7ee8998bdc54b0a68dadb79aae3a68e5e5cf16897de4b6e3211d5e1c07e9294.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n WITH\n mb AS (\n SELECT\n l1_gas_price,\n l2_fair_gas_price,\n fair_pubdata_price\n FROM\n miniblocks\n WHERE\n l1_batch_number = $1\n LIMIT\n 1\n )\n SELECT\n l1_batches.number,\n l1_batches.timestamp,\n l1_batches.l1_tx_count,\n l1_batches.l2_tx_count,\n l1_batches.hash AS \"root_hash?\",\n commit_tx.tx_hash AS \"commit_tx_hash?\",\n commit_tx.confirmed_at AS \"committed_at?\",\n prove_tx.tx_hash AS \"prove_tx_hash?\",\n prove_tx.confirmed_at AS \"proven_at?\",\n execute_tx.tx_hash AS \"execute_tx_hash?\",\n execute_tx.confirmed_at AS \"executed_at?\",\n mb.l1_gas_price,\n mb.l2_fair_gas_price,\n mb.fair_pubdata_price,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash\n FROM\n l1_batches\n INNER JOIN mb ON TRUE\n LEFT JOIN eth_txs_history AS commit_tx ON (\n l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id\n AND commit_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS prove_tx ON (\n l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id\n AND prove_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS execute_tx ON (\n l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id\n AND execute_tx.confirmed_at IS NOT NULL\n )\n WHERE\n l1_batches.number = $1\n ", + "query": "\n WITH\n mb AS (\n SELECT\n l1_gas_price,\n l2_fair_gas_price,\n fair_pubdata_price\n FROM\n miniblocks\n WHERE\n l1_batch_number = $1\n LIMIT\n 1\n )\n SELECT\n l1_batches.number,\n l1_batches.timestamp,\n l1_batches.l1_tx_count,\n l1_batches.l2_tx_count,\n l1_batches.hash AS \"root_hash?\",\n commit_tx.tx_hash AS \"commit_tx_hash?\",\n commit_tx.confirmed_at AS \"committed_at?\",\n prove_tx.tx_hash AS \"prove_tx_hash?\",\n prove_tx.confirmed_at AS \"proven_at?\",\n execute_tx.tx_hash AS \"execute_tx_hash?\",\n execute_tx.confirmed_at AS \"executed_at?\",\n mb.l1_gas_price,\n mb.l2_fair_gas_price,\n mb.fair_pubdata_price,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash,\n l1_batches.evm_simulator_code_hash\n FROM\n l1_batches\n INNER JOIN mb ON TRUE\n LEFT JOIN eth_txs_history AS commit_tx ON (\n l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id\n AND commit_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS prove_tx ON (\n l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id\n AND prove_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS execute_tx ON (\n l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id\n AND execute_tx.confirmed_at IS NOT NULL\n )\n WHERE\n l1_batches.number = $1\n ", "describe": { "columns": [ { @@ -82,6 +82,11 @@ "ordinal": 15, "name": "default_aa_code_hash", "type_info": "Bytea" + }, + { + "ordinal": 16, + "name": "evm_simulator_code_hash", + "type_info": "Bytea" } ], "parameters": { @@ -105,8 +110,9 @@ false, true, true, + true, true ] }, - "hash": "1074d0a2e4a4afb9a92f3822e133db7a71aca15698bafba051a8d9a91a4dbc76" + "hash": "d7ee8998bdc54b0a68dadb79aae3a68e5e5cf16897de4b6e3211d5e1c07e9294" } diff --git a/core/lib/dal/.sqlx/query-5d493cbce749cc5b56d4069423597b16599abaf51df0f19effe1a536376cf6a6.json b/core/lib/dal/.sqlx/query-e4736015a313f552d6763b9a82c3412e502df24849331486c604fb0d36d99554.json similarity index 52% rename from core/lib/dal/.sqlx/query-5d493cbce749cc5b56d4069423597b16599abaf51df0f19effe1a536376cf6a6.json rename to core/lib/dal/.sqlx/query-e4736015a313f552d6763b9a82c3412e502df24849331486c604fb0d36d99554.json index eba36994fb34..57e92a2dfa3f 100644 --- a/core/lib/dal/.sqlx/query-5d493cbce749cc5b56d4069423597b16599abaf51df0f19effe1a536376cf6a6.json +++ b/core/lib/dal/.sqlx/query-e4736015a313f552d6763b9a82c3412e502df24849331486c604fb0d36d99554.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n bootloader_code_hash,\n default_account_code_hash\n FROM\n protocol_versions\n WHERE\n id = $1\n ", + "query": "\n SELECT\n bootloader_code_hash,\n default_account_code_hash,\n evm_simulator_code_hash\n FROM\n protocol_versions\n WHERE\n id = $1\n ", "describe": { "columns": [ { @@ -12,6 +12,11 @@ "ordinal": 1, "name": "default_account_code_hash", "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "evm_simulator_code_hash", + "type_info": "Bytea" } ], "parameters": { @@ -21,8 +26,9 @@ }, "nullable": [ false, - false + false, + true ] }, - "hash": "5d493cbce749cc5b56d4069423597b16599abaf51df0f19effe1a536376cf6a6" + "hash": "e4736015a313f552d6763b9a82c3412e502df24849331486c604fb0d36d99554" } diff --git a/core/lib/dal/.sqlx/query-b7cd7c40282c2ca2287eef93ee79c69a9e494bf1f873291b4ae7bf68b7e3c549.json b/core/lib/dal/.sqlx/query-ebb6c005f99d144963d487841d6e1bc51d4f949f0941156021a4844ed8c959ca.json similarity index 74% rename from core/lib/dal/.sqlx/query-b7cd7c40282c2ca2287eef93ee79c69a9e494bf1f873291b4ae7bf68b7e3c549.json rename to core/lib/dal/.sqlx/query-ebb6c005f99d144963d487841d6e1bc51d4f949f0941156021a4844ed8c959ca.json index ed4744206a48..a9f43d749df1 100644 --- a/core/lib/dal/.sqlx/query-b7cd7c40282c2ca2287eef93ee79c69a9e494bf1f873291b4ae7bf68b7e3c549.json +++ b/core/lib/dal/.sqlx/query-ebb6c005f99d144963d487841d6e1bc51d4f949f0941156021a4844ed8c959ca.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n l1_batches.timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n JOIN protocol_versions ON protocol_versions.id = l1_batches.protocol_version\n WHERE\n eth_commit_tx_id IS NULL\n AND number != 0\n AND protocol_versions.bootloader_code_hash = $1\n AND protocol_versions.default_account_code_hash = $2\n AND commitment IS NOT NULL\n AND (\n protocol_versions.id = $3\n OR protocol_versions.upgrade_tx_hash IS NULL\n )\n ORDER BY\n number\n LIMIT\n $4\n ", + "query": "\n SELECT\n number,\n l1_batches.timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash,\n l1_batches.evm_simulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n JOIN protocol_versions ON protocol_versions.id = l1_batches.protocol_version\n WHERE\n eth_commit_tx_id IS NULL\n AND number != 0\n AND protocol_versions.bootloader_code_hash = $1\n AND protocol_versions.default_account_code_hash = $2\n AND commitment IS NOT NULL\n AND (\n protocol_versions.id = $3\n OR protocol_versions.upgrade_tx_hash IS NULL\n )\n ORDER BY\n number\n LIMIT\n $4\n ", "describe": { "columns": [ { @@ -90,46 +90,51 @@ }, { "ordinal": 17, - "name": "aux_data_hash", + "name": "evm_simulator_code_hash", "type_info": "Bytea" }, { "ordinal": 18, - "name": "pass_through_data_hash", + "name": "aux_data_hash", "type_info": "Bytea" }, { "ordinal": 19, - "name": "meta_parameters_hash", + "name": "pass_through_data_hash", "type_info": "Bytea" }, { "ordinal": 20, + "name": "meta_parameters_hash", + "type_info": "Bytea" + }, + { + "ordinal": 21, "name": "protocol_version", "type_info": "Int4" }, { - "ordinal": 21, + "ordinal": 22, "name": "compressed_state_diffs", "type_info": "Bytea" }, { - "ordinal": 22, + "ordinal": 23, "name": "system_logs", "type_info": "ByteaArray" }, { - "ordinal": 23, + "ordinal": 24, "name": "events_queue_commitment", "type_info": "Bytea" }, { - "ordinal": 24, + "ordinal": 25, "name": "bootloader_initial_content_commitment", "type_info": "Bytea" }, { - "ordinal": 25, + "ordinal": 26, "name": "pubdata_input", "type_info": "Bytea" } @@ -165,11 +170,12 @@ true, true, true, + true, false, true, true, true ] }, - "hash": "b7cd7c40282c2ca2287eef93ee79c69a9e494bf1f873291b4ae7bf68b7e3c549" + "hash": "ebb6c005f99d144963d487841d6e1bc51d4f949f0941156021a4844ed8c959ca" } diff --git a/core/lib/dal/.sqlx/query-8998ddd82cf15feb671b0d4efc6f7496667ce703e30d1bf2e0fb5a66fb0a1d18.json b/core/lib/dal/.sqlx/query-fa4ba80bf19de46f751e0752a1df3c84139791a734ab6d7eafbdb202e6dc32e9.json similarity index 83% rename from core/lib/dal/.sqlx/query-8998ddd82cf15feb671b0d4efc6f7496667ce703e30d1bf2e0fb5a66fb0a1d18.json rename to core/lib/dal/.sqlx/query-fa4ba80bf19de46f751e0752a1df3c84139791a734ab6d7eafbdb202e6dc32e9.json index a8a811f2580f..28ce71634781 100644 --- a/core/lib/dal/.sqlx/query-8998ddd82cf15feb671b0d4efc6f7496667ce703e30d1bf2e0fb5a66fb0a1d18.json +++ b/core/lib/dal/.sqlx/query-fa4ba80bf19de46f751e0752a1df3c84139791a734ab6d7eafbdb202e6dc32e9.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n timestamp,\n hash,\n l1_tx_count,\n l2_tx_count,\n fee_account_address AS \"fee_account_address!\",\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n gas_per_pubdata_limit,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n virtual_blocks,\n fair_pubdata_price,\n gas_limit\n FROM\n miniblocks\n WHERE\n number = $1\n ", + "query": "\n SELECT\n number,\n timestamp,\n hash,\n l1_tx_count,\n l2_tx_count,\n fee_account_address AS \"fee_account_address!\",\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n gas_per_pubdata_limit,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_simulator_code_hash,\n protocol_version,\n virtual_blocks,\n fair_pubdata_price,\n gas_limit\n FROM\n miniblocks\n WHERE\n number = $1\n ", "describe": { "columns": [ { @@ -65,21 +65,26 @@ }, { "ordinal": 12, + "name": "evm_simulator_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 13, "name": "protocol_version", "type_info": "Int4" }, { - "ordinal": 13, + "ordinal": 14, "name": "virtual_blocks", "type_info": "Int8" }, { - "ordinal": 14, + "ordinal": 15, "name": "fair_pubdata_price", "type_info": "Int8" }, { - "ordinal": 15, + "ordinal": 16, "name": "gas_limit", "type_info": "Int8" } @@ -103,10 +108,11 @@ true, true, true, + true, false, true, true ] }, - "hash": "8998ddd82cf15feb671b0d4efc6f7496667ce703e30d1bf2e0fb5a66fb0a1d18" + "hash": "fa4ba80bf19de46f751e0752a1df3c84139791a734ab6d7eafbdb202e6dc32e9" } diff --git a/core/lib/dal/migrations/20240808160800_evm-simulator.down.sql b/core/lib/dal/migrations/20240808160800_evm-simulator.down.sql new file mode 100644 index 000000000000..999728809a5e --- /dev/null +++ b/core/lib/dal/migrations/20240808160800_evm-simulator.down.sql @@ -0,0 +1,3 @@ +ALTER TABLE protocol_versions DROP COLUMN IF NOT EXISTS evm_simulator_code_hash; +ALTER TABLE l1_batches DROP COLUMN IF NOT EXISTS evm_simulator_code_hash; +ALTER TABLE miniblocks DROP COLUMN IF NOT EXISTS evm_simulator_code_hash; diff --git a/core/lib/dal/migrations/20240808160800_evm-simulator.up.sql b/core/lib/dal/migrations/20240808160800_evm-simulator.up.sql new file mode 100644 index 000000000000..ea8e0a83d20c --- /dev/null +++ b/core/lib/dal/migrations/20240808160800_evm-simulator.up.sql @@ -0,0 +1,3 @@ +ALTER TABLE protocol_versions ADD COLUMN IF NOT EXISTS evm_simulator_code_hash BYTEA; +ALTER TABLE l1_batches ADD COLUMN IF NOT EXISTS evm_simulator_code_hash BYTEA; +ALTER TABLE miniblocks ADD COLUMN IF NOT EXISTS evm_simulator_code_hash BYTEA; diff --git a/core/lib/dal/src/blocks_dal.rs b/core/lib/dal/src/blocks_dal.rs index 4f4b3e99ff7b..b23710c2157a 100644 --- a/core/lib/dal/src/blocks_dal.rs +++ b/core/lib/dal/src/blocks_dal.rs @@ -309,6 +309,7 @@ impl BlocksDal<'_, '_> { zkporter_is_available, bootloader_code_hash, default_aa_code_hash, + evm_simulator_code_hash, aux_data_hash, pass_through_data_hash, meta_parameters_hash, @@ -350,6 +351,7 @@ impl BlocksDal<'_, '_> { used_contract_hashes, bootloader_code_hash, default_aa_code_hash, + evm_simulator_code_hash, protocol_version, system_logs, pubdata_input @@ -594,6 +596,7 @@ impl BlocksDal<'_, '_> { used_contract_hashes, bootloader_code_hash, default_aa_code_hash, + evm_simulator_code_hash, protocol_version, system_logs, storage_refunds, @@ -625,6 +628,7 @@ impl BlocksDal<'_, '_> { $18, $19, $20, + $21, NOW(), NOW() ) @@ -643,6 +647,7 @@ impl BlocksDal<'_, '_> { used_contract_hashes, header.base_system_contracts_hashes.bootloader.as_bytes(), header.base_system_contracts_hashes.default_aa.as_bytes(), + header.base_system_contracts_hashes.evm_simulator.as_bytes(), header.protocol_version.map(|v| v as i32), &system_logs, &storage_refunds, @@ -761,6 +766,7 @@ impl BlocksDal<'_, '_> { gas_per_pubdata_limit, bootloader_code_hash, default_aa_code_hash, + evm_simulator_code_hash, protocol_version, virtual_blocks, fair_pubdata_price, @@ -800,6 +806,7 @@ impl BlocksDal<'_, '_> { gas_per_pubdata_limit, bootloader_code_hash, default_aa_code_hash, + evm_simulator_code_hash, protocol_version, virtual_blocks, fair_pubdata_price, @@ -1010,6 +1017,7 @@ impl BlocksDal<'_, '_> { zkporter_is_available, bootloader_code_hash, default_aa_code_hash, + evm_simulator_code_hash, aux_data_hash, pass_through_data_hash, meta_parameters_hash, @@ -1190,6 +1198,7 @@ impl BlocksDal<'_, '_> { zkporter_is_available, bootloader_code_hash, default_aa_code_hash, + evm_simulator_code_hash, aux_data_hash, pass_through_data_hash, meta_parameters_hash, @@ -1270,6 +1279,7 @@ impl BlocksDal<'_, '_> { zkporter_is_available, bootloader_code_hash, default_aa_code_hash, + evm_simulator_code_hash, aux_data_hash, pass_through_data_hash, meta_parameters_hash, @@ -1343,6 +1353,7 @@ impl BlocksDal<'_, '_> { zkporter_is_available, bootloader_code_hash, default_aa_code_hash, + evm_simulator_code_hash, aux_data_hash, pass_through_data_hash, meta_parameters_hash, @@ -1468,6 +1479,7 @@ impl BlocksDal<'_, '_> { zkporter_is_available, bootloader_code_hash, default_aa_code_hash, + evm_simulator_code_hash, aux_data_hash, pass_through_data_hash, meta_parameters_hash, @@ -1532,6 +1544,7 @@ impl BlocksDal<'_, '_> { zkporter_is_available, l1_batches.bootloader_code_hash, l1_batches.default_aa_code_hash, + l1_batches.evm_simulator_code_hash, aux_data_hash, pass_through_data_hash, meta_parameters_hash, @@ -1610,6 +1623,7 @@ impl BlocksDal<'_, '_> { zkporter_is_available, l1_batches.bootloader_code_hash, l1_batches.default_aa_code_hash, + l1_batches.evm_simulator_code_hash, aux_data_hash, pass_through_data_hash, meta_parameters_hash, diff --git a/core/lib/dal/src/blocks_web3_dal.rs b/core/lib/dal/src/blocks_web3_dal.rs index 2957701f9e23..8e455961cdd6 100644 --- a/core/lib/dal/src/blocks_web3_dal.rs +++ b/core/lib/dal/src/blocks_web3_dal.rs @@ -632,6 +632,7 @@ impl BlocksWeb3Dal<'_, '_> { miniblocks.fair_pubdata_price, miniblocks.bootloader_code_hash, miniblocks.default_aa_code_hash, + miniblocks.evm_simulator_code_hash, miniblocks.protocol_version, miniblocks.fee_account_address FROM @@ -699,7 +700,8 @@ impl BlocksWeb3Dal<'_, '_> { mb.l2_fair_gas_price, mb.fair_pubdata_price, l1_batches.bootloader_code_hash, - l1_batches.default_aa_code_hash + l1_batches.default_aa_code_hash, + l1_batches.evm_simulator_code_hash FROM l1_batches INNER JOIN mb ON TRUE diff --git a/core/lib/dal/src/factory_deps_dal.rs b/core/lib/dal/src/factory_deps_dal.rs index 02ce32306cfb..8ba6be700939 100644 --- a/core/lib/dal/src/factory_deps_dal.rs +++ b/core/lib/dal/src/factory_deps_dal.rs @@ -94,6 +94,7 @@ impl FactoryDepsDal<'_, '_> { &mut self, bootloader_hash: H256, default_aa_hash: H256, + evm_simulator_hash: H256, ) -> anyhow::Result { let bootloader_bytecode = self .get_sealed_factory_dep(bootloader_hash) @@ -115,9 +116,21 @@ impl FactoryDepsDal<'_, '_> { code: bytes_to_be_words(default_aa_bytecode), hash: default_aa_hash, }; + + let evm_simulator_bytecode = self + .get_sealed_factory_dep(evm_simulator_hash) + .await + .context("failed loading evm simulator code")? + .with_context(|| format!("evm simulator code with hash {default_aa_hash:?} should be present in the database"))?; + + let evm_simulator_code = SystemContractCode { + code: bytes_to_be_words(evm_simulator_bytecode), + hash: evm_simulator_hash, + }; Ok(BaseSystemContracts { bootloader: bootloader_code, default_aa: default_aa_code, + evm_simulator: evm_simulator_code, }) } diff --git a/core/lib/dal/src/models/storage_block.rs b/core/lib/dal/src/models/storage_block.rs index be8b4e4152b5..ae75c6ba1ca2 100644 --- a/core/lib/dal/src/models/storage_block.rs +++ b/core/lib/dal/src/models/storage_block.rs @@ -44,6 +44,7 @@ pub(crate) struct StorageL1BatchHeader { pub used_contract_hashes: serde_json::Value, pub bootloader_code_hash: Option>, pub default_aa_code_hash: Option>, + pub evm_simulator_code_hash: Option>, pub protocol_version: Option, // `system_logs` are introduced as part of boojum and will be absent in all batches generated prior to boojum. @@ -59,6 +60,8 @@ impl StorageL1BatchHeader { self, l2_to_l1_logs: Vec, ) -> L1BatchHeader { + println!("{:?}", &self); + println!("INTO L1 BATCH HEADER WITH LOGS"); let priority_ops_onchain_data: Vec<_> = self .priority_ops_onchain_data .into_iter() @@ -82,6 +85,7 @@ impl StorageL1BatchHeader { base_system_contracts_hashes: convert_base_system_contracts_hashes( self.bootloader_code_hash, self.default_aa_code_hash, + self.evm_simulator_code_hash, ), system_logs: system_logs.into_iter().map(SystemL2ToL1Log).collect(), protocol_version: self @@ -103,6 +107,7 @@ fn convert_l2_to_l1_logs(raw_logs: Vec>) -> Vec { fn convert_base_system_contracts_hashes( bootloader_code_hash: Option>, default_aa_code_hash: Option>, + evm_simulator_code_hash: Option>, ) -> BaseSystemContractsHashes { BaseSystemContractsHashes { bootloader: bootloader_code_hash @@ -111,6 +116,9 @@ fn convert_base_system_contracts_hashes( default_aa: default_aa_code_hash .map(|hash| H256::from_slice(&hash)) .expect("should not be none"), + evm_simulator: evm_simulator_code_hash + .map(|hash| H256::from_slice(&hash)) + .expect("should not be none"), } } @@ -134,6 +142,7 @@ pub(crate) struct StorageL1Batch { pub zkporter_is_available: Option, pub bootloader_code_hash: Option>, pub default_aa_code_hash: Option>, + pub evm_simulator_code_hash: Option>, pub l2_to_l1_messages: Vec>, pub l2_l1_merkle_root: Option>, @@ -154,6 +163,8 @@ impl StorageL1Batch { self, l2_to_l1_logs: Vec, ) -> L1BatchHeader { + println!("{:?}", &self); + println!("INTO L1 BATCH HEADER WITH LOGS ASD"); let priority_ops_onchain_data: Vec<_> = self .priority_ops_onchain_data .into_iter() @@ -177,6 +188,7 @@ impl StorageL1Batch { base_system_contracts_hashes: convert_base_system_contracts_hashes( self.bootloader_code_hash, self.default_aa_code_hash, + self.evm_simulator_code_hash, ), system_logs: system_logs.into_iter().map(SystemL2ToL1Log).collect(), protocol_version: self @@ -275,12 +287,14 @@ pub(crate) struct StorageBlockDetails { pub fair_pubdata_price: Option, pub bootloader_code_hash: Option>, pub default_aa_code_hash: Option>, + pub evm_simulator_code_hash: Option>, pub fee_account_address: Vec, pub protocol_version: Option, } impl From for api::BlockDetails { fn from(details: StorageBlockDetails) -> Self { + println!("FROM STORAGEBLOCKDETAILS"); let status = if details.number == 0 || details.execute_tx_hash.is_some() { api::BlockStatus::Verified } else { @@ -320,6 +334,7 @@ impl From for api::BlockDetails { base_system_contracts_hashes: convert_base_system_contracts_hashes( details.bootloader_code_hash, details.default_aa_code_hash, + details.evm_simulator_code_hash, ), }; api::BlockDetails { @@ -352,10 +367,12 @@ pub(crate) struct StorageL1BatchDetails { pub fair_pubdata_price: Option, pub bootloader_code_hash: Option>, pub default_aa_code_hash: Option>, + pub evm_simulator_code_hash: Option>, } impl From for api::L1BatchDetails { fn from(details: StorageL1BatchDetails) -> Self { + println!("FROM"); let status = if details.number == 0 || details.execute_tx_hash.is_some() { api::BlockStatus::Verified } else { @@ -395,6 +412,7 @@ impl From for api::L1BatchDetails { base_system_contracts_hashes: convert_base_system_contracts_hashes( details.bootloader_code_hash, details.default_aa_code_hash, + details.evm_simulator_code_hash, ), }; api::L1BatchDetails { @@ -418,6 +436,7 @@ pub(crate) struct StorageL2BlockHeader { // L2 gas price assumed in the corresponding batch pub bootloader_code_hash: Option>, pub default_aa_code_hash: Option>, + pub evm_simulator_code_hash: Option>, pub protocol_version: Option, pub fair_pubdata_price: Option, @@ -437,6 +456,7 @@ pub(crate) struct StorageL2BlockHeader { impl From for L2BlockHeader { fn from(row: StorageL2BlockHeader) -> Self { + println!("FROM L2 BLOCK HEADER"); let protocol_version = row.protocol_version.map(|v| (v as u16).try_into().unwrap()); let fee_input = protocol_version @@ -470,6 +490,7 @@ impl From for L2BlockHeader { base_system_contracts_hashes: convert_base_system_contracts_hashes( row.bootloader_code_hash, row.default_aa_code_hash, + row.evm_simulator_code_hash, ), gas_per_pubdata_limit: row.gas_per_pubdata_limit as u64, protocol_version, diff --git a/core/lib/dal/src/models/storage_protocol_version.rs b/core/lib/dal/src/models/storage_protocol_version.rs index c19fa560b67c..63c1e238b3a1 100644 --- a/core/lib/dal/src/models/storage_protocol_version.rs +++ b/core/lib/dal/src/models/storage_protocol_version.rs @@ -16,6 +16,7 @@ pub struct StorageProtocolVersion { pub recursion_scheduler_level_vk_hash: Vec, pub bootloader_code_hash: Vec, pub default_account_code_hash: Vec, + pub evm_simulator_code_hash: Option>, } pub(crate) fn protocol_version_from_storage( @@ -36,6 +37,11 @@ pub(crate) fn protocol_version_from_storage( base_system_contracts_hashes: BaseSystemContractsHashes { bootloader: H256::from_slice(&storage_version.bootloader_code_hash), default_aa: H256::from_slice(&storage_version.default_account_code_hash), + evm_simulator: H256::from_slice( + &storage_version + .evm_simulator_code_hash + .unwrap_or(H256::zero().as_bytes().to_vec()), + ), }, tx, } @@ -47,6 +53,7 @@ pub struct StorageApiProtocolVersion { pub timestamp: i64, pub bootloader_code_hash: Vec, pub default_account_code_hash: Vec, + pub evm_simulator_code_hash: Option>, pub upgrade_tx_hash: Option>, } @@ -62,6 +69,11 @@ impl From for api::ProtocolVersion { storage_protocol_version.timestamp as u64, H256::from_slice(&storage_protocol_version.bootloader_code_hash), H256::from_slice(&storage_protocol_version.default_account_code_hash), + H256::from_slice( + &storage_protocol_version + .evm_simulator_code_hash + .unwrap_or(H256::zero().as_bytes().to_vec()), + ), l2_system_upgrade_tx_hash, ) } diff --git a/core/lib/dal/src/models/storage_sync.rs b/core/lib/dal/src/models/storage_sync.rs index 688a6f997904..0fb7527aa42a 100644 --- a/core/lib/dal/src/models/storage_sync.rs +++ b/core/lib/dal/src/models/storage_sync.rs @@ -22,6 +22,7 @@ pub(crate) struct StorageSyncBlock { pub fair_pubdata_price: Option, pub bootloader_code_hash: Option>, pub default_aa_code_hash: Option>, + pub evm_simulator_code_hash: Option>, pub fee_account_address: Vec, pub protocol_version: i32, pub virtual_blocks: i64, @@ -75,6 +76,8 @@ impl TryFrom for SyncBlock { .decode_column("bootloader_code_hash")?, default_aa: parse_h256_opt(block.default_aa_code_hash.as_deref()) .decode_column("default_aa_code_hash")?, + evm_simulator: parse_h256_opt(block.evm_simulator_code_hash.as_deref()) + .decode_column("evm_simulator_code_hash")?, }, fee_account_address: parse_h160(&block.fee_account_address) .decode_column("fee_account_address")?, diff --git a/core/lib/dal/src/protocol_versions_dal.rs b/core/lib/dal/src/protocol_versions_dal.rs index 0d17044e6c51..282699c63667 100644 --- a/core/lib/dal/src/protocol_versions_dal.rs +++ b/core/lib/dal/src/protocol_versions_dal.rs @@ -195,7 +195,8 @@ impl ProtocolVersionsDal<'_, '_> { r#" SELECT bootloader_code_hash, - default_account_code_hash + default_account_code_hash, + evm_simulator_code_hash FROM protocol_versions WHERE @@ -214,6 +215,10 @@ impl ProtocolVersionsDal<'_, '_> { .get_base_system_contracts( H256::from_slice(&row.bootloader_code_hash), H256::from_slice(&row.default_account_code_hash), + H256::from_slice( + &row.evm_simulator_code_hash + .unwrap_or(H256::zero().as_bytes().to_vec()), + ), ) .await?; Some(contracts) @@ -234,6 +239,7 @@ impl ProtocolVersionsDal<'_, '_> { protocol_versions.timestamp, protocol_versions.bootloader_code_hash, protocol_versions.default_account_code_hash, + protocol_versions.evm_simulator_code_hash, protocol_patches.patch, protocol_patches.recursion_scheduler_level_vk_hash FROM diff --git a/core/lib/dal/src/protocol_versions_web3_dal.rs b/core/lib/dal/src/protocol_versions_web3_dal.rs index a3a7a162c3dd..05a93ea1b098 100644 --- a/core/lib/dal/src/protocol_versions_web3_dal.rs +++ b/core/lib/dal/src/protocol_versions_web3_dal.rs @@ -21,6 +21,7 @@ impl ProtocolVersionsWeb3Dal<'_, '_> { timestamp, bootloader_code_hash, default_account_code_hash, + evm_simulator_code_hash, upgrade_tx_hash FROM protocol_versions diff --git a/core/lib/dal/src/sync_dal.rs b/core/lib/dal/src/sync_dal.rs index 898770c38f5a..3df3c3240648 100644 --- a/core/lib/dal/src/sync_dal.rs +++ b/core/lib/dal/src/sync_dal.rs @@ -50,6 +50,7 @@ impl SyncDal<'_, '_> { miniblocks.fair_pubdata_price, miniblocks.bootloader_code_hash, miniblocks.default_aa_code_hash, + miniblocks.evm_simulator_code_hash, miniblocks.virtual_blocks, miniblocks.hash, miniblocks.protocol_version AS "protocol_version!", diff --git a/core/lib/dal/src/tests/mod.rs b/core/lib/dal/src/tests/mod.rs index 11f88ba8a70b..497e8e6fa86b 100644 --- a/core/lib/dal/src/tests/mod.rs +++ b/core/lib/dal/src/tests/mod.rs @@ -57,6 +57,7 @@ pub(crate) fn create_l1_batch_header(number: u32) -> L1BatchHeader { BaseSystemContractsHashes { bootloader: H256::repeat_byte(1), default_aa: H256::repeat_byte(42), + evm_simulator: H256::repeat_byte(43), }, ProtocolVersionId::latest(), ) diff --git a/core/lib/env_config/src/genesis.rs b/core/lib/env_config/src/genesis.rs index 1eb83ae2f39e..8aa75827a5fc 100644 --- a/core/lib/env_config/src/genesis.rs +++ b/core/lib/env_config/src/genesis.rs @@ -68,6 +68,7 @@ impl FromEnv for GenesisConfig { genesis_commitment: contracts_config.genesis_batch_commitment, bootloader_hash: state_keeper.bootloader_hash, default_aa_hash: state_keeper.default_aa_hash, + evm_simulator_hash: state_keeper.evm_simulator_hash, // TODO(EVM-676): for now, the settlement layer is always the same as the L1 network l1_chain_id: L1ChainId(network_config.network.chain_id().0), sl_chain_id: Some(network_config.network.chain_id()), diff --git a/core/lib/protobuf_config/src/chain.rs b/core/lib/protobuf_config/src/chain.rs index fafecc0131cd..dfe13e930e08 100644 --- a/core/lib/protobuf_config/src/chain.rs +++ b/core/lib/protobuf_config/src/chain.rs @@ -87,6 +87,7 @@ impl ProtoRepr for proto::StateKeeper { // needed during the initialization from files bootloader_hash: None, default_aa_hash: None, + evm_simulator_hash: None, fee_account_addr: None, l1_batch_commit_data_generator_mode: Default::default(), }) diff --git a/core/lib/protobuf_config/src/genesis.rs b/core/lib/protobuf_config/src/genesis.rs index 92f639aa224e..acf3ce044269 100644 --- a/core/lib/protobuf_config/src/genesis.rs +++ b/core/lib/protobuf_config/src/genesis.rs @@ -68,6 +68,11 @@ impl ProtoRepr for proto::Genesis { .and_then(|x| parse_h256(x)) .context("default_aa_hash")?, ), + evm_simulator_hash: Some( + required(&self.evm_simulator_hash) + .and_then(|x| parse_h256(x)) + .context("evm_simulator_hash")?, + ), l1_chain_id: required(&self.l1_chain_id) .map(|x| L1ChainId(*x)) .context("l1_chain_id")?, @@ -100,6 +105,7 @@ impl ProtoRepr for proto::Genesis { genesis_protocol_semantic_version: this.protocol_version.map(|x| x.to_string()), default_aa_hash: this.default_aa_hash.map(|x| format!("{:?}", x)), bootloader_hash: this.bootloader_hash.map(|x| format!("{:?}", x)), + evm_simulator_hash: this.evm_simulator_hash.map(|x| format!("{:?}", x)), fee_account: Some(format!("{:?}", this.fee_account)), l1_chain_id: Some(this.l1_chain_id.0), l2_chain_id: Some(this.l2_chain_id.as_u64()), diff --git a/core/lib/protobuf_config/src/proto/config/genesis.proto b/core/lib/protobuf_config/src/proto/config/genesis.proto index 6e679d865d92..34d65d8258e7 100644 --- a/core/lib/protobuf_config/src/proto/config/genesis.proto +++ b/core/lib/protobuf_config/src/proto/config/genesis.proto @@ -21,11 +21,12 @@ message Genesis { optional uint64 genesis_protocol_version = 4; // optional; optional string default_aa_hash = 5; // required; h256 optional string bootloader_hash = 6; // required; h256 - optional uint64 l1_chain_id = 7; // required; - optional uint64 l2_chain_id = 8; // required; - optional string fee_account = 9; // h160 - optional Prover prover = 10; + optional string evm_simulator_hash = 7; // required; h256 + optional uint64 l1_chain_id = 8; // required; + optional uint64 l2_chain_id = 9; // required; + optional string fee_account = 10; // h160 + optional Prover prover = 11; optional L1BatchCommitDataGeneratorMode l1_batch_commit_data_generator_mode = 29; // optional, default to rollup - optional string genesis_protocol_semantic_version = 12; // optional; - reserved 11; reserved "shared_bridge"; + optional string genesis_protocol_semantic_version = 13; // optional; + reserved 12; reserved "shared_bridge"; } diff --git a/core/lib/types/src/abi.rs b/core/lib/types/src/abi.rs index 84f8aba64869..c2013dbdbe40 100644 --- a/core/lib/types/src/abi.rs +++ b/core/lib/types/src/abi.rs @@ -198,6 +198,7 @@ pub struct ProposedUpgrade { pub factory_deps: Vec>, pub bootloader_hash: [u8; 32], pub default_account_hash: [u8; 32], + pub evm_simulator_hash: [u8; 32], pub verifier: Address, pub verifier_params: VerifierParams, pub l1_contracts_upgrade_calldata: Vec, @@ -314,6 +315,10 @@ impl ProposedUpgrade { .into_fixed_bytes() .and_then(|b| b.try_into().ok()) .context("default_account_hash")?, + evm_simulator_hash: next() + .into_fixed_bytes() + .and_then(|b| b.try_into().ok()) + .context("evm_simulator_hash")?, verifier: next().into_address().context("verifier")?, verifier_params: VerifierParams::decode(next()).context("verifier_params")?, l1_contracts_upgrade_calldata: next() diff --git a/core/lib/types/src/api/mod.rs b/core/lib/types/src/api/mod.rs index 751de9bd7040..ec612bfdd7fc 100644 --- a/core/lib/types/src/api/mod.rs +++ b/core/lib/types/src/api/mod.rs @@ -673,6 +673,9 @@ pub struct ProtocolVersion { /// Default account code hash #[serde(rename = "defaultAccountCodeHash")] pub default_account_code_hash: Option, + /// Evm simulator code hash + #[serde(rename = "evmSimulatorCodeHash")] + pub evm_simulator_code_hash: Option, /// L2 Upgrade transaction hash #[deprecated] pub l2_system_upgrade_tx_hash: Option, @@ -688,6 +691,7 @@ impl ProtocolVersion { timestamp: u64, bootloader_code_hash: H256, default_account_code_hash: H256, + evm_simulator_code_hash: H256, l2_system_upgrade_tx_hash: Option, ) -> Self { Self { @@ -698,9 +702,11 @@ impl ProtocolVersion { base_system_contracts: Some(BaseSystemContractsHashes { bootloader: bootloader_code_hash, default_aa: default_account_code_hash, + evm_simulator: evm_simulator_code_hash, }), bootloader_code_hash: Some(bootloader_code_hash), default_account_code_hash: Some(default_account_code_hash), + evm_simulator_code_hash: Some(evm_simulator_code_hash), l2_system_upgrade_tx_hash, l2_system_upgrade_tx_hash_new: l2_system_upgrade_tx_hash, } @@ -716,6 +722,13 @@ impl ProtocolVersion { .or_else(|| self.base_system_contracts.map(|hashes| hashes.default_aa)) } + pub fn default_evm_simulator_code_hash(&self) -> Option { + self.evm_simulator_code_hash.or_else(|| { + self.base_system_contracts + .map(|hashes| hashes.evm_simulator) + }) + } + pub fn minor_version(&self) -> Option { self.minor_version.or(self.version_id) } @@ -850,6 +863,7 @@ mod tests { base_system_contracts: Some(Default::default()), bootloader_code_hash: Some(Default::default()), default_account_code_hash: Some(Default::default()), + evm_simulator_code_hash: Some(Default::default()), l2_system_upgrade_tx_hash: Default::default(), l2_system_upgrade_tx_hash_new: Default::default(), }; diff --git a/core/lib/types/src/protocol_upgrade.rs b/core/lib/types/src/protocol_upgrade.rs index bc9bd7667e82..50f8f314027a 100644 --- a/core/lib/types/src/protocol_upgrade.rs +++ b/core/lib/types/src/protocol_upgrade.rs @@ -62,6 +62,8 @@ pub struct ProtocolUpgrade { pub bootloader_code_hash: Option, /// New default account code hash. pub default_account_code_hash: Option, + /// New evm simulator code hash + pub evm_simulator_code_hash: Option, /// New verifier params. pub verifier_params: Option, /// New verifier address. @@ -112,12 +114,15 @@ impl ProtocolUpgrade { let upgrade = abi::ProposedUpgrade::decode(upgrade.into_iter().next().unwrap()).unwrap(); let bootloader_hash = H256::from_slice(&upgrade.bootloader_hash); let default_account_hash = H256::from_slice(&upgrade.default_account_hash); + let evm_simulator_hash = H256::from_slice(&upgrade.evm_simulator_hash); Ok(Self { version: ProtocolSemanticVersion::try_from_packed(upgrade.new_protocol_version) .map_err(|err| anyhow::format_err!("Version is not supported: {err}"))?, bootloader_code_hash: (bootloader_hash != H256::zero()).then_some(bootloader_hash), default_account_code_hash: (default_account_hash != H256::zero()) .then_some(default_account_hash), + evm_simulator_code_hash: (evm_simulator_hash != H256::zero()) + .then_some(evm_simulator_hash), verifier_params: (upgrade.verifier_params != abi::VerifierParams::default()) .then_some(upgrade.verifier_params.into()), verifier_address: (upgrade.verifier != Address::zero()).then_some(upgrade.verifier), @@ -298,6 +303,9 @@ impl ProtocolVersion { default_aa: upgrade .default_account_code_hash .unwrap_or(self.base_system_contracts_hashes.default_aa), + evm_simulator: upgrade + .evm_simulator_code_hash + .unwrap_or(self.base_system_contracts_hashes.evm_simulator), }, tx: upgrade.tx, } diff --git a/core/lib/vm_utils/src/storage.rs b/core/lib/vm_utils/src/storage.rs index fbf52a67623d..7535531b3ec1 100644 --- a/core/lib/vm_utils/src/storage.rs +++ b/core/lib/vm_utils/src/storage.rs @@ -9,8 +9,9 @@ use zksync_multivm::{ zk_evm_latest::ethereum_types::H256, }; use zksync_types::{ - block::L2BlockHeader, fee_model::BatchFeeInput, snapshots::SnapshotRecoveryStatus, Address, - L1BatchNumber, L2BlockNumber, L2ChainId, ProtocolVersionId, ZKPORTER_IS_AVAILABLE, + block::L2BlockHeader, fee_model::BatchFeeInput, snapshots::SnapshotRecoveryStatus, + web3::contract, Address, L1BatchNumber, L2BlockNumber, L2ChainId, ProtocolVersionId, + ZKPORTER_IS_AVAILABLE, }; /// Typesafe wrapper around [`L2BlockHeader`] returned by [`L1BatchParamsProvider`]. @@ -301,7 +302,11 @@ impl L1BatchParamsProvider { let contract_hashes = first_l2_block_in_batch.header.base_system_contracts_hashes; let base_system_contracts = storage .factory_deps_dal() - .get_base_system_contracts(contract_hashes.bootloader, contract_hashes.default_aa) + .get_base_system_contracts( + contract_hashes.bootloader, + contract_hashes.default_aa, + contract_hashes.evm_simulator, + ) .await .context("failed getting base system contracts")?; diff --git a/core/node/api_server/src/web3/namespaces/en.rs b/core/node/api_server/src/web3/namespaces/en.rs index 604d38ef94ab..4355f6dd2b20 100644 --- a/core/node/api_server/src/web3/namespaces/en.rs +++ b/core/node/api_server/src/web3/namespaces/en.rs @@ -154,6 +154,12 @@ impl EnNamespace { genesis_commitment: Some(genesis_batch.metadata.commitment), bootloader_hash: Some(genesis_batch.header.base_system_contracts_hashes.bootloader), default_aa_hash: Some(genesis_batch.header.base_system_contracts_hashes.default_aa), + evm_simulator_hash: Some( + genesis_batch + .header + .base_system_contracts_hashes + .evm_simulator, + ), l1_chain_id: self.state.api_config.l1_chain_id, sl_chain_id: Some(self.state.api_config.l1_chain_id.into()), l2_chain_id: self.state.api_config.l2_chain_id, diff --git a/core/node/eth_sender/src/eth_tx_aggregator.rs b/core/node/eth_sender/src/eth_tx_aggregator.rs index 89533432ef83..126d8149e022 100644 --- a/core/node/eth_sender/src/eth_tx_aggregator.rs +++ b/core/node/eth_sender/src/eth_tx_aggregator.rs @@ -259,9 +259,23 @@ impl EthTxAggregator { ))); } let default_aa = H256::from_slice(&multicall3_default_aa); + + let multicall3_evm_simulator = + Multicall3Result::from_token(call_results_iterator.next().unwrap())?.return_data; + if multicall3_evm_simulator.len() != 32 { + return Err(EthSenderError::Parse(Web3ContractError::InvalidOutputType( + format!( + "multicall3 evm simulator hash data is not of the len of 32: {:?}", + multicall3_evm_simulator + ), + ))); + } + let evm_simulator = H256::from_slice(&multicall3_evm_simulator); + let base_system_contracts_hashes = BaseSystemContractsHashes { bootloader, default_aa, + evm_simulator, }; call_results_iterator.next().unwrap(); diff --git a/core/node/eth_watch/src/client.rs b/core/node/eth_watch/src/client.rs index 39b9b5e9f6b1..58d2cbc4d95c 100644 --- a/core/node/eth_watch/src/client.rs +++ b/core/node/eth_watch/src/client.rs @@ -70,6 +70,7 @@ impl EthHttpQueryClient { diamond_proxy_addr, governance_address ); + dbg!(&state_transition_manager_contract()); Self { client: client.for_component("watch"), topics: Vec::new(), diff --git a/core/node/genesis/src/lib.rs b/core/node/genesis/src/lib.rs index dcb9ba2c012f..68ac3fdccc98 100644 --- a/core/node/genesis/src/lib.rs +++ b/core/node/genesis/src/lib.rs @@ -101,6 +101,9 @@ impl GenesisParams { default_aa: config .default_aa_hash .ok_or(GenesisError::MalformedConfig("default_aa_hash"))?, + evm_simulator: config + .evm_simulator_hash + .ok_or(GenesisError::MalformedConfig("evm_simulator_hash"))?, }; if base_system_contracts_hashes != base_system_contracts.hashes() { return Err(GenesisError::BaseSystemContractsHashes(Box::new( @@ -172,6 +175,7 @@ pub fn mock_genesis_config() -> GenesisConfig { genesis_commitment: Some(H256::default()), bootloader_hash: Some(base_system_contracts_hashes.bootloader), default_aa_hash: Some(base_system_contracts_hashes.default_aa), + evm_simulator_hash: Some(base_system_contracts_hashes.evm_simulator), l1_chain_id: L1ChainId(9), sl_chain_id: None, l2_chain_id: L2ChainId::default(), @@ -236,6 +240,10 @@ pub async fn insert_genesis_batch( .config .default_aa_hash .ok_or(GenesisError::MalformedConfig("default_aa_hash"))?, + evm_simulator: genesis_params + .config + .evm_simulator_hash + .ok_or(GenesisError::MalformedConfig("evm_simulator_hash"))?, }; let commitment_input = CommitmentInput::for_genesis_batch( genesis_root_hash, diff --git a/core/node/genesis/src/utils.rs b/core/node/genesis/src/utils.rs index a6c9513dbde8..d0e8aa020363 100644 --- a/core/node/genesis/src/utils.rs +++ b/core/node/genesis/src/utils.rs @@ -129,10 +129,14 @@ pub(super) async fn insert_base_system_contracts_to_factory_deps( storage: &mut Connection<'_, Core>, contracts: &BaseSystemContracts, ) -> Result<(), GenesisError> { - let factory_deps = [&contracts.bootloader, &contracts.default_aa] - .iter() - .map(|c| (c.hash, be_words_to_bytes(&c.code))) - .collect(); + let factory_deps = [ + &contracts.bootloader, + &contracts.default_aa, + &contracts.evm_simulator, + ] + .iter() + .map(|c| (c.hash, be_words_to_bytes(&c.code))) + .collect(); Ok(storage .factory_deps_dal() diff --git a/core/node/node_sync/src/external_io.rs b/core/node/node_sync/src/external_io.rs index 50734421341e..2fc04ba60bba 100644 --- a/core/node/node_sync/src/external_io.rs +++ b/core/node/node_sync/src/external_io.rs @@ -345,6 +345,9 @@ impl StateKeeperIO for ExternalIO { let default_account_code_hash = protocol_version .default_account_code_hash() .context("Missing default account code hash")?; + let evm_simulator_code_hash = protocol_version + .default_evm_simulator_code_hash() + .context("Missing evm simulator code hash")?; let l2_system_upgrade_tx_hash = protocol_version.l2_system_upgrade_tx_hash(); self.pool .connection_tagged("sync_layer") @@ -362,6 +365,7 @@ impl StateKeeperIO for ExternalIO { BaseSystemContractsHashes { bootloader: bootloader_code_hash, default_aa: default_account_code_hash, + evm_simulator: evm_simulator_code_hash, }, l2_system_upgrade_tx_hash, ) @@ -375,9 +379,14 @@ impl StateKeeperIO for ExternalIO { .get_base_system_contract(default_account_code_hash, cursor.next_l2_block) .await .with_context(|| format!("cannot fetch default AA code for {protocol_version:?}"))?; + let evm_simulator = self + .get_base_system_contract(evm_simulator_code_hash, cursor.next_l2_block) + .await + .with_context(|| format!("cannot fetch EVM simulator code for {protocol_version:?}"))?; Ok(BaseSystemContracts { bootloader, default_aa, + evm_simulator, }) } diff --git a/core/node/node_sync/src/genesis.rs b/core/node/node_sync/src/genesis.rs index ccc26b417e98..645b96c16d05 100644 --- a/core/node/node_sync/src/genesis.rs +++ b/core/node/node_sync/src/genesis.rs @@ -38,6 +38,9 @@ async fn create_genesis_params( let base_system_contracts_hashes = BaseSystemContractsHashes { bootloader: config.bootloader_hash.context("Genesis is not finished")?, default_aa: config.default_aa_hash.context("Genesis is not finished")?, + evm_simulator: config + .evm_simulator_hash + .context("Genesis is not finished")?, }; if zksync_chain_id != config.l2_chain_id { @@ -103,6 +106,10 @@ async fn fetch_base_system_contracts( .fetch_system_contract_by_hash(contract_hashes.default_aa) .await? .context("default AA bytecode is missing on main node")?; + let evm_simulator = client + .fetch_system_contract_by_hash(contract_hashes.evm_simulator) + .await? + .context("EVM Simulator bytecode is missing on main node")?; Ok(BaseSystemContracts { bootloader: SystemContractCode { code: zksync_utils::bytes_to_be_words(bootloader_bytecode), @@ -112,5 +119,9 @@ async fn fetch_base_system_contracts( code: zksync_utils::bytes_to_be_words(default_aa_bytecode), hash: contract_hashes.default_aa, }, + evm_simulator: SystemContractCode { + code: zksync_utils::bytes_to_be_words(evm_simulator), + hash: contract_hashes.evm_simulator, + }, }) } diff --git a/core/node/test_utils/src/lib.rs b/core/node/test_utils/src/lib.rs index 614d64805b9c..57ea74f6a479 100644 --- a/core/node/test_utils/src/lib.rs +++ b/core/node/test_utils/src/lib.rs @@ -53,6 +53,7 @@ pub fn create_l1_batch(number: u32) -> L1BatchHeader { BaseSystemContractsHashes { bootloader: H256::repeat_byte(1), default_aa: H256::repeat_byte(42), + evm_simulator: H256::repeat_byte(43), }, ProtocolVersionId::latest(), ); diff --git a/etc/env/base/chain.toml b/etc/env/base/chain.toml index 6cfacb3c72ce..6bea9dd67837 100644 --- a/etc/env/base/chain.toml +++ b/etc/env/base/chain.toml @@ -90,8 +90,9 @@ fee_model_version = "V2" validation_computational_gas_limit = 300000 save_call_traces = true -bootloader_hash = "0x010008e742608b21bf7eb23c1a9d0602047e3618b464c9b59c0fba3b3d7ab66e" -default_aa_hash = "0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32" +bootloader_hash = "0x010008e7bb87193aa9dd95c07f8e52c7c95809bf6f3e12143a7e3791c444efa7" +default_aa_hash = "0x0100058d112ad774e13568c6109ae438f2493e8c2fa0d4913ff3a1a54adf2775" +evm_simulator_hash = "0x01000f197081a9906cc411d0698c4961aeb5c74877f37f7071681da6e8ef3f31" protective_reads_persistence_enabled = false diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index daa317a8bc90..fe16adf41808 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -26,8 +26,8 @@ RECURSION_NODE_LEVEL_VK_HASH = "0x1186ec268d49f1905f8d9c1e9d39fc33e98c74f91d91a2 RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc8966504064f1f6ba3f1ba863210" RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" -GENESIS_ROOT = "0xabdb766b18a479a5c783a4b80e12686bc8ea3cc2d8a3050491b701d72370ebb5" -GENESIS_BATCH_COMMITMENT = "0x2d00e5f8d77afcebf58a6b82ae56ba967566fe7dfbcb6760319fb0d215d18ffd" +GENESIS_ROOT = "0xa7dda61f7e77ab25d78e87fb824e9db38292994c6be1772be0459372312e368b" +GENESIS_BATCH_COMMITMENT = "0xa4d16b41f77a9fdb2aab608f1130a7c4e7f37c6fc909d7f2f94a090055fae21d" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "54" From 1cc576c1b3c6881bd4e29b63c8ef9e9058b00ade Mon Sep 17 00:00:00 2001 From: Javier Chatruc Date: Fri, 9 Aug 2024 11:07:34 -0300 Subject: [PATCH 02/76] Remove prints --- core/lib/contracts/src/lib.rs | 2 -- core/lib/dal/src/models/storage_block.rs | 7 ------- 2 files changed, 9 deletions(-) diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index c63f940c3704..0d4dcb94a9c0 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -83,7 +83,6 @@ fn load_contract_if_present + std::fmt::Debug>(path: P) -> Option fn load_contract_for_hardhat(path: (&str, &str)) -> Option { let path = Path::new(HARDHAT_PATH_PREFIX).join(path.0).join(path.1); - println!("PATH: {:?}", path); load_contract_if_present(path) } @@ -97,7 +96,6 @@ fn load_contract_for_both_compilers(path: (&str, &str)) -> Contract { return contract; }; - println!("HARDHAT"); load_contract_for_hardhat(path).unwrap_or_else(|| { panic!("Failed to load contract from {:?}", path); }) diff --git a/core/lib/dal/src/models/storage_block.rs b/core/lib/dal/src/models/storage_block.rs index ae75c6ba1ca2..f7632c2ca143 100644 --- a/core/lib/dal/src/models/storage_block.rs +++ b/core/lib/dal/src/models/storage_block.rs @@ -60,8 +60,6 @@ impl StorageL1BatchHeader { self, l2_to_l1_logs: Vec, ) -> L1BatchHeader { - println!("{:?}", &self); - println!("INTO L1 BATCH HEADER WITH LOGS"); let priority_ops_onchain_data: Vec<_> = self .priority_ops_onchain_data .into_iter() @@ -163,8 +161,6 @@ impl StorageL1Batch { self, l2_to_l1_logs: Vec, ) -> L1BatchHeader { - println!("{:?}", &self); - println!("INTO L1 BATCH HEADER WITH LOGS ASD"); let priority_ops_onchain_data: Vec<_> = self .priority_ops_onchain_data .into_iter() @@ -294,7 +290,6 @@ pub(crate) struct StorageBlockDetails { impl From for api::BlockDetails { fn from(details: StorageBlockDetails) -> Self { - println!("FROM STORAGEBLOCKDETAILS"); let status = if details.number == 0 || details.execute_tx_hash.is_some() { api::BlockStatus::Verified } else { @@ -372,7 +367,6 @@ pub(crate) struct StorageL1BatchDetails { impl From for api::L1BatchDetails { fn from(details: StorageL1BatchDetails) -> Self { - println!("FROM"); let status = if details.number == 0 || details.execute_tx_hash.is_some() { api::BlockStatus::Verified } else { @@ -456,7 +450,6 @@ pub(crate) struct StorageL2BlockHeader { impl From for L2BlockHeader { fn from(row: StorageL2BlockHeader) -> Self { - println!("FROM L2 BLOCK HEADER"); let protocol_version = row.protocol_version.map(|v| (v as u16).try_into().unwrap()); let fee_input = protocol_version From 1e716b02d6f1129c0c0dbe3ae044ffb3664972a6 Mon Sep 17 00:00:00 2001 From: Javier Chatruc Date: Fri, 9 Aug 2024 12:31:20 -0300 Subject: [PATCH 03/76] Fix some more missing dal inserts --- ...81a4830813ac80c3dec902e8c437bf9c871df.json | 30 +++++++++++++++++++ ...5b0996a4274e793ed6a9b1bc7d687954f9a0f.json | 29 ------------------ ...85d2efa5902269f3b5ad17b0259c3526877f.json} | 5 ++-- core/lib/dal/src/blocks_dal.rs | 6 ++++ core/lib/dal/src/protocol_versions_dal.rs | 4 ++- etc/env/base/chain.toml | 4 +-- etc/env/base/contracts.toml | 4 +-- 7 files changed, 46 insertions(+), 36 deletions(-) create mode 100644 core/lib/dal/.sqlx/query-d920e3b2c33db5f6a3ed367789a81a4830813ac80c3dec902e8c437bf9c871df.json delete mode 100644 core/lib/dal/.sqlx/query-e296f3e9849910734196c91c2c35b0996a4274e793ed6a9b1bc7d687954f9a0f.json rename core/lib/dal/.sqlx/{query-25fb31277591dd7d5d783bd8777f1a855e76b37b6ed36ae612b551f9a6a55633.json => query-ff68458acd9c98120bf4a6814c1985d2efa5902269f3b5ad17b0259c3526877f.json} (52%) diff --git a/core/lib/dal/.sqlx/query-d920e3b2c33db5f6a3ed367789a81a4830813ac80c3dec902e8c437bf9c871df.json b/core/lib/dal/.sqlx/query-d920e3b2c33db5f6a3ed367789a81a4830813ac80c3dec902e8c437bf9c871df.json new file mode 100644 index 000000000000..598b140253d3 --- /dev/null +++ b/core/lib/dal/.sqlx/query-d920e3b2c33db5f6a3ed367789a81a4830813ac80c3dec902e8c437bf9c871df.json @@ -0,0 +1,30 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n miniblocks (\n number,\n timestamp,\n hash,\n l1_tx_count,\n l2_tx_count,\n fee_account_address,\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n gas_per_pubdata_limit,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_simulator_code_hash,\n protocol_version,\n virtual_blocks,\n fair_pubdata_price,\n gas_limit,\n created_at,\n updated_at\n )\n VALUES\n (\n $1,\n $2,\n $3,\n $4,\n $5,\n $6,\n $7,\n $8,\n $9,\n $10,\n $11,\n $12,\n $13,\n $14,\n $15,\n $16,\n $17,\n NOW(),\n NOW()\n )\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int8", + "Bytea", + "Int4", + "Int4", + "Bytea", + "Numeric", + "Int8", + "Int8", + "Int8", + "Bytea", + "Bytea", + "Bytea", + "Int4", + "Int8", + "Int8", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "d920e3b2c33db5f6a3ed367789a81a4830813ac80c3dec902e8c437bf9c871df" +} diff --git a/core/lib/dal/.sqlx/query-e296f3e9849910734196c91c2c35b0996a4274e793ed6a9b1bc7d687954f9a0f.json b/core/lib/dal/.sqlx/query-e296f3e9849910734196c91c2c35b0996a4274e793ed6a9b1bc7d687954f9a0f.json deleted file mode 100644 index 4de230504559..000000000000 --- a/core/lib/dal/.sqlx/query-e296f3e9849910734196c91c2c35b0996a4274e793ed6a9b1bc7d687954f9a0f.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n miniblocks (\n number,\n timestamp,\n hash,\n l1_tx_count,\n l2_tx_count,\n fee_account_address,\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n gas_per_pubdata_limit,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n virtual_blocks,\n fair_pubdata_price,\n gas_limit,\n created_at,\n updated_at\n )\n VALUES\n (\n $1,\n $2,\n $3,\n $4,\n $5,\n $6,\n $7,\n $8,\n $9,\n $10,\n $11,\n $12,\n $13,\n $14,\n $15,\n $16,\n NOW(),\n NOW()\n )\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Int8", - "Bytea", - "Int4", - "Int4", - "Bytea", - "Numeric", - "Int8", - "Int8", - "Int8", - "Bytea", - "Bytea", - "Int4", - "Int8", - "Int8", - "Int8" - ] - }, - "nullable": [] - }, - "hash": "e296f3e9849910734196c91c2c35b0996a4274e793ed6a9b1bc7d687954f9a0f" -} diff --git a/core/lib/dal/.sqlx/query-25fb31277591dd7d5d783bd8777f1a855e76b37b6ed36ae612b551f9a6a55633.json b/core/lib/dal/.sqlx/query-ff68458acd9c98120bf4a6814c1985d2efa5902269f3b5ad17b0259c3526877f.json similarity index 52% rename from core/lib/dal/.sqlx/query-25fb31277591dd7d5d783bd8777f1a855e76b37b6ed36ae612b551f9a6a55633.json rename to core/lib/dal/.sqlx/query-ff68458acd9c98120bf4a6814c1985d2efa5902269f3b5ad17b0259c3526877f.json index ee88bcdf39bd..5d8b7ffae83f 100644 --- a/core/lib/dal/.sqlx/query-25fb31277591dd7d5d783bd8777f1a855e76b37b6ed36ae612b551f9a6a55633.json +++ b/core/lib/dal/.sqlx/query-ff68458acd9c98120bf4a6814c1985d2efa5902269f3b5ad17b0259c3526877f.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n protocol_versions (\n id,\n timestamp,\n bootloader_code_hash,\n default_account_code_hash,\n upgrade_tx_hash,\n created_at\n )\n VALUES\n ($1, $2, $3, $4, $5, NOW())\n ON CONFLICT DO NOTHING\n ", + "query": "\n INSERT INTO\n protocol_versions (\n id,\n timestamp,\n bootloader_code_hash,\n default_account_code_hash,\n evm_simulator_code_hash,\n upgrade_tx_hash,\n created_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, NOW())\n ON CONFLICT DO NOTHING\n ", "describe": { "columns": [], "parameters": { @@ -9,10 +9,11 @@ "Int8", "Bytea", "Bytea", + "Bytea", "Bytea" ] }, "nullable": [] }, - "hash": "25fb31277591dd7d5d783bd8777f1a855e76b37b6ed36ae612b551f9a6a55633" + "hash": "ff68458acd9c98120bf4a6814c1985d2efa5902269f3b5ad17b0259c3526877f" } diff --git a/core/lib/dal/src/blocks_dal.rs b/core/lib/dal/src/blocks_dal.rs index b23710c2157a..5152b31918be 100644 --- a/core/lib/dal/src/blocks_dal.rs +++ b/core/lib/dal/src/blocks_dal.rs @@ -692,6 +692,7 @@ impl BlocksDal<'_, '_> { gas_per_pubdata_limit, bootloader_code_hash, default_aa_code_hash, + evm_simulator_code_hash, protocol_version, virtual_blocks, fair_pubdata_price, @@ -717,6 +718,7 @@ impl BlocksDal<'_, '_> { $14, $15, $16, + $17, NOW(), NOW() ) @@ -739,6 +741,10 @@ impl BlocksDal<'_, '_> { .base_system_contracts_hashes .default_aa .as_bytes(), + l2_block_header + .base_system_contracts_hashes + .evm_simulator + .as_bytes(), l2_block_header.protocol_version.map(|v| v as i32), i64::from(l2_block_header.virtual_blocks), l2_block_header.batch_fee_input.fair_pubdata_price() as i64, diff --git a/core/lib/dal/src/protocol_versions_dal.rs b/core/lib/dal/src/protocol_versions_dal.rs index 282699c63667..0b0133b956d5 100644 --- a/core/lib/dal/src/protocol_versions_dal.rs +++ b/core/lib/dal/src/protocol_versions_dal.rs @@ -45,17 +45,19 @@ impl ProtocolVersionsDal<'_, '_> { timestamp, bootloader_code_hash, default_account_code_hash, + evm_simulator_code_hash, upgrade_tx_hash, created_at ) VALUES - ($1, $2, $3, $4, $5, NOW()) + ($1, $2, $3, $4, $5, $6, NOW()) ON CONFLICT DO NOTHING "#, version.minor as i32, timestamp as i64, base_system_contracts_hashes.bootloader.as_bytes(), base_system_contracts_hashes.default_aa.as_bytes(), + base_system_contracts_hashes.evm_simulator.as_bytes(), tx_hash.as_ref().map(H256::as_bytes), ) .instrument("save_protocol_version#minor") diff --git a/etc/env/base/chain.toml b/etc/env/base/chain.toml index 6bea9dd67837..db06724eb656 100644 --- a/etc/env/base/chain.toml +++ b/etc/env/base/chain.toml @@ -90,8 +90,8 @@ fee_model_version = "V2" validation_computational_gas_limit = 300000 save_call_traces = true -bootloader_hash = "0x010008e7bb87193aa9dd95c07f8e52c7c95809bf6f3e12143a7e3791c444efa7" -default_aa_hash = "0x0100058d112ad774e13568c6109ae438f2493e8c2fa0d4913ff3a1a54adf2775" +bootloader_hash = "0x010008e7894d0dd14681c76bdb4d5e4e7f6b51bfe40c957d50eed3fec829fdb0" +default_aa_hash = "0x0100058deb36e1f2eeb48bf3846d0e8eb38e9176754b73116bb41a472459a4dd" evm_simulator_hash = "0x01000f197081a9906cc411d0698c4961aeb5c74877f37f7071681da6e8ef3f31" protective_reads_persistence_enabled = false diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index fe16adf41808..86a140ef7548 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -26,8 +26,8 @@ RECURSION_NODE_LEVEL_VK_HASH = "0x1186ec268d49f1905f8d9c1e9d39fc33e98c74f91d91a2 RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc8966504064f1f6ba3f1ba863210" RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" -GENESIS_ROOT = "0xa7dda61f7e77ab25d78e87fb824e9db38292994c6be1772be0459372312e368b" -GENESIS_BATCH_COMMITMENT = "0xa4d16b41f77a9fdb2aab608f1130a7c4e7f37c6fc909d7f2f94a090055fae21d" +GENESIS_ROOT = "0x5f71cdcbe47d9bba4317f12b790e15f7510ed142f956c90ef005f908e5d35f57" +GENESIS_BATCH_COMMITMENT = "0xfee67ea8705ea3f0fcc235ac3f4e5b906e0805a1cecb4ea566e6dc58ac3884ff" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "54" From 8e68c43dc37c9a46530cd9cc04f2cce4a59a6165 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 9 Aug 2024 19:10:01 -0300 Subject: [PATCH 04/76] Update contracts submodule --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index aa30514b6f99..04f5920b6cce 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit aa30514b6f99b4849937fe632abc80dd807e7dc7 +Subproject commit 04f5920b6cce11dca03adaa545db6d28d54c02f6 From 6b3b8ffa9cafa07ab6cd8a017e0c0e0226cb2d1a Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 9 Aug 2024 19:12:26 -0300 Subject: [PATCH 05/76] Update support for evm simulator --- core/lib/dal/src/models/storage_block.rs | 5 +++++ core/lib/types/src/commitment/mod.rs | 19 ++++++++++++------- core/node/commitment_generator/src/lib.rs | 1 + core/node/eth_sender/src/eth_tx_aggregator.rs | 14 +++++++++++++- core/node/eth_sender/src/tests.rs | 1 + core/node/eth_sender/src/zksync_functions.rs | 4 ++++ core/node/test_utils/src/lib.rs | 1 + etc/env/base/contracts.toml | 2 +- .../src/l2upgrade/deployer.ts | 4 ++++ 9 files changed, 42 insertions(+), 9 deletions(-) diff --git a/core/lib/dal/src/models/storage_block.rs b/core/lib/dal/src/models/storage_block.rs index f7632c2ca143..19dc8ebd967c 100644 --- a/core/lib/dal/src/models/storage_block.rs +++ b/core/lib/dal/src/models/storage_block.rs @@ -248,6 +248,11 @@ impl TryFrom for L1BatchMetadata { .default_aa_code_hash .ok_or(L1BatchMetadataError::Incomplete("default_aa_code_hash"))?, ), + evm_simulator_code_hash: H256::from_slice( + &batch + .evm_simulator_code_hash + .ok_or(L1BatchMetadataError::Incomplete("evm_simulator_code_hash"))?, + ), protocol_version: batch .protocol_version .map(|v| (v as u16).try_into().unwrap()), diff --git a/core/lib/types/src/commitment/mod.rs b/core/lib/types/src/commitment/mod.rs index 63d1bad486f3..b35a2cb11f80 100644 --- a/core/lib/types/src/commitment/mod.rs +++ b/core/lib/types/src/commitment/mod.rs @@ -467,6 +467,7 @@ pub struct L1BatchMetaParameters { pub zkporter_is_available: bool, pub bootloader_code_hash: H256, pub default_aa_code_hash: H256, + pub evm_simulator_code_hash: H256, pub protocol_version: Option, } @@ -477,14 +478,15 @@ impl L1BatchMetaParameters { result.push(self.zkporter_is_available as u8); result.extend(self.bootloader_code_hash.as_bytes()); result.extend(self.default_aa_code_hash.as_bytes()); + // result.extend(self.evm_simulator_code_hash.as_bytes()); - if self - .protocol_version - .map_or(false, |ver| ver.is_post_1_5_0()) - { - // EVM simulator hash for now is the same as the default AA hash. - result.extend(self.default_aa_code_hash.as_bytes()); - } + // if self + // .protocol_version + // .map_or(false, |ver| ver.is_post_1_5_0()) + // { + // EVM simulator hash for now is the same as the default AA hash. + result.extend(self.evm_simulator_code_hash.as_bytes()); + // } result } @@ -551,6 +553,7 @@ impl L1BatchCommitment { zkporter_is_available: ZKPORTER_IS_AVAILABLE, bootloader_code_hash: input.common().bootloader_code_hash, default_aa_code_hash: input.common().default_aa_code_hash, + evm_simulator_code_hash: input.common().evm_simulator_code_hash, protocol_version: Some(input.common().protocol_version), }; @@ -653,6 +656,7 @@ pub struct CommitmentCommonInput { pub rollup_root_hash: H256, pub bootloader_code_hash: H256, pub default_aa_code_hash: H256, + pub evm_simulator_code_hash: H256, pub protocol_version: ProtocolVersionId, } @@ -693,6 +697,7 @@ impl CommitmentInput { rollup_root_hash, bootloader_code_hash: base_system_contracts_hashes.bootloader, default_aa_code_hash: base_system_contracts_hashes.default_aa, + evm_simulator_code_hash: base_system_contracts_hashes.evm_simulator, protocol_version, }; if protocol_version.is_pre_boojum() { diff --git a/core/node/commitment_generator/src/lib.rs b/core/node/commitment_generator/src/lib.rs index 64e60b6dec0e..c1c136ec859d 100644 --- a/core/node/commitment_generator/src/lib.rs +++ b/core/node/commitment_generator/src/lib.rs @@ -178,6 +178,7 @@ impl CommitmentGenerator { rollup_root_hash: tree_data.hash, bootloader_code_hash: header.base_system_contracts_hashes.bootloader, default_aa_code_hash: header.base_system_contracts_hashes.default_aa, + evm_simulator_code_hash: header.base_system_contracts_hashes.evm_simulator, protocol_version, }; let touched_slots = connection diff --git a/core/node/eth_sender/src/eth_tx_aggregator.rs b/core/node/eth_sender/src/eth_tx_aggregator.rs index 4947cb1086f0..5a908fc3ad5b 100644 --- a/core/node/eth_sender/src/eth_tx_aggregator.rs +++ b/core/node/eth_sender/src/eth_tx_aggregator.rs @@ -174,6 +174,17 @@ impl EthTxAggregator { calldata: get_l2_default_aa_hash_input, }; + let get_l2_evm_simulator_hash_input = self + .functions + .get_evm_simulator_bytecode_hash + .encode_input(&[]) + .unwrap(); + let get_evm_simulator_hash_call = Multicall3Call { + target: self.state_transition_chain_contract, + allow_failure: ALLOW_FAILURE, + calldata: get_l2_evm_simulator_hash_input, + }; + // Third zksync contract call let get_verifier_params_input = self .functions @@ -210,6 +221,7 @@ impl EthTxAggregator { vec![ get_bootloader_hash_call.into_token(), get_default_aa_hash_call.into_token(), + get_evm_simulator_hash_call.into_token(), get_verifier_params_call.into_token(), get_verifier_call.into_token(), get_protocol_version_call.into_token(), @@ -230,7 +242,7 @@ impl EthTxAggregator { if let Token::Array(call_results) = token { // 5 calls are aggregated in multicall - if call_results.len() != 5 { + if call_results.len() != 6 { return parse_error(&call_results); } let mut call_results_iterator = call_results.into_iter(); diff --git a/core/node/eth_sender/src/tests.rs b/core/node/eth_sender/src/tests.rs index 83c37dd5d0a5..a82e7a4a193c 100644 --- a/core/node/eth_sender/src/tests.rs +++ b/core/node/eth_sender/src/tests.rs @@ -74,6 +74,7 @@ pub(crate) fn default_l1_batch_metadata() -> L1BatchMetadata { zkporter_is_available: false, bootloader_code_hash: H256::default(), default_aa_code_hash: H256::default(), + evm_simulator_code_hash: H256::default(), protocol_version: Some(ProtocolVersionId::default()), }, aux_data_hash: H256::default(), diff --git a/core/node/eth_sender/src/zksync_functions.rs b/core/node/eth_sender/src/zksync_functions.rs index 8f13f0e63ae8..242095e416fd 100644 --- a/core/node/eth_sender/src/zksync_functions.rs +++ b/core/node/eth_sender/src/zksync_functions.rs @@ -11,6 +11,7 @@ pub(super) struct ZkSyncFunctions { pub(super) post_shared_bridge_execute: Option, pub(super) get_l2_bootloader_bytecode_hash: Function, pub(super) get_l2_default_account_bytecode_hash: Function, + pub(super) get_evm_simulator_bytecode_hash: Function, pub(super) get_verifier: Function, pub(super) get_verifier_params: Function, pub(super) get_protocol_version: Function, @@ -59,6 +60,8 @@ impl Default for ZkSyncFunctions { get_function(&zksync_contract, "getL2BootloaderBytecodeHash"); let get_l2_default_account_bytecode_hash = get_function(&zksync_contract, "getL2DefaultAccountBytecodeHash"); + let get_evm_simulator_bytecode_hash = + get_function(&zksync_contract, "getL2EvmSimulatorBytecodeHash"); let get_verifier = get_function(&zksync_contract, "getVerifier"); let get_verifier_params = get_function(&zksync_contract, "getVerifierParams"); let get_protocol_version = get_function(&zksync_contract, "getProtocolVersion"); @@ -74,6 +77,7 @@ impl Default for ZkSyncFunctions { post_shared_bridge_execute, get_l2_bootloader_bytecode_hash, get_l2_default_account_bytecode_hash, + get_evm_simulator_bytecode_hash, get_verifier, get_verifier_params, get_protocol_version, diff --git a/core/node/test_utils/src/lib.rs b/core/node/test_utils/src/lib.rs index 57ea74f6a479..a0e70b02a22d 100644 --- a/core/node/test_utils/src/lib.rs +++ b/core/node/test_utils/src/lib.rs @@ -86,6 +86,7 @@ pub fn create_l1_batch_metadata(number: u32) -> L1BatchMetadata { zkporter_is_available: ZKPORTER_IS_AVAILABLE, bootloader_code_hash: BaseSystemContractsHashes::default().bootloader, default_aa_code_hash: BaseSystemContractsHashes::default().default_aa, + evm_simulator_code_hash: BaseSystemContractsHashes::default().evm_simulator, protocol_version: Some(ProtocolVersionId::latest()), }, aux_data_hash: H256::zero(), diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index 86a140ef7548..60a2c39d0859 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -27,7 +27,7 @@ RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc896650406 RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" GENESIS_ROOT = "0x5f71cdcbe47d9bba4317f12b790e15f7510ed142f956c90ef005f908e5d35f57" -GENESIS_BATCH_COMMITMENT = "0xfee67ea8705ea3f0fcc235ac3f4e5b906e0805a1cecb4ea566e6dc58ac3884ff" +GENESIS_BATCH_COMMITMENT = "0xf924b9c66bc141712971a0c4d1c8e3120da70ee58bee0d2e0e87da50d8b229b9" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "54" diff --git a/infrastructure/protocol-upgrade/src/l2upgrade/deployer.ts b/infrastructure/protocol-upgrade/src/l2upgrade/deployer.ts index e3b5f364efd9..98a4cf1fbd83 100644 --- a/infrastructure/protocol-upgrade/src/l2upgrade/deployer.ts +++ b/infrastructure/protocol-upgrade/src/l2upgrade/deployer.ts @@ -8,6 +8,7 @@ export async function callSystemContractDeployer( nonce: string, bootloader: boolean, defaultAA: boolean, + evmSimulator: boolean, systemContracts: boolean, file: string ) { @@ -20,6 +21,9 @@ export async function callSystemContractDeployer( if (defaultAA) { argsString += ' --default-aa'; } + if (evmSimulator) { + argsString += '--evm-simulator'; + } if (systemContracts) { argsString += ' --system-contracts'; } From c4ae99d3fd3155a90dac5659744a49c6aaa020b4 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 12 Aug 2024 17:48:35 -0300 Subject: [PATCH 06/76] Update commit for contracts submodule --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index 04f5920b6cce..90e7043091b4 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 04f5920b6cce11dca03adaa545db6d28d54c02f6 +Subproject commit 90e7043091b4a00a5a2b1afe2da0877aa61e258b From 3c36c88d9851eab1d0a2ad25b778d843c29b595c Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 14 Aug 2024 11:21:47 -0300 Subject: [PATCH 07/76] Update cached bootloader contracts for v1.5.0 of the vm --- .../fee_estimate.yul/fee_estimate.yul.zbin | Bin 76320 -> 76320 bytes .../gas_test.yul/gas_test.yul.zbin | Bin 72416 -> 72416 bytes .../playground_batch.yul.zbin | Bin 76512 -> 76512 bytes .../proved_batch.yul/proved_batch.yul.zbin | Bin 72928 -> 72928 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin index 75ee6377bdb645532c55f06f0e883cc078b5bd2b..643d7ee425b3a724d1e6902875b8d8475c57cbef 100644 GIT binary patch delta 80 zcmV-W0I&a`)C8c^1c0;w!v-CtNvoIO=8XA^oVi3J85*w!8SUDm*D1%`HP&nL?am*uLc?NozDb0?w`HwpTx7E_#h%6 jZjsZ*x;sUtf(^oyOZ1(`yiK60a0HofqJh7q;3}R%UsNe! delta 77 zcmV-T0J8t!wFKa`1h9kn9kcSoroGjz0In&g%eyk%qr)Gz2(`^p`11v7I7hRf_#h%6 jy73)7D_ugL(hyhJ_<|n-!lEmoN-aa!txw|=0J|5~Sq3KV diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/playground_batch.yul/playground_batch.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/playground_batch.yul/playground_batch.yul.zbin index b1a5e063d84b66ebea9a6e021ef42d29b1346760..efb5769b16fdf8862042b5c551663de951bb7899 100644 GIT binary patch delta 80 zcmV-W0I&bx)db+x1c0;wBL^L&NvoIO=8XA^oVi3J85*w!8S7u&@nK^+jml;siE>nDc_Ud#B+OJzk0%Jh^_9UJF delta 80 zcmV-W0I&bx)db+x1c0;wBL^L`^24UR)vW-oDW}W3GTfuXAGQd!%~JUD1!_1)w?GF0 mfFmHtf0L(63WdYOS7J7@C~q5w@LxJ& diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/proved_batch.yul/proved_batch.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/proved_batch.yul/proved_batch.yul.zbin index 26bb767d1b306421afbad07509e3e3e0b1e68f8c..95b84f683f6e03a80e721899a77d356009272b67 100644 GIT binary patch delta 77 zcmV-T0J8t!xdh<31h5189i>UDm*D1%`HP&nL?am*uLc?NozDb0?w`HwpTx5u`k*2p j;+hb%^|IhtXOqY8Od|2%F}_w+2jOSI7+3uauMb&WOfD!- delta 77 zcmV-T0J8t!xdh<31h5189kcSoroGjz0In&g%eyk%qr)Gz2(`^p`11v7I7hP}`k*2p jXc{9jR7OBR^0>~&a5T`->?Yn|vctJGM$vQ67&>EnJtHTy From 2a10e166302514e012dac958fd51a34a7ee43ab4 Mon Sep 17 00:00:00 2001 From: Nacho Avecilla Date: Wed, 14 Aug 2024 14:14:57 -0700 Subject: [PATCH 08/76] Add support for EVM contracts deployment (#231) * Update functions to support None address to deploy EVM contract * Update contracts submodule * Update compiled contracts for multivm bootloader * Add evm simulator code hash to the decommitment processor --- contracts | 2 +- .../system-constants-generator/src/utils.rs | 4 +- core/lib/dal/src/consensus/mod.rs | 16 +++- .../lib/dal/src/models/storage_transaction.rs | 12 ++- core/lib/dal/src/models/tests.rs | 2 +- core/lib/dal/src/tests/mod.rs | 6 +- core/lib/dal/src/transactions_dal.rs | 75 ++++++++++++++---- core/lib/env_config/src/chain.rs | 3 + core/lib/mempool/src/tests.rs | 4 +- .../src/versions/vm_1_3_2/test_utils.rs | 2 +- .../src/versions/vm_1_3_2/transaction_data.rs | 6 +- .../types/internals/transaction_data.rs | 6 +- .../types/internals/transaction_data.rs | 6 +- .../types/internals/transaction_data.rs | 6 +- .../src/versions/vm_fast/tests/code_oracle.rs | 8 +- .../vm_fast/tests/get_used_contracts.rs | 2 +- .../versions/vm_fast/tests/l1_tx_execution.rs | 2 +- .../src/versions/vm_fast/tests/l2_blocks.rs | 2 +- .../versions/vm_fast/tests/nonce_holder.rs | 2 +- .../src/versions/vm_fast/tests/refunds.rs | 4 +- .../versions/vm_fast/tests/require_eip712.rs | 4 +- .../src/versions/vm_fast/tests/rollbacks.rs | 4 +- .../src/versions/vm_fast/tests/sekp256r1.rs | 2 +- .../src/versions/vm_fast/tests/storage.rs | 4 +- .../vm_fast/tests/tracing_execution_error.rs | 2 +- .../src/versions/vm_fast/tests/transfer.rs | 6 +- .../src/versions/vm_fast/tests/upgrade.rs | 4 +- .../src/versions/vm_fast/transaction_data.rs | 6 +- .../src/versions/vm_latest/tests/block_tip.rs | 2 +- .../versions/vm_latest/tests/call_tracer.rs | 4 +- .../src/versions/vm_latest/tests/circuits.rs | 2 +- .../versions/vm_latest/tests/code_oracle.rs | 8 +- .../vm_latest/tests/get_used_contracts.rs | 2 +- .../vm_latest/tests/l1_tx_execution.rs | 2 +- .../versions/vm_latest/tests/nonce_holder.rs | 2 +- .../versions/vm_latest/tests/precompiles.rs | 6 +- .../vm_latest/tests/prestate_tracer.rs | 4 +- .../src/versions/vm_latest/tests/refunds.rs | 4 +- .../vm_latest/tests/require_eip712.rs | 4 +- .../src/versions/vm_latest/tests/rollbacks.rs | 4 +- .../src/versions/vm_latest/tests/sekp256r1.rs | 2 +- .../src/versions/vm_latest/tests/storage.rs | 2 +- .../tests/tracing_execution_error.rs | 2 +- .../src/versions/vm_latest/tests/transfer.rs | 6 +- .../src/versions/vm_latest/tests/upgrade.rs | 4 +- .../vm_latest/tracers/default_tracers.rs | 2 +- .../types/internals/transaction_data.rs | 15 +++- .../vm_latest/types/internals/vm_state.rs | 14 +++- .../src/versions/vm_latest/utils/mod.rs | 6 ++ .../multivm/src/versions/vm_m5/test_utils.rs | 2 +- .../src/versions/vm_m5/transaction_data.rs | 6 +- .../multivm/src/versions/vm_m6/test_utils.rs | 2 +- .../src/versions/vm_m6/transaction_data.rs | 6 +- .../types/internals/transaction_data.rs | 6 +- .../types/internals/transaction_data.rs | 6 +- core/lib/tee_verifier/src/lib.rs | 4 + core/lib/types/src/l1/mod.rs | 4 +- core/lib/types/src/l2/mod.rs | 6 +- core/lib/types/src/lib.rs | 8 +- core/lib/types/src/transaction_request.rs | 8 +- core/lib/types/src/tx/execute.rs | 9 ++- core/node/eth_watch/src/tests.rs | 5 +- core/node/proof_data_handler/src/tests.rs | 4 + .../src/batch_executor/tests/tester.rs | 4 +- core/node/state_keeper/src/testonly/mod.rs | 4 +- core/node/test_utils/src/lib.rs | 2 +- core/node/vm_runner/src/tests/mod.rs | 2 +- .../vm_runner/src/tests/output_handler.rs | 4 + .../src/sdk/operations/deploy_contract.rs | 4 +- .../src/sdk/operations/execute_contract.rs | 4 +- .../loadnext/src/sdk/operations/transfer.rs | 4 +- core/tests/loadnext/src/sdk/signer.rs | 8 +- core/tests/test_account/src/lib.rs | 8 +- core/tests/vm-benchmark/harness/src/lib.rs | 2 +- .../fee_estimate.yul/fee_estimate.yul.zbin | Bin 76320 -> 76256 bytes .../gas_test.yul/gas_test.yul.zbin | Bin 72416 -> 72352 bytes .../playground_batch.yul.zbin | Bin 76512 -> 76448 bytes .../proved_batch.yul/proved_batch.yul.zbin | Bin 72928 -> 72864 bytes 78 files changed, 262 insertions(+), 159 deletions(-) diff --git a/contracts b/contracts index 90e7043091b4..6b78beb8a268 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 90e7043091b4a00a5a2b1afe2da0877aa61e258b +Subproject commit 6b78beb8a268974362511fa1932b998cbe7b6a4d diff --git a/core/bin/system-constants-generator/src/utils.rs b/core/bin/system-constants-generator/src/utils.rs index 3f1ee892c890..e2f7b328bf1e 100644 --- a/core/bin/system-constants-generator/src/utils.rs +++ b/core/bin/system-constants-generator/src/utils.rs @@ -94,7 +94,7 @@ pub(super) fn get_l2_tx( pubdata_price: u32, ) -> L2Tx { L2Tx::new_signed( - contract_address, + Some(contract_address), vec![], Nonce(0), Fee { @@ -139,7 +139,7 @@ pub(super) fn get_l1_tx( ) -> L1Tx { L1Tx { execute: Execute { - contract_address, + contract_address: Some(contract_address), calldata: custom_calldata.unwrap_or_default(), value: U256::from(0), factory_deps, diff --git a/core/lib/dal/src/consensus/mod.rs b/core/lib/dal/src/consensus/mod.rs index 658da6c76821..5bc0bd0fc7e0 100644 --- a/core/lib/dal/src/consensus/mod.rs +++ b/core/lib/dal/src/consensus/mod.rs @@ -371,9 +371,11 @@ impl ProtoRepr for proto::Transaction { } }, execute: Execute { - contract_address: required(&execute.contract_address) - .and_then(|x| parse_h160(x)) - .context("execute.contract_address")?, + contract_address: Some( + required(&execute.contract_address) + .and_then(|x| parse_h160(x)) + .context("execute.contract_address")?, + ), calldata: required(&execute.calldata).context("calldata")?.clone(), value: required(&execute.value) .and_then(|x| parse_h256(x)) @@ -457,7 +459,13 @@ impl ProtoRepr for proto::Transaction { } }; let execute = proto::Execute { - contract_address: Some(this.execute.contract_address.as_bytes().into()), + contract_address: Some( + this.execute + .contract_address + .unwrap_or_default() + .as_bytes() + .into(), + ), calldata: Some(this.execute.calldata.clone()), value: Some(u256_to_h256(this.execute.value).as_bytes().into()), factory_deps: this.execute.factory_deps.clone(), diff --git a/core/lib/dal/src/models/storage_transaction.rs b/core/lib/dal/src/models/storage_transaction.rs index 31a182a7eca0..911dfad65852 100644 --- a/core/lib/dal/src/models/storage_transaction.rs +++ b/core/lib/dal/src/models/storage_transaction.rs @@ -364,11 +364,11 @@ impl From for TransactionReceipt { .transfer_to .or(storage_receipt.execute_contract_address) .map(|addr| { - serde_json::from_value::
(addr) + serde_json::from_value::>(addr) .expect("invalid address value in the database") }) // For better compatibility with various clients, we never return null. - .or_else(|| Some(Address::default())), + .flatten(), cumulative_gas_used: Default::default(), // TODO: Should be actually calculated (SMA-1183). gas_used: { let refunded_gas: U256 = storage_receipt.refunded_gas.into(); @@ -507,6 +507,12 @@ impl StorageApiTransaction { .signature .and_then(|signature| PackedEthSignature::deserialize_packed(&signature).ok()); + let to = if let Ok(address) = serde_json::from_value(self.execute_contract_address) { + Some(address) + } else { + Some(Address::zero()) + }; + let mut tx = api::Transaction { hash: H256::from_slice(&self.tx_hash), nonce: U256::from(self.nonce.unwrap_or(0) as u64), @@ -514,7 +520,7 @@ impl StorageApiTransaction { block_number: self.block_number.map(|number| U64::from(number as u64)), transaction_index: self.index_in_block.map(|idx| U64::from(idx as u64)), from: Some(Address::from_slice(&self.initiator_address)), - to: Some(serde_json::from_value(self.execute_contract_address).unwrap()), + to, value: bigdecimal_to_u256(self.value), gas_price: Some(bigdecimal_to_u256( self.effective_gas_price diff --git a/core/lib/dal/src/models/tests.rs b/core/lib/dal/src/models/tests.rs index 34cfde108f19..b4949dc101d6 100644 --- a/core/lib/dal/src/models/tests.rs +++ b/core/lib/dal/src/models/tests.rs @@ -13,7 +13,7 @@ use crate::{models::storage_transaction::StorageTransaction, BigDecimal}; fn default_execute() -> Execute { Execute { - contract_address: H160::random(), + contract_address: Some(H160::random()), value: U256::from(10i32), calldata: hex::decode( "a9059cbb00000000000000000000000058d595f318167d5af45d9e44ade4348dd4e\ diff --git a/core/lib/dal/src/tests/mod.rs b/core/lib/dal/src/tests/mod.rs index 497e8e6fa86b..7c8b8a9006ee 100644 --- a/core/lib/dal/src/tests/mod.rs +++ b/core/lib/dal/src/tests/mod.rs @@ -71,7 +71,7 @@ pub(crate) fn mock_l2_transaction() -> L2Tx { gas_per_pubdata_limit: U256::from(DEFAULT_GAS_PER_PUBDATA), }; let mut l2_tx = L2Tx::new_signed( - Address::random(), + Address::random().into(), vec![], zksync_types::Nonce(0), fee, @@ -107,7 +107,7 @@ pub(crate) fn mock_l1_execute() -> L1Tx { }; let execute = Execute { - contract_address: H160::random(), + contract_address: H160::random().into(), value: Default::default(), calldata: vec![], factory_deps: vec![], @@ -135,7 +135,7 @@ pub(crate) fn mock_protocol_upgrade_transaction() -> ProtocolUpgradeTx { }; let execute = Execute { - contract_address: H160::random(), + contract_address: H160::random().into(), value: Default::default(), calldata: vec![], factory_deps: vec![], diff --git a/core/lib/dal/src/transactions_dal.rs b/core/lib/dal/src/transactions_dal.rs index f76b61ec1646..083ef5af3629 100644 --- a/core/lib/dal/src/transactions_dal.rs +++ b/core/lib/dal/src/transactions_dal.rs @@ -61,7 +61,13 @@ impl TransactionsDal<'_, '_> { tx: &L1Tx, l1_block_number: L1BlockNumber, ) -> DalResult<()> { - let contract_address = tx.execute.contract_address.as_bytes(); + let contract_address = tx.execute.contract_address; + let unwrapped_contract_address = contract_address.unwrap_or_default(); + let contract_address_b: &[u8] = if contract_address.is_none() { + &[] + } else { + unwrapped_contract_address.as_bytes() + }; let tx_hash = tx.hash(); let tx_hash_bytes = tx_hash.as_bytes(); let json_data = serde_json::to_value(&tx.execute) @@ -146,7 +152,7 @@ impl TransactionsDal<'_, '_> { serial_id, full_fee, layer_2_tip_fee, - contract_address, + contract_address_b, l1_block_number.0 as i32, value, empty_address.as_bytes(), @@ -164,7 +170,13 @@ impl TransactionsDal<'_, '_> { } pub async fn insert_system_transaction(&mut self, tx: &ProtocolUpgradeTx) -> DalResult<()> { - let contract_address = tx.execute.contract_address.as_bytes().to_vec(); + let contract_address = tx.execute.contract_address; + let unwrapped_contract_address = contract_address.unwrap_or_default(); + let contract_address_b: &[u8] = if contract_address.is_none() { + &[] + } else { + unwrapped_contract_address.as_bytes() + }; let tx_hash = tx.common_data.hash().0.to_vec(); let json_data = serde_json::to_value(&tx.execute) .unwrap_or_else(|_| panic!("cannot serialize tx {:?} to json", tx.common_data.hash())); @@ -241,7 +253,7 @@ impl TransactionsDal<'_, '_> { gas_per_pubdata_limit, json_data, upgrade_id, - contract_address, + contract_address_b, l1_block_number, value, &Address::default().0.to_vec(), @@ -287,7 +299,13 @@ impl TransactionsDal<'_, '_> { } let initiator_address = tx.initiator_account(); - let contract_address = tx.execute.contract_address.as_bytes(); + let contract_address = tx.execute.contract_address; + let unwrapped_contract_address = contract_address.unwrap_or_default(); + let contract_address_b: &[u8] = if contract_address.is_none() { + &[] + } else { + unwrapped_contract_address.as_bytes() + }; let json_data = serde_json::to_value(&tx.execute) .unwrap_or_else(|_| panic!("cannot serialize tx {:?} to json", tx.hash())); let gas_limit = u256_to_big_decimal(tx.common_data.fee.gas_limit); @@ -416,7 +434,7 @@ impl TransactionsDal<'_, '_> { input_data, &json_data, tx_format, - contract_address, + contract_address_b, value, &paymaster, &paymaster_input, @@ -700,8 +718,15 @@ impl TransactionsDal<'_, '_> { .arg_error(&format!("transactions[{index_in_block}].refunded_gas"), err) })?; + let contract_address = transaction.execute.contract_address; + let unwrapped_contract_address = contract_address.unwrap_or_default(); + let contract_address_b: Vec = if contract_address.is_none() { + Vec::new() + } else { + unwrapped_contract_address.as_bytes().to_vec() + }; l2_values.push(u256_to_big_decimal(transaction.execute.value)); - l2_contract_addresses.push(transaction.execute.contract_address.as_bytes()); + l2_contract_addresses.push(contract_address_b); l2_paymaster_input.push(&common_data.paymaster_params.paymaster_input[..]); l2_paymaster.push(common_data.paymaster_params.paymaster.as_bytes()); l2_hashes.push(tx_res.hash.as_bytes()); @@ -821,7 +846,7 @@ impl TransactionsDal<'_, '_> { &l2_inputs as &[&[u8]], &l2_datas, &l2_tx_formats, - &l2_contract_addresses as &[&[u8]], + &l2_contract_addresses, &l2_values, &l2_paymaster as &[&[u8]], &l2_paymaster_input as &[&[u8]], @@ -904,8 +929,15 @@ impl TransactionsDal<'_, '_> { .arg_error(&format!("transactions[{index_in_block}].refunded_gas"), err) })?; + let contract_address = transaction.execute.contract_address; + let unwrapped_contract_address = contract_address.unwrap_or_default(); + let contract_address_b: Vec = if contract_address.is_none() { + Vec::new() + } else { + unwrapped_contract_address.as_bytes().to_vec() + }; l2_values.push(u256_to_big_decimal(transaction.execute.value)); - l2_contract_addresses.push(transaction.execute.contract_address.as_bytes()); + l2_contract_addresses.push(contract_address_b); l2_paymaster_input.push(&common_data.paymaster_params.paymaster_input[..]); l2_paymaster.push(common_data.paymaster_params.paymaster.as_bytes()); l2_hashes.push(tx_res.hash.as_bytes()); @@ -1016,7 +1048,7 @@ impl TransactionsDal<'_, '_> { &l2_datas, &l2_refunded_gas, &l2_values, - &l2_contract_addresses as &[&[u8]], + &l2_contract_addresses, &l2_paymaster as &[&[u8]], &l2_paymaster_input as &[&[u8]], l2_block_number.0 as i32, @@ -1086,6 +1118,13 @@ impl TransactionsDal<'_, '_> { .arg_error(&format!("transactions[{index_in_block}].refunded_gas"), err) })?; + let contract_address = transaction.execute.contract_address; + let unwrapped_contract_address = contract_address.unwrap_or_default(); + let contract_address_b: Vec = if contract_address.is_none() { + Vec::new() + } else { + unwrapped_contract_address.as_bytes().to_vec() + }; let tx = &tx_res.transaction; l1_hashes.push(tx_res.hash.as_bytes()); l1_initiator_address.push(common_data.sender.as_bytes()); @@ -1099,7 +1138,7 @@ impl TransactionsDal<'_, '_> { l1_priority_op_id.push(common_data.serial_id.0 as i64); l1_full_fee.push(u256_to_big_decimal(common_data.full_fee)); l1_layer_2_tip_fee.push(u256_to_big_decimal(common_data.layer_2_tip_fee)); - l1_contract_address.push(tx.execute.contract_address.as_bytes()); + l1_contract_address.push(contract_address_b); l1_l1_block_number.push(common_data.eth_block as i32); l1_value.push(u256_to_big_decimal(tx.execute.value)); l1_tx_format.push(common_data.tx_format() as i32); @@ -1206,7 +1245,7 @@ impl TransactionsDal<'_, '_> { &l1_priority_op_id, &l1_full_fee, &l1_layer_2_tip_fee, - &l1_contract_address as &[&[u8]], + &l1_contract_address, &l1_l1_block_number, &l1_value, &l1_tx_format, @@ -1376,6 +1415,14 @@ impl TransactionsDal<'_, '_> { .arg_error(&format!("transactions[{index_in_block}].refunded_gas"), err) })?; + let contract_address = transaction.execute.contract_address; + let unwrapped_contract_address = contract_address.unwrap_or_default(); + let contract_address_b: Vec = if contract_address.is_none() { + Vec::new() + } else { + unwrapped_contract_address.as_bytes().to_vec() + }; + let tx = &tx_res.transaction; upgrade_hashes.push(tx_res.hash.as_bytes()); upgrade_initiator_address.push(common_data.sender.as_bytes()); @@ -1388,7 +1435,7 @@ impl TransactionsDal<'_, '_> { .unwrap_or_else(|_| panic!("cannot serialize tx {:?} to json", tx.hash())), ); upgrade_upgrade_id.push(common_data.upgrade_id as i32); - upgrade_contract_address.push(tx.execute.contract_address.as_bytes()); + upgrade_contract_address.push(contract_address_b); upgrade_l1_block_number.push(common_data.eth_block as i32); upgrade_value.push(u256_to_big_decimal(tx.execute.value)); upgrade_tx_format.push(common_data.tx_format() as i32); @@ -1487,7 +1534,7 @@ impl TransactionsDal<'_, '_> { &upgrade_gas_per_pubdata_limit, &upgrade_data, &upgrade_upgrade_id, - &upgrade_contract_address as &[&[u8]], + &upgrade_contract_address, &upgrade_l1_block_number, &upgrade_value, &upgrade_tx_format, diff --git a/core/lib/env_config/src/chain.rs b/core/lib/env_config/src/chain.rs index f62f8b859caa..196f4bb8bd17 100644 --- a/core/lib/env_config/src/chain.rs +++ b/core/lib/env_config/src/chain.rs @@ -102,6 +102,9 @@ mod tests { default_aa_hash: Some(hash( "0x0100055b041eb28aff6e3a6e0f37c31fd053fc9ef142683b05e5f0aee6934066", )), + evm_simulator_hash: Some(hash( + "0x01000f197081a9906cc411d0698c4961aeb5c74877f37f7071681da6e8ef3f31", + )), l1_batch_commit_data_generator_mode, max_circuits_per_batch: 24100, protective_reads_persistence_enabled: true, diff --git a/core/lib/mempool/src/tests.rs b/core/lib/mempool/src/tests.rs index 6ea1be3b514b..4594e72f64ff 100644 --- a/core/lib/mempool/src/tests.rs +++ b/core/lib/mempool/src/tests.rs @@ -371,7 +371,7 @@ fn gen_l2_tx(address: Address, nonce: Nonce) -> Transaction { fn gen_l2_tx_with_timestamp(address: Address, nonce: Nonce, received_at_ms: u64) -> Transaction { let mut txn = L2Tx::new( - Address::default(), + Address::default().into(), Vec::new(), nonce, Fee::default(), @@ -386,7 +386,7 @@ fn gen_l2_tx_with_timestamp(address: Address, nonce: Nonce, received_at_ms: u64) fn gen_l1_tx(priority_id: PriorityOpId) -> Transaction { let execute = Execute { - contract_address: Address::repeat_byte(0x11), + contract_address: Address::repeat_byte(0x11).into(), calldata: vec![1, 2, 3], factory_deps: vec![], value: U256::zero(), diff --git a/core/lib/multivm/src/versions/vm_1_3_2/test_utils.rs b/core/lib/multivm/src/versions/vm_1_3_2/test_utils.rs index 603725790f8d..0193940e3595 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/test_utils.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/test_utils.rs @@ -153,7 +153,7 @@ pub fn get_create_execute(code: &[u8], calldata: &[u8]) -> Execute { .expect("failed to encode parameters"); Execute { - contract_address: CONTRACT_DEPLOYER_ADDRESS, + contract_address: Some(CONTRACT_DEPLOYER_ADDRESS), calldata, factory_deps: vec![code.to_vec()], value: U256::zero(), diff --git a/core/lib/multivm/src/versions/vm_1_3_2/transaction_data.rs b/core/lib/multivm/src/versions/vm_1_3_2/transaction_data.rs index 788a52206e80..00c4beabf39d 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/transaction_data.rs @@ -22,7 +22,7 @@ use crate::vm_1_3_2::vm_with_bootloader::{ pub struct TransactionData { pub tx_type: u8, pub from: Address, - pub to: Address, + pub to: Option
, pub gas_limit: U256, pub pubdata_price_limit: U256, pub max_fee_per_gas: U256, @@ -170,7 +170,7 @@ impl TransactionData { encode(&[Token::Tuple(vec![ Token::Uint(U256::from_big_endian(&self.tx_type.to_be_bytes())), Token::Address(self.from), - Token::Address(self.to), + Token::Address(self.to.unwrap_or_default()), Token::Uint(self.gas_limit), Token::Uint(self.pubdata_price_limit), Token::Uint(self.max_fee_per_gas), @@ -593,7 +593,7 @@ mod tests { let transaction = TransactionData { tx_type: 113, from: Address::random(), - to: Address::random(), + to: Address::random().into(), gas_limit: U256::from(1u32), pubdata_price_limit: U256::from(1u32), max_fee_per_gas: U256::from(1u32), diff --git a/core/lib/multivm/src/versions/vm_1_4_1/types/internals/transaction_data.rs b/core/lib/multivm/src/versions/vm_1_4_1/types/internals/transaction_data.rs index 1379b853a542..307d15164783 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/types/internals/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/types/internals/transaction_data.rs @@ -22,7 +22,7 @@ use crate::vm_1_4_1::{ pub(crate) struct TransactionData { pub(crate) tx_type: u8, pub(crate) from: Address, - pub(crate) to: Address, + pub(crate) to: Option
, pub(crate) gas_limit: U256, pub(crate) pubdata_price_limit: U256, pub(crate) max_fee_per_gas: U256, @@ -169,7 +169,7 @@ impl TransactionData { encode(&[Token::Tuple(vec![ Token::Uint(U256::from_big_endian(&self.tx_type.to_be_bytes())), Token::Address(self.from), - Token::Address(self.to), + Token::Address(self.to.unwrap_or_default()), Token::Uint(self.gas_limit), Token::Uint(self.pubdata_price_limit), Token::Uint(self.max_fee_per_gas), @@ -311,7 +311,7 @@ mod tests { let transaction = TransactionData { tx_type: 113, from: Address::random(), - to: Address::random(), + to: Address::random().into(), gas_limit: U256::from(1u32), pubdata_price_limit: U256::from(1u32), max_fee_per_gas: U256::from(1u32), diff --git a/core/lib/multivm/src/versions/vm_1_4_2/types/internals/transaction_data.rs b/core/lib/multivm/src/versions/vm_1_4_2/types/internals/transaction_data.rs index 3498e51ec308..b2e344a5458b 100644 --- a/core/lib/multivm/src/versions/vm_1_4_2/types/internals/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_1_4_2/types/internals/transaction_data.rs @@ -22,7 +22,7 @@ use crate::vm_1_4_2::{ pub(crate) struct TransactionData { pub(crate) tx_type: u8, pub(crate) from: Address, - pub(crate) to: Address, + pub(crate) to: Option
, pub(crate) gas_limit: U256, pub(crate) pubdata_price_limit: U256, pub(crate) max_fee_per_gas: U256, @@ -169,7 +169,7 @@ impl TransactionData { encode(&[Token::Tuple(vec![ Token::Uint(U256::from_big_endian(&self.tx_type.to_be_bytes())), Token::Address(self.from), - Token::Address(self.to), + Token::Address(self.to.unwrap_or_default()), Token::Uint(self.gas_limit), Token::Uint(self.pubdata_price_limit), Token::Uint(self.max_fee_per_gas), @@ -311,7 +311,7 @@ mod tests { let transaction = TransactionData { tx_type: 113, from: Address::random(), - to: Address::random(), + to: Address::random().into(), gas_limit: U256::from(1u32), pubdata_price_limit: U256::from(1u32), max_fee_per_gas: U256::from(1u32), diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/transaction_data.rs b/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/transaction_data.rs index ad740a279dcd..e00fbe8c71f9 100644 --- a/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/transaction_data.rs @@ -22,7 +22,7 @@ use crate::vm_boojum_integration::{ pub(crate) struct TransactionData { pub(crate) tx_type: u8, pub(crate) from: Address, - pub(crate) to: Address, + pub(crate) to: Option
, pub(crate) gas_limit: U256, pub(crate) pubdata_price_limit: U256, pub(crate) max_fee_per_gas: U256, @@ -169,7 +169,7 @@ impl TransactionData { encode(&[Token::Tuple(vec![ Token::Uint(U256::from_big_endian(&self.tx_type.to_be_bytes())), Token::Address(self.from), - Token::Address(self.to), + Token::Address(self.to.unwrap_or_default()), Token::Uint(self.gas_limit), Token::Uint(self.pubdata_price_limit), Token::Uint(self.max_fee_per_gas), @@ -325,7 +325,7 @@ mod tests { let transaction = TransactionData { tx_type: 113, from: Address::random(), - to: Address::random(), + to: Address::random().into(), gas_limit: U256::from(1u32), pubdata_price_limit: U256::from(1u32), max_fee_per_gas: U256::from(1u32), diff --git a/core/lib/multivm/src/versions/vm_fast/tests/code_oracle.rs b/core/lib/multivm/src/versions/vm_fast/tests/code_oracle.rs index 24fda3beed4b..ce57c7711d88 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/code_oracle.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/code_oracle.rs @@ -55,7 +55,7 @@ fn test_code_oracle() { // Firstly, let's ensure that the contract works. let tx1 = account.get_l2_tx_for_execute( Execute { - contract_address: precompiles_contract_address, + contract_address: Some(precompiles_contract_address), calldata: call_code_oracle_function .encode_input(&[ Token::FixedBytes(normal_zkevm_bytecode_hash.0.to_vec()), @@ -79,7 +79,7 @@ fn test_code_oracle() { // the decommitted bytecode gets erased (it shouldn't). let tx2 = account.get_l2_tx_for_execute( Execute { - contract_address: precompiles_contract_address, + contract_address: Some(precompiles_contract_address), calldata: call_code_oracle_function .encode_input(&[ Token::FixedBytes(normal_zkevm_bytecode_hash.0.to_vec()), @@ -149,7 +149,7 @@ fn test_code_oracle_big_bytecode() { // Firstly, let's ensure that the contract works. let tx1 = account.get_l2_tx_for_execute( Execute { - contract_address: precompiles_contract_address, + contract_address: Some(precompiles_contract_address), calldata: call_code_oracle_function .encode_input(&[ Token::FixedBytes(big_zkevm_bytecode_hash.0.to_vec()), @@ -217,7 +217,7 @@ fn refunds_in_code_oracle() { let tx = account.get_l2_tx_for_execute( Execute { - contract_address: precompiles_contract_address, + contract_address: Some(precompiles_contract_address), calldata: call_code_oracle_function .encode_input(&[ Token::FixedBytes(normal_zkevm_bytecode_hash.0.to_vec()), diff --git a/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs b/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs index af90566671ee..056b588382ad 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs @@ -60,7 +60,7 @@ fn test_get_used_contracts() { let account2 = Account::random(); let tx2 = account2.get_l1_tx( Execute { - contract_address: CONTRACT_DEPLOYER_ADDRESS, + contract_address: Some(CONTRACT_DEPLOYER_ADDRESS), calldata: big_calldata, value: Default::default(), factory_deps: vec![vec![1; 32]], diff --git a/core/lib/multivm/src/versions/vm_fast/tests/l1_tx_execution.rs b/core/lib/multivm/src/versions/vm_fast/tests/l1_tx_execution.rs index 033a7b2658fa..ed2f7cacd9e0 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/l1_tx_execution.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/l1_tx_execution.rs @@ -176,7 +176,7 @@ fn test_l1_tx_execution_high_gas_limit() { let mut tx = account.get_l1_tx( Execute { - contract_address: L1_MESSENGER_ADDRESS, + contract_address: Some(L1_MESSENGER_ADDRESS), value: 0.into(), factory_deps: vec![], calldata, diff --git a/core/lib/multivm/src/versions/vm_fast/tests/l2_blocks.rs b/core/lib/multivm/src/versions/vm_fast/tests/l2_blocks.rs index 1f9d0aaff091..c92f29ee3e07 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/l2_blocks.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/l2_blocks.rs @@ -35,7 +35,7 @@ fn get_l1_noop() -> Transaction { ..Default::default() }), execute: Execute { - contract_address: H160::zero(), + contract_address: Some(H160::zero()), calldata: vec![], value: U256::zero(), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_fast/tests/nonce_holder.rs b/core/lib/multivm/src/versions/vm_fast/tests/nonce_holder.rs index b18676cf2ba6..6e3d507555cf 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/nonce_holder.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/nonce_holder.rs @@ -59,7 +59,7 @@ fn test_nonce_holder() { vm.reset_state(true); let mut transaction = account.get_l2_tx_for_execute_with_nonce( Execute { - contract_address: account.address, + contract_address: Some(account.address), calldata: vec![12], value: Default::default(), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_fast/tests/refunds.rs b/core/lib/multivm/src/versions/vm_fast/tests/refunds.rs index 21a3129a3a61..98c9bd3dd3d1 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/refunds.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/refunds.rs @@ -181,7 +181,7 @@ fn negative_pubdata_for_transaction() { let expensive_tx = vm.rich_accounts[0].get_l2_tx_for_execute( Execute { - contract_address: expensive_contract_address, + contract_address: Some(expensive_contract_address), calldata: expensive_function .encode_input(&[Token::Uint(10.into())]) .unwrap(), @@ -200,7 +200,7 @@ fn negative_pubdata_for_transaction() { // This transaction cleans all initial writes in the contract, thus having negative `pubdata` impact. let clean_up_tx = vm.rich_accounts[0].get_l2_tx_for_execute( Execute { - contract_address: expensive_contract_address, + contract_address: Some(expensive_contract_address), calldata: cleanup_function.encode_input(&[]).unwrap(), value: U256::zero(), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_fast/tests/require_eip712.rs b/core/lib/multivm/src/versions/vm_fast/tests/require_eip712.rs index 7e378a2b62c4..c5de3953e019 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/require_eip712.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/require_eip712.rs @@ -67,7 +67,7 @@ async fn test_require_eip712() { let tx = private_account.get_l2_tx_for_execute( Execute { - contract_address: account_abstraction.address, + contract_address: Some(account_abstraction.address), calldata: encoded_input, value: Default::default(), factory_deps: vec![], @@ -124,7 +124,7 @@ async fn test_require_eip712() { // // Now send the 'classic' EIP712 transaction let tx_712 = L2Tx::new( - beneficiary.address, + Some(beneficiary.address), vec![], Nonce(1), Fee { diff --git a/core/lib/multivm/src/versions/vm_fast/tests/rollbacks.rs b/core/lib/multivm/src/versions/vm_fast/tests/rollbacks.rs index c530c5af18ea..4419aaeedfaa 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/rollbacks.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/rollbacks.rs @@ -83,7 +83,7 @@ fn test_vm_loadnext_rollbacks() { let loadnext_tx_1 = account.get_l2_tx_for_execute( Execute { - contract_address: address, + contract_address: Some(address), calldata: LoadnextContractExecutionParams { reads: 100, writes: 100, @@ -101,7 +101,7 @@ fn test_vm_loadnext_rollbacks() { let loadnext_tx_2 = account.get_l2_tx_for_execute( Execute { - contract_address: address, + contract_address: Some(address), calldata: LoadnextContractExecutionParams { reads: 100, writes: 100, diff --git a/core/lib/multivm/src/versions/vm_fast/tests/sekp256r1.rs b/core/lib/multivm/src/versions/vm_fast/tests/sekp256r1.rs index 1e761b30ca62..9c7c4777fc32 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/sekp256r1.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/sekp256r1.rs @@ -49,7 +49,7 @@ fn test_sekp256r1() { let tx = account.get_l2_tx_for_execute( Execute { - contract_address: P256VERIFY_PRECOMPILE_ADDRESS, + contract_address: Some(P256VERIFY_PRECOMPILE_ADDRESS), calldata: [digest, encoded_r, encoded_s, x, y].concat(), value: U256::zero(), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_fast/tests/storage.rs b/core/lib/multivm/src/versions/vm_fast/tests/storage.rs index 733ce1f0618c..6dfaf19103df 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/storage.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/storage.rs @@ -28,7 +28,7 @@ fn test_storage(first_tx_calldata: Vec, second_tx_calldata: Vec) -> u32 let tx1 = account.get_l2_tx_for_execute( Execute { - contract_address: test_contract_address, + contract_address: Some(test_contract_address), calldata: first_tx_calldata, value: 0.into(), factory_deps: vec![], @@ -38,7 +38,7 @@ fn test_storage(first_tx_calldata: Vec, second_tx_calldata: Vec) -> u32 let tx2 = account.get_l2_tx_for_execute( Execute { - contract_address: test_contract_address, + contract_address: Some(test_contract_address), calldata: second_tx_calldata, value: 0.into(), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_fast/tests/tracing_execution_error.rs b/core/lib/multivm/src/versions/vm_fast/tests/tracing_execution_error.rs index 75144839006e..efa64ea17708 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/tracing_execution_error.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/tracing_execution_error.rs @@ -24,7 +24,7 @@ fn test_tracing_of_execution_errors() { let tx = account.get_l2_tx_for_execute( Execute { - contract_address, + contract_address: Some(contract_address), calldata: get_execute_error_calldata(), value: Default::default(), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_fast/tests/transfer.rs b/core/lib/multivm/src/versions/vm_fast/tests/transfer.rs index 3b61b8ac7f1e..683797d6a026 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/transfer.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/transfer.rs @@ -70,7 +70,7 @@ fn test_send_or_transfer(test_option: TestOptions) { let account = &mut vm.rich_accounts[0]; let tx = account.get_l2_tx_for_execute( Execute { - contract_address: test_contract_address, + contract_address: Some(test_contract_address), calldata, value: U256::zero(), factory_deps: vec![], @@ -167,7 +167,7 @@ fn test_reentrancy_protection_send_or_transfer(test_option: TestOptions) { let account = &mut vm.rich_accounts[0]; let tx1 = account.get_l2_tx_for_execute( Execute { - contract_address: reentrant_recipeint_address, + contract_address: Some(reentrant_recipeint_address), calldata: reentrant_recipient_abi .function("setX") .unwrap() @@ -188,7 +188,7 @@ fn test_reentrancy_protection_send_or_transfer(test_option: TestOptions) { let tx2 = account.get_l2_tx_for_execute( Execute { - contract_address: test_contract_address, + contract_address: Some(test_contract_address), calldata, value, factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_fast/tests/upgrade.rs b/core/lib/multivm/src/versions/vm_fast/tests/upgrade.rs index 616436776090..2a211640c759 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/upgrade.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/upgrade.rs @@ -265,7 +265,7 @@ fn get_forced_deploy_tx(deployment: &[ForceDeployment]) -> Transaction { .expect("failed to encode parameters"); let execute = Execute { - contract_address: CONTRACT_DEPLOYER_ADDRESS, + contract_address: Some(CONTRACT_DEPLOYER_ADDRESS), calldata, factory_deps: vec![], value: U256::zero(), @@ -315,7 +315,7 @@ fn get_complex_upgrade_tx( .unwrap(); let execute = Execute { - contract_address: COMPLEX_UPGRADER_ADDRESS, + contract_address: Some(COMPLEX_UPGRADER_ADDRESS), calldata: complex_upgrader_calldata, factory_deps: vec![], value: U256::zero(), diff --git a/core/lib/multivm/src/versions/vm_fast/transaction_data.rs b/core/lib/multivm/src/versions/vm_fast/transaction_data.rs index 502be0dc22cc..9ebfbea3ac2b 100644 --- a/core/lib/multivm/src/versions/vm_fast/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_fast/transaction_data.rs @@ -22,7 +22,7 @@ use crate::vm_latest::{ pub(crate) struct TransactionData { pub(crate) tx_type: u8, pub(crate) from: Address, - pub(crate) to: Address, + pub(crate) to: Option
, pub(crate) gas_limit: U256, pub(crate) pubdata_price_limit: U256, pub(crate) max_fee_per_gas: U256, @@ -169,7 +169,7 @@ impl TransactionData { encode(&[Token::Tuple(vec![ Token::Uint(U256::from_big_endian(&self.tx_type.to_be_bytes())), Token::Address(self.from), - Token::Address(self.to), + Token::Address(self.to.unwrap_or_default()), Token::Uint(self.gas_limit), Token::Uint(self.pubdata_price_limit), Token::Uint(self.max_fee_per_gas), @@ -305,7 +305,7 @@ mod tests { let transaction = TransactionData { tx_type: 113, from: Address::random(), - to: Address::random(), + to: Address::random().into(), gas_limit: U256::from(1u32), pubdata_price_limit: U256::from(1u32), max_fee_per_gas: U256::from(1u32), diff --git a/core/lib/multivm/src/versions/vm_latest/tests/block_tip.rs b/core/lib/multivm/src/versions/vm_latest/tests/block_tip.rs index 78136602dae2..0503710c7942 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/block_tip.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/block_tip.rs @@ -164,7 +164,7 @@ fn execute_test(test_data: L1MessengerTestData) -> TestStatistics { for (i, data) in txs_data.into_iter().enumerate() { let tx = account.get_l2_tx_for_execute( Execute { - contract_address: CONTRACT_FORCE_DEPLOYER_ADDRESS, + contract_address: Some(CONTRACT_FORCE_DEPLOYER_ADDRESS), calldata: data, value: U256::zero(), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_latest/tests/call_tracer.rs b/core/lib/multivm/src/versions/vm_latest/tests/call_tracer.rs index a4d0eb2d17e2..df7a78855426 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/call_tracer.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/call_tracer.rs @@ -34,7 +34,7 @@ fn test_max_depth() { let account = &mut vm.rich_accounts[0]; let tx = account.get_l2_tx_for_execute( Execute { - contract_address: address, + contract_address: Some(address), calldata: vec![], value: Default::default(), factory_deps: vec![], @@ -69,7 +69,7 @@ fn test_basic_behavior() { let account = &mut vm.rich_accounts[0]; let tx = account.get_l2_tx_for_execute( Execute { - contract_address: address, + contract_address: Some(address), calldata: hex::decode(increment_by_6_calldata).unwrap(), value: Default::default(), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_latest/tests/circuits.rs b/core/lib/multivm/src/versions/vm_latest/tests/circuits.rs index 02ec2dc58aaa..35412ee4d1bd 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/circuits.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/circuits.rs @@ -22,7 +22,7 @@ fn test_circuits() { let account = &mut vm.rich_accounts[0]; let tx = account.get_l2_tx_for_execute( Execute { - contract_address: Address::random(), + contract_address: Some(Address::random()), calldata: Vec::new(), value: U256::from(1u8), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_latest/tests/code_oracle.rs b/core/lib/multivm/src/versions/vm_latest/tests/code_oracle.rs index 7174e9be67de..63a1069ad47d 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/code_oracle.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/code_oracle.rs @@ -69,7 +69,7 @@ fn test_code_oracle() { // Firstly, let's ensure that the contract works. let tx1 = account.get_l2_tx_for_execute( Execute { - contract_address: precompiles_contract_address, + contract_address: Some(precompiles_contract_address), calldata: call_code_oracle_function .encode_input(&[ Token::FixedBytes(normal_zkevm_bytecode_hash.0.to_vec()), @@ -93,7 +93,7 @@ fn test_code_oracle() { // the decommitted bytecode gets erased (it shouldn't). let tx2 = account.get_l2_tx_for_execute( Execute { - contract_address: precompiles_contract_address, + contract_address: Some(precompiles_contract_address), calldata: call_code_oracle_function .encode_input(&[ Token::FixedBytes(normal_zkevm_bytecode_hash.0.to_vec()), @@ -169,7 +169,7 @@ fn test_code_oracle_big_bytecode() { // Firstly, let's ensure that the contract works. let tx1 = account.get_l2_tx_for_execute( Execute { - contract_address: precompiles_contract_address, + contract_address: Some(precompiles_contract_address), calldata: call_code_oracle_function .encode_input(&[ Token::FixedBytes(big_zkevm_bytecode_hash.0.to_vec()), @@ -251,7 +251,7 @@ fn refunds_in_code_oracle() { let tx = account.get_l2_tx_for_execute( Execute { - contract_address: precompiles_contract_address, + contract_address: Some(precompiles_contract_address), calldata: call_code_oracle_function .encode_input(&[ Token::FixedBytes(normal_zkevm_bytecode_hash.0.to_vec()), diff --git a/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs b/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs index 1798c700ea2d..782762577c36 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs @@ -75,7 +75,7 @@ fn test_get_used_contracts() { let account2 = Account::random(); let tx2 = account2.get_l1_tx( Execute { - contract_address: CONTRACT_DEPLOYER_ADDRESS, + contract_address: Some(CONTRACT_DEPLOYER_ADDRESS), calldata: big_calldata, value: Default::default(), factory_deps: vec![vec![1; 32]], diff --git a/core/lib/multivm/src/versions/vm_latest/tests/l1_tx_execution.rs b/core/lib/multivm/src/versions/vm_latest/tests/l1_tx_execution.rs index 6b3be989fb3a..cbed159db644 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/l1_tx_execution.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/l1_tx_execution.rs @@ -173,7 +173,7 @@ fn test_l1_tx_execution_high_gas_limit() { let mut tx = account.get_l1_tx( Execute { - contract_address: L1_MESSENGER_ADDRESS, + contract_address: Some(L1_MESSENGER_ADDRESS), value: 0.into(), factory_deps: vec![], calldata, diff --git a/core/lib/multivm/src/versions/vm_latest/tests/nonce_holder.rs b/core/lib/multivm/src/versions/vm_latest/tests/nonce_holder.rs index 076ecb523618..ea11dd01818e 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/nonce_holder.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/nonce_holder.rs @@ -64,7 +64,7 @@ fn test_nonce_holder() { let mut transaction_data: TransactionData = account .get_l2_tx_for_execute_with_nonce( Execute { - contract_address: account.address, + contract_address: Some(account.address), calldata: vec![12], value: Default::default(), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_latest/tests/precompiles.rs b/core/lib/multivm/src/versions/vm_latest/tests/precompiles.rs index 2ab40faf22ca..9388d0161846 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/precompiles.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/precompiles.rs @@ -31,7 +31,7 @@ fn test_keccak() { let account = &mut vm.rich_accounts[0]; let tx = account.get_l2_tx_for_execute( Execute { - contract_address: address, + contract_address: Some(address), calldata: hex::decode(keccak1000_calldata).unwrap(), value: Default::default(), factory_deps: vec![], @@ -75,7 +75,7 @@ fn test_sha256() { let account = &mut vm.rich_accounts[0]; let tx = account.get_l2_tx_for_execute( Execute { - contract_address: address, + contract_address: Some(address), calldata: hex::decode(sha1000_calldata).unwrap(), value: Default::default(), factory_deps: vec![], @@ -112,7 +112,7 @@ fn test_ecrecover() { let account = &mut vm.rich_accounts[0]; let tx = account.get_l2_tx_for_execute( Execute { - contract_address: account.address, + contract_address: Some(account.address), calldata: Vec::new(), value: Default::default(), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_latest/tests/prestate_tracer.rs b/core/lib/multivm/src/versions/vm_latest/tests/prestate_tracer.rs index 893ca57bc4d1..2d1ac098ba08 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/prestate_tracer.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/prestate_tracer.rs @@ -88,7 +88,7 @@ fn test_prestate_tracer_diff_mode() { //enter ether to contract to see difference in the balance post execution let tx0 = Execute { - contract_address: vm.test_contract.unwrap(), + contract_address: Some(vm.test_contract.unwrap()), calldata: Default::default(), value: U256::from(100000), factory_deps: vec![], @@ -98,7 +98,7 @@ fn test_prestate_tracer_diff_mode() { .push_transaction(account.get_l2_tx_for_execute(tx0.clone(), None)); let tx1 = Execute { - contract_address: deployed_address2, + contract_address: Some(deployed_address2), calldata: Default::default(), value: U256::from(200000), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_latest/tests/refunds.rs b/core/lib/multivm/src/versions/vm_latest/tests/refunds.rs index 52dbd6efb339..2c54ae4c4109 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/refunds.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/refunds.rs @@ -188,7 +188,7 @@ fn negative_pubdata_for_transaction() { let expensive_tx = vm.rich_accounts[0].get_l2_tx_for_execute( Execute { - contract_address: expensive_contract_address, + contract_address: Some(expensive_contract_address), calldata: expensive_function .encode_input(&[Token::Uint(10.into())]) .unwrap(), @@ -207,7 +207,7 @@ fn negative_pubdata_for_transaction() { // This transaction cleans all initial writes in the contract, thus having negative `pubdata` impact. let clean_up_tx = vm.rich_accounts[0].get_l2_tx_for_execute( Execute { - contract_address: expensive_contract_address, + contract_address: Some(expensive_contract_address), calldata: cleanup_function.encode_input(&[]).unwrap(), value: U256::zero(), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_latest/tests/require_eip712.rs b/core/lib/multivm/src/versions/vm_latest/tests/require_eip712.rs index 5178c5dc29cf..674bbe4ef6e7 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/require_eip712.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/require_eip712.rs @@ -63,7 +63,7 @@ async fn test_require_eip712() { let tx = private_account.get_l2_tx_for_execute( Execute { - contract_address: account_abstraction.address, + contract_address: Some(account_abstraction.address), calldata: encoded_input, value: Default::default(), factory_deps: vec![], @@ -120,7 +120,7 @@ async fn test_require_eip712() { // // Now send the 'classic' EIP712 transaction let tx_712 = L2Tx::new( - beneficiary.address, + Some(beneficiary.address), vec![], Nonce(1), Fee { diff --git a/core/lib/multivm/src/versions/vm_latest/tests/rollbacks.rs b/core/lib/multivm/src/versions/vm_latest/tests/rollbacks.rs index e0c3ec4157dc..13f88b487370 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/rollbacks.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/rollbacks.rs @@ -92,7 +92,7 @@ fn test_vm_loadnext_rollbacks() { let loadnext_tx_1 = account.get_l2_tx_for_execute( Execute { - contract_address: address, + contract_address: Some(address), calldata: LoadnextContractExecutionParams { reads: 100, writes: 100, @@ -110,7 +110,7 @@ fn test_vm_loadnext_rollbacks() { let loadnext_tx_2 = account.get_l2_tx_for_execute( Execute { - contract_address: address, + contract_address: Some(address), calldata: LoadnextContractExecutionParams { reads: 100, writes: 100, diff --git a/core/lib/multivm/src/versions/vm_latest/tests/sekp256r1.rs b/core/lib/multivm/src/versions/vm_latest/tests/sekp256r1.rs index 07b25eb0a8b0..17a41cd0e8e5 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/sekp256r1.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/sekp256r1.rs @@ -48,7 +48,7 @@ fn test_sekp256r1() { let tx = account.get_l2_tx_for_execute( Execute { - contract_address: P256VERIFY_PRECOMPILE_ADDRESS, + contract_address: Some(P256VERIFY_PRECOMPILE_ADDRESS), calldata: [digest, encoded_r, encoded_s, x, y].concat(), value: U256::zero(), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_latest/tests/storage.rs b/core/lib/multivm/src/versions/vm_latest/tests/storage.rs index b7c14c54f6df..ac55776e4a11 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/storage.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/storage.rs @@ -48,7 +48,7 @@ fn test_storage(txs: Vec) -> u32 { let tx = account.get_l2_tx_for_execute( Execute { - contract_address: test_contract_address, + contract_address: Some(test_contract_address), calldata, value: 0.into(), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_latest/tests/tracing_execution_error.rs b/core/lib/multivm/src/versions/vm_latest/tests/tracing_execution_error.rs index 58c5ef77dc42..2db37881352f 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/tracing_execution_error.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/tracing_execution_error.rs @@ -27,7 +27,7 @@ fn test_tracing_of_execution_errors() { let tx = account.get_l2_tx_for_execute( Execute { - contract_address, + contract_address: Some(contract_address), calldata: get_execute_error_calldata(), value: Default::default(), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_latest/tests/transfer.rs b/core/lib/multivm/src/versions/vm_latest/tests/transfer.rs index f4198d541f73..46a18ef87ca4 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/transfer.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/transfer.rs @@ -73,7 +73,7 @@ fn test_send_or_transfer(test_option: TestOptions) { let account = &mut vm.rich_accounts[0]; let tx = account.get_l2_tx_for_execute( Execute { - contract_address: test_contract_address, + contract_address: Some(test_contract_address), calldata, value: U256::zero(), factory_deps: vec![], @@ -169,7 +169,7 @@ fn test_reentrancy_protection_send_or_transfer(test_option: TestOptions) { let account = &mut vm.rich_accounts[0]; let tx1 = account.get_l2_tx_for_execute( Execute { - contract_address: reentrant_recipeint_address, + contract_address: Some(reentrant_recipeint_address), calldata: reentrant_recipient_abi .function("setX") .unwrap() @@ -190,7 +190,7 @@ fn test_reentrancy_protection_send_or_transfer(test_option: TestOptions) { let tx2 = account.get_l2_tx_for_execute( Execute { - contract_address: test_contract_address, + contract_address: Some(test_contract_address), calldata, value, factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_latest/tests/upgrade.rs b/core/lib/multivm/src/versions/vm_latest/tests/upgrade.rs index 80e16248fb2d..3c935f782061 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/upgrade.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/upgrade.rs @@ -277,7 +277,7 @@ fn get_forced_deploy_tx(deployment: &[ForceDeployment]) -> Transaction { .expect("failed to encode parameters"); let execute = Execute { - contract_address: CONTRACT_DEPLOYER_ADDRESS, + contract_address: Some(CONTRACT_DEPLOYER_ADDRESS), calldata, factory_deps: vec![], value: U256::zero(), @@ -327,7 +327,7 @@ fn get_complex_upgrade_tx( .unwrap(); let execute = Execute { - contract_address: COMPLEX_UPGRADER_ADDRESS, + contract_address: Some(COMPLEX_UPGRADER_ADDRESS), calldata: complex_upgrader_calldata, factory_deps: vec![], value: U256::zero(), diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs b/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs index 988abec7d156..4c00e7dbf771 100755 --- a/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs @@ -39,7 +39,7 @@ use crate::{ }; /// Default tracer for the VM. It manages the other tracers execution and stop the vm when needed. -pub(crate) struct DefaultExecutionTracer { +pub struct DefaultExecutionTracer { tx_has_been_processed: bool, execution_mode: VmExecutionMode, diff --git a/core/lib/multivm/src/versions/vm_latest/types/internals/transaction_data.rs b/core/lib/multivm/src/versions/vm_latest/types/internals/transaction_data.rs index 502be0dc22cc..2fa939d9a136 100644 --- a/core/lib/multivm/src/versions/vm_latest/types/internals/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_latest/types/internals/transaction_data.rs @@ -22,7 +22,7 @@ use crate::vm_latest::{ pub(crate) struct TransactionData { pub(crate) tx_type: u8, pub(crate) from: Address, - pub(crate) to: Address, + pub(crate) to: Option
, pub(crate) gas_limit: U256, pub(crate) pubdata_price_limit: U256, pub(crate) max_fee_per_gas: U256, @@ -62,6 +62,13 @@ impl From for TransactionData { U256::zero() }; + let should_deploy_contract = if execute_tx.execute.contract_address.is_none() { + println!("DEPLOYING"); + U256([1, 0, 0, 0]) + } else { + U256::zero() + }; + // Ethereum transactions do not sign gas per pubdata limit, and so for them we need to use // some default value. We use the maximum possible value that is allowed by the bootloader // (i.e. we can not use u64::MAX, because the bootloader requires gas per pubdata for such @@ -85,7 +92,7 @@ impl From for TransactionData { value: execute_tx.execute.value, reserved: [ should_check_chain_id, - U256::zero(), + should_deploy_contract, U256::zero(), U256::zero(), ], @@ -169,7 +176,7 @@ impl TransactionData { encode(&[Token::Tuple(vec![ Token::Uint(U256::from_big_endian(&self.tx_type.to_be_bytes())), Token::Address(self.from), - Token::Address(self.to), + Token::Address(self.to.unwrap_or_default()), Token::Uint(self.gas_limit), Token::Uint(self.pubdata_price_limit), Token::Uint(self.max_fee_per_gas), @@ -305,7 +312,7 @@ mod tests { let transaction = TransactionData { tx_type: 113, from: Address::random(), - to: Address::random(), + to: Address::random().into(), gas_limit: U256::from(1u32), pubdata_price_limit: U256::from(1u32), max_fee_per_gas: U256::from(1u32), diff --git a/core/lib/multivm/src/versions/vm_latest/types/internals/vm_state.rs b/core/lib/multivm/src/versions/vm_latest/types/internals/vm_state.rs index b9ac0bfad229..cea875f48d10 100644 --- a/core/lib/multivm/src/versions/vm_latest/types/internals/vm_state.rs +++ b/core/lib/multivm/src/versions/vm_latest/types/internals/vm_state.rs @@ -96,6 +96,18 @@ pub(crate) fn new_vm_state( Timestamp(0), ); + decommittment_processor.populate( + vec![( + h256_to_u256(system_env.base_system_smart_contracts.evm_simulator.hash), + system_env + .base_system_smart_contracts + .evm_simulator + .code + .clone(), + )], + Timestamp(0), + ); + memory.populate( vec![( BOOTLOADER_CODE_PAGE, @@ -129,7 +141,7 @@ pub(crate) fn new_vm_state( // For now, the default account hash is used as the code hash for the EVM simulator. // In the 1.5.0 version, it is not possible to instantiate EVM bytecode. evm_simulator_code_hash: h256_to_u256( - system_env.base_system_smart_contracts.default_aa.hash, + system_env.base_system_smart_contracts.evm_simulator.hash, ), zkporter_is_available: system_env.zk_porter_available, }, diff --git a/core/lib/multivm/src/versions/vm_latest/utils/mod.rs b/core/lib/multivm/src/versions/vm_latest/utils/mod.rs index 0fb803de5d4e..521a2955dcd6 100644 --- a/core/lib/multivm/src/versions/vm_latest/utils/mod.rs +++ b/core/lib/multivm/src/versions/vm_latest/utils/mod.rs @@ -1,6 +1,12 @@ +use zk_evm_1_5_0::aux_structures::MemoryPage; + /// Utility functions for the VM. pub mod fee; pub mod l2_blocks; pub(crate) mod logs; pub mod overhead; pub mod transaction_encoding; + +pub const fn heap_page_from_base(base: MemoryPage) -> MemoryPage { + MemoryPage(base.0 + 2) +} diff --git a/core/lib/multivm/src/versions/vm_m5/test_utils.rs b/core/lib/multivm/src/versions/vm_m5/test_utils.rs index 785eb49835f1..d7c0dfb9f6d0 100644 --- a/core/lib/multivm/src/versions/vm_m5/test_utils.rs +++ b/core/lib/multivm/src/versions/vm_m5/test_utils.rs @@ -151,7 +151,7 @@ pub fn get_create_execute(code: &[u8], calldata: &[u8]) -> Execute { .expect("failed to encode parameters"); Execute { - contract_address: CONTRACT_DEPLOYER_ADDRESS, + contract_address: Some(CONTRACT_DEPLOYER_ADDRESS), calldata, factory_deps: vec![code.to_vec()], value: U256::zero(), diff --git a/core/lib/multivm/src/versions/vm_m5/transaction_data.rs b/core/lib/multivm/src/versions/vm_m5/transaction_data.rs index 7ef739fd5bf5..22fec0362c50 100644 --- a/core/lib/multivm/src/versions/vm_m5/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_m5/transaction_data.rs @@ -22,7 +22,7 @@ const L1_TX_TYPE: u8 = 255; pub struct TransactionData { pub tx_type: u8, pub from: Address, - pub to: Address, + pub to: Option
, pub gas_limit: U256, pub pubdata_price_limit: U256, pub max_fee_per_gas: U256, @@ -144,7 +144,7 @@ impl TransactionData { encode(&[Token::Tuple(vec![ Token::Uint(U256::from_big_endian(&self.tx_type.to_be_bytes())), Token::Address(self.from), - Token::Address(self.to), + Token::Address(self.to.unwrap_or_default()), Token::Uint(self.gas_limit), Token::Uint(self.pubdata_price_limit), Token::Uint(self.max_fee_per_gas), @@ -479,7 +479,7 @@ mod tests { let transaction = TransactionData { tx_type: 113, from: Address::random(), - to: Address::random(), + to: Address::random().into(), gas_limit: U256::from(1u32), pubdata_price_limit: U256::from(1u32), max_fee_per_gas: U256::from(1u32), diff --git a/core/lib/multivm/src/versions/vm_m6/test_utils.rs b/core/lib/multivm/src/versions/vm_m6/test_utils.rs index ecad7d911b40..4bd39bc56dd4 100644 --- a/core/lib/multivm/src/versions/vm_m6/test_utils.rs +++ b/core/lib/multivm/src/versions/vm_m6/test_utils.rs @@ -151,7 +151,7 @@ pub fn get_create_execute(code: &[u8], calldata: &[u8]) -> Execute { .expect("failed to encode parameters"); Execute { - contract_address: CONTRACT_DEPLOYER_ADDRESS, + contract_address: Some(CONTRACT_DEPLOYER_ADDRESS), calldata, factory_deps: vec![code.to_vec()], value: U256::zero(), diff --git a/core/lib/multivm/src/versions/vm_m6/transaction_data.rs b/core/lib/multivm/src/versions/vm_m6/transaction_data.rs index 99ce4671c29b..91e6839e5d5f 100644 --- a/core/lib/multivm/src/versions/vm_m6/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_m6/transaction_data.rs @@ -23,7 +23,7 @@ pub(crate) const L1_TX_TYPE: u8 = 255; pub struct TransactionData { pub tx_type: u8, pub from: Address, - pub to: Address, + pub to: Option
, pub gas_limit: U256, pub pubdata_price_limit: U256, pub max_fee_per_gas: U256, @@ -171,7 +171,7 @@ impl TransactionData { encode(&[Token::Tuple(vec![ Token::Uint(U256::from_big_endian(&self.tx_type.to_be_bytes())), Token::Address(self.from), - Token::Address(self.to), + Token::Address(self.to.unwrap_or_default()), Token::Uint(self.gas_limit), Token::Uint(self.pubdata_price_limit), Token::Uint(self.max_fee_per_gas), @@ -592,7 +592,7 @@ mod tests { let transaction = TransactionData { tx_type: 113, from: Address::random(), - to: Address::random(), + to: Address::random().into(), gas_limit: U256::from(1u32), pubdata_price_limit: U256::from(1u32), max_fee_per_gas: U256::from(1u32), diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/types/internals/transaction_data.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/types/internals/transaction_data.rs index 205090ba633e..59a52569e306 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/types/internals/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/types/internals/transaction_data.rs @@ -22,7 +22,7 @@ use crate::vm_refunds_enhancement::{ pub(crate) struct TransactionData { pub(crate) tx_type: u8, pub(crate) from: Address, - pub(crate) to: Address, + pub(crate) to: Option
, pub(crate) gas_limit: U256, pub(crate) pubdata_price_limit: U256, pub(crate) max_fee_per_gas: U256, @@ -169,7 +169,7 @@ impl TransactionData { encode(&[Token::Tuple(vec![ Token::Uint(U256::from_big_endian(&self.tx_type.to_be_bytes())), Token::Address(self.from), - Token::Address(self.to), + Token::Address(self.to.unwrap_or_default()), Token::Uint(self.gas_limit), Token::Uint(self.pubdata_price_limit), Token::Uint(self.max_fee_per_gas), @@ -325,7 +325,7 @@ mod tests { let transaction = TransactionData { tx_type: 113, from: Address::random(), - to: Address::random(), + to: Address::random().into(), gas_limit: U256::from(1u32), pubdata_price_limit: U256::from(1u32), max_fee_per_gas: U256::from(1u32), diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/types/internals/transaction_data.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/types/internals/transaction_data.rs index b42950399f61..54581a5ae57a 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/types/internals/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/types/internals/transaction_data.rs @@ -22,7 +22,7 @@ use crate::vm_virtual_blocks::{ pub(crate) struct TransactionData { pub(crate) tx_type: u8, pub(crate) from: Address, - pub(crate) to: Address, + pub(crate) to: Option
, pub(crate) gas_limit: U256, pub(crate) pubdata_price_limit: U256, pub(crate) max_fee_per_gas: U256, @@ -169,7 +169,7 @@ impl TransactionData { encode(&[Token::Tuple(vec![ Token::Uint(U256::from_big_endian(&self.tx_type.to_be_bytes())), Token::Address(self.from), - Token::Address(self.to), + Token::Address(self.to.unwrap_or_default()), Token::Uint(self.gas_limit), Token::Uint(self.pubdata_price_limit), Token::Uint(self.max_fee_per_gas), @@ -325,7 +325,7 @@ mod tests { let transaction = TransactionData { tx_type: 113, from: Address::random(), - to: Address::random(), + to: Address::random().into(), gas_limit: U256::from(1u32), pubdata_price_limit: U256::from(1u32), max_fee_per_gas: U256::from(1u32), diff --git a/core/lib/tee_verifier/src/lib.rs b/core/lib/tee_verifier/src/lib.rs index 32443b60c8ca..aeef91dcaa17 100644 --- a/core/lib/tee_verifier/src/lib.rs +++ b/core/lib/tee_verifier/src/lib.rs @@ -277,6 +277,10 @@ mod tests { code: vec![U256([1; 4])], hash: H256([1; 32]), }, + evm_simulator: SystemContractCode { + code: vec![U256([1; 4])], + hash: H256([1; 32]), + }, }, bootloader_gas_limit: 0, execution_mode: TxExecutionMode::VerifyExecute, diff --git a/core/lib/types/src/l1/mod.rs b/core/lib/types/src/l1/mod.rs index 05f08987a2d3..215836cb52f5 100644 --- a/core/lib/types/src/l1/mod.rs +++ b/core/lib/types/src/l1/mod.rs @@ -274,7 +274,7 @@ impl From for abi::NewPriorityRequest { transaction: abi::L2CanonicalTransaction { tx_type: PRIORITY_OPERATION_L2_TX_TYPE.into(), from: address_to_u256(&t.common_data.sender), - to: address_to_u256(&t.execute.contract_address), + to: address_to_u256(&t.execute.contract_address.unwrap_or_default()), gas_limit: t.common_data.gas_limit, gas_per_pubdata_byte_limit: t.common_data.gas_per_pubdata_limit, max_fee_per_gas: t.common_data.max_fee_per_gas, @@ -345,7 +345,7 @@ impl TryFrom for L1Tx { }; let execute = Execute { - contract_address: u256_to_account_address(&req.transaction.to), + contract_address: Some(u256_to_account_address(&req.transaction.to)), calldata: req.transaction.data, factory_deps: req.factory_deps, value: req.transaction.value, diff --git a/core/lib/types/src/l2/mod.rs b/core/lib/types/src/l2/mod.rs index 5a5276407529..abd60491af38 100644 --- a/core/lib/types/src/l2/mod.rs +++ b/core/lib/types/src/l2/mod.rs @@ -153,7 +153,7 @@ pub struct L2Tx { impl L2Tx { #[allow(clippy::too_many_arguments)] pub fn new( - contract_address: Address, + contract_address: Option
, calldata: Vec, nonce: Nonce, fee: Fee, @@ -185,7 +185,7 @@ impl L2Tx { #[allow(clippy::too_many_arguments)] pub fn new_signed( - contract_address: Address, + contract_address: Option
, calldata: Vec, nonce: Nonce, fee: Fee, @@ -233,7 +233,7 @@ impl L2Tx { /// Returns recipient account of the transaction. pub fn recipient_account(&self) -> Address { - self.execute.contract_address + self.execute.contract_address.unwrap_or_default() } /// Returns the account nonce associated with transaction. diff --git a/core/lib/types/src/lib.rs b/core/lib/types/src/lib.rs index a55f6b5753db..4e693eaa6194 100644 --- a/core/lib/types/src/lib.rs +++ b/core/lib/types/src/lib.rs @@ -109,7 +109,7 @@ impl Eq for Transaction {} impl Transaction { /// Returns recipient account of the transaction. - pub fn recipient_account(&self) -> Address { + pub fn recipient_account(&self) -> Option
{ self.execute.contract_address } @@ -258,7 +258,7 @@ impl TryFrom for abi::Transaction { tx: abi::L2CanonicalTransaction { tx_type: PRIORITY_OPERATION_L2_TX_TYPE.into(), from: address_to_u256(&data.sender), - to: address_to_u256(&tx.execute.contract_address), + to: address_to_u256(&tx.execute.contract_address.unwrap_or_default()), gas_limit: data.gas_limit, gas_per_pubdata_byte_limit: data.gas_per_pubdata_limit, max_fee_per_gas: data.max_fee_per_gas, @@ -289,7 +289,7 @@ impl TryFrom for abi::Transaction { tx: abi::L2CanonicalTransaction { tx_type: PROTOCOL_UPGRADE_TX_TYPE.into(), from: address_to_u256(&data.sender), - to: address_to_u256(&tx.execute.contract_address), + to: address_to_u256(&tx.execute.contract_address.unwrap_or_default()), gas_limit: data.gas_limit, gas_per_pubdata_byte_limit: data.gas_per_pubdata_limit, max_fee_per_gas: data.max_fee_per_gas, @@ -382,7 +382,7 @@ impl TryFrom for Transaction { unknown_type => anyhow::bail!("unknown tx type {unknown_type}"), }, execute: Execute { - contract_address: u256_to_account_address(&tx.to), + contract_address: Some(u256_to_account_address(&tx.to)), calldata: tx.data, factory_deps, value: tx.value, diff --git a/core/lib/types/src/transaction_request.rs b/core/lib/types/src/transaction_request.rs index 887dfcbff378..4b310ef24227 100644 --- a/core/lib/types/src/transaction_request.rs +++ b/core/lib/types/src/transaction_request.rs @@ -108,8 +108,8 @@ impl CallRequestBuilder { } /// Set to address (None allowed for eth_estimateGas) - pub fn to(mut self, to: Address) -> Self { - self.call_request.to = Some(to); + pub fn to(mut self, to: Option
) -> Self { + self.call_request.to = to; self } @@ -818,9 +818,7 @@ impl L2Tx { validate_factory_deps(&meta.factory_deps)?; let mut tx = L2Tx::new( - value - .to - .ok_or(SerializationTransactionError::ToAddressIsNull)?, + value.to, value.input.0.clone(), nonce, fee, diff --git a/core/lib/types/src/tx/execute.rs b/core/lib/types/src/tx/execute.rs index 03762040a6b8..c5d31c0f8a03 100644 --- a/core/lib/types/src/tx/execute.rs +++ b/core/lib/types/src/tx/execute.rs @@ -15,7 +15,7 @@ use crate::{ethabi, Address, EIP712TypedStructure, StructBuilder, H256, U256}; #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct ExecuteSerde { - contract_address: Address, + contract_address: Option
, #[serde(with = "ZeroPrefixHexSerde")] calldata: Vec, value: U256, @@ -25,7 +25,7 @@ struct ExecuteSerde { /// `Execute` transaction executes a previously deployed smart contract in the L2 rollup. #[derive(Clone, Default, PartialEq)] pub struct Execute { - pub contract_address: Address, + pub contract_address: Option
, pub calldata: Vec, pub value: U256, /// Factory dependencies: list of contract bytecodes associated with the deploy transaction. @@ -72,7 +72,10 @@ impl EIP712TypedStructure for Execute { const TYPE_NAME: &'static str = "Transaction"; fn build_structure(&self, builder: &mut BUILDER) { - builder.add_member("to", &U256::from(self.contract_address.as_bytes())); + builder.add_member( + "to", + &U256::from(self.contract_address.unwrap_or_default().as_bytes()), + ); builder.add_member("value", &self.value); builder.add_member("data", &self.calldata.as_slice()); // Factory deps are not included into the transaction signature, since they are parsed from the diff --git a/core/node/eth_watch/src/tests.rs b/core/node/eth_watch/src/tests.rs index 7ae3b5494e98..899690d6dabe 100644 --- a/core/node/eth_watch/src/tests.rs +++ b/core/node/eth_watch/src/tests.rs @@ -147,7 +147,7 @@ impl EthClient for MockEthClient { fn build_l1_tx(serial_id: u64, eth_block: u64) -> L1Tx { let tx = L1Tx { execute: Execute { - contract_address: Address::repeat_byte(0x11), + contract_address: Some(Address::repeat_byte(0x11)), calldata: vec![1, 2, 3], factory_deps: vec![], value: U256::zero(), @@ -178,7 +178,7 @@ fn build_l1_tx(serial_id: u64, eth_block: u64) -> L1Tx { fn build_upgrade_tx(id: ProtocolVersionId, eth_block: u64) -> ProtocolUpgradeTx { let tx = ProtocolUpgradeTx { execute: Execute { - contract_address: Address::repeat_byte(0x11), + contract_address: Some(Address::repeat_byte(0x11)), calldata: vec![1, 2, 3], factory_deps: vec![], value: U256::zero(), @@ -582,6 +582,7 @@ fn upgrade_into_diamond_cut(upgrade: ProtocolUpgrade) -> Token { factory_deps, bootloader_hash: upgrade.bootloader_code_hash.unwrap_or_default().into(), default_account_hash: upgrade.default_account_code_hash.unwrap_or_default().into(), + evm_simulator_hash: upgrade.evm_simulator_code_hash.unwrap_or_default().into(), verifier: upgrade.verifier_address.unwrap_or_default(), verifier_params: upgrade.verifier_params.unwrap_or_default().into(), l1_contracts_upgrade_calldata: vec![], diff --git a/core/node/proof_data_handler/src/tests.rs b/core/node/proof_data_handler/src/tests.rs index 88d4930e6920..6a97fcddb8bb 100644 --- a/core/node/proof_data_handler/src/tests.rs +++ b/core/node/proof_data_handler/src/tests.rs @@ -62,6 +62,10 @@ async fn request_tee_proof_inputs() { code: vec![U256([1; 4])], hash: H256([1; 32]), }, + evm_simulator: SystemContractCode { + code: vec![U256([1; 4])], + hash: H256([1; 32]), + }, }, bootloader_gas_limit: 0, execution_mode: TxExecutionMode::VerifyExecute, diff --git a/core/node/state_keeper/src/batch_executor/tests/tester.rs b/core/node/state_keeper/src/batch_executor/tests/tester.rs index 6730d427c67f..ac358ffb1bd4 100644 --- a/core/node/state_keeper/src/batch_executor/tests/tester.rs +++ b/core/node/state_keeper/src/batch_executor/tests/tester.rs @@ -373,7 +373,7 @@ impl AccountLoadNextExecutable for Account { self.get_l2_tx_for_execute( Execute { - contract_address: address, + contract_address: Some(address), calldata: LoadnextContractExecutionParams { reads: 100, writes: writes as usize, @@ -409,7 +409,7 @@ impl AccountLoadNextExecutable for Account { self.get_l2_tx_for_execute( Execute { - contract_address: address, + contract_address: Some(address), calldata, value: Default::default(), factory_deps: vec![], diff --git a/core/node/state_keeper/src/testonly/mod.rs b/core/node/state_keeper/src/testonly/mod.rs index e47e1182699d..92e58fe65381 100644 --- a/core/node/state_keeper/src/testonly/mod.rs +++ b/core/node/state_keeper/src/testonly/mod.rs @@ -164,7 +164,7 @@ pub(crate) fn fee(gas_limit: u32) -> Fee { pub fn l2_transaction(account: &mut Account, gas_limit: u32) -> Transaction { account.get_l2_tx_for_execute( Execute { - contract_address: Address::random(), + contract_address: Some(Address::random()), calldata: vec![], value: Default::default(), factory_deps: vec![], @@ -176,7 +176,7 @@ pub fn l2_transaction(account: &mut Account, gas_limit: u32) -> Transaction { pub fn l1_transaction(account: &mut Account, serial_id: PriorityOpId) -> Transaction { account.get_l1_tx( Execute { - contract_address: Address::random(), + contract_address: Some(Address::random()), value: Default::default(), calldata: vec![], factory_deps: vec![], diff --git a/core/node/test_utils/src/lib.rs b/core/node/test_utils/src/lib.rs index a0e70b02a22d..85f54bd7223f 100644 --- a/core/node/test_utils/src/lib.rs +++ b/core/node/test_utils/src/lib.rs @@ -137,7 +137,7 @@ pub fn create_l2_transaction(fee_per_gas: u64, gas_per_pubdata: u64) -> L2Tx { gas_per_pubdata_limit: gas_per_pubdata.into(), }; let mut tx = L2Tx::new_signed( - Address::random(), + Some(Address::random()), vec![], Nonce(0), fee, diff --git a/core/node/vm_runner/src/tests/mod.rs b/core/node/vm_runner/src/tests/mod.rs index 4cb2d26f6bd6..6d613849a4c1 100644 --- a/core/node/vm_runner/src/tests/mod.rs +++ b/core/node/vm_runner/src/tests/mod.rs @@ -230,7 +230,7 @@ pub fn create_l2_transaction( }; let tx = account.get_l2_tx_for_execute( Execute { - contract_address: Address::random(), + contract_address: Some(Address::random()), calldata: vec![], value: Default::default(), factory_deps: vec![], diff --git a/core/node/vm_runner/src/tests/output_handler.rs b/core/node/vm_runner/src/tests/output_handler.rs index 453507328c4f..fcb26ccafa37 100644 --- a/core/node/vm_runner/src/tests/output_handler.rs +++ b/core/node/vm_runner/src/tests/output_handler.rs @@ -68,6 +68,10 @@ impl OutputHandlerTester { code: vec![], hash: Default::default(), }, + evm_simulator: SystemContractCode { + code: vec![], + hash: Default::default(), + }, }, bootloader_gas_limit: 0, execution_mode: TxExecutionMode::VerifyExecute, diff --git a/core/tests/loadnext/src/sdk/operations/deploy_contract.rs b/core/tests/loadnext/src/sdk/operations/deploy_contract.rs index 161d156a53e9..a761bbd72b97 100644 --- a/core/tests/loadnext/src/sdk/operations/deploy_contract.rs +++ b/core/tests/loadnext/src/sdk/operations/deploy_contract.rs @@ -70,7 +70,7 @@ where self.wallet .signer .sign_execute_contract_for_deploy( - CONTRACT_DEPLOYER_ADDRESS, + Some(CONTRACT_DEPLOYER_ADDRESS), execute_calldata, fee, nonce, @@ -145,7 +145,7 @@ where let mut factory_deps = self.factory_deps.clone().unwrap_or_default(); factory_deps.push(bytecode); let l2_tx = L2Tx::new( - CONTRACT_DEPLOYER_ADDRESS, + Some(CONTRACT_DEPLOYER_ADDRESS), Execute::encode_deploy_params_create(Default::default(), main_contract_hash, calldata), Nonce(0), Default::default(), diff --git a/core/tests/loadnext/src/sdk/operations/execute_contract.rs b/core/tests/loadnext/src/sdk/operations/execute_contract.rs index d5fe57c7b79f..119744b22129 100644 --- a/core/tests/loadnext/src/sdk/operations/execute_contract.rs +++ b/core/tests/loadnext/src/sdk/operations/execute_contract.rs @@ -63,7 +63,7 @@ where self.wallet .signer .sign_execute_contract( - contract_address, + Some(contract_address), calldata, fee, nonce, @@ -144,7 +144,7 @@ where .unwrap_or_default(); let execute = L2Tx::new( - contract_address, + Some(contract_address), calldata, Nonce(0), Default::default(), diff --git a/core/tests/loadnext/src/sdk/operations/transfer.rs b/core/tests/loadnext/src/sdk/operations/transfer.rs index 94ee3aeb6082..651fabeb788b 100644 --- a/core/tests/loadnext/src/sdk/operations/transfer.rs +++ b/core/tests/loadnext/src/sdk/operations/transfer.rs @@ -153,7 +153,7 @@ where let tx = if token.is_zero() || token == L2_BASE_TOKEN_ADDRESS { // ETH estimate Execute { - contract_address: to, + contract_address: Some(to), calldata: Default::default(), factory_deps: vec![], value: amount, @@ -161,7 +161,7 @@ where } else { // ERC-20 estimate Execute { - contract_address: token, + contract_address: Some(token), calldata: create_transfer_calldata(to, amount), factory_deps: vec![], value: Default::default(), diff --git a/core/tests/loadnext/src/sdk/signer.rs b/core/tests/loadnext/src/sdk/signer.rs index 0f4b1cf29717..11d734f72cd2 100644 --- a/core/tests/loadnext/src/sdk/signer.rs +++ b/core/tests/loadnext/src/sdk/signer.rs @@ -51,7 +51,7 @@ impl Signer { // Sign Ether transfer if token.is_zero() || token == L2_BASE_TOKEN_ADDRESS { let mut transfer = L2Tx::new( - to, + Some(to), Default::default(), nonce, fee, @@ -73,7 +73,7 @@ impl Signer { // Sign ERC-20 transfer let data = create_transfer_calldata(to, amount); let mut transfer = L2Tx::new( - token, + Some(token), data, nonce, fee, @@ -94,7 +94,7 @@ impl Signer { pub async fn sign_execute_contract( &self, - contract: Address, + contract: Option
, calldata: Vec, fee: Fee, nonce: Nonce, @@ -114,7 +114,7 @@ impl Signer { pub async fn sign_execute_contract_for_deploy( &self, - contract: Address, + contract: Option
, calldata: Vec, fee: Fee, nonce: Nonce, diff --git a/core/tests/test_account/src/lib.rs b/core/tests/test_account/src/lib.rs index e259ce209c63..bd49f5c092c0 100644 --- a/core/tests/test_account/src/lib.rs +++ b/core/tests/test_account/src/lib.rs @@ -129,7 +129,7 @@ impl Account { .expect("failed to encode parameters"); let execute = Execute { - contract_address: CONTRACT_DEPLOYER_ADDRESS, + contract_address: Some(CONTRACT_DEPLOYER_ADDRESS), calldata, factory_deps, value: U256::zero(), @@ -158,7 +158,7 @@ impl Account { tx: abi::L2CanonicalTransaction { tx_type: PRIORITY_OPERATION_L2_TX_TYPE.into(), from: address_to_u256(&self.address), - to: address_to_u256(&execute.contract_address), + to: address_to_u256(&execute.contract_address.unwrap_or_default()), gas_limit, gas_per_pubdata_byte_limit: REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE.into(), max_fee_per_gas, @@ -216,7 +216,7 @@ impl Account { .expect("failed to encode parameters"); let execute = Execute { - contract_address: address, + contract_address: Some(address), calldata, value: value.unwrap_or_default(), factory_deps: vec![], @@ -235,7 +235,7 @@ impl Account { ) -> Transaction { let calldata = params.to_bytes(); let execute = Execute { - contract_address: address, + contract_address: Some(address), calldata, value: U256::zero(), factory_deps: vec![], diff --git a/core/tests/vm-benchmark/harness/src/lib.rs b/core/tests/vm-benchmark/harness/src/lib.rs index a30221cfa0be..5adcb342cced 100644 --- a/core/tests/vm-benchmark/harness/src/lib.rs +++ b/core/tests/vm-benchmark/harness/src/lib.rs @@ -133,7 +133,7 @@ pub fn get_deploy_tx_with_gas_limit(code: &[u8], gas_limit: u32) -> Transaction .collect(); let mut signed = L2Tx::new_signed( - CONTRACT_DEPLOYER_ADDRESS, + Some(CONTRACT_DEPLOYER_ADDRESS), calldata, Nonce(0), Fee { diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin index 643d7ee425b3a724d1e6902875b8d8475c57cbef..0e113d4d2a22275040a990fea3632661b47fb2e9 100644 GIT binary patch literal 76256 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%0DcnqIJ|zV=hwmdZPL&;>@U$gm;5DK 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])C}L|!>=|NzU`;%j>4}RC!_V$RdbJ%ExHdF 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 literal 76320 zcmeHw3w&KwneW=?m3^ADNz*oI9&L6ch*glbJTwS$PG3+h(9!~qsN~R`me4jyleDxt zpN-*)#G$0mE?4e(_Mbr<8-^9M&qedkeW;q9Oa(mELXQH zHUA8yu0BgGMotoNsQm=PJIM8w`(mes%dO>dN*(6+)N^jvJsDN7gZX_sp6P_g{QXHi&xUT&spZU%o#`C#Nd?o)-%cv$JW6TJ zUrutl@OkPu=If7YKJQG?Jm3#q4WHU$K2P>BKPQEb74aj(O(lf?QwxQkQwxQ^ zlS$!w@G0|sa)G>e7DzcKulb(mY2J0f1kvegnosJ79>1YWL#Ku=4V@ag)O0#yx?B@W zmmO%=VY&qWR701oS89AM*7F4fF&>Gu3F`NCKJ}OQ(thtap1J|AyL(&IZz&si>sJsC zC`fd^4)yYQo@3GHx%&Nj>-{U_J=F&vbhtF9YgL!KfuF7JdHhT&h#7Sj^P{466v+*u zH`VH-PG$W|a*_0<^y7Sj+xm%;{KoY|`8Gd*ywtK#zRhnJRDjR(9jb4`7k&=8Cn>is85c9N|~@l0=UCvsRZoJXga>&t*85BsNlh)9)nTQ49x2vHG(m zBmLf^%N@=ToOYDUNWU`~#%FhCfbgA|Y|!mw_A*}4vqOy6OaqteaR?Iar}NuD_h{kWd; z(E;K+)v!Yr!oyKkoUo8G1I*`>#OQ1@Ro z@OYa*D|xD?=_^6~5c{z~Ex~&Qdx`AUZoCJ+klxOC`U``n2Ek{K%j0qm7(8jb26(zP zil>Gl!Bgf|!IQQNos7m)hVkCy<0+%@g#JhHl(|CilzFqp(`Xb=$R|9Z4$YsBr(PdV z*BLzZ5*`RIG+&6U zf6UvYf-f-lYC}iaeVUH07yQK2(cHIc_-6ic+;6h*O3feRd+rZSzZ$Ya=W}HK9y0Ui z3SW4QnjRY;jLx6?Zs}k4LFr#s(|K0UU-qUboo5fyI31O}N#<{k;h)=N{<8PT{LPt^ z`I|FG=sbHH&)=b$&Yvs%NBAUuQ`vX%{Q7i`e$xC6pdbBe0TmEB&k7#8@gDhj&3K>t zh{01<_^xLTkIVU{!BZo_!TdEDJbfXGr>3_Ep4^88PoO)ZFYtMe>N)OY6i=?k6Z(HW z_+&>NH<^Q*JnGX`5Hs_urtt}GvIhK4$*IT!**jcY}7;OuQM5+ zKkqi3f3QUU-IAX;9x!O!yOYvi$m9a0|1%-!SLyT-Nt^y3IpVNBP9UGg-vaxV;V5Sd z;i36if&brTobbJ4`?o2WhpTDa+Mb*?50g&pJj@i&&Qyu|9~V5K-3;UH-8$U^s%QQS z@SI2g=DkhE;cf%GJg9Ly@L0lsfk#FvWXTXL7tyCP50 zzt{4c;xIcf`Ea8T5xzX6NiS&mjbA$cX5@zWxvD!Y^R5yX^1NvOH`$XEJ?5eO4XCY> z$2lVq4o6aKk2Kw>?VvVH5cfBwYA9;r9wm+Pf+?g1^oTF_p9 z>wW&Z55-l1-`2-8-w|KZI?Y@vNBsa_EdhT54eBiL{W~S@t=f^#d|~*^%zI*$(7(J- z_8@*la6IrK^I76T<`W$cQ)#TvwZNAJ;}HM5*CdzA_%lh85AL-|_NU!zGwNVoHS_ud zY(q5<9pd&~kt52vLg=R995)AC0-c`2{cWFPXllbeK}o#XU) zRtS8I8*s@i5q=i@1^jH`MMd%9UYg{24*1!hr&irgZ`pQyezw}_2H(hhtkiHMPHylI z`KQM-vvz!bw%SpN`oI@{23-K(h>JA;K+|7?wCBDFbR&E~%qYi4Tb6=N&Qc&M z<$`XS@T7PM+0PWO0Wl&E^rYtWwWz1*xiaT;;;Ecg!f(q9MP8lI;^c@vPH0J~gZ-)z z1yWScy$*DeZ+*C=o)x<~$d8vRLB1_l{#OO~w9dOM)PA+_ude`K*F-03iO&hqUZfpy~}x?)XEj=A5s5Rn19Sm z^WVulxi^ANU~?I`%}sNPQBq&x5xPFnqtu7sENfT3Jz`frFwL&C z>_~`bme=z>=VPDcEu*9%l{u>MK- z((=@oOU??BOY%Nxeo88~2U%X{q2HBR2iJBRnkyxLR#he6eEX}sd~*~f+y}YgtzR2r#<-rz!{Wb3&g#NVs708iz`zy$gr?(*A zqBmFUuOQ!sFYE0=ewFZz9dnHBuTM|2zXEc&-N?7` z*oN}ULUOsvc~UObM?X|b>|NjfO&j}H_Dz9o2p_5M8U4_^McqU7R&HXws$h>oe>H!T z^(w7zk)1S;0OJXNTJ*M)!@6#N#O@M%lI$nOcX_$je4OZQXMo|*I*is6+F#IiSo6t( zPhZYAIgDrO7TO{Fb6g<(i1_2~yDhx8aev!j0nQ5E-P@z>)qP&YKA>?5zrTmuE6tDM z&j$JNbQI*<{Qkcyz!y3V>Q@P0wZSn5ox1OJeoFRQ%U*4#9Yi`$lPUfxhRb&NJotpf zPc(e+8y1%Y5B~lzW5=;Q+4!=qOH?!BZU$dXD6NvZKE~; z7jTEDyt7ct$-MLf`2@#`8z_-qs$~_!0rO}%+z7eJ@;O;f@zZ*0 zcShsU`-jWK%__y~?e&hkF}^&tuj8VMoVXv>t17Hj+Q7+S2ME zjeil+;O~}KYdNt<<5@Wu0xuL77ya;r(RX;i9`EOQEebkAE$(emzrk}J+5y~_(-~hh zeu)n#Cyo8CLHy6w+u8Etz-m1@7Lpfs{TlVYdk?`!Z?*k22{)7N7Gpn|b&$Rp+Ed2g zoC7>k91t=(vW`*0-)#D!#xKb?%tr>eWqx9RlDen&u`PByq1)+nnCnL|9dB&@fTr68 zW`mVv)$s@A zY!d#o{8116;W%Zom;Fhz|1+)Efv!pE^+DN(?p~V;$0ub$hxyhu>jklKNt_b!*BQ9~ z&-FUP&FLKJ>!!m>^%CCv{r3M~t}`gaIlORO(tQ);2lHXl*xN55xvb-mm9@>a(iefuxL>oqOd=fmwN#2?qAJ`@DeLFS*e{xbW2 zCc*EdpUnQ~dq7utN+X_p8kqWCtn=K8R0?tCv++Du`qu0VFy}HLp1D6C#kgm4-Sa+z zPs7)7n}tXdo{imM^s2!F(-rd9%+L-o=OJ9odz>ADI7c=6DVninSqRYw(aRyE-SuW1 znm){UO#i(Z_V?q}t)IHn&PQOJj8ERr0b&LpFujSrEcETKuP*levCmQe%h;zi%8Tjt zk(Q^#FC-_m-Q>sXJ@6&lM-s1BW}lYC#hXxp<(_*D_=(4x=D3l2ZDJ$Y7w)yN>*@VG z&F?Cs<4TE(MLsvc9;bF2GC4f|upZ#crRw7K$7VeMb`t0~ynd_w>tOvhY34U1 z_7bgIk(~shVmql3Px8w^9C)_`|5mqt+hXcfT)(Yx{ZrdbK^(-^v$CHq$dA{vLB6fW z#cm4nZTL0DVU&rhwKyDaHS4!QoSEfi5Rc114h4Fa*8L=2`2@))q)4ukJe!}C_=j27 zYfR)M&f@6(Jt$B74L{bS^7I4xn8e0Zhobpo`2o9YIphq{1r?m2 zuDd>It-Ia?8|J~0UeJ1uu)p{gB_8qXN{;=-L z`yhjTI{!W8e4p4W?uqb+NRRvb)ST2L@iWDZh{kbj~3EZj=#yy6!I z`X*jJ1o@VHn6}Pq`~l-HRFcQ#*Lk~vdDb^fXQM=a(R&D7_-2Pl?%v9B@ZOU9Uu2v? ze*8Ftd~2L~ohiVBt(Qqp_J{Uu+4VIZFq{@dCY1X&>Muq|`V)Sp;{DZl8oV8Ce7Dqk zIq_)>{^lcsC49nq)5o{_T(3vgXs7x6YyZY!c|-AvUZRtONHg9`tVgCWFVIh?{|a*N zMvnjRI)jUK^E;^imuTL~#Qmk;fj*6=vmoE56B8Hl_t{b0rSX*3r#K!$@kZtc_iroo zgZsUyiot?|W!gv$FmUds6HKKR%vVt@q*0#2%!6i+x6T*a0SkPSA9I zD%qWszWS`zd-XbKo9}nOpU3&Zl5#}+?jS!NuR*>wzj_@s$hYN)tQ!USRl-+uHQs0= z{VN0d&92bnH~Z>nz2-__Nljm`5&PWii{y1s(4DtJeFVkZS1#vuH60IaxlPO8uQ1+9 z%SWNdAU}RwLB54I|9+Ad^qcI*cJL>y17RNXq@Q6XK<|-*Gzac@_Jf;Pt9a=+ECXp9Ol(<}(?0kRQ)yL4K6a7Gd^f|4$UoBBl(?|Fr#D zi%_B5KD=7@|I|2-?)w;Df&8=aCH)WbbNAacHuQL2VZrSh&q2c`y@$iHCHvE4e z_(TU{&rTw|19?pQ|AbGCU2F7DcS7Pt-43tkQ?WAfA-zwNz*mUxME!|RYd;de^?A(_ zcJLgm)Ey%G?rSJo=KP0@D`e-#H3xBlMu<7}|R$#|^qIdoJ+nY`PbF zF369c&miBXd)e0(J&R-e&LOhP}QJuel3MKYUYJb7EA6lRXma)|) z>plwW1?y2=&B!n5LP4_k13Mv}|AKs*zvWzekRQLFG03<0U+Mj4!G1=)Pru8_G5vMn zd?De_-?z_nMcrOVeAMz|rFu#4T!iwsBmG<1SD_m1dC`3TjGhZjzjUW z4wX|L-na4%6ep=J+@7Tr>}d5YhJo^Qf1z_$>wQa$tY6if$w->~E4D|n_r<@b_*uBV z_7~XC!~44oT)iK{v_o{vaMPeo$Y)9?)e_*>vNvhPkmz^D_i{$<#0RJ0yM&$C_}Yk_ zSo%I#AR6{`kRMNfLH;y4(t1tXiSDx&Jsqp@zCn-o*VKM!JT|}9d%V91jhE;b@Ua7z zq*_aAbrtjcTg_J@ryla|5c>7kdml9N6ml8sGPb;&H0Q;PyreYAb4y;%nC_x-)7(>x z!IqbsA}>*j?*Yd>&9}-p>~ku9oD2gD+l%B*4D<*0$&|Q1i7Yy{hphXPI{o+2`;$oj zO8MyhNyMk@_v!nM0y?+pM&xvmUnQSZgwJt}5Z%@rKFifvgfI8p9zA~S`;!>om>uJf zo48M(*867PyRiezI@F-f=l-DnwUVAO-AC_HGIUS$c2xHu&xfsFfL?O{BP1tIt3obB z^{wd-(=Ff23_MkHFZ29Ib$@7P46?3lhD7+KOs1lesF*P-(=jdUwIzv{g%d$ zlY3;8`wG)vZU5?f=`l{aX9ng*J@8fH%PxJhxb8b zaqfh_*C6|3Yo^au;F#u#$cp`8{78{~hcw@}WA24tDeWRdzHe}f9w+QZ_76OyF;48( zleDb6D0RG+2L&lVe>))S_Ua0Mpw94VpEZrg^#8It!?*GC<5`CPlUauUc%9)BABFM% z**e3w@&8zz;oJQ`RA=~h|EKB<-|qiAD!~7U$cOm|3)Y3dd(d8Z{(n)S{c7dY5)1y% z>I|RaN8$dzDgvME39*ki()*A;vF!q}Qv-byZ>I+Nwmq<^0(`NvgZfp%uUSvf_`-O) zFoGwbsYX2{-$x4M_%G`WpW@Tu{{Otr@NGK!Rh{9}zNB#f|Gm!eX`gWz{^mNvxApW- z>kQwPvp=dc{Dg&{AJ!SZjh{cNGkjW)3(xPX>kQw<|7+?DpZwTx|6dn{?^cq}6pvmO zlHXOzPxt%OUZ}n$|K0y<~W&sA?wQUcf;nLYy4QOYjj{%&G*PudYzmbo!R%u=H);J?4LsLU>$DWB^s`|=dUa2 z@psB*_d8_M>GK)jH{W`9N&1AHgmr}=Kb}5=e2YG(;s4uJ;(uSA@Q=Od5&U0wZ1L~r z3D2M(y?>(hJYXg+Uh&;J`#ZKg+%5g6TfD@!19r_a{NY)KKN5xS-bCrvkC)^Rk>5dn zJbwiFmH4Atf7A98xW70ad9?8`eg3iqJHtSqq{rx-EUm|oUL*M-dhJ%m%ZE$iMf|@Y zKOQeZzKs{DAK=Z_n{xgo$hYg;{@uGQxnttRw%qR&x!;WKNClDCwaNV>QMuC!+0Sr| z-0z%Sxliq39`RSDzpLq>WZd=BQ9h{|zU{9(RA=}$pL{9;e>#1CjOqI`CFz^w>ax}# zKc2pWe2YHaO7MmLgZfp%pEe(VStb2Le$<2hn=gyffAik|N9f2ozO6@h&NBR=I>Wd5YqUoAmE_NdYlN@y-|{E3Bp*LipZ@vuXUoU8&NBSB)Cj-Q z{M}X~e4Bslc+R7BhHuBCuBUQc$A zJ{xb1+_LfVunpI;3%*xp|HB^FXDYN`t^I3{@69#BuSB;Ws55*!p7d9<4F8jLhHvY| zPt*wC=4-Np!tu68D!~6njr3b-{vWK+ekJ;~;oIvZ57ZgH%^&yI2;b<eD}8{@HT7SONaw3iR_$JKvJaUyRCS)stB6yq)B6YB}8#(()B!SL2)s#}hLfWgkvM zLE?${PWH=C-obaPAH`Fty?hSUNpEC6P?@#7kN@+=uEvGXw6FhL#;!KsZFBTJA^N@( z2j7EZcxio4NcwpB4siPT#L3i*>_^4-&^`WMuyT6!`(7#MY;xX9<7PYc9$!3&pwO{Y^jKGVdw$_-Nt^_PpEcxc?{G@0#(#>mNX`p|5|8!gp6VeBY*9 zExs+em8JE%d?@bbAdP+7fZsy*c~%Xd_Qi(iHtR;=A2nRtPdhaVw`P2|MEmXjv%ptt z^?tq6B(3S5&T&XQ@eTAow4c(B_enhD==UX8f=~0gEYyBH{Ri#a@tjKVX+CEYzQmz} z{#EF|>X10+wEg_H9J1HT%=x4q@D1xV=ojd<`5!TQt+sWt`F9z;2Ezq+mZYG&({ z^S`R`-<{(1Pq3%V!;hxTL*H!9gN|DVc>m91jQ1mA=RrQneOV>&-r7_jytm?fRi5;z zh4)shz;GPatQV-{F~xh9{FQQYxz6;SZI~h6VI#-Jr>ms*R`6OZ-tBdoS;o6Bcl39$ z+&s?L-wt|ENr(6I4>-JU-(7`$|9PeAW;fdQ(bs9dLw1a<4=UM7WM9yEH4}d#y&AG( z-2MoBT3;0Xzn0#I^slY|Yt_${;Mb_1r`b(8i;m5`>XzPYy`=;lcT^|0TW{2K+!2-A z^R7F#@`KuQAjet}o5VTWk9oJrxj~)&a5Rl_Pw4XZa`}%>%g1?1hW9w<-#;xM_5tUA zLO&nlat}@`hx>BTpNH)Cpg$)C|F?CD^FI^KZ=JHzk6G!*t@IOC`bm@4?O;_Me+j-f zETQB(9&&EcI$u0V{zE_CQ_T71{M?MszeUa)x9^WIDKfb-7zKv%ik0FmhPgo=Xz$N%s$#;~pjRvob zce+1`=#tKB@;XA*^v37xe0l>Q*pC$F8o>A0u?GwDww%9j;hFn%Q*xiKmy-K*d(t@_ zFUyf%vEU^}K9;{%7cE>Tak9(+>l@Xuj{JuOh^^$wu2LEPZsmft8lJvCH~9XLd}j&e z^u4&|p4JLolETZ=g;(C zo}1CiK;&N6jJfv+;X@hM8~kxa>DHplEZt9%5Al)BXF~UZ{E4UgAirApjK5I(72xZ8 z^_23`%Za|G`OWkl(;IN!(}P?)i@ypfd_?C>Ps95hzX$#Zzx*9klYbo3i^ugF{dv^& zP+s6toGh=J?R@7j?qlv(bMapDwLTwO^1EYjG|*2J=kH)Ajv)FB+o7#h?)6G2wAatK za_Ih<@1-R!WIi_E$Ci7<>7F!wk4~bh`^4Lpio7-7Pl9*vq1`Oth1*51U`dL+inQ-u zD)PVWh5G&)-#>C@^xfFD)2;S%+&)g3McSuX5I$3hRWaj7G#so)e2DLbSMy!)wpCX9 z1KfVYwDwE2TWx#iN7_q4K6vV8;1*=X_p@NwbY563(BnxZ`JV3uzY>0i+!pzh!ny^< zi+kBOihrWzw@RgRBzR2a?7mGk^CjTI3#$>mY2V*=9mup z#9o0sBtG}=H=3~?EiZ=w(AKAFxr4s@de!Kc&&hbQWUrL7FQlKCT;Os^2v70yu(X{) zcxFCe`9pSu$Rl&FGSndSF_bv|z|RZK{lLaPnKb&2>!X~$|2Gr8|F`XzG9T`5Xj}|U zz6U~aXKJ7H;cCK%$**89M(%3?o!tQtBxN-o+d&(Jv#1?j9|Q60aTz_WBK_9)0ZVzZ zKNg{eu3ugsdRjl|@7e%DRBxF3xs6^hc=Nw+r1*PXS<-8H)HdH;G39xENBYHfh%eWi zyvQ}iyYj!kB-f!v zF}`y08sd-cSEuc_%vUVGLUPNJ@7f*8 z-t)cWV!s=?4?1K!NbL7T+I}f5_tPTJbNG%?3(z>2@U*;-+U4+1MBXP>Rgm}c{Ux#6 zE6IK8|IFk***h4^qGt@hVZ5h6FX{ai*-k6o4!w}vj`6@CB)-HxEFD)$a$ITAHO4N3 zfktvHUG+Y!)7ZX4ydzKij{Q}HH!?)%efx15ej0Hv!mDyt$a<;9qk}luqg+18_Lw^A z{aE~+0&0)s&dld|mh`%snSav0R^#Vv`JPn!3-rC>X5K(;$x*@&;tyEs!#pxSw7*EH zUc$GRVmifp{=SO;UOBz8j}G_Zay@vYh`*$I(>bz(+Fz{W1&A~9d@aOxw*D0Pw7(8< zkyI~S4~~zdi#(5@9iCrLmsg47#U4vYe?WuWpPs}aV>gMx35x6SBt(;p03g=$?++SMAKEOPxkMn`ewM#kNt9B zSiXNz-X2@PD;Xz&?w%We4D6OP_B(%vx$Qd!Uygi-Ib-Gj%;d{=o7=#f1>zg~-r^Rc z=Rs*_6E<|(#8<)3d~fs`@%Lx!ZyNue?+5kc8W3(ePCO8aui~x4an*Jc2WNX1rI9l$ z_o+ROuH?ZdtIz=P8Tk_-Ia~EUwiMuzTr~UdK0C|s-%)4yG1(^A?~pb4lY6_Zeame_MxLdQR$ubI<+g(1KdmPRjXXOx`h9$SM9Z|V84gLWe|8;Jk&gYW6D5V!K zwd94dV@voS?F(w2Z}vah8})n#cH?v6e;E4*_tEC`x{%qo#&&P1{c7ze3O~V*V?N2^ zyDFrI3?JdW=qG%CFZ@2+j`yK*sK;qY%Go(zQQf|FbR)|D*+q~8W%O(NMK#j{>(}=4 zqWn+#PV~pI;eR79XSRP4aa-OW20K`uyR7|E4L~HJ5=xcVnW2R7dkHZW-Y((wBw1(5 zMb=@c9>34hxq*B~Yx(^(q5Rl&uTZ`f$5T3}N{Bu7V$7 z_=M>L>#gwDO`Iiu9~0dl-QTgmUzbu4jAUO79Nm7J_B#xn!OvworC~tq6nD4yrLL>} z=Ggr-?U<)L`vtO}rrqfIW4)iofxNg0a^e%Aco3~$V?8eA@ssrr(ribWd0PB#8NdBK zk4fWK$$pyZ=ZU|AjCm@*&OzOget%uBV}6b3q+@<5`jmc!^5f|ESS5Fl}td zdd^1nYjO#Wdt^P_7tZslR_gsI@;+z1AJFBOf+h2WXI*}P=#LjK~EChEdHF}KjD>!?_Qc_eYW_^W}k_Xqcd#hUp0MdyeAN66};4W zJm1&j8L;8wyHAWSS>J{K(jx6Uy@IdI3Z363_yRprdGLea3woFE^-G2y+ApH%%B*MV zb;iXTwR|ygmoGC+_coHXl< zk{?-ToW_5?9#AFXD%9UYpnLhAdq+ztK9uh!hVtY2FsN_yVFU2GEX2q5emB~8(jUr? z)(6w#ZwdXwct>Hwe&fd*I9$o6!OrH zo6Z`19XG8Td>cQH%`$!t)fv9s|EW5|x6ei0CGg|VNkh)Fe+2y?&sP0hpq~rnsrmV2 z-bYI=280g#O#mM8o0NMFvhq}(?XxWXP)kt8Q~bR?c&o-vpzj2uHqs=wJa`L4moO0c zJ-!=*H?(iI74@M=9sUk#C(4ps>o_UO4~S#3+%s~#^8+G(?RrWbm%z#%0=4KmwX5A{H=ucw_xvK-a0?7%X`2l+4)&tzw`HhJAWf|l6@ZLndU*? zFQU#wn*9QqZ#ou9^n~}znf_om3LU1H9y-6J@#L?2ri~xKaSRls$oLxXpkn&x6`2Q=!Q|6 zzfSm{hiDwh4BNGig57()l#}shw##~LX0Jo*j$T7f-sAiU@u5OK+ErQ56Y$%i{n^fI z44-BA`^Q~f{y5fhKRna#%ogsSuHSWn#@i(N(NFLjc%NbCR}DU89lY}@-R~?|iuiHB ztXpR|4%yZ0mlwRLM=gj8XrQ>osVez_laLX`0pkBkRJy=_uIum9hr}$ z@WB&iK1@Fn$6NEE_oJp$(vO7xE;Q(n`w`u@7R-x$AIrZ72WF_?KXIJQ3-E_ zMnCmBJMu9v9e*wT^5>&h(>?7Qz<6k0WPFJ&+z&793EmS-r+PlJKmeb6$o9dH)^y4B zeEz{cA;Qno2Jc9(C;v(OBjay@DpHd)-kj{m48@z|{eaomqxaiGjKaevI3_M7<))(L zCTZVsf7d!oK9W2Zc{@-lK2<_a{=4BL&^7h9S~&?m&J*2eIoXNs6`0S`vacy^{PtNs z=jAvY-{}Bf9YXur=R=O=yEc{d#~?>lM<_qmt_|f|cCGlWUFVmC&wfiNKOTNi--0i8 zcc^{aFJiwnlyBF!^aSC>;d#NhNsfTtF#hv;rXZmqLy$}K2O_|aC0(nvf7@WrnTdbf zl`lD7_HRS^@#78ZTm2RPHdNmpui!JNUnP8%@bw>^hakI&{rb*JG`;%q6sH>h7I3tG z>qhHWL-e;24=RdkuYI-BOs>R=1YQaAq={)3lz2MXOVyOS_Wp##c`!j`EhCdL6 zZ}w?cy?@BMzb$)0o#4{Bs1Uxhy-~O%i zCq?0d4w-);F=V~?6rG;ocSp0!qwwlZFM9p3Zt}&R&lk>a|J|R=GJO4A)A)D^X0=v% zUm`vu^8ver<1mo_7n6R0-i)Npd-LpCAI!P3za)PicRS=!DK!t5WM`T_4kSC9hw1KT(nnWSl{MJRXC5iw=kk$sfg2)4jvBK*=YrOuN#~I+orXLw+kY6iaPp^R28u?kVUxrx}c>*U$%NG+z zRuVU)?K%bWSMGs`%G10n*^lh6`yoy7m%b|Z-M?M-k4^Hv`|hV_O6Sxc@}F!vG~*%u z2+2p1pDZ`CFJXKJ^HcBnBYn>PGs|TkpV^mIXqW4S__YGvV4H=s<0W!5PWNmymB%Rc z`4HSc!tXI`Sr1V9{tYjpSCl%8_z~h`+5V)CD*;Xipdh|B0JzyRQt}?>q6&{9{W6^n z#cjFVnF(Dkm7{V{SEtgx0E7p*pOcv+pYtI#7lw~=yuSqR^?C;4jW<$#Od0nhtvvJt z<&Nil5uj6yKxNOu{L*+So`p0zynx#Se3na7{`(dD-bwTRa98h_o}_c^1lM2J*72>( zT=WR);L@F9z z>VCW=J|U(sZ$W-MK7)J<9}-^*)wjpbax#=(C4Ay1Ef*s9ZFIk1$Cqebi{wVasV2Sz zy43L{>pqU|Pii{k_)>@t>~Yz26hE#&URrqb<4Z~Oo96d{5^*J_AB+$4TbJ`uCH#PR zzXSBdegN?%n=ZQ12n?rDP8Yt1?)#m^~@PW(>sLD1>at(s1i`!>v9o@W+`S%S6SJlQeR_W@6m z{c?2sfI$a$m^e8)OnQs-67(w8YpS|eZ^`rYe35HNaH?EyS%P&e8lSmW&y0V`3Jv!; zTAyC>k}`6i*H5vr5$k3&KZj_3ta~?MZXDhG2)}HdF~1zp?X&;1v`~TWgZy~94Dv0y zCow>F%2JT0L*u=P`5-87%W00whx&6g?bQ-DrE~sdFPZbA++U>EYI~pkKjq(l95a9F zsQ9be`TGw`-gyqoJLhmh%RP>#U@$DlA+)tTMpAVw9qgIXd~ELvJl1w|vd(t1v6F54 z8Rw*r~0PwVws++SGMo;GqTMRqjg;@uHDn)MC7R}1+VIZy2x zJCD|>Xg|i%IYthK?ZTx4THhv2d0BT{`nr;Q%63O6Kb~)b`WByxT^Oow^CjDzq5LZ0 z^FFE_ph5aug8#p($4%!;$R12P)!2hjbbT%AQw)#n7Nl3^)Nk=5{}1wYDf9r#SGEg7 z^28n+YCkVo<33i2(yDY~ze`k!$;e&RkX+E=^utdM;el1C^Rdp^vqB!_9J9X0e5 z^}}(jB?o{h^b!9?)+J5J}-$Lr*H z-;-#Od4YTh&&zo;oEN3!o?yf~#7>rdY)jYq^TFphmtLyjCH4Lr*>8ys=s1SLxtT8^ zi6`IhkxI45_damGvHw!|h~y>W9NtIZKfM@o zko^|WMS<`F`sXz4WO;7Y&p}fT@c2IUY##9POZS$Pm*^SzDaeoK`yk)ud)kN5zw{~} zzMW6~I0^aE&wW<^$iE`ZOnRaL@+*U)0NvVhUy_)kuzCWa|QSz1gFuz|T<+EO+ zIgcgf@6_*e{`*&O`D;_A{;8ZE#Qra$Tcz%&blOYaL}_SOj(7DyX5>k3cqx9b9?x?5 zw3@^DOW!Z_hP3W)W0vKMx_6H3zis?N3U|EWLcKFsUVw%eo=V;#<&xLX`ySxp5ZZAL zCk0RbJ~`wAzZ4Lo{TMh0wp{v~94EY*^Itt%{PSPBzJFfoTB$$n{MUq>XPVi$teyes zAI^W3h3{UP&5=LX1D$d;;mzMiHp6yw94e73-;N5-u~j#YYxOt=z~?;g{&~9tf+wAp z`4SO_4aGV6&M?J8SFpp3&;E^TxS0(;V>LvC4WXPiVMBGX0 z!4E~99^j1TpYF%d^DFu8AS0z%D)DFf;@(F(ciS{@b1-q8I`mAW<~esLYQ#;mHJEi7RWH;WxdV$YDv$7 z+Ad5-?ZTc<`f|v&Z#eE1%8!+Ep?ph@iCq}Vx8bwh8OpB`eh`<&1iq5vPHZ3cER*@s z@mjI3t^`(8qL=tPOfR0MJ9+P@sSbh@f8MI+gF+XwAFb!1l6d2NcA@vK(Y>%Wbk$7Z?zhw2R9?*G*6!q2X$GyD>E zdwhHd@><)kJ&zLKL7qg@4_j&f`#-w;qb8r_!pT}bCSXpH0F-+uWW9GCjnliiq&y=P z(-F##m1m)RTb}848*Jgxdfu$JCVE95J8}nEUou9*dN*|PT!;z%;IV#Eb>v^lSUQZ|4Pk>(`c7&J8F<+}RpR@2T zK(j38GAgwQ%{62O*nUpSxfd8xT(0MrV&`S2fKrkR>iKf+OQnlqXJ%HhJ^4cmUM31J zyB>Z&>;Mn`62?t-z1S;*a$X2_0^`A)j{r3!*q#6$$S;Q-V(bWcZ|sNx@rO{J?Tzd! z^gaTbkAB~-z~r+1AkWQ&Tuk^9{7dym3BGEfd-`!aN&GCj7j%^SNpwWDJ?EXuk2hss z2~Z(=qU#?K-$((f=ez^(Y&(G0M?&;dHGQEy(1oY(Zi-iJ^g zK1HSS-o30*bo>eR{O_Yv)8+n-;ICwU@~v;Y^NC52WU0UG;`7H2I_Le{x34HwqQv{Y z$b0HUnZNmw!qXG(XZIhR{x*2Cy*P1U;i}amgT-?T<5zgw3PU@KgF$xOuVVP6qnx|e zfB4qJ-@WlSZ@K+bYmV#ayf4%7^Y?ry)&Jx7KJugYKK}im-Pj&3U-`E~QErz6o#7==QO~V3GUDMH0WgWWOmp!{@c(a_e}&-o%JEUYziTi&uG<7bdn| zafTNzRN{B?se`!^S^OIL0~PWQQkd{)|3DW18B;exlgoZK_K}z}J}$#M;;=bbt5xv#8q-u&!wXWsnAKl%8-Jei#Oj{4;0&mTD9WpDWH*Hf>3 z)19z$%KRNTbD&JFQU}VnpX}Uluw4CQ-=gyQPaT|^*tctiMYIi0`T65R+lLDid&VqO`uW=m zTPH@w_OB_9LjMMT*rZVQZ|6vP67%7Y7WVHdKo*UyA0FKk%#WWxRva&m?JW+j**{#^ zHMG?9DIHG_6J`dhm`{)c-cyn=Lg2WSP-VH0g%Xf}!-4Ry4na}(!uML$46v@3aoC@@p(eKe#!~hM~i2mLK zuHHB{vKNYPaHG)B#<8KT#WQrV?S=7;C?PrKWe5c7PK<0F+38y@6Z)aJkB<#~&z{4YT?u zhlfT2Sr}J%V&9gLiNa2>;fA4IL(|KS6?g9$8Y>Q70PEt4Vj*IC5WEpEZvlecR0bO{wH53og168Cj1su zsflO(@V1fZ_BZHjRdL(MSaIW6kz|}b>V~odIC5m$Rpk}j&K2GjF#N+^iu}%xjuwa6 zfB@mbN;ceM3T3{x34U|wzp)~8_ArUw(O5faap|g@gYjQ94)Pc-G5*n!^7;|=K{9LE z3X3C{tq_j+%Mt1+@rU{^ASbibAM&@1XaNydrtI|m^pUB!I{v%nRXMRA(R0$zdv;Eo z;f?Rvy0tiNWd8L0D4s7bj2AV5`C!98wEbDK$gVv*&+y=e3+rPv536M6dI1jLj!`or9Y*@KrWP7(=!Ai%-|6I7p-YZMf zHkG?bJJjIrZE?Q;h81Uk@@S6EfhF~F4-*v;qi$=zW;2C+aWPsoiZ|6u@q>q%JezmW{{O>OAoz`af#RXdboG|W@ z157H4dvV3kb{3jOFM0F=lQwZhVK|JWon>SzwKIN2`S8WW=umjL;jZ!T@xaxXmPapk zU$wg|0~E%woutek$q(lH5@m*e{+cr$_>bEk+H<61_cK2)q?-Caw*8y!Cw+DC#_N7} z(dN583Hr22G!+JA=!x`tTu+cM`tRbx&LOCgi1QH!6!ZHB-+uqsO32^enc|N5QQ|pX z*jwDPk78rRapDA{&ET%=r5=@lFRy?4$fH~c-OjICAKSvvI1el~k6vQ@r2l}Pcm#}- zOeW!6LMZF@Nr7w|8Xm$hq9zt>(V=boH%D|zxHEx%iLI_axap&D)8>N+%eM({V&4U0 zL)(W!cH5OZ$}{k`K`e)q`McyVF7)Rzu2|5%NHM#Nyj?$h4x}4=Lo&_x3=L15eyT1Q z&Yv#*aAeg6Xr<>_X*)UBeqp7Tf9H#jSg$H2Bm5PNpDZ13vxHMuOE?vfXrb_E|B`(z z0}CruPFKjkXn4o)$W_Cj3~yrp=ydMhkl(!JvUL}(U3=N)4Hs;w0L;pU{o$2}ulX{3 zynOgY6~@boPgN*yUaQdx3d)Zk`Hp^c5Ptry!ag{jBV$7o`_~nV@Hs)TC>qWWzc*0) zd zH^k;nNJR=kObo$}n<(rWm53@iJ1f*5zx&I-uDGP zix>0Se>FN*JV`el5UrnE{)hLXFMf|UvXuMVvd;@fhGno_qdSXXBWP!#y#6c)`+YZd z{Lv*ijPuem~gS>#u!`)|Kk{LJnO_9?c7mi@z8e%U`A836l(5+}-q{&dYO^#lK4Xkxs$bJ|>%FdO_{K)CIxT5#&xuYKtW zKAgB8Xa3VEo8sP^cR&2irP!NO`tSDhHeXsI*E8=U^Ap40G(TtfrA@8iIWbZ$SE*OO za`PXZzxuM(`7Nu@z3lw8`3v!L!-k;#)o*AoD?boDnYdsS;hBjsulFo?t;0n)+H3qZ z#8TxuPeB>pYYQ3Ew@~;?5CTT-gMg7`pbqN O{r%AO7i_xup8oie{N@0mF>bKY}i?p&2p^hv2+{f)1*qq^}moL-ljP|CeKz0P@qa&TvT`ZD}? z9N)P`siogn>exnH&pIlzk?T9E57$T2bdCBM`OY)EhiWq1=j+wMHEw5~hJOY=!*J!^ zlWJ49D%JL7rEVa6Dx0Q$x$jM_ik)KS9!zSIzvQ)*y9eHHi|)uuM8G~EGSqD+SI_c}vr zANuzLp@Tb%Ar!b&TjngKW|rc5P<7#sj60*+GS4P@nsODw(xJFZLZI4V1&UcvXT5P0?qDW5GlZ=?Ha2loR5SN$lCDlCWi z$@rZV%j0s;lKSC32!0biUnJMgTIK`cVZOKzY5M!Z59Jem0bL7GLT1L;ctEP^)oG z{n!0dJ^FgB9!Iyn-mI^C_4SBc&sm;7qQ|$C#@9Zv<{s`h*&Qdn9shwheO2XgKu=hI z&3Kmg>+yUN{V8C)pVE9$s-5J;{j|RS8SDOMzo;Lqj+xKBeE$N|3rKml?*)BG}T*GG=4yDlgXv%$E zm;0VBca+ODmzDcQTJT-3%gv^#y(K7@mVRZ@-0r`m^W3kay4>+5-LGtuh7S>Z8OU=3 z#t*3_IEZ8Lqy^7E=h#m*zh0L+o}+TBP%bC!<#J5dUf5UAIW^`U?$Lxg%mf+`nXdO;5g z$K!I=8#-zFhID#EoKEhj&?)x@p_BHHPEOM)$8- z==4mBP6Gj*ZZ>opAUY6Th+n?$zsm7=n*%zbpP)m^XF8IVAnl z^*4!}j|Ti3h8&<@P+6A8C3jf-d!_KtyF>a1dJ^3rzar<}OkB>rTWFk)@@9m8O&YKF z3gMskM&TdyU-XLgA92zvn1A455%db=d;oeSdLnY{D>WeeyE@K4Pxu?~5B((m4Wl1} z3fiMQ)rbE|>s2rA1CHy%G_Ga9DRlC*J!s-_Ie%v8w1n`0PD>4)J`ktV(rblI?wvxX zn)X1`3G(*};B^e0+#}i^yg}3H-ElerPICSiHl0lUrZ-ai&Ay>i)6GJsrMGbZm3tk- zg-)oXmJ(gu@44@0fB*l`AClV(l)8=R-0$jfQ6;(q55Jsy|`rgNQf zzk~4?n9kWD_CH_H_)d1*?>IiU|23lrI*wLOTgC_dh_2)x5VtU2pclue-#IvJmIEDs z{1kBt=-vXl@VHikPk=kajxX{j<#31bwDt-fXQl!i5hJzZ98HF|d_==%E5JV{aMc;_ zC*rfVSigTJ^3w7Nk>AvF(I$=W0OB5!+xKa{{7PScMqi(hYa_=eP5>{J2YdkaTU#_9 zmD)jcYrRbR6UZ~>khh`SuZuiG3q?QYDbFeRh62&8U*tLU`%kPqr_R*;*LDHiNS5bY zbh+lZoIE%r{A^vL?V1~h1E0t-=yr_8{hO)}ch->Osb4cWKC(bLhHa0@@y$=L9K-Li ze9c#mFA3%N29nb{<=EIYvg@}|ePh>;I*E3@VRrek&@OYowZ64{O4Fmm(nrg#tA31| z`V?mzM&Lwd9mUtpo3*`NiTpkHH>1}@GCKs1 zzV6TDxgRRCmg*y&c&3JL61%1I{}78j_1DSdX&%)4dwLw5)$zNJWhJlqOzk&j!E>on(?Eb??W_~vZdL8hq zUAHq(wVgn(t#*2$Kho|7jfdA|RKMl}?4Tac+}a8B+GT*dqUE90@o7Ir>z^|pl(&-F1r?E6O^nk_9A@G)q&-<)bKvI-sG74u zMq2)$8i<(&2U+`8<>@9B7;vpRnFXX(HW4p4uxC(RDlH=g?K zV14+-4t6RZJ`3?p%YewAj&DLewf8AVd=tWxC;^5#i=6T)r$oY#)n!8-9P&Hs}e z-;9*SH+uqoruc@|TScE~9$8JFW&EMOCXYXa+w`Sw~q=NUD&SZ`R%YXl$wCE)%%p}d2P!jn$C!eIPPQlL%JHe(*dzhaTTXeCWq`Bl@A*xc?oh1AIUZyU~2`{CInf#!qUm_^i=XVfxfk|M4gc!4-zMb_R$_6 z>D^#}N4eJcyi;q?Z=w8oat-_ojPtd;EfM-*oOiMPYcum$@3b22bG$r%|LZ-a2L6SP zkL3iTLmE`#cEp=xACGJMsPh|YspCt0UvAeVzQ@iD%*%*gvuyv?uGe<;OtGsXzipdz zT)9NcDa}7dx!y``Hw%IXaKdBF&s7K8FV(uA@lbw1>@v+iNbXfy&p%L(>&Np@tw(hG zq)!)6`8kb;_EAB9BKdpUe+eJLJd~{`*7}0?I~ZSq+Shqc%G(Y`@LPIh*5j5P$2@zG zs%gL0;qZQV)sa<4Y5c2j4gGF?Slfvp&*NMQx>6om{6jcDx)gNiQp@}{bw6NT18wSO z_+Ex~XkPeIrWcK0=HtrAVqGX4r%i{Z>f`W!kL5YECwBb>#sS_Lgde@t@ze~aolGwi zPnmTGGk*nJ=QRH$d8ND?*4O5;@4NZ1)*rHO;78Ma`r52pD80Y8%kf2S%jGaneAfBB zmY-|6U7__Rh!fK67h1lr`K{%;=@_cQ|En%tz8&olKY_Cl<^j6`JNAd@XSF=3CBLpM z-?E=NlnYya>z()dutS{JmwB%;>xnYI1W@87Z&}J0erGvu@>)_uc76?dlH93Oee>TdE6HcYJY#+ME9Dt8!rwXO8JA*U zImAKD_$GUX%G!VYHqXeLC8&#Gbfw^@0|d)e*>_PBji+j9jwPU|f#x<5-C$!otwsez6BoP%kP z9ycH^whl@`D*y%a9z~N z%#h!uygfzlX8k`ed1G$~{)gqn;dM_^SBcNkoM* zJgriB*&hJ&FVAb{X~S3i&G>gO}@+!E|e_}pgha{b( z>=gRc`U~;fO+M^lys=ZVm5 zzVn-8I*Oh~^2LUJt+yFH`8CVOiJuJfZOQx!;WoYXx+wB-Y;Rh=7Ubi!U8<0e3-Yt5 zx0lx^c%JPcLr41NZD%_uKeelUHe>yyBAk+YfO5FI+F#QKKIV zTrVNDi{)o8i?2pXoY({MtX5M%SWh> z_P7?fzNUJ0|C=43$I*$nWS{Vn{WFbw5K%XEJeuFL>3;?HGmO9OexiCTFP2RIu)c*~ z>y6GcGMz||LcOiE&apr`c~7dr2iuP&k1yn-JwENru9AAe6DkU?k+vdza{|`zh2b5FOPD-gnXAP@b9A^CT{y=Kw-G-N7p) zSpV?8CF^FIA5R$l)hZr$C;F89ehb*E5HtMY5f2Ri+@ z|53)CtO7rHKF9ncd;zRx@geS{k2#?F*DpFHk|BB;T#gYO3m*qb= zZy8zNvfEqe`qu*a=+#>PlKzK!Y4>09wjn%DFXcU#`4QSJn;#3bd*1U1Ke!*y*VB5q z=&6|x7`f?9$$C+*qu0GrpZpE-{Nji3gZ&WiGs9EN+MfemwLHJIk78u5dH$yJwI92Z z=@in@qSFkz6^rxh5=(Ro%j{kXFFEi&&as79YcE(&-GgITsW_@_$kk? zMCOgj{S52ddL`?+A>76<{x*cyiC@Qa%wN)vrZ?$$&g?hrsw;1bcy7Iqcn;s2+9Zxk zokDVE;yBfeE#PF&S9iZ!z(L*a6i6|4;GkN@St9-_Bg@3CRo3 z4@iF;(jR)xXD^Ibza9te+vRrk{?1^1J;nRZ+kO}3PV{cQUVmnNZ8CWo^W5YN?A##m z>vcZw42-Wp*J>TbGu}GvSAPSpGD^Py;k$iTU9~F5H{YbJr zhj3e8o<{h2{IV}u>v@nbVm}JFp@WV$gXhO;*njU#o$vQJk66CWtLl3`tOYsmVnjZc zyiw%C{frrhmJjXsg7XLbx$XP&o}v3Y$LB%Z&tP0aKRKuCv*y~7by0e5lI2bIBT#=? zzT?lU8$Z**I|9%6O}3kuZ$QVFfM&;tk4E0-HxGtAN}m4){<#_Yemc)WWWKDNbL-fj zvKl?4`D+;WCi{~RZtI^s7Z|`R>`w{c_C7DD2iv`He~R9Rx!TFod|R!?^BH6pgMFDs z{+*R%@7v%$20&-`>nMLKt`Py=Ky+UMyC?Qk?@vNI#FzbAztq5)dY{qy=>E;NXE5I= zu3>t5R~dPSy@dT#W*>#IpJt!TT5V4^&ruJJ-H`nuX8i%3)X$aDI>!X9f5guPG|y2k zzmmogt^=0Y&4uo#5xX1m&E~tr{~_G6yTS9VouD7{LF_&Ad$9faLB7kbM}!BTydp?Z zz=g4Mwe0ZD*t+Y&pVNI@;pW-4x5W;6R}w$l_Xd2o?FI94AL*L(-?EQ$?oZrKnsZ1onCf;?>?2Ci zegry?7kWbH@s{}?Cv_E;XMK#o6XhNLmh~r6&hii5jlU-2{=SU6Y(8i5 z5s3Kl+`V#xbB}ertIwInI2rD}v=MZxLa&zzy}X-YzYA!U+NJo{$9?!0@8#Bg%4ZC= z@2_NMaSEr#qsOyZ=8f3r!}sZVGK$~9#?%Z+xx%^h$iia(&pNrEmix0QIyXS}7tptI zACh(f;5fs*Uyl=UBHIg1 zFYFqXYnm^Ce(F?h556Pim+t{)-QI%m%erKU|KAoF|92M`zc;nW_@^6;KLdOb{(9#x zE`Im_8jRnPAMb)i#(!Re@!Ry@+F<-PeYRA`?~RImX#GO6etYYy!|S#$^xS4t{tj2~ zU)}gQo(}DocWs05TlUdA*kJsW|Buq=ng-*iJXHk0`^^}BikCS4cfU;cBmUBkdn67I z{b^#{6RB^-JMLF%;Fo#CyzwvC57PLeboy$HP9W0){VY9y5XJws2IHsoj0k@3NQ3cP za^zjtVEpu)eYF3F8jRnvlkT?~jGxwRBK>zCZ!mt#4!Or0jGxw_qW%BZ2IHrBXcYgq z+Kbe;?3*`k!Ry4oVEdrsZ@hJa=N}D=ziGZ7rTf1(7=J2` z-#gG?{FdH&lQH}>&(2`JPkv1D%CrtpXdeyceHNefeuogA%;ykp`7y5+etCX6tlwz- z@*LaZ;g{#7=8fOh11}e!j|S_H{f;m16~pr{IKM;TeILjlsbz>uWuA+~bvN#3Gcvzc z*{yP}X*SExsW~{m5;+@u~HQ0WzN-&rB$@I2SssC~&xPdKRl9l<(8>zNCyALMatJDHd9&)bja{ss7LJOAtk4`!2;s^64&jzR(EA7jc_>@=rhO-a5qY!gTXN%J zKR3O%5g%D6Gs+ZcUqfekK1>}5M_CffmHFMAf(UQ&C`#svPI#r)e- zk$=2jsy&1!^Dl&3^!IAv7x@V5*NNY@3*OV~UpJHQjlhk5)XZ;NcE$aLv~TQU&_33q2tWSUXUBcuL)_6iJJ0&I zowe=wns|Tf?q4nZzrV=%pSnQ&n!as+I8XZO`hg#_=ea+O_b-r#zmxWY>p!us4_nta zHK>1f9)#w-1su;GtjA!#1h4nVzFGG}_!fV``@!7%^*R`~8}oXPS?96ks$k=d%e}WR z=3nQn7XjVv_BU5=A9RoT!J2w*he3&d~hy_E;>&RJyq z&uTD!o4>!iK>W5{AU_|;lX&M=$M5Zp>qpIb1?BHfkHmq=aYPtLT5$@j%e?$jpnsMh zl>SETN}c#^`Lg-5u{!-~>Yt6@${%`XSI6(Yz_K5okn(FD#=7}B^7C;!>fybNQ9Fur z>euP_p0A_)MC*4=9ERsII4_YK;&p%J7NhSYr}v%fyu=~ipWxvAo-jt zmgW6jt^aG{F!SDXN1vym&jktc99eyyM)p+6H)K!M`3K(j=BSh}c?oAg-yhI{<`09 zFn)Wz=D!+@-(GL}K{EcfTN)IXTK3odadLYN+lTbO$@m*K9?RdmKS^${VdMFqMaKW% zi;VwA4aQIF7*YGZzrpxz`}BMZzk_S!U+2wV+dlnSgYowOUz9$tj^U^LCZA*LzMt+_ zUe}cU!4Y_J+!^k>u;Nbl12yoI9xY&9mLBt75FhM$**{T#!?3(G2s=eMwa&meEo=pF6f4EKmTKGv$7J$EOUh%Pb+-#mJ!uv&I`RC;qn0VM) zr|Zq;d0kD-ZJlm;LC3?r8D9URc$DJg<jak1*gcxYWluNRfk zr{25-*`cT&591nRR$KIb+Xv)Y$J_MWm8@G(JXB4tMDIemsZ*}>I(AsU!E##@{{rQ< zCVq-n>d*_-E$b;|&*P~0{HJU^yA$~~$V-`i{Cx%esB;~A`P;RA7`^yVnO;2kr09h{ zmq6=9xW2ZlhMaGiRY?k_pX zbic{+3l-?z-rN|v(=k~ET92{(LOWJ^i*(`SRZ4$zxAM5uN&D$UI`Y_3he%{53+ucWqpC(?!K7sdO0|B1PY@d*M zbGu&mX~%P>c&>T43|`XZ_UiBb`dhEp(D~Y^wvPxbua7==-Pv1d zJzx44fhWc_5x5mE)3E6|Equ#4v)2oMaYOb~P~MIF^~oCdJ<;c{BmK7HE$&wYzR+>M zhQ{65SBcIG*IUQu2>Iq*?2Md??Pt^s#ozteyw2z6DWBhd+}KN; zuS9q%oR1C2&63B@4Rai?+^sY}Y5yvQM}A1<_uDJm`)lGcLU78~yBf zioVwTa(w0&Dri2vHpVBMCxYuxKM>q%zO5C$;T)p6&S?nFBT56+V8B1qe=Mfx=ZA-5 z=Zoab`DMrt$hdwd7*||wExGhwN8^d;k*#MU_o4ksmirK1FMg(9r2QKB_4$|z@1^Gb zt7Y>KdOzPQaqgK9yS9mw`1*_ z_hGMse%}y_GjZN8*$I^zAiW}Vd~LngYt^@{_Ve664wH+uPh1c^Q>oZ{%7gb~uarCl zs%@y}eYdOr%W8j^+jq;_uhee6?fo*=UK;knSFZ){AXa=X4TjDBc!eHM2K%%j7b~z= zx(NEhZj=1Ms=*Y%?%?_AAz7Ey_FHALd7^t>+f&T{z)zIRn&-3AGXy95(S~m&`>=t> zyk|k+vnG$E-&fD)CI$A0`s+Kd<6b-I%OD%I>{1E?9E|u+%TDmQLVIC32qkp!) zRqLF$MEtJtKhrW^?+xfzwfIB&2_*o{`yzBqwwIOT5W+)r6?;T+hS;m+Mt>YSZwpQy zpFYUlzi57#_+`fUL$+@y=dV}D-KgA#b^QJ~ea?5s?V2AiqH!@cd4G>tXP|g;6Vb!K zMegTzt_|eyUKl*gJB%OiL|;iicwEmCd8Gd1y?8ucehvY8pvO&de_*G{KCQevs9)7z zYQKW>A7Rg!j`I9M;8)ChIE~*hbTjW=S4z%J{3|_f^Zo!+o}L>F`4h2wPC@Lc_?5tq z1a{9^AAL_a`H=$A!@L(DcyC+<`&q9YGk&AV&>`?oG5c)Z6HfkNfcg{UA?oxGbS?zb zMYprq{=l``t7!kz+TY|>X#PB1{2lm6b{6`UC%MBpi_R?&$6snY2JsU+uiMF_eX?^a zpCfWuzn#wwYdb$I{vfCAe0Esue0B@P#jx{nKQJ5k0qlE$UBUdT%6krt-4{DL7kmD0 ztygTnB6iEN{|(ctH~m(xL=NW|cm1a7)$+JrttuG3gP&UuJ-h-cN%jbO7@OBGmRuhF ztz79SA&uNGOg zK}|MH`h0r@uY8;VzCAJXGq6e9KPBhmcVNAP^%MHX z=U?Y6_)!Cw@~a*YdfMlgD)ZiYoi`88dp7x4gMYKk|K~jajGbc|vPZ+3%@xBtzr0W z`sj1Y8iwDd&(;Rh-|qjGIDYqosXVRUcz<5~IgAb+S3u$B>p%H9j1Krl(NFQ4ogK!W znRT1ReGY@#BfshWji$qQlI7gH#ELIy9gOk@{Z4E@9^wezKi2`@#r{pf-mtx&-}xCG zXBzr|aTHhVH}uhQM0RnX2dDOkKKLKg`?~3Y_4|g<IPH?MFI0E70dJL|!@q zc|snN<5lPt=~s>CoH}kY^je^PU2o{6<5I-h%!goI^yKK5EkAYp4cl(r7PnhAey`c4 ze_VbS-2NM@x9>h?*^3~qO`eZ*e0ah9=J`m+2QuvG--rJl!Jx^%#(0i*~!=TBzyk*ZLE>KSD+h>e! zSa#vf)%|X#yI?sHzk4EX7f!a{HFk7v&p#r+`yR|-S`i=1cfYmo3RGcI!rAhAHJmdX zZy!zmLEt`Kcan9Pd~BVG>hXQ=cGBmrhpO+>iNF)r$0Bem-=}om-~Fk>d6mw+LVtHw z>DC$rC=~A?iilmzMRhOM$Rz*<@m)NmOO@cK<2BSr{~j& z`*J$5-df+a7zZLfF zk(BYd-Nw$b9s_Tsb;kI9J@Dxsl4mrIhOy2KJ|)ldI+1%gM)B#DBqv=DR+7&do(D$Y z$?_T2x8;-Q5Ty&)#__H14Doz0pW=K-laKS)nXhVt-q#}c^Va=gDet`+-`S zr+j@X)pw4g9A5|Pd}ew_d|LgkF$GDi666 zdcp4!z3yQAS(a>;6D?O}-BYhec7dHmf}4EIX5^{BU#ugtydeL)PU41iW`^3y>pbd6 zZkYN7_^@7&6!>tk9(k7Jr_*LVQsA@E^~f^)3;aMOJ*57!9@4($Lf3~Y>7jA~KRp6Z z*2A#At%p)S)Kh!k9PM8jjOcm1K9m-pKKjRWM`8TvLx1jKdlT&E^G@S&9IH4E%0ryq z6~dFp5yIpBQ1X8HNd2U7EC9bs!>-7F2HICb{Nr(VA@?Y91%?qkdEn9ePTcsu zlP=h6=KtkPx61sn`Ik($u)ak%>^qTur_gWezY9Iw2fcc>wkyI{0QA1D&1V4A|JO zr-2RgeXoZ-Z`JwKu77F}e$rFe!{Gb}oljjX{3f5;F#I-s&Leq-ye}4gbUw9V`0f7d zd}_n+ThGau^EZ;8TZNtH`4Rksd_SbWAJ*TG$T#GL^!cg0AD4nB7#(PGAA~FYUi=M|~I)hu@Ff z{m)|8y1p6L2P~tq-BUWx+VdQ-zji&PPDx?K4;!=5b+VVL;PAC_R#2SM^$o5^{(;7a z$qe^jd3T^ZkBjGBg~=TQIx z(T%T)^DZn<5!}zp^AK6AyJLNjjzKB1y_w&9tLx_&4%P3+`X%D9ZtP)Xd{5APt9zB^ zm!>1=Desx5YuHn;LC?1k?}2YUBf7i~dQzO<6!>>ON4n=ukrVHo0pIu>C3Oz2d0rs= z?s=c~ljk_=SpE<3*dAFkw_rfPpIT>$mkF4Y74ml*RzMGf(c#ehX3pmliW~3h}{l0j}A@?Jt`vFTA( zfAV0@Pc8dM_E_v~y>{|%jUGX+slRnTFV+n`E|A<9JNaIX?+LP#U0>C5{r9kAh1Kbb z^D)>>)g6H+#>|qI9{ILM&OC#jliw`%KSD0 zx5vx$jKJ%}uTp{kqxmhxO+3HtfyNh!E%+^V^=ERiv9o z{D{Dl#}(GM=w{+MgoQry)sy*c&uZg`B<=!RC0+>PI+=em-xo3;v(8WR?!kBpu#b-e zGy4;XPv$+}TLXN9;E&lqb611$x5x3j-)S&@Yd+)t+alxtZXEx->E02ii}$Vu;kD0) zd`BGbg5}YoxA*P_)55tqZjG74kD8|AnjJAK`4ut}kTy z3F(qN&Jey(y0ZVPLe~ZAv*LLfxG44nR!rL$lSfvPH(Y&>%!9l$V4_66`Mn##{34@x zT}rL3Z=Z&@O7@S<(DTiMz1PiI&e5M^X8sV7Lo*&)SB}_6vY%`>Jw7M3ie89)nLq!? zpY!~g?Q%d*kI%cT(k|DFz-!12wpmC!ekxDnbnin`!WVvS1m~FWeGJ>2Un2WF{Fq-+ z>NxU8$d7rmY2GJAZb0Q)qLYoIsD!L2hXu ziSN7)5N`EP@=KBW_W0ROM&NbghZM0MkT@Z~Byk_&xZcZjeu>t#$Zn*Zdh$!aqw`DF zxgEV%YdPfnQbZ2yaoKW|Jg(3lT67ESe;WNJ{_d`jS7Q0W_&@;K*FbD0eV=#!p~5^M zd7T#W#Pa~qLB5aZ?`!q|2!b zx9j`);Qk+S`I~T#1>1LZCSQ+WokXthq3f)lzJ;!{D#L!EZwI^s<+ExD z!+WtGzX&+4b$^#Ou|HFHEs=HVr612c9rac7*|bj6`+kj2rC%@Q(l4R=eZ!(Z&hfO+ zDOgVe9P}l}LGp|JlIx_u=_#VC*(cctUAPVX0E=|}U|-=)Qon4UU)XS%iuYbIkxi}p+hRaNaG0hN2c^Rf_&rzSO>HfT7n zR}-cA8vD8OBtMRd)W#UT*CYJD- zxFUn~Xv8Odh&f5l%zB=CcP_sFQO7B`uj8szW`^1sj<45Yzr#A&SD6<0tgLgQL+ujJ zq_V1e&4bo@9`Klb=8Ddvf-&JZ1^;st=YSYyyzEyQuKM~ut^H~??pOOh8Q7sj{}6#E z+PMhavSZ>`BXAo(`-KR+PW)l~#(q`oBKX{w*M3#v8c@Tj$FBlU^1j4A#J0!4caQyQ z-)Ae*jn|_h@Z@oY^)0#u`w}zgH^l{dUn1fIjuZN}8$T=S!jNkp8cLtW_*XkG`7yLx z09`+Z1~7j7Uzqop%~FkZXgdjDU;`fca;&u?)5E&OKxU&H!u)91X!?Z3CR!T9a| zZ&_sgA8j!Hy5d&YYn{LD`x5CL>`DCk^Vanjt?MtDYqkqd)%&(n2#?5N%JW*17vcBD zuX$%hdqys%I|5I%XA!t<&-DBTsc!A(OBJd2J@H#+qs;|tU_~cZkXfetn3d%gem2kCC+P_1xYzhc(Uw|#Q7x>XXei3 zc4-(pghMD-luiGjrcJb#1&vJ#}D$oornvD_u)U)5Az)$7eM5X=$xGi?kC9+)%Kmg zP^loU_zX}LLV2L$Q&2BBcdjhI!1L>{yj!xc}GQgCOdL^1fJYp zSl^assb5)NIR6qEk6qu)hjE@D%lnLuSIDnM^O>M*L*~nLo)gKZ@w=ZV`hZ?9L<20B z3-sp{mqhV@vcdRmyRYMsMeG0Pr2onJ1kllnf4t9%UI8G_mD2N}q$mAO{JaXxC+Iy< zYhG*k4SniHx$OMTt61|&u#x!(0+D^YEr@$5(~E8{?s*mFxni?_YHrULLoe8mt@%6s zeW&H8sN)Jdi0Px{A8~F6U+U)-&3*8R=tt$Ait)c+4P*xBitL-d&-o@?n{v2b^Ffq5 zrFJ>I5o;OMTXPKMiJ!IbKFA(Lt$7Ij`F+%T7~ku-A9MV70-uUS)31Kf?T^f0$dx`# zT^CIrtq3RF^x0XQDs3&5Dj}(QKmC!T`Dz6KAFcsEy5*0Dwrtw5W%E_%7PfD>YU`FQ zb_MBX#sACg^47KY;E|)&t=Od=zdt&*YkX{KbZWXZHXSQaei0+qg^xXs{AyjFwb9ah zO4FAXuh}#{QaZmlb+x~{IJ&Pi5-EUFj^BQ3@qO3)s6hR;&b@vQ2V|qICTU=-tS}Z)1|}H{=tbolf{t|_k)Y1etyLf zQ+AHuH$}^B+8--jOXx$8;O6@r8kD!1*&ei5ycG$A zqc!5c!S2bS$?-#@Bc+ick)ff<(Osppb+J9gsUegQh`AX-fx6SR_gr1_Vcg0c+1h8Xs(_pe6a8s4ye6(%N1W9;C;ctn9l`b@FhcQ3il{7(9wEWxLak?ER9jAO9L zrs@a%zibNR9jnm)iSg?G3-v+rEgU5=!L8PI!MGH5j#_uaOVob~O%^MC0N*jL6)dSt zRrC47`)8Bt1ov9c%}acTo|FGPxNrJwf9l|_U8N}#gp|YMbf)={7LWjK^oNcQD;C** zaNpTJCOKOs_e^bvC`^Nz6$?iZ<2UAyGyBJo%B%93EbTrxHu4mZF`3HwW35$9+>xp3 zzG3e~b@_;PEs0mPCTH8B9sYjsqqwKU`msKWQK`$_H+>|2r{-16hD7Z@TH3b$LbO#H z+k=o`+lFo9dwOf2OR%r`Xq7`Rs4V+b?lL{0g!Y%sZ3(_@{n?OA;^BFSRQ|vRBV&eg zs<<0gapY`&Vw|Stqs4ufa%n@RO7IPY9G_h;I3PbN{72j{J~fJ&jgLqH3>f$KjblSa z@ENZz9_nxn`8ZHI6yQqwaj~}Vr%n0e+68bgt{&aPM%CDTpKgF@(^n$~ix6pF728Yg zOM(>(a@J>Tp+OcaG775UAio&YZX?egNjQMefs z_eXJ5`u*>Z|IL?^bRPG9Vd@|RuKJlO9xClPOu3)Z6lsF-c9>Hfq8{--bgOXg1&Me@ zr?}&ZFuIBHk^jT+lLt6OHkpib1*5FnCkL{7bZivejG33}^Q#};{{UjW(cMS3$9zt- zv!VYOMR#)KNBUs+6^10%#E)95@R4i;? zte9P9-M2q+zkRR9bxeLk{1j>U+a+DMNz!#d)K>#pHE?=u+pzTdg0b^peK9wr(EQ-& z*!0uS)D@%fa_fw@$yI9ru$497Ej8fFYQVEK;Fpc<9UH%943gnbADJlE?rnwbJFeP# z>6R^5ZQpkBjvB};Fya%xLVhf;;ZxPqC#pDA)qJXA_35vgsNtZ3{7*2^j}Ib%?=K$4 z#BO|YbovO^12Ct9M4)IC9=&g{1aKIda3XjvGD_mcqwttx*9ZdmbeK~yxam89Q=%mb z(7zw(f80;F9o!1_hw{(pq(4E^*8qO&qd)Qf;gRQTzVXdpxcR=NliT-pU-GhxA2@bV z`&A#E{M(@y4<`7RwLxY4c=}mC`cCxP{tdIb4_1?=_|v0^^QMdYCnO_ElcDwM`Zs^} zM|Pd)weJ6fpo!p+>Z&JNIN^7seNMbb+fFDRyS4LAcSS5|3?vsfo^v$eZg}g)b7sSf zgkLwFb3EZL<;6c_?uYy{B;c@hipPOMt4+ZQ-~lch6s)1lA?(CR<@-~GgQX~Rmj z50$9~-*MOvM~-Ep{S*62(I9DGvATb)hWoEy)${#o@boL!eyFKh0l=tCwIUtWfPl5u zfLCR1jk=HhsOwt?YQ(>?O|>$jbY&1jbY=qP1(H5pHB>6Y^vzpWy&_g0;ip|_+pd*A zwC_c)b(o6CRqJOISmXDPzw@T^susEN?CQ?(#nyLZfp`B$Uiw&uCP4)Tbq3P-Yf*Dib2Wg7B zb2P}`A4<%Mg5Oc@@M1H_)v-w5* zhS($)+H(N|FZb+HKb&8TPEVEgmGQDd*b(#s#_wR=hF8~q{xeSt@Fe{>=W9>9BoQpPHwW+XU)A?6jw54zDMkbFe1-g3;>oziV%G6-U4%{x`bN6LzoauWxr8 zT2l-(CAnyg^{HPb*J`@n+>dt4O09B{c2lszcd>?Wk-G0MjvayF;`L)*=!)Qa{r@yA mf9aFn`IVJ-{9t+id-m?=earRk%dg#V!`h$T*NVmZpZ{y(ce{EZedqOZF3X2x%K)n{G!BH8HY_O#(4+~m$j%l5UDz=sY;9>N%bx})`Tx#2_rB%Mn;DH} zl<@H}`aaFPckey--m{-`@4HW>6n#>vSAXLx?Wk^i4W-wm#+7n!ORsaTR}Sv1PhW)p zj^jJmDYft?O3j>x>m!cJoW|`P)rafDX}U)HjC|+0yoXwHxzE=tgKON*JO}?w`81a+ z_x4n~xV>LbWE)M)Cu(M7Nj57rG6Zh9aPuw{Y#`gdx_M~mYf^uzS_p)z{J&RR7Vr$ zL;Pg;PKx<)2{29LaPI@X37@Z)YiBLff#5J*-1{~DeW8c)3BM>^3ygt2;1{{x#N{h+ zC&lz0mU8z#)Gy%f>va7tTpx$)oAvd58t&tu1i?Ej@ElElXRW?Z;|Kjg?{=p51Df7B z8PBx4SjIuDM|`0&`a7$?iGJXV8I-g|@G=B=+z``eZ5xCqg!8Z($~HEdRVS!&Cd_(`7NaRbxf`L1dqEHJv-^G_z$@0%PP+U za>DX!=Cfptp3mnoo&x6kh^C8D9mFs07xeu{t@~e;`_wP$b-Q1}ugz+u`_KHn#Qhik zCJiBa#LQoHIGGb!&k;Waa_#;r!Ry$u>Z3d#<^E&5KgI1M<#$-+S+pOBl;0UIcmJ&h ze5OaFeVy8c<$H1^^nuWVCO5T-VnH!30zT zIt0%*?Y-CYyrBQCr28xNybtT~D_7E1L-pc5^QXI$ z;4Vhl47F3P;B~df^K#Z3JZb!fc)C80CwD~fl)GN=r0t`V(|F1;-a|a)G@da27@l&w zw7q-1#?yElPbeomJd^Nqr7RM zUyFw8T_g1K-X-*d{EJ+%{KHSWhUo_y7D1nY&-=lzTu<{c_*~O(SDb#H&^MqT#!2)W z!Z-#Lq(^xQyo@iwLoe>59M=bFUW?B)c=EJ9XyJJ|Z!vgUKyX06g$7S|#__c9<$@>o z7Qs_ZeW39K{<{Wn9fK$Lkk$v+YdqZ=#}mql&;P>4lWE`bF6w_#fTxzL1y2jFNZ(pR;O(Z9)T|IByzZUmjsrk8A^hlsL#yu`~o-p*u zxztbUB^rMY^fcO&+g&8MsSIDY-z#{(_X5}(l(%1@;j2`d+PA+}%Ab5P)z0PcxoKSP zOkmG__G68o1jv|FfAv^81|!^n9Qm7|(V3 z{mwmFFR#uHvi*U-#Q1rt{eH*sx&N;kInaKza@sRK@JDzh`vAX%>2jT}mvdOoP%i$* z6Yx`j_tsAvdjmQhhteU(7ygraRG;9qZ5KGsbaHv?XLb4E3gw^I!F zsck%8Slk)h5BT}5zg_$cDHQ&jBR{9QXU!rJNRIqdk-j2!CKEDYAR`)^UTQ zh6dns(v3d+cO4%TR4(~<1**q+idOnT<(`V&Zwu}_vHO6a>!(0RhQoFpUas`xA-#+F z?y8ti;=D|xJbAuhdn=z*6Mj4TKW-l3x6L#B)&}8c2>+l4M1%cxlLs??JL3nXYjr-9 z=Y#7_`kM0o@FUf*zUJ}Z`gQsmWUl7-d)Zi?w5ao>0BZ8y8AtNx$SA{yQA6>3ubn4d z{0?momgsRo?_^E}yBfZZ`w<}@dZ=IMDAnM@usoR$!*ZJsTWY}Xpz%ifuMD6hmJ3i`jejvTZ8G{mdGP92K@1k{D-!9AO_8GlylG!G3^!4gYp2wjw zYpFeEaH1~XD0&O+i66igd9o8uCQotFqEq!eR#b=YK9-fd=h@nB1nW4n>}Q+qr_<^u zz)O?nGo<@jYW1UP!H0)U_)+OI1Yc>5ue8P&);S4Zdl-JZ^6~e_-~-U72tM#guB+)~ z$-{?wH<@3y^^(NKmhz>UoQ`{-XY9UE?lU7lC=@xV;0sOZa5Dq;@OiN%K3V)EzNmQ zuPvtz7t}&tKYKT7FUEjakGP^ol*9Q~j6Wy+J8r%kYs9!ga8pk@>{o?yZQ5%+q@03o zC-974r_vXQTsv#@yw(e!0zX6_xF;glg2zyu1QwwbhSGH3z=PHTVPi9(nDy(={Ku(x2Ck zakD(6X&!CBIP(eQW*x1MwZS(moTk8BybggR8t2);jJOB7s|9P@)x-3?AVMSdgiBk;)16*@*L+F6nNusm6>gyptgSy}_W_)B5?df_jt z0bl&RIm1`2njhL6pY~g{-NbZI-g4>}Sghoy89&VUX-JDQzve*Cmr*lkgYZ4zuzWen zXFVkOK1i}U(oM-F{2=;5ysP?coiV?yROYu?ej3~o)`zVehqx!52NaLiw;+@NZg= z5&qNuO(>`KJ_hk`!t!K(3(GBj^TfXi%We3a_m1enI^nAoLjR}Ozu8sh-@sNBiN8ob zp08*~eE_(kmZF@N$t0qC)gQs39K{|L1Pz1oYB zihgT#e6r`QJ47#etKxJ~qUSoHiPx!p=-=j3&eKKoa-DQi3(z0y)r|Omfq$7b{-x}z z1KSWjvam_QPyO4}-(ePN!v)xvh);^+nARV#zMy?2o&i5QLkwprb&P)KOZ+|U=d@zKU4i(%P3vLur$*Q>minCz+iw~s z`XzdB9G=7ef}7CJ^DR2G^Y}YeC+L7NG@A}yf4skD!zZ!Vd?)h%4DPS8{%cgfuBicE z_%`f6nQy~#OTVa2xWwRFZ>{rV$}hJ;Hm)SP9fRuv5mVwr%$xn*MF%xM2p-6vW;_J@ z4M`7>9CQ(#7d*Ifv1-FUM&b*q*N*=x4LOxOP9SgX%u$g2GJ1)h9O_4Vek6AT0UYI8 z^Yflr1AmRu=hzzX8}#!vzbz2_VV)8{x0^WDdsdD9*Hk0l(4tF`r;|NP~*s z4u6yMimXU==kE_m+Lk0@3FJvg$#%MdwkZe*Lw9t(W}D0?PqB}Y=P!eia$oU z-7>8=3jzn_1jmZcRj26RwpTG6$`6QMruc*SUZr*XfqL9No`-6?M)yzhbPm;@)qH55 z733$9zqjp|&>_r2*>Ym7FL-~5`4y;to%f`?@IVB?6<4CQP$PpuAaa*@=Y8UVxQ5> zX|NVz2l3@(u`U$O)5ZhkpR3HnJD&MD)F*cP2K@l<*#sZM)c({o!cNAQ@u$qXgNa{3 z)>*}$#IKZh!}{E8_JuEcrIsJkZ=gpDa9f04S7zNp>HWW5jxT&$&WCxTv(E34q6Zz6 zTB_wH@DtK(7g~R&>8<&?<$g4!`dzwyha+)5a)X6157-sxu@@5Fs?gQqU)Sbu*>4^4 zh0VY9#=SoD5a;zJ?o~Z{9ui-oQ2ZsYHRTJvv+Or{ZK*-Bqh1^2f%t&(psW{i+OJAo ztn~}{809LJ%S)b-{i)x_*T5(1msEZ6?@%TFte9u455C0Lsw~f#5&F(D&$ti-&ne1> zi#|hRZ9jgWXXNLg%KX21$}@)X8t1`+{2Ya=BCmX3`(2RdEu^17Ez;}6p9{qgP>W#q zXPSM9o7{o^)A%_E(;xdK?FiFw zUwP-zd_sMz+PHly{P5)XSn`sgeyvyk%6y6cDGpHH`P_eHJ1l-{Sf1QpSZ?ck^ZXO7 z3qX&1gAg^L-`w(`DX4tbv;Z z_6I=y%k!N1_`wld-aqJGr{M6h37hrANe6Yjy&|#wTKhG zDE!dk!w-%;Z|v2|do~)k+j&oh2YeYnUG!Cie=6+bPtJSx0ut*vdmoQ-99|!CKO^(@ zsNX`z|~g4OQu&?ZsS|8iy|M#`lj`0kdM=PsX{(3$j_qPZeE|@ zINL*Jw@CJW8}nIcFKs@Mafju};||O1aT|MU@+z&AS6ndDv7hsQ;d;qMHOA54dI^bL zEI)g3yuV-_U||J6r@{C?@WX=rQmKuS=b6>IH0cfT*9Z@Y+gstg5dAQ(6De+_>nl%# zzPOeB!OkFlmOS8}R@5UBKZoVX^bN}``szGjSZ?!=;4Lh#6TX7EjPY$r`w5+}tK@f4 zo`U`C@;rqPI}fzQ^M4)Kw{Zu{f#l~pHssYWsh;Ek+u(`MkX&5C{1M8dJul(MusnHQ zVY!7j)vL$9$nkj|E8v&x5jwJcrg;y*>n6sH=JzZ(-ku+)BC8%tNRGr6$p=NDX**2I@t(6CoX;gJqHl#=}ulD!TN{y zeOWit^my9vua@(?S72Pp@nEBJv4Zf3`MyZjoygAhlRVCD-6`bLs`Og$$rWqk_D30g zvK;gvy(07@c>M}{g}oOuABJ|$mNS`mSf0#>VR>B6mXnzB`d1vza^{Sr^)Jp_M%K6N z{u*8XYLJdzt@SS%e<+vs_$6-}mdEj>yq7RNLcL|vqd~pry_Db+AIScPY01~qdbr4` zi3bed^ddeSL20j}*S*o6;xx1qJA@z51H@NHy3M`?x~`t*xAsx&nr)uHWsA0BmolD0 zJX&~?c}4vEI_Y4>k8gQ?G5#DP?NbnZ5h5`E1;7dWEdkyf@=Hn1*e_ks7t?b=yyVrg zGY#5-ns$cvJs#Hpp13{hvFdh4_(AJ2^e6sYujS8$ah*j^ImaauHzw0FY;Vhztm}s5 zHhjTzSY9W5?azVOA|EY(t^GN(->|E$yeU>G*Zc72@V&8J{J7K_;xpsNsYTcVPWpTq z9)S_Pevsu-rLPisggs+9jjzYHKcdH_GI~AMSu6D`$#q87m(6;T$ses?dkH@k30CUA z1Nj>sN1La*7u?nR4&yI~9>8;f?d;DkLl%n1?aW4>5WjGIK=R|jUMkvuw;Rf9jh+YX z3+8_H{?1^1J;nRZ+fRVHqjn1WJrJ!UN9UcS^Zg#@5zE(kRejHgwZ28uQ}f4y8-zdHN6kDme`vcG z?ECX)Io{{h_dJMOc3v0e$@p|+U6juAV}6tU2sB>i@A&iV#?ExIWj+3PS#KiVfWBI= z+2~CjkIXF&hCWJ;e*=Gb5#;?ijzT0}R?Zo9>`z$EtQiRx9y*2I<9MU#8)IXBp}Hc0^kJ(2MRjP#?V4zEJXR zY60|~=u^Ev3H=aVuuqQlrRqOX?=xB--M`t6T=|UTvl*Y>kl}aeOX$yFABEAMW}nPj ztxxOK8?rydtUq9o`nghC=NK=~pPJ_=mkiN7!gathz1iq~8qvEU-E6vx{~wlHdRG~J zulIptUb22i^d9Ia2Kg?#9V%u(C+~99E8xQDIq|zH=Jmbpv31wRpVP%YUgDEuY2Pd9 zH#vu~2g9KAN5M-X*WM0?^1a+>Sb z`A3rPpPX%+v*3rK2R(^%#sa$AdIpF^9xN7#+(A#@8 z^&gqfe9!kak@*t8lDxFzD+9k^ihBYCdl4$9N@*zn;^O6I9#6x5%RgsH=>ur@;c?DCVbAz zMfkSa@L7+}BYZjEb?*2f`&0lmjNLKu0Lc;bWw2j^sO8@=ip7TIJ{y0?C1~doY(_&lp%i({7Cz#+`G^p@+j`z z(k}`)zukEx9JZ2@=vTmrXf4|A_ zE&O;>^9+CgJi~uMli_px6yo1IXMW+kziu*oo4#i^8NQ95vziRw9{-uu;d?I={m_o| zc9ML18>*MrtzRg=9g$D(VD<6U4S%%-|4@_RTl&R2&}8@=4@BhW6-|cUXW{3HCc~$F z^%45IUyH#fe~jY`_seuYVvlXVO8orLUMKtcVY%f`xnHRPU*eRoeVy2emI{xp);n&nZl%GB>qMz#258fE{7in+lH@s~kUS22shV_H? z@4bC-yfh4#@(EGA|7Vlor{eIvi5Pr}vonbI$<9b#nb!FV9eabg&!U6g?+}(J(;+Ok z?2K0nzC1r2wr@6kd5&%V;LGz;bB1s8ljp|c(O@6zYR8xNj^X*22~ZF313~^sE&j5J zbFt3Rjr-Y*#Mdf&rkrb<&GK_|TPAk(s^{3MM`5k($gyCiM^R<~}^8Sj4)@9jZ;*+D*^-*chTOXa?^RO;b* zt{bU;S$C%X;9r;X=Wq@FL=RYZXdeDc_2Iu2aRK8A;?xNK=|RY+6aVgKMNjB``l{`7 zOb_Le9W8VW*U%4Pd9wTl!>#trs_m-_DEk zTgUm9y!XtnyiGfa{fP=+IQ@( z$p5@wDpH=z|6zNJf4y4pMZUuJb;7sxg7@4y<>SsK$p_XOWBT~vr$;`J-@!nz-*T78 zi@9#cdJxG^aQ#l}`or<-MX>47`p}oN%XeG+>Hc4wKZE`+7x?%;r~G=`!8x|K<<*Lt zJj!5J!rczs9q$+~yr`$2HKQoR4m{iI&^a&Ub*?p9dW@y@W}#`)UY8`Hx86feiT zc^?J}W+!JhUu~}5f8FqHylrYSe0%(qUn_)k3HSi|d0zPNf8zbsO^;f7F*+XReOQi4`4T5P{rY~tj*~CYaq==6kBQUV&*C`_Syz|$oDVr1 z_q(4%yj@Ug)x%itUI*>ds9rL8u&r_Y*Nh7(zk6IH4oda|!#K+FGaDYa<+sRqLw!^? zd|N+Q`BU%tas1fuy*<_Kg}2+X7oQV&O{1f&Z+2E6Z{7BVo#hdj+xWKEYffo0 zd|RIlGzj0;XPoDRI2w7ntU>rTeysH}?++S;Z;#*NANRkT4BuX_`Eirs+v`m~Z8CgI zAGrUo$?)y*{~{TF`(bFFNPf+}p7XvZyZ@gh_djR&mc4iXx5@DB@&A0D;s2z`@M#?* zs$WN&4BysIe`>*ZaE*Q7bEdDYpZ>hb@M#}!6hCi?!KeH%zgNcn1l_N^?kM|%Bjw3{ zOSmt>@>|@0ssUf}V`2L`;bZ${V|1|N_j_V^nmc_hf6Ki$2Dcmd=ls0;X~s{uzuR7K zBtAJVvadB6KVf?t|Fz%~pELm9_Uqiw#Qiq&ToK+c8q41=IoHG=);dvdHqYy7YIf^% zOYmGG#~-~JUjL&7If_e`Tx#MFb3R^rEyp$Uv|eZ85Y>(OKrfi}qB8u{n+G916qVy5 z@e8hC2|***U49U9Xo7q!*7spYr=1kZ)?IQ|D_JO zP~EZ~RrWlN6>pZUXPf51N#t?>_UhCG~@l+rx@>Vo+aLq`)>-~pIZU%_IkQ{itMp| zPtlz1F|QB9s+x5X%WrodBzl@W8unQrA4<<|||34H1o?X+Hk>y+vX&xf<0vz{h@ zJ2)p0we@p^vwiL^e!kR-XUz7w>yCFtpSxb+S6a`P@kPoL{hCO* zU(8g_TcNxg{JW=Y-k*p*e;paOt*?1pk@808eI3nvMSmqc6P{Feq&&I5u)U3EijN47 zd46sV7Xa9Y|4QBm;=Psnr)$RhQYzr`jI2}E&2Rj?VZd(y2Y-m7upzv+cN}s2ZFoQP z^|@%_pg@4AM}1coYkw(HD46a11w1V(2|F~ zBR(7={PO!@Mb4C3!~EiN`-OHp)MvQfUl6|dea5C8!*!10T=fBdU!az2{hX|FE?{{9 zVTkX7_q#&QqVKs$Jqhl=7O!!-U(V-CDfBlGeUF5BKVa%Yfv2zKeE@jU7K|=&l#L#zKh_YZGY%aM8CkvRuerDE?X58jWxO!5$DwxOQ)-7f#R)&CIpk5fRb{wwuc zXMeOzHbZz4e5auweDyZa4)^(78gxs~O{=APJ{j!O245_FpU5-xHt`=A390~k2hUdz z$~v&t-zt;M6W;S$pAL)ua&OC;=d;t(R8IN>u?N%%@52Th^PUAMKVtGo`hE5M{;5D8 z(Rh95?L2BHeGz!0mR?F>f&&rzY3T`-LHTaz-$AXnD4#=mmGm#>-wFSc@rHFT$(KQ% zo{#6)ug5H~4&J$6%Dw9P8C2D9&G`@F-v#GC%+}7<(9;;WZEw{&=RFa-YwQp9y%oU^ z-n%faYW|0e6G{U(?~C9uSzlK6LkJGxRrC@08KSS2XnuovfxN=V=Be^F#`TttH}S9Zyv_Rqw0$Z&CoRx>PC@i3k3X~{f!=f0 zN8b}pcBBBlQs%t?Mvpd0j|Fz4#mqObPci*$-V;vtp`XSxSNlNcGcsOvKLK9m$sV{? ze--hT*7hd1RMY2Vv3H;^=~>8Ip7;*uEIQXgE^vE>@BsD`J+J%8q6*KAffB^}8xpOX701e6x`|*tzvE3on5LYB`L>_4CD-H~pS3f4BHD zW%ND2-;eZp6@Aa|9}xfE=zZ;PY5#sXo@gtAA1mwqtmyN6M)s`^rzlP%eQ*3Ft?!NB zo;st3zUOn7Fw+KDs_z3KQf*l>hY{j4N9IfJxF=Z z4{(Eb6KFg{!=d&;q z&1adl`g!WLv)m_co~M@g-c*mbm-5QT@u1t&6Q6-hTK_3IAHNgp9fB`?K7P(BzuA;a z{pI%xKJD{Mm3eQy&YK74J)3;2((pIw{Uo!EKg~Jue2!_52Z6Ffz@669RblwX9zkvASe?`CGzkUu1`WAWqy7zNaK8Ez9*{`h6DVs0&=A5#o z!H0T_jbEQr)-?Dwe)KtIO@nWb|I9dj-MdnGqO13|>d(D&YQF*kH&^?~&%JaaCn@qN zc5_9K(Pw7eW`3W0q5jBjdN*r4{ChH=dly>%1+9Zo-e9#8+m8o7g7b)-c|8vWeZ%^G zZs%uoKF{C>goD2C+-LBk{fO-RK2J~m5q|JLCiivYOwHEr;v{ZjN@BzgwxqEC%{+5A(t-LUo6d*gb` zhVL!5@gL{khWr1^>ixTqS^6UIYvKPT#3P*#G)!-fM>;>L=^grwPfI*v^6xmuH?P-` z%=3io_f~rTtn)h}Pl)S8PX0Ph$Kd{rW%tEy9gg4k4m){zPTR<#ccWZG0_6GWWC^Czs~-k+MxHf$o;%^e@NyfD^Wq(;0e&2-gK#OWP8NJU7 zvmw4!`g*m=&msSTHc$^I>hg``R}(?`8r!ww%kb@=XM$Oqkk`d6F% zDkgrJWk1M)&JbQT-c!iO3SOE#AFS0;KdB)bKHi(f_>y&C#5L{Gztb=H%B|Psoq{j0 zF4YI$3BF)=317D`{48@e^NHpwv+k+aBfFqhiacNN2gOmFkf#EDv5v_6g8cJ3@f*^a zY3e7h^QgnQAsSa?JyObtg7wIgBtM-t>yc7^B)T41CVzn)P(#W278)<%&7UqyR z;OKoPZhYTK7xXpL{}RSqW%}6kOU7H+-ohL9oyfRT7&na{=XTQj?z%Q=y&`l)f!Hta zZ+SeG{T6_Ix#dSG*Y$ zHu@{F&eU++sPm~^pK20(l2hnIJD)mV@J&9oY4Gj1UguMr2H(cdStKuzr)J^b9>30~ zHVwY@oQyetBl)>i=y{HhU?1fBA^rWZ{{FOlgI`FVPvHHyZO&h_@U?Q5lAqG`ZEi>Qf#wG* z&f{0!2T;F2^*Qb$yGijP)moQ1oozM!GHwqtSm>+tO|71J`>!Dc_2XJ157(o2mcpT94J{g~P3;bsI`91x{9%r)5 z->Y*RFLb{^?b04uQ7PX z^*IzjNql7DEpSCgJiJDQi0dPm~*rdwG*{@T)yq>n}4 z4pqueRnU`vZ{%ohda@gGT!`w)f7I}vCOz2&xthUvybnW<6;`?x<1sSL-I4M{zcx~C z`Lz`ismq=AZ8S z8Z>kpU9(*Q6W~W*&l5Vnb$Oq}yMa%RZ+m`GalRbiM#>ZC8!5NOEAefl+@3GvGg4kB ze3gPe;d%3O6XZ8>eA}~F^J|b#aq5Y00Y}HTUOc|-`47#99N+f*Uq!rmM2|>$^1QJZ7Dz=G~6@6rdk}p!tpXsuB3B z0FUgW+28V^Cd0SS8~c8f;al;H`@?yL|ARREIn$LMfQaJ#BTa%!&x1$d{#_hy!~AIB z+xv$m!?)w#Tbm5u9>3oA)--vt;eULd$N#Z7eCQX}50L1&owxmuad=JV7e05ciTcaN z_ebY>{QKt_{**Stog_@cLGb*H_oTtIRXRTcddWB=#pIEdty^PzR+h<+sf$$Hb{b5eUl`XuvdSY9vv$ev3aNqP7HpWcxge8cS`cL!{Nc#ei9^`RO=hFQA51F|reAMIpC6svJJYpL8 zMm#@FX*Q{sRX)W7$kXw@2=FOppuGD*Uz#uFvv7?8FXjFKpY_s_;Qo5P?__!3xYE}a;uf$$E4(BU-d$pe6eG9#> zsG)zu@??64<+lE{^|#H(R6Y>lC#${p0LmkN0zF0tzNLL6zVmj>&xY5a{#Mj}w^F@0 z&uE77Oz0?TKlC-2gX9!=yOr^uiRYJkUtSTPP*b2=Se}f}u-wMSag2|!+@3${$+^QP zd5Ywhh@UvW)cYcxU!rv_(iw#PZldqYD&&=ze=tALm-aO67x4h`lRno8 zh=v{`LFRpfW?z|a*0Ealu^#n3pY`A4i?8Ev<$RgeDZGak7&~$k?>EdW5IcHgq3BDc z?&SMw!3U_mTDwr&S#=BF-z4>0{Do%UqSU`x-_Hm4U%>TWhjT1Q4=Z&dUk_uQM6Pe6 z>#U!?j;^yR!*-$XPcS^vAAW}KtNU8GepW5u@?Px6FQOdRdb|r;Sg)%OE|7KVg`dfs zOx-Oyh1O|$@6_;A`W;d){aU);H!Skw98C+Jg7qYn1HWWA$X;Q;DR zLg+&JfX;oJv|Say2H0@wv8#ZSyf3luUg1}XdTd*%NgK?8z zp!X%hKVUzh?-FBYWnCD2;zL5|(;WM1=OsUbeha|s=g|T50sc3(Ze!MK9&R#Rd)#{e zU(?2I=l9QP^7t+IX8&K)#&6^2?D-wPcUF_(+v7iTp5cGG$?)s)TcNMn|AX9pmE;ck zB!2yG*7aAc>#v$?)(ahbrnbGBMqe@~qVsF3;mW zT_2Wf_sMiSp9`YW>&dTM^{1l0ac%|Y5fEjHAK_>6V&}8GA88fhm;&p$oXRXmcW!Qo z_Zwwpe;7PWsfXOdO{mv$1Sn-c;hC~O66cqQpP4&@`-Me`!OO+rd5<8Uf&E0Q4)DCm zuNQx1SoYPyPhdQleMI1f6#EmvgX{}}e~k9Pi`+MU#E|4mP@nw??+ZHLM)Vj6{0b14 z{RjEpO2`GlVMnce2hfEgvPX2z&N#;(#7ETHcm6`90>9!>fGULipoIRxxpQUt1&*)7 z`flC)h5o=7tFZ5G2K12qH>*Bak)KJA92Y51?k{X_^Ru+CEH9jYiOk1tZ{lH`C&>K% zI_4?uoN6#nO%4ByuK+8>#> z@qbCipPWx9$Cvj-kt>wQbEWirD9OocCw^W9;t4wUcGWu#y|o_8&h5O4Rd`;p!1M!x zNWZ;5@OvfBfL!u9yYv12D7}AbcFz|>F4&H(`mp}~h-IgQAD0rI4gbT>?c_`SyrQ`e zI(6%MCt&_}s{TwrwIcnd?{mHh*QOq>SKWhpYiifS8?hEsyH)q2KGCxl+y~jBs8tVP ze8_c%&)xG_X7TSyd@5E;zxmZSKQN6cSNgPcoi}l~VmZO4&*jC*(wU`FB_LJrryn|; zuT}x&Lp90|Z~l|P%^SCE-gMa+g{_+}J9G19yMYX|;{PRfee2r0_t0VMR_s#G-ya#> zJ~lczGC5Tmor+Z`zlb60-0wV&{quEw)<$dZEKOZlykg_naOv#gSFO`k4Gw>EM*Ve|+aeak#|e;3}zKUUJCPo#i*|SNJ)TC*)6!`IDt7f3$Rke|d3g z`>s=bU4_z>bNzrR@a#p|ry|dn)qKXO(`EOfH=c3o(EVRL(|P?b)|~pbSHJ3`Uw<%t ziwsCwj8e3KD~B%_40=fADKEh zIE9B?Dt<}_OWXHP#aKF4cl-W{35dkzgX5*`Q>Ec;2hZQJ1C$KvOdZ@*oGMy3gHolo z9rTA$!5`yh{>UUt8enc07@Hw?!y}_Rb%jXFvY)f3D|B;N>+%~(b;|AqAJFtWWkdMEyS&scR93*e6z5A7{NmM6{`9p4|) zCn%pNO_nAOl!iAQ8ZGV}*=~Bdyg2M%erT#R>6bJmOo@CCzr1??!!J+5N(iH(;zq%* zpL^LoHOjv^IyQQIY47;dAwPKn)!LKwtWoX+XaisRyGs+Jr9J-ScyYTSV^Gd$^)Vd( z<)sOv^z~=Q#Ms^nO}T~{^}6z=vGVmb$~V*~e@=z+vx<}ccxl2P-+wvFAq4P>iLue0 zX8ghYDzra;bk8Aw^ErdZKX?5Ge|vG%-#=NRs>g3WzhGcg{Dw5S)d}z$xT3lMXtDB#Ay-LLC{69!Slojp(7AkCZ_ih4)_S{Nqr7UdYQ62~*3#4z zsXwxeTQ>NY?-|>^J1~xDo%`e$POc85tn}vSopSpd??oKpXp8u7kb7cqV(h@kaA|l@ zcxZ59WP9lpU2SJ^au7A7#N3R4K-;OY?PGfa&tmEz$Ta2e7@3$PEp>Kb>)Dr`f99E6 zH*bry3V&`YY%5&0W%GGwZ96->8TkcYe(s-^M~_x(oVoAzYQ=Ex|NH33Sg320Do-8U zHa1n<12Nn(vUjAs?nG(d{*j5&@c9Qy6T3>qsO!hz#vr^!7!Ff@=GerxiQ?!atjWmO zs8a7e=D$Ca)Nhr0o1$f~<(hcsjP4jK_dh}3GfF$gCQ5@7C6ZC;HH5Hdy}t{NYk0%@ zRTv*Hjk19U;o$`u?laYL-@gFsmz6&gCD_zaQeESTehe1hs(vv3izb2I(F)@qAFFP^ z&>kq?%w7^B-0E#RluP0A5$kSviT2N;V6oB%<=e)zfF;$bsy=^w_mQMF!M(OK^5WlN z}F;yeglG(vJP3!_NX5ld+tiX{)N@4oz0K4ZFvy^G9@ONwlgJoNa}4 z_Y@0ZnpZI$64n3cY0LU^(N}47CtQLp8@7z?#3r?>p9KAy zk2W~)vdX+q^)Au@C8WPBwx#kd>rVk^5)IFSr}D=>2pLn9lf@m-io>V)<6{(>j}-S@ z$h8fcDwS^_;P`BR**^JE;XnL_vB?ocHaI!?pSs9PzP)9$G*~m2(Q&7adFQG%#88-qcAG{{*TAs_isruk9)s1 zZQue|{Y(}Ql(rqD+)rteB*9oa#1sc;MEnoKDx7gnBAk&)9(ZCI-NgLJ{$cvb6PzTS zOv<@}Qr7*G0ogG!I)Y)w)JygF>c@BA17B}s$Dyq;n-d*uXnzvHs}Ef8;UuyJAfozh z%AY!T{=~@65%@*s^RnI51$f8s4pTMp`;x!BFrZ~pg|L6oVs@Q%-~H^}_PrX{G5!tV zlc(Wtm2}-kN!I~TUkzZ@iqmV`hh)^}jGhJUi`bA{^Zg^EQzxIO8%E2^wKLu(SFHn- zEvr%9TBCe%jq+@b@{2}ykB(h23eNDS4vm*f_m;xeZI_*S;pWYkZQXMIwi>{!V)!S1 zh5T5c!zZh!PgHTTs`^yL>fx^%uVJ8q{7(?*$0re#?=2ogU^g}~GIa>+0f_0q5vUq1 zkKQ*>f^sODFc3Tg86`2}(ejvK*8qa@sW7KvVAFR{PKlOif&P8Z>c{O=d15nII(qi_XV#%|DKuiIxc&7;%^3DGmv0k)&`C7 z$0Z|5!O(j3%6C8dQ@c&{T91ERz(in3bJY{A zobWr+KPTR!eJ50p-Maiu+asDZRwNf!oq9OoZg}geQ;&of3BRs7^=QIf%8TD+?uYa< zC}6jBlIMX+D^0};--tJN6h|gP$_J7u4FEq(jxlS*D{P%APH=)IG=#C9{;BO>+haGZ zi*QK z5jb3$;-MYfcSThP@xbL}D2q+0bVc>}^T1Sf2f@rKu!9t$UOp1!?++wq#lj&RnA#s+ zB>XxsRXsjDu($gBBK)&HiT^5??O-J2HpC2aP$EBIwORebe}iulbM3i;DKEF|(msqY zMy4i9d&+28!R-h}0p+*9ZpEuxU;4ab12{=PPW|e0E=am>?)~QzFL|T+o%DUfxm#b7 zbRYM8b3aC(1o?jP3%9=Lyp5M_ENt6&_GRa7E?kJ8Teg_i*n#+p6;&Lv%RRLDg?a{Y>>47_+zxi*jTKuVZ fyzpo5dGM}t5C8pm<}b(Jd*wavKl%rMea8O>MN#_5 diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/playground_batch.yul/playground_batch.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/playground_batch.yul/playground_batch.yul.zbin index efb5769b16fdf8862042b5c551663de951bb7899..6b91911a965d4a0401f9f0ddcd5b86275181f281 100644 GIT binary patch literal 76448 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
RIb%MfdDNnQ;6S|7OVEVsvJ{Y`3{w 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 literal 72928 zcmeHw37lL-oqxT)-kW5SnM{(IOyMs$W(8?)p`|dMc&pFQt0*6_>Q5x^WpvuSrcP=^r@(azijF-;s1DQn93uBpe<)h$Rnu1oDWDm$#M=jWFRJbRgx&z79G&~vqw`+*kJDilW*mP7nx z{7#DHamj_!5BD?RH_`LOa_9|#Zg#r>?NzmI$HL-|BsTn9lhx_5N>4GizXlN9rB zyTIMgpnL&Ouhr#O;C?mkZ`1d8YrGGD6NK-u;Bzwa+=0CCbLv0%4}P~Zzdxt>os<5| zxQnD;BzhzlDxXWZB#w(alS5b@8>I7 z2(cq8P@d?cI-JZIZ0ATGh$F1m?so`Z$IboUqp?9u;5wLABw;~8Hc;y zt%0BU5vgA%exkeDh0&~poMD^`Fb>vd!*`W(SkHP~O$X;R()-r?wf$EEZiFsM`OrVu zq1O8}Jnu|EzaXqaFI*U(`$I@Q^mGv**O2`ffz*;7s#J>F1Dx$*>+Kpo!*D2t)<;wB zN4nhmbh*P^4qn45_g`tj_Xb_=XqwtvfO2WpZ`e(4_s8ix^{e%xy4>*=-LGtmh7U9R zivow#5*)-ac+!IBhdK6Bi~4oB<2fp~9OZJ-UM|OU?S*{>-BUBJZYQ^&=(`A>?AW;q z%C1^;d6&zt@^i6a(UdXYoSgI7kNujKZX=pN>}yaUj@HGex(=BK{wp*WO}{T z$fGNCUFGq(9N;SwzVkGFLpt3Yr;|G>bjsZ{Z~02Z%8Nf6Ld)VOh@upiSmWVB3C6t zrySGKeGq&kJ$$X^OExz`{8xnUY&`!nBS)U}L*=flMxRAzY5YC9UwQ6VXO(`jTrAof z^h@MvRg1{^Xuv-$=TKRe^966W`1cCopZ9j@ALvPRgZzq|doyu4_im(dI?9_7{p$Y8>zRMxA<0!B=L3*eE~n)fFwMU!KoV_fGcrzeayZZqHZht-zsHxq94qegmGPuh-D?Ua=#A-I(wg?mTSxlXIz^ z)blj`9N1~pr?8v)tx_4jZ~vvx{jSaMH-NXlL*rMeG}UkapukU@NVPNksPxPI_rRa~ z9B-L83z8@CKgweq6i3Yz(B4rU560vFn`a;Y%REW>S&9F%nPH0iololVz&tRW>x}!I zBib&n$_}&t`GUrGvg3Zo@wxr489mT(v~t=rKIlhuCI5i9h52$!m&-YMP6#~1mNa#Wu1v>g^a&P+0V@%J?Ra0U1eH2i1<_>XiyyW;&seAX`d zult=7d0G5pk>AvF(L<8cy@-2AZa<{?@_+i?@acry8#z940(hxB-~*`N_IDbON^Rxw zZj}B6^8E2XEO~|&ihj;fo>TA*1)`gl=hWjKS$R&Kq4}@v0=SVZ&v)r^t#LWIYgqW% zwpsY8+&Dat<1M=WAFDpxQA3XJ{sWWagAK|tYoZQGT|ZfN+kG&!+dMAqR~G+7)1lMSSIh3JRiMid#^Z-}oA|!? z*COxk!^n#kK(61yGQzL5ekx!R;5M+56V#-bEA|qbR$0yquWR_-P(UB_$v9s z_G>l#aE1El<1zH#Ia&e!8G(BXK$mLy71&GU!NUAYz4?!oA|L2Uiu@j~dfwouks-vK z^q>#_x{ePHDsLhFEl@emQ!J(*1ov8F&)b6Mi(=1#L6=_)J~AHm>+nX>j@O3v3mtE$ zm`~!oOaz`h-mt!vPpXN(9qq54NBlIt`NY4tLHsoS0=NOy;CS8S!A#uF^Z|5G=R)Za+^b>io|Ch>vB zOY;Glmyup_UN`-DO_%=@dz#xO_J;G{yATgwqVIk5gY2&MBlyMnWwqSc4arxk-mLIl zr7o8FwLDL+N{ip|QJ(Vy=~J9>7=aU+HDrHVU#jixGUWHUzZt!5lG!SF^!=(#p8KIP zgH#`hx-&Fn3cRI#(fR!GOrhrwVG`^Mcq!P z)lNW{CXHv0ZfB|0j;e(p5jIJ;N}n(EN^3ix*7U+UC(-L5<8N0!{`VBf0mfAXJv^G1 zRkO>IhY#&;vb=_HTOVkhpc?)L?XqeYc}1Rq;{*2y=vN?mq%t!^ml22kTOjB8l-w() z!+8sr({>B;4Bs8pI~tT5pmJWfwqMj9t!p5@;dM*BPSmBJOturp7a)b|h)u&`7 z>s;vl{kmS6o*BNU&KG_fJwrT0c#!uHJxg88dZO1guzb7*p4df+H2dq7X^xkW7v+4t z*OMNhae2sF9xkZGyngm3lwJhBuwHs%N0g)UpKeatcfCC5mpb8aJQeD*si*Caatcyj z-%UyuKds%#lf6H!J);gwT$!PIUO(id(DBBKewO`n1fFbH!uqydSycl+$14rsC;wQj z|6;eo{?*xkMeD^RZ|#mx`z_i&$NW&<0JV$f-GMxE9#-YFeQ4GGI15&xex{`P{_KG@ z%qO*OE%tXP^=$ATd}&)GeDY3#oREFfc-x?Z*O2``75$+0U}1C~cMY%OFV_7V#PjnA zoW4L^NY~UhTfh7vey-;kX?3)l=ND{`V4sK8RRm9WNPXA?Yd#|NB_By<4E0GKrM{{W zS3WuxSH7++uC(Gvm}kzjE=KHB#Q0%|$o`Xl@O;R74AH;i^%dn-_#VQO`5wY8xefMZ z$o>S1Bgut{?*hAo6+iIIJWm@tn=yXFDUf|iD|iF&o$Pgi#QeKaC6X>@)E%_ZQd9?B?CUemmKpRBj&?HtMil(ev*S zXE=pe!tArM=iQ6PG@TK@DYE-4pS+I&b`0??EVu0E<9&d=C?WQZ{2b<=i=Qrb$$MO! zFG}oOC$wXY!kT&6ek0B!M(lE(d{UHeW4oG>csGcDvnKwPeSZ)eqDS_bMxF+?s&`@( zYTah`s|xWb#ZRZQJ}(D=;v{%kaHJ3a_K4qh^2l2bv0u^l-NdtqpP1gMs&VS#OU1rA zBaCM$Fqh*&KNer1?R=-U!>ta}nYx8`i2j@x$ekkdac_-9_fGC_Cp_-F(A`@bZ?EZm z75`1+6n$UE?N!#tM(ybnYTy?+4ckwa(-3ai6V-`S4&>B3!}%%2Yi+mcIPFZ_7l@g% zzZS#gIK1`Mn*TzF1%?j6{zntXaoo4yc+XQ*8}!rAtChq(4ZRdS4)m*)Be2sG^ibmV z&>q_3BRv}m@F>?BpLbRb`Zda*C)U8<;Jkyx4DlkAi{uUCyr1n|tC?4OPpZ+rLJhW~hc6cG|Cfob;I;jsk zNBzLCq`u_E+CHq?Cw;mQa5by((7rF?f0*~OH}Mnm0nowO#Z#V{Z!Q48C=ZDB!rAOoZ+)$%FWEQnqvcEbp68R)J-r{f z+wnzi%jGaC_q057jN;v;T5p2+9p>4H3)*CV848G8w|on~sC>6B-+^|(&o=y52=kKN zfgO7u(X9$!E%|km?N}%mmK}p!);G`fVTWFU{wta1Dzm;R^T}2KI6m@LrhMUdmh*RB zPik25pU{T_N>N^x?LtoSdn$FQ*asJKO!(bg9@jt3qd~_ZqDQK}dG5)XM=Rbh5Y2mP zzZB*@(}urKWPNxM$+;r`KzSv~_fWnQLdE&cg}9PEgK%j7QD5E@L7UX8nfGikZ|K#^ zd&)X=7(XQIWeB(Q((_sGL%3~^8;oC+iAUQUo~M|+XE;COb%ZdErFe+-m7nXl3-R$^ zP(ML+vg;(L?P-Y{Og?O3DlhSgqu0eyp7a~`-)Fft`NkB*C&WLtA7?#;xZxEn7bGWC zLB|hO>ytcjeUz`h4*q;AU-=XEAE+krOvm3FKMa3B>qrZDen#$n4f}D}@qu$WziQg! z{_g_RM=+w9Wzh z?~Oo33uqm~om0Lv^{0HP_&J@A2-mm%Fzx)H#JBDd<@ZVZ%sz&^ zBKPbGaGvBSXkzNnD3=>7@6DmCDOL2Pmezmzt07 zOLyOB^cX3A>Su+0=`F$gFUjwvy02ls73}AA->LD2@1x3lr+UA7i=WAh-*)wW3s=8) z>gxAU@qQNUO891t@54&^&%r7!v$8g^Q{}Fv} z+N+fxZFIhG=SLYI`eow#8uqwGe$?biM9wBi{^IYSx(~>>y~na0ys6^4k&H8hC)>dg zZreedPPSjBea}OYJic9D(*d04{ny^9)L+nv{3qp=d0!H)hHi767gfqLlb$BfuN`la zvm8nP0(yIobRMt4IL+)!K^~9o&EkiHJf1IfuaL*ffG>!5&Uy%T?*?AS;QX!kSe?J! zPJD~x*K9eEeuw@vSnb|V2<2f%yuDz( zV6mE)yfxxUi93URU#aza{dzX>AoW|~Gol0L`-?9Kjle}KXy1e==A(#AN8+;D=9d9R(tMa@>*bW^>E3uqof^A@^xK|hf@ zAwCw!57M}0y(gX*wD5RWazDfP+NMA3U@V`O+|RJSgXcS2ha!f_s#_U3pBn8cGTE0lkaNN`rM)8|6aCh-(2xKwrdeQU?lX@`;_Rb z`*qagcGOb#lbsIDGilwA=Rf=&TPW|Hyt0CIlNJykRMuxk|y6$HNRucC*CmI^?{a>_G5c!9FaKQqLYj(0#Bw>$R~?V+8z;EKF;DU8JZVBiHdhJrAXYAh>oE5WkVZ2t$&ot-U`#GNLwc@#OUT5)BNjw+Alld9KEq>~FE`;0o8=ZGbJO^frezg3vj_1t2 z#BStEuOeZXRh|^{%(Xt^Ib7GbOB|Qt{h%g}Q*GGF4u7JSd2&^$1Cp;wA0m0A^u6e5 zd>wZQAQT6J`evW$pp=(>lQ_rqIwR}SW*y4pkGj}jq79^)sUICV-H$d;buaj0?w*IIrsl>+&hyN8dgI zGa>QCTD@+~`r7hKt*?4K&J66_5aE%0pZ64uuR!-|4aGBF0eR<}ahFlD&-Y}lgPQlY zOkAxbpX;s1xU1!_MV>=HkgP8u+}4*3grCPRc@M4ULEeM?DBy+;+#c>X%yNBrqt5Sp zoJTBQA6E6f=eGFmnx9%e7W|{ghx<)44lN%hk7N4p&$7QytM9!Qx9r?8jFai<$a)){ zOUUvj`xvOdEZ_0>@{OPANB`2;O+An7cIGkt`>XF_%{*uQDyANz$cj`pX)kiagwKSKFi zaDR^E-PFRgv8Q@p6ZD7pf;FWg+tGnD^!_Aye?p~r-LU-t^Nr#frl&VywwhoWxzo$D4H_Cw9(|Hx*lFZTNj-TE-+fIgRpy zL+FK^C%F>cpmS7}(&uG*`yI;nu26a95-!|KM4i!I!@q04QIUMlaj$1)k%m+ibZD&N@LU@_n==e;}bG*L+z5-K2{Qk)r zudm1Zx72=QJo7!?S4GB4@=E&Bj!On{!TQ0r4J1O=NrRcptI(HcQNAD?=?W+vpQFK)MMe&yo zotqJ!d+a(%=VriCNnCH8o3S!@9zQpO{4LJ|y!g2pq_>>6(C1o&a&F6w*yRvjr=HZr z&w06s+%_9O+tGQ%FZ1iU(}&j63gCwEJ7zvWdPMIFv**oGYq_SoiqFv(Od7;@$t>NKXLzR`onTNr*n_>yw!UR^(P_^ zw!F{EFTmfj{zULt{=vKH4`bXNrwAX)=5r<=fruaH2Pii<-&x1IIoMIQ>jL*)*9^K< zq1VkqFYonew*cx=zbO9o@f`i|-e5haIDV+()=GBPd!yh3n2$@~c&&rm!Ed8GV| zdoS8U9>u*++692)4ENvkI1wkZz0mZ+Zd19Z{2KA`RBaD_CFPf3jEL8okN=lV#!vIT zX#aoFWc(I=yldwf|4W;UpXWCrf4%3-Gk$t+q=4@?%#-|h&u%h)n?9E{8NV$*m(DZ( z=T^t>y+G_k+xL?7+dIEHyl(qK`^6*riBq1ND<2$BN96mJO~y}ogJ}O>(PaFT|BvE- zd6V%|-Zp~Y{XvuQ_r>vh*TwKtJjU}2_W^ny@yB*tC2@Y}uao2a5N^d&?)Pfomw8H9 zzfSxO`&k-aln>vJ(W!AiOZmtMe(#3)#qa)ilkr=A+5s$f#NV*|>-f^UCQg@z@zVNPgzoPDG#NjwXGQV< ztjYLkejdgD^Csh``F<4tZ<>tX(ku6;O~!B81@|X0{4~$bV7^a&M)Jy3zR>aa!MxAX z1HIoNgeU7k2)F!(xo=l@dp5S_F zC%sgjJ4>Y;-V1&UJ(s)$wTJn0xqMF7kWaLLb%#02PZ|C9)kpuu1I?lT;_gS5{_aj(U^=D!~8r!OSP^Sh+IK)(OEN$uPDKYD*J(mtjC#J|ZtU-v#-?}4@| z#rxOXf79!B*dER6Q+c@2{_+{6X7qOq_)GCNTF@ z+1xO%%PY4S{VqCvcU|WV_VfM$2j5AjajD!!$`iEx6l%h8QkM5$wYw%xGT&c!^m!Nh z+>Rg*k=5s2WKWfRK=xFfAK-myj!OBGH*f~@^8uYV*sSvg%cwtQ-s*k@@3mkJl@b)Z z|6s)7JP7E-?*oN&irc}u?U2dKZj1A?<~*75V5=kZn&h}RoEKSfcisAG%cC8~@w~nP z`)1n%+kT!Cr%%KEx9!c{Pw!X@0yI?>c6L&jNkT$sV3vM`%m&(D7QcDpNPjl_Whjq zZQ1^q_OT?iKWF^*`0)N>Q}J8&&;8#fvw*g;7|GXDB8NY2m#w`5A5A5rm zGk;3qw5VBH)sBWyA!Y-Kgt}^=6yFZxhP*jiilDuHN8})wSPs_cYk8~Ni z((B}*T-b6YdKbd$l&hNf8jN+oGM}E?I{cEaY5g#IVb=G}I=o6h`lRTEK375OMYujVP4XMDZ?>FLT-xY+fKLeh zv}do!S6JWc=xC08>R6C$pE|H^&Gs+k!@Sxjy}lRH{qIgP-Ct|@g-UcUG>Pu8nMr=3 zWAh_S_ghXf-QPS*x=%ET?pIcz`^?Fud*F}t_n7AFk9mC?Ue&CNSaG}idE%#u7du|v z|9yF{v_syvRvmgBvjgwR;=SzGmcidB^V5#Q`g*IrBKPPZuA%e5QSX*`J?u}4wFCPZ zzrWSGzsT<-dm}Cy61fbO9{a6jN*05*}kV5$XhN2xeeqE=rB*9S=b1^pA6dv zd0oTjAo=E8?~I)5?Pt^s#ow#4dA;6|r}d7dIKie!^A7rCF5#(gzBeG($vQ`FgyVSS zUO@Acr8q&qAocmXb4yRr`1Cp6;djb&dR-%@&*wJhb-S_-qFgtAp0_#YJFCzA&X)B0 z##ZhJ%{x~S^Yr`j5M+u^&G!d7pJK-4WT>B=&)4^wUyjfGLIusIe~9r31H*l&A0WEs z+o13b=P1>6&P4FOe>%oL(|;^B>Gz*UV&_Ze%=v4`5AgS1J1-B$6_;B}F1_1mJP|#z z^-SbGv_HvmAHwU!&-9D5Ujx5B-&5iH;Jp8~Z2m#tA;cLs`ds$bfFF9FY)c;Yj^uEJ z=*!o2tHp*-XDZYO$$-_JlfelOTLj&tFM_`8T&ul0Mr%Gu2N0>+Ts z1>doSo<+a!lRAOb!yEAVs)yu!!IVOKLkiKfmZ#u*N2!YiU+jAZ@IVmkKK!dvb$!=> zjyXI=^w8({Aba4W-4;Tm@zMTd%nl@fhR3n?&G*SWq2JdKo*=%*dBtQWRI2P8raajf zeXf2dcHqU@&vX0OJsWGEs4RM>QnByF2j44ShIu3DA-?xp&v$)0A8oZi!tG-f)@r{} zyY;rWF4kTe_Q6-L0q-DIe69|frT4zoQazpw_L)O2mVQC>8FriG4}t_!fbrt{5W})= ztL?YSWb;J#yk0-vF80ekk~Qy_r)LOG_M;tFCHu&M$HXrJKWg$wP6yjl{_a-bPpH4X za})R4NnZllsAZQ@7~oLEe_D1zWdPp=`+JSHTW0-_>@UXOdAp_?&cTs<8T9GNh!ft9 zQ6P5ge4D_%>h>92MLQ%XgA&I`2$ex}RicpDgl7{WsrTW*fnPD- z5zv0Yv>$v2N-6%1kN5xdxZC1*%FcNU?4DB)d&+bV{YYT_6aQ=XE=ov`=Be^vRuqp|y9M`vTtzo+$z?N`KZS@yqadiAb9>6OUgEaR>} zR=rvh*Q@1NH#@yoI2Ui1y)#k|+-EAT#G<>%oS(mP2n5!ym8F`v_Ur!?oCmX}OimKA?m|32F@ z$saF&zK(~mf0pP*fe1bC!c4EoaS8HbG9Owi>w}t(c+Xe%?`G394%D0Lep~*Y3bjXe zXZC!aC%>*{H$UlmtftR-^4+_xR{i~hfN$qJnR74?dymK=eI7;lp32bt418t%=t2fz zfavUJSZ?v0zY7&SSI&U!o5uOaTn{r?>`%@NWb+gkbs_(F4b?|plKHnRJM8>5;Iy9_ z`JT)GrXsk4KPBcXPOdC)d%CfyW%hBalH@xBx#Dpxf0u4wWmwLZf4sV!WmTHhtZTyz+tb+`LC-eg?W~`={i5|IYgiy&O5;KWD+eXy8(Q`7ec@_W7&kJ9IE7 z@_rB7H}G*#-z$xOLw)Nw!F-?3VGZ&iFm^hxO!*YftH-~W*wwH3&halwqx^iFqvt(W z;)^cKksOkHnqNfhZr%IzDIY_2((EUG&OGDS=eRYk|1fW{{y%%3`+r%J@!S2sG>+fB zHwSh^qFXn?|~Wp0+kx`8@Angf81`__`PnM{!MQGoz>fSAGGX65Z5NpM>>DqFu!>|()pm~ z_ai(XG5L3#L!8&^Nap=Nj(aP;_t&*l^a=Ai(UbSa`4~LEqwKl(tvln-y*r&ey{B#T z(7QwK;bG*Qg|hcG8fwEx>+ z{Yt@LQrs~zw|zNXFE?_A`7g&W?ug7+y}dGD^*lYFPTZH%b&Zj)9Pi8NdY#61viIdU zup?L>>B3s>F*ARmb#SG>+o=5#?m50Pd|Gix`deY&9!VLWJ8tY8>oM?FT4xOQPw{tN zz^5OQJfm?mjCF4Cslq((i1b^&^RnVMmE?1V=YbJ;vV4a1ZTTcRMCk&y@w%Ar4D);^ zpW=K-i;wf;nT~3m-q#|}^VahbDewIgRI)(y*5yY?PWk>+s_z^}Ild3p5zYP%KEE!# zD(y4eM?KENq)(ys$kYkhU$)|~+1G;o3XCVC_jzG7B)3Z6uQGWQtOKi6ft?%>dgaz?c&E?{qD$o=cS0}tU82`F7=M-}JF0JH-BYheu6Uxh z2PPl00eLF$7wd>DFUUWyk+>n9nW1*_I*+D`cf(I5Fv1nplLis*T~ zK9m-Jee@6OGYaEJANq4Y+nZoNpZ6qy3M(F}I1b9wtd78w#}U?#_e06|R3r71#?b(N zm4;p6b$i}dBK{xaUU7wyE6|PL8K<7_0|JlUcjCtPoveVpX8!MFx>e?n&A(*2h4n4E zVc&`LJB5Bz|6Std7Jb$^8lI+x_ACXbufhe$n=a zFq?CWSLVqNYW)l8n>^kSZjV>fx9ejVu(4l_yk zEc;&%4?0jEhQ#6TJFjdPyVi}^GpcV`MrFIFa$*lxV*k=H(nqTvwpXXH;)jjdWan^I z1&8mIvy|eLZmbWY9{C3vA0{*0f93rP%JaB*-bH?s=8IHnP3AmYwH>JRUCbb!&!B%p zJ&)D#JfW#E@4^BV#WQ|Z-iOFy-5u+L-DhdPMO`F#o$o<(KOVy&`mDnGCE~E|4I1Ag zG~eoey5^UrBk0NR0Wn=+Pr(K~-$J|xzO8(NF7Jb$6z8`D{+-XkUU^*P#QSi-H$G=d zor8Ox7YM&s{+ITX=QwLv{t!2c9A;P^R^F@W6s(74%{+kDBS-)wuFb^e0V}^C{qz16 zaWmrll@}X-oXPU~{i+<#7rI}l>3&`&FYUU6&IHP1pHPwbqcWEGYj~sv3on9ZkM*6jp`{A2@=eBbHbp0Oevn)`#8T4ZaSLO14#FZa0^py4Sm4B)G z-2#;&eH=0C**VTnu6!scFLYDsGld@6EkX~}V|rvYJw%>Y-lpmQ5t$bd{Rg<;m|sE9 zgLbiSB>YH=9=yl!!}KF{s>Khz??0Q7ex&sG?m-ytM@shtmM+E@`CeLZ9vZ?>p?~TW z;S2VMGGEd>KZae<>+gVrFWn!s_%VR?SdOuu0OKLP$oNuQxgUPk7rLidPBlMTKw&DuZKHdh-$DrRqp#=B^!(N}@2koDw&yVw$IJ8E2t0Yb zVSTH=GQW+~x5q2=4C~j4U!?;7NAFEg+@w?=^w_*t801r&dgiylqvy9?e16;0tL2dA zw>^)mNH>cAS4ZH<;|l9rbTjcB!a|?<>dE|e<*@NXRvt2l>zcH`Wd-_A{>$t?xf}Nd z*jv~>mN$~CM&^6{7XFVm8NYoV*e{xl-#4^sg@SCxF_#J+3 zu03nw@Sb(n{TcE5pxzV9o$605*+genV)dJN5^G|Ywsia_rAAcJV8x$N8pL^L`PcSKF+T9Cq4n$DJ7&9n-GjYu z#~|afe%kQmZ@6jwQKhWAxep=+ajv(K|(d?%5vAJ=r{^K7cn zRmK_8tx>xE$NcKE;&~akDE0)CAZ=ev9$87=u;+&|Z}*-86ICF-EB+2gFu%y)p7Jk) z_3hK}9xeOFW_Uk-@13)jbM%Mg+?GQ#9$Ht9*hjLTY&ShV&vYL7NAU>HpV=-4^z=T% zd<^BnwmV!e(ytnFgKZYlj-SfYINeX8Dd7vhH-d9a_&J6x>jCsWKjvJ@kNFj)jw64B z{FwLIw0{2#c&HrmYa_txeJ&%<@%~it2<|_x?<09zF876$E|AcXkP%*gWS)V zT$8?0-?g;IODMd&Z=*v~nR0MmHCP~cxlu83Zo z_jogPQu}Mi;e2H;_UW_z<$Vji@2+8gLwGX3L%3~!ZToG@6Tycf@?_Qb_5|N5b75q_3iPqos7Wi#83L9?LzEaj$Y)Ti)6<#On*p|Q%`;ga;fu6*0~+MZ`N|i z`K5>)*yFP0D0y6=-LmKw*#9*8P5gaRg}f5W55@`pHs!sk3iE*Ec?aa_`y@}GgIwRM zuXpI{opROv!`hzrWtNAJSClu1DdOl5o=mq8ZqtqOl|#LE1^8_^(+P0t@7-4aD4$Q3 zhvoyWl66*Imw?^m^-xk|-ZyCWmHDW`>m4n7*^c_2&-U+uMK|(QIbWf53hyfmj30R` z?>EdW5I=f!q1a2MKFrV6f_G4PHMmgwS@kY{zCp^j_zTUxMJa!qex47WKb^~8i*qd4 zzN<6%emmAl(tTEC*e~>5kM5Da_!)k#?r!1oS+#)Sy$^~$;a>N5VGG-J z_3j0-PQCC`8La){;Fq&$ou>E48lOu4os>(zgr4`kR`ka?o)$U<>q&r;21woh_e_WjLn|6*UbPqHe0_rVt4C)qd0eUg253msB< z_U2;*&neKG|)vp64FP#rHqz zI0esjT$ReqP&*i>j#v0RF6?($6We!rRMt7sAvv#0rLwBK|2Nip9`KlTJVobG!I*HI zf`4-q=YSYyyzEyQuKM~j+OKBgeziXp*r7!K5P>J!xd_~{W3p}&f!p}mFGS#V;t%6D zFz^|??*z=j|MzLXnguCV6E&QA{3?uP^1j5rUy8hX>{t7973oIyeRTw$Jg%_5MYmvI zVg~)D{_A~-h!1!?eJ?kDR@Q|f*FH3q{+i=o?Y!#O(QW~BJ%I+u{*r%bBoA-agTC5i zymr6!{=cU6o8myS2d4keX>$K<{CfXi)B11INALe@8h*R~djDV3@Z0^@`~T(*|JRz# z-@4*f*lUjelAZU^x7!mG1z#03v^s<@kg8NpeKBedo0*6~q;3O_xGdp{;Ao$UktrqKi2IMR59WUVPgpXCRW5{#sT%Yw~bKIN_$hD~eO43reL*NUAum2d6BA52BXlOrRj@{SFa!6UV2(_>Pmk{addZS zd!ztPH@^MCcinva`!_uN%3D6P;gs%`cjUT%{^tM84E@hrKKhfl-2J1U-Ov>&K8v3Y zweOpPQwK5RJw66MT{Zb>nSBKww z_~`V3;pxdLNJVkB;rs1tK-ee$Jk+u*qe$%O50_DSH<5k490B zLj~}u(Vb((>3x$HDFgV9;tUkKq zzo0aUw7&k^F*&}cLRBtddcCH+Y7D-%27Fx&_!BC?pIV&qCrXq4#J($7521ipPmYi6 zH2n|8SE2qzW4jOf8!sF_{fTSW`P+(P{=TUa6+M09MFoSS;uYHDR%gHopk90CnM3|W zak99_>KozRadmYC&}!vxhh8NOp)`Hv`r_{06}wm!u=s=d8gRb`yee2N{=o4qrRixh zf8-fAt@E$gJ-%&M;2cpq_p#6L+EjH!G3ag4yK?^QtDL#}gVn$Y>mNKmIv(2Eq{7n& zwvJC1cS8*~jqVvOFFRStu0k3f^RN zd@QNO$g|W9zuJ3s0@L%ClceR6-kvM&(Qx%roi5@3jLoLukJrlA1vRbY#)=Xjgvd4wm=l7LCuPVqlobv^VgX@V@M%Z`I{{5*f+NQF(6|y zmGj5is+!n?Q`LRbu8HdM5$#$MuWC&Ww?I4mJ>W-iXNmQLPHK<*UFyE^-pK82e#UHA z)c>HRO>3Wtwn}3=5t3|Lw`qK5Zw-tI_B|i1vj3{evQOnM(Gyx|f7#rc;G5Q-4ap=P zJ{6JDQ+zNoW~ir%J7AT!pY2bKQ)*zexcg!*ZOBv!zK)RNZ`)OSYEO?kcvIT9~@Bdir2`Vl+D3vc67*QerM_+1h4uxRoq|NdVq3Ir76+`-&tWi{Y<$-U|y_I_9W%T|TL|BUS#8^3xClHpGu zoG91sO@%F6FTdd8jTduKRB@`R`BcT~({D9V!$Af4 zry$V~A4CA(Q#^o)<@n_2^g*mgU``2%K+z~X`rKd%;4n1dMD%=Qw8V`^;W5Xq5d`q* zFsEa1(=~uoq9+Q_zmKeXz)yG_JPP%P^55vBKS9&y0Dj9ozxM9<Z}OcHH z|MU-NqfE6wDpL)<^?)Ca9LrRDCU%#iLDKGGb^lro_pLXq{GV#@^eYBG(o(GeU{t1B zkYvU`z`Q`xr>llaWq7`Q%kt}E^$~vB zg*I(l_EY;=^j?Rlh+MUPMu9bc|LXg1d}`Gqht96<91op6vK|tN%*GT2s1zYdk{wGa zdWnl9mf+))3@)35(%K7Fz-0B87NNtXG49%dy;oNa5cgkEMzYwDN>^8(f9{{I9w3-8 z1%8mGs8@^z>j(Q2vtnTv_D^Hmb(O#U)79sP`}b5IUqpV^Cdpp~w;l9|!iJbb4j}Ra zUYpG?;y1)5vCy6i7NdQ(_Vb@~T7W0%$2nhn z!sevs=GlKg{Jd9~-$~b7p1I|DNzd`jH_v1INzm`-K4Z&sp0)n+^@XkLpLY4PHWn_% z&rO?5ZR~t}VOLfCNA_g;q6wsDrYHS@b1`cjD`BF&Ay|{XYP7oiZ`)N}#St)x|BWs* zh25+A>wBI1`-_35Bp0o*KKA?MS}iX!&!gS4Qmb5~!xXG=E!Ge&QujT@v4b#Nynf9K yZ541OJ^s!c+duHD_aA@u&YSLeaMPoHc6{x}F1^IPf9J6km;Ju=j<)AK|NjGM<1Tjq From 2ac29bdb8b0c053b7ccbeba2d828fbc6643c68ec Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 14 Aug 2024 19:27:49 -0300 Subject: [PATCH 09/76] Comment out hash checks for easier debug --- core/node/genesis/src/lib.rs | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/core/node/genesis/src/lib.rs b/core/node/genesis/src/lib.rs index 68ac3fdccc98..a306dead859d 100644 --- a/core/node/genesis/src/lib.rs +++ b/core/node/genesis/src/lib.rs @@ -105,14 +105,15 @@ impl GenesisParams { .evm_simulator_hash .ok_or(GenesisError::MalformedConfig("evm_simulator_hash"))?, }; - if base_system_contracts_hashes != base_system_contracts.hashes() { - return Err(GenesisError::BaseSystemContractsHashes(Box::new( - BaseContractsHashError { - from_config: base_system_contracts_hashes, - calculated: base_system_contracts.hashes(), - }, - ))); - } + // FIXME: uncomment this and update hashes. + // if base_system_contracts_hashes != base_system_contracts.hashes() { + // return Err(GenesisError::BaseSystemContractsHashes(Box::new( + // BaseContractsHashError { + // from_config: base_system_contracts_hashes, + // calculated: base_system_contracts.hashes(), + // }, + // ))); + // } // Try to convert value from config to the real protocol version and return error // if the version doesn't exist let _: ProtocolVersionId = config @@ -310,13 +311,14 @@ pub async fn ensure_genesis_state( "expected_rollup_last_leaf_index", ))?; - if expected_root_hash != root_hash { - return Err(GenesisError::RootHash(expected_root_hash, root_hash)); - } + // FIXME: uncomment this and update hashes. + // if expected_root_hash != root_hash { + // return Err(GenesisError::RootHash(expected_root_hash, root_hash)); + // } - if expected_commitment != commitment { - return Err(GenesisError::Commitment(expected_commitment, commitment)); - } + // if expected_commitment != commitment { + // return Err(GenesisError::Commitment(expected_commitment, commitment)); + // } if expected_rollup_last_leaf_index != rollup_last_leaf_index { return Err(GenesisError::LeafIndexes( From 5ecfe1b779e3bc772060372d11ee007fb657135a Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 15 Aug 2024 02:24:57 -0300 Subject: [PATCH 10/76] Update compiled and cached multivm bootloader contracts --- .../fee_estimate.yul/fee_estimate.yul.zbin | Bin 76256 -> 76256 bytes .../gas_test.yul/gas_test.yul.zbin | Bin 72352 -> 72352 bytes .../playground_batch.yul.zbin | Bin 76448 -> 76448 bytes .../proved_batch.yul/proved_batch.yul.zbin | Bin 72864 -> 72864 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin index 0e113d4d2a22275040a990fea3632661b47fb2e9..785b3b1fc1768b9dc0d9cca3605b7e7b001f9470 100644 GIT binary patch delta 78 zcmV-U0I~nz(*)qt1c0;wqy`*GtC!&BjQNY4xkMuw8m|T!@}18FIqsjm?VrS_zy<*$ kAj#c11hF^Qg#?y+g*G@qp+$~#@wd17YeBbgZ?M)R2=MDB5&!@I delta 78 zcmV-U0I~nz(*)qt1c0;wqy`+EVYPR+cB$#kxECXtvNF7Z-=4+6Gd*BIn#=5`zy<*$ kAgCU(pBbl-?yn)}I#lbT@U_qM8?4yAAA|RCX h2@!=Nsn`^!?-3udYg8PadMmW diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/playground_batch.yul/playground_batch.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/playground_batch.yul/playground_batch.yul.zbin index 6b91911a965d4a0401f9f0ddcd5b86275181f281..286052468b316f596234fc492881b0bc0087229a 100644 GIT binary patch delta 79 zcmV-V0I>g{)dZl`1c0;w1P2^RtC!&BjQNY4xkMuw8m|T!@}18FIqsjm?VrTAAO`_p lBOpB&1Ug{)dZl`1c0;w1P2_PVYPR+cB$#kxECXtvNF7Z-=4+6Gd*BIn#=6BAO`_p lBOvSMcR^cR{UJ->YkmnAV<^}{gaB1ug7kvdhVfjub$;hDzLPb4!sq5VCyxLC delta 75 zcmV-R0JQ(0xdfoO1hC}!9Gqdbcei$_>CU(pBbl-?yn)}I#lbT@U_qM8?6UfRA|Md- hq|r)nn1s%zJm2fE;)tBgW*8jSh@zr2o9To?D&#SiDXahh From d1be20356f142b43ca50a244a7d2f949a2694f93 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 15 Aug 2024 15:57:00 -0300 Subject: [PATCH 11/76] Add evm gas manager to the system contract list --- core/lib/constants/src/contracts.rs | 5 +++++ core/lib/types/src/system_contracts.rs | 11 ++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/core/lib/constants/src/contracts.rs b/core/lib/constants/src/contracts.rs index 44bb05a89764..3edfc3585d92 100644 --- a/core/lib/constants/src/contracts.rs +++ b/core/lib/constants/src/contracts.rs @@ -125,6 +125,11 @@ pub const CODE_ORACLE_ADDRESS: Address = H160([ 0x00, 0x00, 0x80, 0x12, ]); +pub const EVM_GAS_MANAGER_ADDRESS: Address = H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x13, +]); + /// Note, that the `Create2Factory` is explicitly deployed on a non-system-contract address. pub const CREATE2_FACTORY_ADDRESS: Address = H160([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/core/lib/types/src/system_contracts.rs b/core/lib/types/src/system_contracts.rs index a28c45b8feae..1a4fe96074a1 100644 --- a/core/lib/types/src/system_contracts.rs +++ b/core/lib/types/src/system_contracts.rs @@ -4,8 +4,7 @@ use once_cell::sync::Lazy; use zksync_basic_types::{AccountTreeId, Address, U256}; use zksync_contracts::{read_sys_contract_bytecode, ContractLanguage, SystemContractsRepo}; use zksync_system_constants::{ - BOOTLOADER_UTILITIES_ADDRESS, CODE_ORACLE_ADDRESS, COMPRESSOR_ADDRESS, CREATE2_FACTORY_ADDRESS, - EVENT_WRITER_ADDRESS, P256VERIFY_PRECOMPILE_ADDRESS, PUBDATA_CHUNK_PUBLISHER_ADDRESS, + BOOTLOADER_UTILITIES_ADDRESS, CODE_ORACLE_ADDRESS, COMPRESSOR_ADDRESS, CREATE2_FACTORY_ADDRESS, EVENT_WRITER_ADDRESS, EVM_GAS_MANAGER_ADDRESS, P256VERIFY_PRECOMPILE_ADDRESS, PUBDATA_CHUNK_PUBLISHER_ADDRESS }; use crate::{ @@ -25,7 +24,7 @@ use crate::{ pub const TX_NONCE_INCREMENT: U256 = U256([1, 0, 0, 0]); // 1 pub const DEPLOYMENT_NONCE_INCREMENT: U256 = U256([0, 0, 1, 0]); // 2^128 -static SYSTEM_CONTRACT_LIST: [(&str, &str, Address, ContractLanguage); 25] = [ +static SYSTEM_CONTRACT_LIST: [(&str, &str, Address, ContractLanguage); 26] = [ ( "", "AccountCodeStorage", @@ -147,6 +146,12 @@ static SYSTEM_CONTRACT_LIST: [(&str, &str, Address, ContractLanguage); 25] = [ COMPLEX_UPGRADER_ADDRESS, ContractLanguage::Sol, ), + ( + "", + "EvmGasManager", + EVM_GAS_MANAGER_ADDRESS, + ContractLanguage::Sol, + ), // For now, only zero address and the bootloader address have empty bytecode at the init // In the future, we might want to set all of the system contracts this way. ("", "EmptyContract", Address::zero(), ContractLanguage::Sol), From 092ef15a6a08578db29690d065335ed67ff422db Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 15 Aug 2024 20:04:46 -0300 Subject: [PATCH 12/76] Update evm deploy compatibility --- core/lib/multivm/src/vm_instance.rs | 28 ++++++++++++- core/lib/state/src/in_memory.rs | 8 ++-- core/lib/types/src/storage/mod.rs | 11 +++++- core/lib/types/src/system_contracts.rs | 17 +++++++- core/lib/types/src/tx/execute.rs | 2 +- core/node/genesis/src/lib.rs | 28 ++++++------- .../src/batch_executor/main_executor.rs | 12 +++++- .../state_keeper/src/batch_executor/mod.rs | 3 +- core/node/state_keeper/src/io/persistence.rs | 1 + core/node/state_keeper/src/io/tests/mod.rs | 4 ++ core/node/state_keeper/src/keeper.rs | 6 +++ .../state_keeper/src/seal_criteria/mod.rs | 1 + core/node/state_keeper/src/testonly/mod.rs | 1 + .../src/testonly/test_batch_executor.rs | 1 + .../src/updates/l1_batch_updates.rs | 1 + .../src/updates/l2_block_updates.rs | 39 ++++++++++--------- core/node/state_keeper/src/updates/mod.rs | 5 ++- core/node/vm_runner/src/process.rs | 2 + 18 files changed, 126 insertions(+), 44 deletions(-) diff --git a/core/lib/multivm/src/vm_instance.rs b/core/lib/multivm/src/vm_instance.rs index c8a7ce837991..7a53da4d8e6d 100644 --- a/core/lib/multivm/src/vm_instance.rs +++ b/core/lib/multivm/src/vm_instance.rs @@ -1,6 +1,6 @@ use zksync_state::{ImmutableStorageView, ReadStorage, StoragePtr, StorageView}; -use zksync_types::vm::{FastVmMode, VmVersion}; -use zksync_utils::bytecode::CompressedBytecodeInfo; +use zksync_types::{vm::{FastVmMode, VmVersion}, H256}; +use zksync_utils::{be_words_to_bytes, bytecode::CompressedBytecodeInfo, h256_to_u256}; use crate::{ glue::history_mode::HistoryMode, @@ -270,4 +270,28 @@ impl VmInstance { _ => Self::new(l1_batch_env, system_env, storage_view), } } + + // TOOD: this should be refactored to be returned as part of the execution result + pub fn ask_decommitter(&mut self, hashes: Vec) -> Vec> { + let vm = if let VmInstance::Vm1_5_0(vm) = &self { + vm + } else { + panic!("No supported for old VMs"); + }; + + let mut result = vec![]; + for hash in hashes { + let bytecode = vm + .state + .decommittment_processor + .known_bytecodes + .inner() + .get(&h256_to_u256(hash)) + .expect("Bytecode not found") + .clone(); + result.push(be_words_to_bytes(&bytecode)); + } + + result + } } diff --git a/core/lib/state/src/in_memory.rs b/core/lib/state/src/in_memory.rs index 594eae128169..21467cc64ce4 100644 --- a/core/lib/state/src/in_memory.rs +++ b/core/lib/state/src/in_memory.rs @@ -1,9 +1,7 @@ use std::collections::{hash_map::Entry, BTreeMap, HashMap}; use zksync_types::{ - block::DeployedContract, get_code_key, get_known_code_key, get_system_context_init_logs, - system_contracts::get_system_smart_contracts, L2ChainId, StorageKey, StorageLog, StorageValue, - H256, U256, + block::DeployedContract, get_code_key, get_deployer_key, get_known_code_key, get_system_context_init_logs, system_contracts::{get_evm_interpreter_hash, get_system_smart_contracts}, L2ChainId, StorageKey, StorageLog, StorageValue, H256, U256 }; use zksync_utils::u256_to_h256; @@ -63,6 +61,10 @@ impl InMemoryStorage { ] }) .chain(system_context_init_log) + .chain(vec![StorageLog::new_write_log( + get_deployer_key(u256_to_h256(1.into())), + get_evm_interpreter_hash(), + )]) .filter_map(|log| (log.is_write()).then_some((log.key, log.value))) .collect(); let state: HashMap<_, _> = state_without_indices diff --git a/core/lib/types/src/storage/mod.rs b/core/lib/types/src/storage/mod.rs index a30a57bffa51..9ef037dc29b2 100644 --- a/core/lib/types/src/storage/mod.rs +++ b/core/lib/types/src/storage/mod.rs @@ -5,7 +5,7 @@ pub use log::*; use serde::{Deserialize, Serialize}; use zksync_basic_types::{web3::keccak256, L2ChainId}; pub use zksync_system_constants::*; -use zksync_utils::address_to_h256; +use zksync_utils::{address_to_h256, u256_to_h256}; use crate::{AccountTreeId, Address, H160, H256, U256}; @@ -78,6 +78,10 @@ pub fn get_code_key(account: &Address) -> StorageKey { StorageKey::new(account_code_storage, address_to_h256(account)) } +pub fn get_evm_code_hash_key(account: &Address) -> StorageKey { + get_deployer_key(get_address_mapping_key(account, u256_to_h256(1.into()))) +} + pub fn get_known_code_key(hash: &H256) -> StorageKey { let known_codes_storage = AccountTreeId::new(KNOWN_CODES_STORAGE_ADDRESS); StorageKey::new(known_codes_storage, *hash) @@ -88,6 +92,11 @@ pub fn get_system_context_key(key: H256) -> StorageKey { StorageKey::new(system_context, key) } +pub fn get_deployer_key(key: H256) -> StorageKey { + let deployer_contract = AccountTreeId::new(CONTRACT_DEPLOYER_ADDRESS); + StorageKey::new(deployer_contract, key) +} + pub fn get_is_account_key(account: &Address) -> StorageKey { let deployer = AccountTreeId::new(CONTRACT_DEPLOYER_ADDRESS); diff --git a/core/lib/types/src/system_contracts.rs b/core/lib/types/src/system_contracts.rs index 1a4fe96074a1..6e45b7f437ec 100644 --- a/core/lib/types/src/system_contracts.rs +++ b/core/lib/types/src/system_contracts.rs @@ -1,11 +1,12 @@ -use std::path::PathBuf; +use std::{env, path::PathBuf}; use once_cell::sync::Lazy; -use zksync_basic_types::{AccountTreeId, Address, U256}; +use zksync_basic_types::{AccountTreeId, Address, H256, U256}; use zksync_contracts::{read_sys_contract_bytecode, ContractLanguage, SystemContractsRepo}; use zksync_system_constants::{ BOOTLOADER_UTILITIES_ADDRESS, CODE_ORACLE_ADDRESS, COMPRESSOR_ADDRESS, CREATE2_FACTORY_ADDRESS, EVENT_WRITER_ADDRESS, EVM_GAS_MANAGER_ADDRESS, P256VERIFY_PRECOMPILE_ADDRESS, PUBDATA_CHUNK_PUBLISHER_ADDRESS }; +use zksync_utils::bytecode::hash_bytecode; use crate::{ block::DeployedContract, ACCOUNT_CODE_STORAGE_ADDRESS, BOOTLOADER_ADDRESS, @@ -175,6 +176,18 @@ static SYSTEM_CONTRACT_LIST: [(&str, &str, Address, ContractLanguage); 26] = [ ), ]; +static EVM_INTERPRETER_HASH: Lazy = Lazy::new(|| { + hash_bytecode(&read_sys_contract_bytecode( + "", + "EvmInterpreter", + ContractLanguage::Yul, + )) +}); + +pub fn get_evm_interpreter_hash() -> H256 { + EVM_INTERPRETER_HASH.clone() +} + static SYSTEM_CONTRACTS: Lazy> = Lazy::new(|| { SYSTEM_CONTRACT_LIST .iter() diff --git a/core/lib/types/src/tx/execute.rs b/core/lib/types/src/tx/execute.rs index c5d31c0f8a03..3b45cc0c53cf 100644 --- a/core/lib/types/src/tx/execute.rs +++ b/core/lib/types/src/tx/execute.rs @@ -74,7 +74,7 @@ impl EIP712TypedStructure for Execute { fn build_structure(&self, builder: &mut BUILDER) { builder.add_member( "to", - &U256::from(self.contract_address.unwrap_or_default().as_bytes()), + &U256::from(self.contract_address.unwrap().as_bytes()), ); builder.add_member("value", &self.value); builder.add_member("data", &self.calldata.as_slice()); diff --git a/core/node/genesis/src/lib.rs b/core/node/genesis/src/lib.rs index a306dead859d..1b9199e20421 100644 --- a/core/node/genesis/src/lib.rs +++ b/core/node/genesis/src/lib.rs @@ -106,14 +106,14 @@ impl GenesisParams { .ok_or(GenesisError::MalformedConfig("evm_simulator_hash"))?, }; // FIXME: uncomment this and update hashes. - // if base_system_contracts_hashes != base_system_contracts.hashes() { - // return Err(GenesisError::BaseSystemContractsHashes(Box::new( - // BaseContractsHashError { - // from_config: base_system_contracts_hashes, - // calculated: base_system_contracts.hashes(), - // }, - // ))); - // } + if base_system_contracts_hashes != base_system_contracts.hashes() { + return Err(GenesisError::BaseSystemContractsHashes(Box::new( + BaseContractsHashError { + from_config: base_system_contracts_hashes, + calculated: base_system_contracts.hashes(), + }, + ))); + } // Try to convert value from config to the real protocol version and return error // if the version doesn't exist let _: ProtocolVersionId = config @@ -312,13 +312,13 @@ pub async fn ensure_genesis_state( ))?; // FIXME: uncomment this and update hashes. - // if expected_root_hash != root_hash { - // return Err(GenesisError::RootHash(expected_root_hash, root_hash)); - // } + if expected_root_hash != root_hash { + return Err(GenesisError::RootHash(expected_root_hash, root_hash)); + } - // if expected_commitment != commitment { - // return Err(GenesisError::Commitment(expected_commitment, commitment)); - // } + if expected_commitment != commitment { + return Err(GenesisError::Commitment(expected_commitment, commitment)); + } if expected_rollup_last_leaf_index != rollup_last_leaf_index { return Err(GenesisError::LeafIndexes( diff --git a/core/node/state_keeper/src/batch_executor/main_executor.rs b/core/node/state_keeper/src/batch_executor/main_executor.rs index d3595323a9a3..430c791b4133 100644 --- a/core/node/state_keeper/src/batch_executor/main_executor.rs +++ b/core/node/state_keeper/src/batch_executor/main_executor.rs @@ -14,7 +14,7 @@ use zksync_multivm::{ }; use zksync_shared_metrics::{InteractionType, TxStage, APP_METRICS}; use zksync_state::{OwnedStorage, ReadStorage, StorageView}; -use zksync_types::{vm::FastVmMode, vm_trace::Call, Transaction}; +use zksync_types::{event::extract_bytecodes_marked_as_known, vm::FastVmMode, vm_trace::Call, Transaction}; use zksync_utils::bytecode::CompressedBytecodeInfo; use super::{BatchExecutor, BatchExecutorHandle, Command, TxExecutionResult}; @@ -188,6 +188,15 @@ impl CommandReceiver { } else { self.execute_tx_in_vm(tx, vm) }; + + let factory_deps_marked_as_known = + extract_bytecodes_marked_as_known(&tx_result.logs.events); + let preimages = vm.ask_decommitter(factory_deps_marked_as_known.clone()); + let new_known_factory_deps = factory_deps_marked_as_known + .into_iter() + .zip(preimages) + .collect(); + latency.observe(); APP_METRICS.processed_txs[&TxStage::StateKeeper].inc(); APP_METRICS.processed_l1_txs[&TxStage::StateKeeper].inc_by(tx.is_l1().into()); @@ -208,6 +217,7 @@ impl CommandReceiver { compressed_bytecodes, call_tracer_result, gas_remaining, + new_known_factory_deps, } } diff --git a/core/node/state_keeper/src/batch_executor/mod.rs b/core/node/state_keeper/src/batch_executor/mod.rs index d4fea2e9dfd5..426baa4c86b9 100644 --- a/core/node/state_keeper/src/batch_executor/mod.rs +++ b/core/node/state_keeper/src/batch_executor/mod.rs @@ -9,7 +9,7 @@ use zksync_multivm::interface::{ FinishedL1Batch, Halt, L1BatchEnv, L2BlockEnv, SystemEnv, VmExecutionResultAndLogs, }; use zksync_state::{OwnedStorage, StorageViewCache}; -use zksync_types::{vm_trace::Call, Transaction}; +use zksync_types::{vm_trace::Call, Transaction, H256}; use zksync_utils::bytecode::CompressedBytecodeInfo; use crate::{ @@ -30,6 +30,7 @@ pub enum TxExecutionResult { tx_metrics: Box, compressed_bytecodes: Vec, call_tracer_result: Vec, + new_known_factory_deps: Vec<(H256, Vec)>, gas_remaining: u32, }, /// The VM rejected the tx for some reason. diff --git a/core/node/state_keeper/src/io/persistence.rs b/core/node/state_keeper/src/io/persistence.rs index de9ac22e1777..a6a8429cfd9b 100644 --- a/core/node/state_keeper/src/io/persistence.rs +++ b/core/node/state_keeper/src/io/persistence.rs @@ -463,6 +463,7 @@ mod tests { tx, tx_result, vec![], + vec![], BlockGasCount::default(), ExecutionMetrics::default(), vec![], diff --git a/core/node/state_keeper/src/io/tests/mod.rs b/core/node/state_keeper/src/io/tests/mod.rs index 7c70607c763b..1152c30c82d6 100644 --- a/core/node/state_keeper/src/io/tests/mod.rs +++ b/core/node/state_keeper/src/io/tests/mod.rs @@ -249,6 +249,7 @@ async fn processing_storage_logs_when_sealing_l2_block() { ExecutionMetrics::default(), vec![], vec![], + vec![], ); let tx = create_transaction(10, 100); @@ -267,6 +268,7 @@ async fn processing_storage_logs_when_sealing_l2_block() { ExecutionMetrics::default(), vec![], vec![], + vec![], ); let l1_batch_number = L1BatchNumber(2); @@ -356,6 +358,7 @@ async fn processing_events_when_sealing_l2_block() { ExecutionMetrics::default(), vec![], vec![], + vec![], ); } @@ -456,6 +459,7 @@ async fn l2_block_processing_after_snapshot_recovery(commitment_mode: L1BatchCom tx.into(), create_execution_result([]), vec![], + vec![], BlockGasCount::default(), ExecutionMetrics::default(), vec![], diff --git a/core/node/state_keeper/src/keeper.rs b/core/node/state_keeper/src/keeper.rs index 934ed9493f86..8ec4b7e1c2de 100644 --- a/core/node/state_keeper/src/keeper.rs +++ b/core/node/state_keeper/src/keeper.rs @@ -461,6 +461,7 @@ impl ZkSyncStateKeeper { tx_metrics, compressed_bytecodes, call_tracer_result, + new_known_factory_deps, .. } = result else { @@ -489,6 +490,7 @@ impl ZkSyncStateKeeper { tx, *tx_result, compressed_bytecodes, + new_known_factory_deps, tx_l1_gas_this_tx, tx_execution_metrics, call_tracer_result, @@ -600,6 +602,7 @@ impl ZkSyncStateKeeper { tx_metrics, call_tracer_result, compressed_bytecodes, + new_known_factory_deps, .. } = exec_result else { @@ -615,6 +618,7 @@ impl ZkSyncStateKeeper { tx, *tx_result, compressed_bytecodes, + new_known_factory_deps, tx_l1_gas_this_tx, tx_execution_metrics, call_tracer_result, @@ -674,6 +678,7 @@ impl ZkSyncStateKeeper { tx_result, tx_metrics, compressed_bytecodes, + new_known_factory_deps, .. } = exec_result else { @@ -695,6 +700,7 @@ impl ZkSyncStateKeeper { tx, *tx_result, compressed_bytecodes, + new_known_factory_deps, tx_l1_gas_this_tx, tx_execution_metrics, vec![], diff --git a/core/node/state_keeper/src/seal_criteria/mod.rs b/core/node/state_keeper/src/seal_criteria/mod.rs index 01be129dde6f..576fa3d6d287 100644 --- a/core/node/state_keeper/src/seal_criteria/mod.rs +++ b/core/node/state_keeper/src/seal_criteria/mod.rs @@ -288,6 +288,7 @@ mod tests { tx, create_execution_result([]), vec![], + vec![], BlockGasCount::default(), ExecutionMetrics::default(), vec![], diff --git a/core/node/state_keeper/src/testonly/mod.rs b/core/node/state_keeper/src/testonly/mod.rs index 92e58fe65381..170648b41ba2 100644 --- a/core/node/state_keeper/src/testonly/mod.rs +++ b/core/node/state_keeper/src/testonly/mod.rs @@ -70,6 +70,7 @@ pub(crate) fn successful_exec() -> TxExecutionResult { compressed_bytecodes: vec![], call_tracer_result: vec![], gas_remaining: Default::default(), + new_known_factory_deps: vec![], } } diff --git a/core/node/state_keeper/src/testonly/test_batch_executor.rs b/core/node/state_keeper/src/testonly/test_batch_executor.rs index aefc8d50bc7d..581b03f5a72b 100644 --- a/core/node/state_keeper/src/testonly/test_batch_executor.rs +++ b/core/node/state_keeper/src/testonly/test_batch_executor.rs @@ -267,6 +267,7 @@ pub(crate) fn successful_exec_with_metrics( compressed_bytecodes: vec![], call_tracer_result: vec![], gas_remaining: Default::default(), + new_known_factory_deps: vec![], } } diff --git a/core/node/state_keeper/src/updates/l1_batch_updates.rs b/core/node/state_keeper/src/updates/l1_batch_updates.rs index 7bc2095ff9b1..7930955b00d8 100644 --- a/core/node/state_keeper/src/updates/l1_batch_updates.rs +++ b/core/node/state_keeper/src/updates/l1_batch_updates.rs @@ -79,6 +79,7 @@ mod tests { ExecutionMetrics::default(), vec![], vec![], + vec![], ); let mut l1_batch_accumulator = L1BatchUpdates::new(L1BatchNumber(1)); diff --git a/core/node/state_keeper/src/updates/l2_block_updates.rs b/core/node/state_keeper/src/updates/l2_block_updates.rs index 8b3060babad1..c697a0a28f27 100644 --- a/core/node/state_keeper/src/updates/l2_block_updates.rs +++ b/core/node/state_keeper/src/updates/l2_block_updates.rs @@ -87,10 +87,12 @@ impl L2BlockUpdates { tx_l1_gas_this_tx: BlockGasCount, execution_metrics: ExecutionMetrics, compressed_bytecodes: Vec, + new_known_factory_deps: Vec<(H256, Vec)>, call_traces: Vec, ) { let saved_factory_deps = extract_bytecodes_marked_as_known(&tx_execution_result.logs.events); + self.new_factory_deps.extend(new_known_factory_deps); self.events.extend(tx_execution_result.logs.events); self.user_l2_to_l1_logs .extend(tx_execution_result.logs.user_l2_to_l1_logs); @@ -120,24 +122,24 @@ impl L2BlockUpdates { }; // Get transaction factory deps - let factory_deps = &tx.execute.factory_deps; - let tx_factory_deps: HashMap<_, _> = factory_deps - .iter() - .map(|bytecode| (hash_bytecode(bytecode), bytecode)) - .collect(); - - // Save all bytecodes that were marked as known on the bootloader - let known_bytecodes = saved_factory_deps.into_iter().map(|bytecode_hash| { - let bytecode = tx_factory_deps.get(&bytecode_hash).unwrap_or_else(|| { - panic!( - "Failed to get factory deps on tx: bytecode hash: {:?}, tx hash: {}", - bytecode_hash, - tx.hash() - ) - }); - (bytecode_hash, bytecode.to_vec()) - }); - self.new_factory_deps.extend(known_bytecodes); + // let factory_deps = &tx.execute.factory_deps; + // let tx_factory_deps: HashMap<_, _> = factory_deps + // .iter() + // .map(|bytecode| (hash_bytecode(bytecode), bytecode)) + // .collect(); + + // // Save all bytecodes that were marked as known on the bootloader + // let known_bytecodes = saved_factory_deps.into_iter().map(|bytecode_hash| { + // let bytecode = tx_factory_deps.get(&bytecode_hash).unwrap_or_else(|| { + // panic!( + // "Failed to get factory deps on tx: bytecode hash: {:?}, tx hash: {}", + // bytecode_hash, + // tx.hash() + // ) + // }); + // (bytecode_hash, bytecode.to_vec()) + // }); + // self.new_factory_deps.extend(known_bytecodes); self.l1_gas_count += tx_l1_gas_this_tx; self.block_execution_metrics += execution_metrics; @@ -207,6 +209,7 @@ mod tests { ExecutionMetrics::default(), vec![], vec![], + vec![] ); assert_eq!(accumulator.executed_transactions.len(), 1); diff --git a/core/node/state_keeper/src/updates/mod.rs b/core/node/state_keeper/src/updates/mod.rs index e05432c57b21..feb1e148554d 100644 --- a/core/node/state_keeper/src/updates/mod.rs +++ b/core/node/state_keeper/src/updates/mod.rs @@ -8,7 +8,7 @@ use zksync_types::{ block::BlockGasCount, fee_model::BatchFeeInput, storage_writes_deduplicator::StorageWritesDeduplicator, tx::tx_execution_info::ExecutionMetrics, vm_trace::Call, Address, L1BatchNumber, L2BlockNumber, - ProtocolVersionId, Transaction, + ProtocolVersionId, Transaction, H256, }; use zksync_utils::bytecode::CompressedBytecodeInfo; @@ -110,6 +110,7 @@ impl UpdatesManager { tx: Transaction, tx_execution_result: VmExecutionResultAndLogs, compressed_bytecodes: Vec, + new_known_factory_deps: Vec<(H256, Vec)>, tx_l1_gas_this_tx: BlockGasCount, execution_metrics: ExecutionMetrics, call_traces: Vec, @@ -125,6 +126,7 @@ impl UpdatesManager { tx_l1_gas_this_tx, execution_metrics, compressed_bytecodes, + new_known_factory_deps, call_traces, ); latency.observe(); @@ -234,6 +236,7 @@ mod tests { tx, create_execution_result([]), vec![], + vec![], new_block_gas_count(), ExecutionMetrics::default(), vec![], diff --git a/core/node/vm_runner/src/process.rs b/core/node/vm_runner/src/process.rs index 3c5a00e074c0..14f8e8024e76 100644 --- a/core/node/vm_runner/src/process.rs +++ b/core/node/vm_runner/src/process.rs @@ -87,6 +87,7 @@ impl VmRunner { tx_metrics, call_tracer_result, compressed_bytecodes, + new_known_factory_deps, .. } = exec_result else { @@ -100,6 +101,7 @@ impl VmRunner { tx, *tx_result, compressed_bytecodes, + new_known_factory_deps, tx_l1_gas_this_tx, tx_execution_metrics, call_tracer_result, From 55bd93a51ed62a65a4fea0795eb2be8b8ee6e197 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 15 Aug 2024 20:05:06 -0300 Subject: [PATCH 13/76] Update base system contract hashes --- etc/env/base/chain.toml | 2 +- etc/env/base/contracts.toml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/etc/env/base/chain.toml b/etc/env/base/chain.toml index db06724eb656..58fca8eff96e 100644 --- a/etc/env/base/chain.toml +++ b/etc/env/base/chain.toml @@ -90,7 +90,7 @@ fee_model_version = "V2" validation_computational_gas_limit = 300000 save_call_traces = true -bootloader_hash = "0x010008e7894d0dd14681c76bdb4d5e4e7f6b51bfe40c957d50eed3fec829fdb0" +bootloader_hash = "0x010008e54ed4ed2784197a39309255faa062e7f130424f0075bfd7ff11eb22d6" default_aa_hash = "0x0100058deb36e1f2eeb48bf3846d0e8eb38e9176754b73116bb41a472459a4dd" evm_simulator_hash = "0x01000f197081a9906cc411d0698c4961aeb5c74877f37f7071681da6e8ef3f31" diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index 60a2c39d0859..47f1e57fea13 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -26,11 +26,11 @@ RECURSION_NODE_LEVEL_VK_HASH = "0x1186ec268d49f1905f8d9c1e9d39fc33e98c74f91d91a2 RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc8966504064f1f6ba3f1ba863210" RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" -GENESIS_ROOT = "0x5f71cdcbe47d9bba4317f12b790e15f7510ed142f956c90ef005f908e5d35f57" -GENESIS_BATCH_COMMITMENT = "0xf924b9c66bc141712971a0c4d1c8e3120da70ee58bee0d2e0e87da50d8b229b9" +GENESIS_ROOT = "0xf511c8e55095e444bd86bc2813689935b2098edda19aa7f9d080b506e2cfc69f" +GENESIS_BATCH_COMMITMENT = "0x7c46546a6d6268914e6ee58b51a38fa44dcc707efadf8af3e68e5f3b3a28e0af" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 -GENESIS_ROLLUP_LEAF_INDEX = "54" +GENESIS_ROLLUP_LEAF_INDEX = "56" GENESIS_PROTOCOL_VERSION = "24" GENESIS_PROTOCOL_SEMANTIC_VERSION = "0.24.2" L1_WETH_BRIDGE_IMPL_ADDR = "0x5E6D086F5eC079ADFF4FB3774CDf3e8D6a34F7E9" From c93f229a3791a48a7b4bd63ab3dd9c93b12b5bca Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 16 Aug 2024 10:15:53 -0300 Subject: [PATCH 14/76] Add evm deploy tracer to default tracers --- core/lib/contracts/src/lib.rs | 4 + .../vm_latest/tracers/default_tracers.rs | 17 ++- .../vm_latest/tracers/evm_debug_tracer.rs | 124 ++++++++++++++++++ .../vm_latest/tracers/evm_deploy_tracer.rs | 99 ++++++++++++++ .../src/versions/vm_latest/tracers/mod.rs | 4 + .../src/versions/vm_latest/utils/mod.rs | 21 ++- core/lib/multivm/src/vm_instance.rs | 5 +- core/lib/state/src/in_memory.rs | 5 +- core/lib/types/src/system_contracts.rs | 14 +- core/lib/types/src/tx/execute.rs | 5 +- .../src/batch_executor/main_executor.rs | 4 +- .../src/updates/l2_block_updates.rs | 2 +- 12 files changed, 288 insertions(+), 16 deletions(-) create mode 100644 core/lib/multivm/src/versions/vm_latest/tracers/evm_debug_tracer.rs create mode 100644 core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index 0d4dcb94a9c0..0a08af35cf1c 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -184,6 +184,10 @@ pub fn deployer_contract() -> Contract { load_sys_contract("ContractDeployer") } +pub fn known_code_storage_contract() -> Contract { + load_sys_contract("KnownCodesStorage") +} + pub fn l1_messenger_contract() -> Contract { load_sys_contract("L1Messenger") } diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs b/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs index 4c00e7dbf771..ae7c707ccd65 100755 --- a/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs @@ -14,7 +14,7 @@ use zk_evm_1_5_0::{ }; use zksync_state::{StoragePtr, WriteStorage}; -use super::PubdataTracer; +use super::{EvmDebugTracer, EvmDeployTracer, PubdataTracer}; use crate::{ glue::GlueInto, interface::{ @@ -64,6 +64,10 @@ pub struct DefaultExecutionTracer { // It only takes into account circuits that are generated for actual execution. It doesn't // take into account e.g circuits produced by the initial bootloader memory commitment. pub(crate) circuits_tracer: CircuitsTracer, + + pub(crate) evm_tracer: Option>, + pub(crate) evm_deploy_tracer: EvmDeployTracer, + subversion: MultiVMSubversion, storage: StoragePtr, _phantom: PhantomData, @@ -93,7 +97,9 @@ impl DefaultExecutionTracer { pubdata_tracer, ret_from_the_bootloader: None, circuits_tracer: CircuitsTracer::new(), + evm_deploy_tracer: EvmDeployTracer::new(), storage, + evm_tracer: None, _phantom: PhantomData, } } @@ -172,7 +178,11 @@ macro_rules! dispatch_tracers { if let Some(tracer) = &mut $self.pubdata_tracer { tracer.$function($( $params ),*); } + if let Some(tracer) = &mut $self.evm_tracer { + tracer.$function($( $params ),*); + } $self.circuits_tracer.$function($( $params ),*); + $self.evm_deploy_tracer.$function($( $params ),*); }; } @@ -289,6 +299,11 @@ impl DefaultExecutionTracer { .circuits_tracer .finish_cycle(state, bootloader_state) .stricter(&result); + + result = self + .evm_deploy_tracer + .finish_cycle(state, bootloader_state) + .stricter(&result); result.stricter(&self.should_stop_execution()) } diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/evm_debug_tracer.rs b/core/lib/multivm/src/versions/vm_latest/tracers/evm_debug_tracer.rs new file mode 100644 index 000000000000..823258a259b3 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_latest/tracers/evm_debug_tracer.rs @@ -0,0 +1,124 @@ +use std::{marker::PhantomData, str::FromStr}; + +use circuit_sequencer_api_1_4_2::sort_storage_access::sort_storage_access_queries; +use itertools::Itertools; +use zk_evm_1_4_1::aux_structures::LogQuery as LogQuery_1_4_1; +use zk_evm_1_5_0::{ + aux_structures::{LogQuery, Timestamp}, + tracing::{BeforeExecutionData, VmLocalStateData}, + zkevm_opcode_defs::{FatPointer, Opcode, UMAOpcode}, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::{ + event::{ + extract_bytecode_publication_requests_from_l1_messenger, + extract_l2tol1logs_from_l1_messenger, extract_long_l2_to_l1_messages, L1MessengerL2ToL1Log, + }, + writes::StateDiffRecord, + AccountTreeId, Address, StorageKey, H256, L1_MESSENGER_ADDRESS, U256, +}; +use zksync_utils::{h256_to_u256, u256_to_bytes_be, u256_to_h256}; + +use crate::{ + interface::{dyn_tracers::vm_1_5_0::DynTracer, tracer::TracerExecutionStatus}, + vm_latest::{ + old_vm::utils::{heap_page_from_base, IntoFixedLengthByteIterator}, + BootloaderState, HistoryMode, SimpleMemory, VmTracer, ZkSyncVmState, + }, +}; + +pub(crate) struct EvmDebugTracer { + counter: u32, + + _storage: PhantomData, + _history: PhantomData, +} + +impl EvmDebugTracer { + pub fn new() -> Self { + Self { + counter: 0, + _storage: PhantomData, + _history: PhantomData, + } + } +} + +impl DynTracer> for EvmDebugTracer { + fn before_execution( + &mut self, + state: VmLocalStateData<'_>, + data: BeforeExecutionData, + memory: &SimpleMemory, + storage: StoragePtr, + ) { + // FIXME: this catches not only Evm contracts + + let opcode_variant = data.opcode.variant; + let heap_page = + heap_page_from_base(state.vm_local_state.callstack.current.base_memory_page).0; + + let src0_value = data.src0_value.value; + + let fat_ptr = FatPointer::from_u256(src0_value); + + let value = data.src1_value.value; + + const DEBUG_SLOT: u32 = 32 * 32; + + let debug_magic = U256::from_dec_str( + "33509158800074003487174289148292687789659295220513886355337449724907776218753", + ) + .unwrap(); + + // Only `UMA` opcodes in the bootloader serve for vm hooks + if !matches!(opcode_variant.opcode, Opcode::UMA(UMAOpcode::HeapWrite)) + || fat_ptr.offset != DEBUG_SLOT + || value != debug_magic + { + // println!("I tried"); + return; + } + + let how_to_print_value = memory.read_slot(heap_page as usize, 32 + 1).value; + let value_to_print = memory.read_slot(heap_page as usize, 32 + 2).value; + + let print_as_hex_value = + U256::from_str("0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebde") + .unwrap(); + let print_as_string_value = + U256::from_str("0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdf") + .unwrap(); + + if how_to_print_value == print_as_hex_value { + print!("PRINTED: "); + println!("0x{:02x}", value_to_print); + } + + if how_to_print_value == print_as_string_value { + print!("PRINTED: "); + let mut value = value_to_print.0; + value.reverse(); + for limb in value { + print!( + "{}", + String::from_utf8(limb.to_be_bytes().to_vec()).unwrap() + ); + } + println!(""); + } + + self.counter += 1; + } +} + +impl VmTracer for EvmDebugTracer { + // fn finish_cycle( + // &mut self, + // _state: &mut ZkSyncVmState, + // _bootloader_state: &mut BootloaderState, + // ) -> TracerExecutionStatus { + // let contract = _state.local_state.callstack.current.code_address; + + // } +} diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs b/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs new file mode 100644 index 000000000000..6481994ebe86 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs @@ -0,0 +1,99 @@ +use std::marker::PhantomData; + +use zk_evm_1_5_0::{aux_structures::Timestamp, zkevm_opcode_defs::{FatPointer, CALL_IMPLICIT_CALLDATA_FAT_PTR_REGISTER}}; +use zksync_contracts::known_code_storage_contract; +use zksync_state::WriteStorage; +use zksync_types::{CONTRACT_DEPLOYER_ADDRESS, KNOWN_CODES_STORAGE_ADDRESS}; +use zksync_utils::{bytes_to_be_words, h256_to_u256}; + +use crate::{interface::{dyn_tracers::vm_1_5_0::DynTracer, tracer::TracerExecutionStatus}, vm_latest::{utils::hash_evm_bytecode, BootloaderState, HistoryMode, SimpleMemory, ZkSyncVmState}}; + +use super::{traits::VmTracer, utils::read_pointer}; + +/// Tracer responsible for collecting information about EVM deploys and providing those +/// to the code decommitter. +#[derive(Debug, Clone)] +pub(crate) struct EvmDeployTracer { + _phantom: PhantomData, +} + +impl EvmDeployTracer { + pub(crate) fn new() -> Self { + Self { + _phantom: PhantomData, + } + } +} + +impl DynTracer> for EvmDeployTracer {} + +impl VmTracer for EvmDeployTracer { + fn finish_cycle( + &mut self, + state: &mut ZkSyncVmState, + bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + // We check if ContractDeployer was called with provided evm bytecode. + // It is assumed that by that time the user has already paid for its size. + // So even if we do not revert the addition of the this bytecode it is not a ddos vector, since + // the payment is the same as if the bytecode publication was reverted. + + let current_callstack = &state.local_state.callstack.current; + + // Here we assume that the only case when PC is 0 at the start of the execution of the contract. + let known_code_storage_call = current_callstack.this_address == KNOWN_CODES_STORAGE_ADDRESS + && current_callstack.pc == 0 + && current_callstack.msg_sender == CONTRACT_DEPLOYER_ADDRESS; + + if !known_code_storage_call { + // Just continue executing + return TracerExecutionStatus::Continue; + } + + // Now, we need to check whether it is indeed a call to publish EVM code. + let calldata_ptr = + state.local_state.registers[CALL_IMPLICIT_CALLDATA_FAT_PTR_REGISTER as usize]; + + let data = read_pointer(&state.memory, FatPointer::from_u256(calldata_ptr.value)); + + let contract = known_code_storage_contract(); + + if data.len() < 4 { + // Not interested + return TracerExecutionStatus::Continue; + } + + let (signature, data) = data.split_at(4); + + if signature + != contract + .function("publishEVMBytecode") + .unwrap() + .short_signature() + { + // Not interested + return TracerExecutionStatus::Continue; + } + + let Ok(call_params) = contract + .function("publishEVMBytecode") + .unwrap() + .decode_input(data) + else { + // Not interested + return TracerExecutionStatus::Continue; + }; + + let published_bytecode = call_params[0].clone().into_bytes().unwrap(); + + let hash = hash_evm_bytecode(&published_bytecode); + let as_words = bytes_to_be_words(published_bytecode); + + state.decommittment_processor.populate( + vec![(h256_to_u256(hash), as_words)], + Timestamp(state.local_state.timestamp), + ); + + TracerExecutionStatus::Continue + } +} diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs b/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs index fe916e19e8ca..859be2d150d2 100755 --- a/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs @@ -3,12 +3,16 @@ pub(crate) use default_tracers::DefaultExecutionTracer; pub(crate) use pubdata_tracer::PubdataTracer; pub(crate) use refunds::RefundsTracer; pub(crate) use result_tracer::ResultTracer; +pub(crate) use evm_debug_tracer::EvmDebugTracer; +pub(crate) use evm_deploy_tracer::EvmDeployTracer; pub(crate) mod circuits_tracer; pub(crate) mod default_tracers; pub(crate) mod pubdata_tracer; pub(crate) mod refunds; pub(crate) mod result_tracer; +pub(crate) mod evm_debug_tracer; +pub(crate) mod evm_deploy_tracer; pub(crate) mod circuits_capacity; pub mod dispatcher; diff --git a/core/lib/multivm/src/versions/vm_latest/utils/mod.rs b/core/lib/multivm/src/versions/vm_latest/utils/mod.rs index 521a2955dcd6..233c7a6137fb 100644 --- a/core/lib/multivm/src/versions/vm_latest/utils/mod.rs +++ b/core/lib/multivm/src/versions/vm_latest/utils/mod.rs @@ -1,4 +1,6 @@ -use zk_evm_1_5_0::aux_structures::MemoryPage; +use zk_evm_1_4_1::sha2; +use zk_evm_1_5_0::{aux_structures::MemoryPage, zkevm_opcode_defs::{BlobSha256Format, VersionedHashLen32}}; +use zksync_types::H256; /// Utility functions for the VM. pub mod fee; @@ -7,6 +9,23 @@ pub(crate) mod logs; pub mod overhead; pub mod transaction_encoding; +/// TODO: maybe move to a different folder +pub(crate) fn hash_evm_bytecode(bytecode: &[u8]) -> H256 { + use sha2::{Digest, Sha256}; + let mut hasher = Sha256::new(); + let len = bytecode.len() as u16; + hasher.update(bytecode); + let result = hasher.finalize(); + + let mut output = [0u8; 32]; + output[..].copy_from_slice(&result.as_slice()); + output[0] = BlobSha256Format::VERSION_BYTE; + output[1] = 0; + output[2..4].copy_from_slice(&len.to_be_bytes()); + + H256(output) +} + pub const fn heap_page_from_base(base: MemoryPage) -> MemoryPage { MemoryPage(base.0 + 2) } diff --git a/core/lib/multivm/src/vm_instance.rs b/core/lib/multivm/src/vm_instance.rs index 7a53da4d8e6d..964f2780ef8d 100644 --- a/core/lib/multivm/src/vm_instance.rs +++ b/core/lib/multivm/src/vm_instance.rs @@ -1,5 +1,8 @@ use zksync_state::{ImmutableStorageView, ReadStorage, StoragePtr, StorageView}; -use zksync_types::{vm::{FastVmMode, VmVersion}, H256}; +use zksync_types::{ + vm::{FastVmMode, VmVersion}, + H256, +}; use zksync_utils::{be_words_to_bytes, bytecode::CompressedBytecodeInfo, h256_to_u256}; use crate::{ diff --git a/core/lib/state/src/in_memory.rs b/core/lib/state/src/in_memory.rs index 21467cc64ce4..a97cc1e847c2 100644 --- a/core/lib/state/src/in_memory.rs +++ b/core/lib/state/src/in_memory.rs @@ -1,7 +1,10 @@ use std::collections::{hash_map::Entry, BTreeMap, HashMap}; use zksync_types::{ - block::DeployedContract, get_code_key, get_deployer_key, get_known_code_key, get_system_context_init_logs, system_contracts::{get_evm_interpreter_hash, get_system_smart_contracts}, L2ChainId, StorageKey, StorageLog, StorageValue, H256, U256 + block::DeployedContract, + get_code_key, get_deployer_key, get_known_code_key, get_system_context_init_logs, + system_contracts::{get_evm_interpreter_hash, get_system_smart_contracts}, + L2ChainId, StorageKey, StorageLog, StorageValue, H256, U256, }; use zksync_utils::u256_to_h256; diff --git a/core/lib/types/src/system_contracts.rs b/core/lib/types/src/system_contracts.rs index 6e45b7f437ec..ed6e0c879901 100644 --- a/core/lib/types/src/system_contracts.rs +++ b/core/lib/types/src/system_contracts.rs @@ -4,7 +4,9 @@ use once_cell::sync::Lazy; use zksync_basic_types::{AccountTreeId, Address, H256, U256}; use zksync_contracts::{read_sys_contract_bytecode, ContractLanguage, SystemContractsRepo}; use zksync_system_constants::{ - BOOTLOADER_UTILITIES_ADDRESS, CODE_ORACLE_ADDRESS, COMPRESSOR_ADDRESS, CREATE2_FACTORY_ADDRESS, EVENT_WRITER_ADDRESS, EVM_GAS_MANAGER_ADDRESS, P256VERIFY_PRECOMPILE_ADDRESS, PUBDATA_CHUNK_PUBLISHER_ADDRESS + BOOTLOADER_UTILITIES_ADDRESS, CODE_ORACLE_ADDRESS, COMPRESSOR_ADDRESS, CREATE2_FACTORY_ADDRESS, + EVENT_WRITER_ADDRESS, EVM_GAS_MANAGER_ADDRESS, P256VERIFY_PRECOMPILE_ADDRESS, + PUBDATA_CHUNK_PUBLISHER_ADDRESS, }; use zksync_utils::bytecode::hash_bytecode; @@ -177,11 +179,11 @@ static SYSTEM_CONTRACT_LIST: [(&str, &str, Address, ContractLanguage); 26] = [ ]; static EVM_INTERPRETER_HASH: Lazy = Lazy::new(|| { - hash_bytecode(&read_sys_contract_bytecode( - "", - "EvmInterpreter", - ContractLanguage::Yul, - )) + hash_bytecode(&read_sys_contract_bytecode( + "", + "EvmInterpreter", + ContractLanguage::Yul, + )) }); pub fn get_evm_interpreter_hash() -> H256 { diff --git a/core/lib/types/src/tx/execute.rs b/core/lib/types/src/tx/execute.rs index 3b45cc0c53cf..a628ffaa20dd 100644 --- a/core/lib/types/src/tx/execute.rs +++ b/core/lib/types/src/tx/execute.rs @@ -72,10 +72,7 @@ impl EIP712TypedStructure for Execute { const TYPE_NAME: &'static str = "Transaction"; fn build_structure(&self, builder: &mut BUILDER) { - builder.add_member( - "to", - &U256::from(self.contract_address.unwrap().as_bytes()), - ); + builder.add_member("to", &U256::from(self.contract_address.unwrap().as_bytes())); builder.add_member("value", &self.value); builder.add_member("data", &self.calldata.as_slice()); // Factory deps are not included into the transaction signature, since they are parsed from the diff --git a/core/node/state_keeper/src/batch_executor/main_executor.rs b/core/node/state_keeper/src/batch_executor/main_executor.rs index 430c791b4133..5dd8ad9c5780 100644 --- a/core/node/state_keeper/src/batch_executor/main_executor.rs +++ b/core/node/state_keeper/src/batch_executor/main_executor.rs @@ -14,7 +14,9 @@ use zksync_multivm::{ }; use zksync_shared_metrics::{InteractionType, TxStage, APP_METRICS}; use zksync_state::{OwnedStorage, ReadStorage, StorageView}; -use zksync_types::{event::extract_bytecodes_marked_as_known, vm::FastVmMode, vm_trace::Call, Transaction}; +use zksync_types::{ + event::extract_bytecodes_marked_as_known, vm::FastVmMode, vm_trace::Call, Transaction, +}; use zksync_utils::bytecode::CompressedBytecodeInfo; use super::{BatchExecutor, BatchExecutorHandle, Command, TxExecutionResult}; diff --git a/core/node/state_keeper/src/updates/l2_block_updates.rs b/core/node/state_keeper/src/updates/l2_block_updates.rs index c697a0a28f27..7cb155128e44 100644 --- a/core/node/state_keeper/src/updates/l2_block_updates.rs +++ b/core/node/state_keeper/src/updates/l2_block_updates.rs @@ -209,7 +209,7 @@ mod tests { ExecutionMetrics::default(), vec![], vec![], - vec![] + vec![], ); assert_eq!(accumulator.executed_transactions.len(), 1); From 8df3b0ec4b5f4bb9d2dba0a5c16f7fe2b7e45f61 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 16 Aug 2024 10:17:08 -0300 Subject: [PATCH 15/76] Fix format --- core/lib/contracts/src/lib.rs | 2 +- .../versions/vm_latest/tracers/default_tracers.rs | 4 ++-- .../versions/vm_latest/tracers/evm_deploy_tracer.rs | 13 ++++++++++--- .../multivm/src/versions/vm_latest/tracers/mod.rs | 8 ++++---- .../lib/multivm/src/versions/vm_latest/utils/mod.rs | 5 ++++- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index 0a08af35cf1c..8c93cd277a99 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -185,7 +185,7 @@ pub fn deployer_contract() -> Contract { } pub fn known_code_storage_contract() -> Contract { - load_sys_contract("KnownCodesStorage") + load_sys_contract("KnownCodesStorage") } pub fn l1_messenger_contract() -> Contract { diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs b/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs index ae7c707ccd65..20af48331eb7 100755 --- a/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs @@ -67,7 +67,7 @@ pub struct DefaultExecutionTracer { pub(crate) evm_tracer: Option>, pub(crate) evm_deploy_tracer: EvmDeployTracer, - + subversion: MultiVMSubversion, storage: StoragePtr, _phantom: PhantomData, @@ -299,7 +299,7 @@ impl DefaultExecutionTracer { .circuits_tracer .finish_cycle(state, bootloader_state) .stricter(&result); - + result = self .evm_deploy_tracer .finish_cycle(state, bootloader_state) diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs b/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs index 6481994ebe86..102dfc2976f9 100644 --- a/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs @@ -1,14 +1,21 @@ use std::marker::PhantomData; -use zk_evm_1_5_0::{aux_structures::Timestamp, zkevm_opcode_defs::{FatPointer, CALL_IMPLICIT_CALLDATA_FAT_PTR_REGISTER}}; +use zk_evm_1_5_0::{ + aux_structures::Timestamp, + zkevm_opcode_defs::{FatPointer, CALL_IMPLICIT_CALLDATA_FAT_PTR_REGISTER}, +}; use zksync_contracts::known_code_storage_contract; use zksync_state::WriteStorage; use zksync_types::{CONTRACT_DEPLOYER_ADDRESS, KNOWN_CODES_STORAGE_ADDRESS}; use zksync_utils::{bytes_to_be_words, h256_to_u256}; -use crate::{interface::{dyn_tracers::vm_1_5_0::DynTracer, tracer::TracerExecutionStatus}, vm_latest::{utils::hash_evm_bytecode, BootloaderState, HistoryMode, SimpleMemory, ZkSyncVmState}}; - use super::{traits::VmTracer, utils::read_pointer}; +use crate::{ + interface::{dyn_tracers::vm_1_5_0::DynTracer, tracer::TracerExecutionStatus}, + vm_latest::{ + utils::hash_evm_bytecode, BootloaderState, HistoryMode, SimpleMemory, ZkSyncVmState, + }, +}; /// Tracer responsible for collecting information about EVM deploys and providing those /// to the code decommitter. diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs b/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs index 859be2d150d2..8f660df7ac1f 100755 --- a/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs @@ -1,18 +1,18 @@ pub(crate) use circuits_tracer::CircuitsTracer; pub(crate) use default_tracers::DefaultExecutionTracer; +pub(crate) use evm_debug_tracer::EvmDebugTracer; +pub(crate) use evm_deploy_tracer::EvmDeployTracer; pub(crate) use pubdata_tracer::PubdataTracer; pub(crate) use refunds::RefundsTracer; pub(crate) use result_tracer::ResultTracer; -pub(crate) use evm_debug_tracer::EvmDebugTracer; -pub(crate) use evm_deploy_tracer::EvmDeployTracer; pub(crate) mod circuits_tracer; pub(crate) mod default_tracers; +pub(crate) mod evm_debug_tracer; +pub(crate) mod evm_deploy_tracer; pub(crate) mod pubdata_tracer; pub(crate) mod refunds; pub(crate) mod result_tracer; -pub(crate) mod evm_debug_tracer; -pub(crate) mod evm_deploy_tracer; pub(crate) mod circuits_capacity; pub mod dispatcher; diff --git a/core/lib/multivm/src/versions/vm_latest/utils/mod.rs b/core/lib/multivm/src/versions/vm_latest/utils/mod.rs index 233c7a6137fb..84bc99cc620d 100644 --- a/core/lib/multivm/src/versions/vm_latest/utils/mod.rs +++ b/core/lib/multivm/src/versions/vm_latest/utils/mod.rs @@ -1,5 +1,8 @@ use zk_evm_1_4_1::sha2; -use zk_evm_1_5_0::{aux_structures::MemoryPage, zkevm_opcode_defs::{BlobSha256Format, VersionedHashLen32}}; +use zk_evm_1_5_0::{ + aux_structures::MemoryPage, + zkevm_opcode_defs::{BlobSha256Format, VersionedHashLen32}, +}; use zksync_types::H256; /// Utility functions for the VM. From 21c08d3d36f518ffad9f4ae1bb1a71fea1946666 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 16 Aug 2024 19:19:55 -0300 Subject: [PATCH 16/76] Update decommit process for new factory deps --- .../vm_latest/old_vm/oracles/decommitter.rs | 77 +++++++++++-------- .../vm_latest/tracers/evm_deploy_tracer.rs | 7 +- .../types/internals/transaction_data.rs | 1 - core/lib/types/src/event/mod.rs | 9 +-- .../src/updates/l2_block_updates.rs | 48 ++++++------ 5 files changed, 72 insertions(+), 70 deletions(-) diff --git a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs b/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs index f5cd38779217..30fe45cb104c 100644 --- a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs +++ b/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs @@ -164,8 +164,8 @@ impl DecommittmentProcess _monotonic_cycle_counter: u32, mut partial_query: DecommittmentQuery, ) -> anyhow::Result { - let (stored_hash, length) = stored_hash_from_query(&partial_query); - partial_query.decommitted_length = length; + let versioned_hash = VersionedCodeHash::from_query(&partial_query); + let stored_hash = versioned_hash.to_stored_hash(); if let Some(memory_page) = self .decommitted_code_hashes @@ -176,19 +176,12 @@ impl DecommittmentProcess { partial_query.is_fresh = false; partial_query.memory_page = MemoryPage(memory_page); + partial_query.decommitted_length = versioned_hash.get_preimage_length() as u16; Ok(partial_query) } else { partial_query.is_fresh = true; - if self - .decommitted_code_hashes - .inner() - .get(&stored_hash) - .is_none() - { - self.decommitted_code_hashes - .insert(stored_hash, None, partial_query.timestamp); - } + partial_query.decommitted_length = versioned_hash.get_preimage_length() as u16; Ok(partial_query) } @@ -202,11 +195,10 @@ impl DecommittmentProcess memory: &mut M, ) -> anyhow::Result>> { assert!(partial_query.is_fresh); - self.decommitment_requests.push((), partial_query.timestamp); - let stored_hash = stored_hash_from_query(&partial_query).0; - + let versioned_hash = VersionedCodeHash::from_query(&partial_query); + let stored_hash = versioned_hash.to_stored_hash(); // We are fetching a fresh bytecode that we didn't read before. let values = self.get_bytecode(stored_hash, partial_query.timestamp); let page_to_use = partial_query.memory_page; @@ -249,28 +241,49 @@ impl DecommittmentProcess } } -fn concat_header_and_preimage( - header: VersionedHashHeader, - normalized_preimage: VersionedHashNormalizedPreimage, -) -> [u8; 32] { - let mut buffer = [0u8; 32]; +#[derive(Debug)] +// TODO: consider moving this to the zk-evm crate +enum VersionedCodeHash { + ZkEVM(VersionedHashHeader, VersionedHashNormalizedPreimage), + EVM(VersionedHashHeader, VersionedHashNormalizedPreimage), +} - buffer[0..4].copy_from_slice(&header.0); - buffer[4..32].copy_from_slice(&normalized_preimage.0); +impl VersionedCodeHash { + fn from_query(query: &DecommittmentQuery) -> Self { + match query.header.0[0] { + 1 => Self::ZkEVM(query.header, query.normalized_preimage), + 2 => Self::EVM(query.header, query.normalized_preimage), + _ => panic!("Unsupported hash version"), + } + } - buffer -} + /// Returns the hash in the format it is stored in the DB. + fn to_stored_hash(&self) -> U256 { + let (header, preimage) = match self { + Self::ZkEVM(header, preimage) => (header, preimage), + Self::EVM(header, preimage) => (header, preimage), + }; -/// For a given decommitment query, returns a pair of the stored hash as U256 and the length of the preimage in 32-byte words. -fn stored_hash_from_query(partial_query: &DecommittmentQuery) -> (U256, u16) { - let full_hash = - concat_header_and_preimage(partial_query.header, partial_query.normalized_preimage); + let mut hash = [0u8; 32]; + &mut hash[0..4].copy_from_slice(&header.0); + &mut hash[4..32].copy_from_slice(&preimage.0); - let versioned_hash = - ContractCodeSha256::try_deserialize(full_hash).expect("Invalid ContractCodeSha256 hash"); + // Hash[1] is used in both of the versions to denote whether the bytecode is being constructed. + // We ignore this param. + hash[1] = 0; - let stored_hash = H256(ContractCodeSha256::serialize_to_stored(versioned_hash).unwrap()); - let length = versioned_hash.code_length_in_words; + h256_to_u256(H256(hash)) + } - (h256_to_u256(stored_hash), length) + fn get_preimage_length(&self) -> u32 { + // In zkEVM the hash[2..3] denotes the length of the preimage in words, while + // in EVM the hash[2..3] denotes the length of the preimage in bytes. + match self { + Self::ZkEVM(header, _) => { + let length_in_words = header.0[2] as u32 * 256 + header.0[3] as u32; + length_in_words * 32 + } + Self::EVM(header, _) => header.0[2] as u32 * 256 + header.0[3] as u32, + } + } } diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs b/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs index 102dfc2976f9..320774242958 100644 --- a/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs @@ -4,9 +4,9 @@ use zk_evm_1_5_0::{ aux_structures::Timestamp, zkevm_opcode_defs::{FatPointer, CALL_IMPLICIT_CALLDATA_FAT_PTR_REGISTER}, }; -use zksync_contracts::known_code_storage_contract; +use zksync_contracts::known_codes_contract; use zksync_state::WriteStorage; -use zksync_types::{CONTRACT_DEPLOYER_ADDRESS, KNOWN_CODES_STORAGE_ADDRESS}; +use zksync_types::{CONTRACT_DEPLOYER_ADDRESS, KNOWN_CODES_STORAGE_ADDRESS, U256}; use zksync_utils::{bytes_to_be_words, h256_to_u256}; use super::{traits::VmTracer, utils::read_pointer}; @@ -44,7 +44,6 @@ impl VmTracer for EvmDeployTracer { // It is assumed that by that time the user has already paid for its size. // So even if we do not revert the addition of the this bytecode it is not a ddos vector, since // the payment is the same as if the bytecode publication was reverted. - let current_callstack = &state.local_state.callstack.current; // Here we assume that the only case when PC is 0 at the start of the execution of the contract. @@ -63,7 +62,7 @@ impl VmTracer for EvmDeployTracer { let data = read_pointer(&state.memory, FatPointer::from_u256(calldata_ptr.value)); - let contract = known_code_storage_contract(); + let contract = known_codes_contract(); if data.len() < 4 { // Not interested diff --git a/core/lib/multivm/src/versions/vm_latest/types/internals/transaction_data.rs b/core/lib/multivm/src/versions/vm_latest/types/internals/transaction_data.rs index 2fa939d9a136..06f60d9c5a1f 100644 --- a/core/lib/multivm/src/versions/vm_latest/types/internals/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_latest/types/internals/transaction_data.rs @@ -63,7 +63,6 @@ impl From for TransactionData { }; let should_deploy_contract = if execute_tx.execute.contract_address.is_none() { - println!("DEPLOYING"); U256([1, 0, 0, 0]) } else { U256::zero() diff --git a/core/lib/types/src/event/mod.rs b/core/lib/types/src/event/mod.rs index 81e796097249..6e86b88b2ff3 100644 --- a/core/lib/types/src/event/mod.rs +++ b/core/lib/types/src/event/mod.rs @@ -10,14 +10,7 @@ use zksync_utils::{ }; use crate::{ - api::Log, - ethabi, - l2_to_l1_log::L2ToL1Log, - tokens::{TokenInfo, TokenMetadata}, - web3::{Bytes, Index}, - zk_evm_types::{LogQuery, Timestamp}, - Address, L1BatchNumber, CONTRACT_DEPLOYER_ADDRESS, H256, KNOWN_CODES_STORAGE_ADDRESS, - L1_MESSENGER_ADDRESS, U256, U64, + api::Log, ethabi, l2_to_l1_log::L2ToL1Log, tokens::{TokenInfo, TokenMetadata}, web3::{Bytes, Index}, zk_evm_types::{LogQuery, Timestamp}, Address, L1BatchNumber, StorageLogQuery, CONTRACT_DEPLOYER_ADDRESS, H256, KNOWN_CODES_STORAGE_ADDRESS, L1_MESSENGER_ADDRESS, U256, U64 }; #[cfg(test)] diff --git a/core/node/state_keeper/src/updates/l2_block_updates.rs b/core/node/state_keeper/src/updates/l2_block_updates.rs index 7cb155128e44..7db7f110e44c 100644 --- a/core/node/state_keeper/src/updates/l2_block_updates.rs +++ b/core/node/state_keeper/src/updates/l2_block_updates.rs @@ -5,12 +5,7 @@ use zksync_multivm::{ vm_latest::TransactionVmExt, }; use zksync_types::{ - block::{BlockGasCount, L2BlockHasher}, - event::extract_bytecodes_marked_as_known, - l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log}, - tx::{tx_execution_info::TxExecutionStatus, ExecutionMetrics, TransactionExecutionResult}, - vm_trace::Call, - L2BlockNumber, ProtocolVersionId, StorageLogWithPreviousValue, Transaction, VmEvent, H256, + block::{BlockGasCount, L2BlockHasher}, event::{convert_vm_events_to_log_queries, extract_bytecodes_marked_as_known}, l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log}, tx::{tx_execution_info::TxExecutionStatus, ExecutionMetrics, TransactionExecutionResult}, vm_trace::Call, L2BlockNumber, ProtocolVersionId, StorageLogKind, StorageLogQuery, StorageLogWithPreviousValue, Transaction, VmEvent, H256 }; use zksync_utils::bytecode::{hash_bytecode, CompressedBytecodeInfo}; @@ -92,7 +87,7 @@ impl L2BlockUpdates { ) { let saved_factory_deps = extract_bytecodes_marked_as_known(&tx_execution_result.logs.events); - self.new_factory_deps.extend(new_known_factory_deps); + self.new_factory_deps.extend(new_known_factory_deps.clone()); self.events.extend(tx_execution_result.logs.events); self.user_l2_to_l1_logs .extend(tx_execution_result.logs.user_l2_to_l1_logs); @@ -122,24 +117,27 @@ impl L2BlockUpdates { }; // Get transaction factory deps - // let factory_deps = &tx.execute.factory_deps; - // let tx_factory_deps: HashMap<_, _> = factory_deps - // .iter() - // .map(|bytecode| (hash_bytecode(bytecode), bytecode)) - // .collect(); - - // // Save all bytecodes that were marked as known on the bootloader - // let known_bytecodes = saved_factory_deps.into_iter().map(|bytecode_hash| { - // let bytecode = tx_factory_deps.get(&bytecode_hash).unwrap_or_else(|| { - // panic!( - // "Failed to get factory deps on tx: bytecode hash: {:?}, tx hash: {}", - // bytecode_hash, - // tx.hash() - // ) - // }); - // (bytecode_hash, bytecode.to_vec()) - // }); - // self.new_factory_deps.extend(known_bytecodes); + let factory_deps = &tx.execute.factory_deps; + let mut tx_factory_deps: HashMap<_, _> = factory_deps + .iter() + .map(|bytecode| (hash_bytecode(bytecode), bytecode.clone())) + .collect(); + new_known_factory_deps.into_iter().for_each(|(hash, bytecode)| { + tx_factory_deps.insert(hash, bytecode); + }); + + // Save all bytecodes that were marked as known on the bootloader + let known_bytecodes = saved_factory_deps.into_iter().map(|bytecode_hash| { + let bytecode = tx_factory_deps.get(&bytecode_hash).unwrap_or_else(|| { + panic!( + "Failed to get factory deps on tx: bytecode hash: {:?}, tx hash: {}", + bytecode_hash, + tx.hash() + ) + }); + (bytecode_hash, bytecode.to_vec()) + }); + self.new_factory_deps.extend(known_bytecodes); self.l1_gas_count += tx_l1_gas_this_tx; self.block_execution_metrics += execution_metrics; From 4b8774aae9232e4d4230e79ebf08a2228b6b26fe Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 16 Aug 2024 19:22:51 -0300 Subject: [PATCH 17/76] Update contracts submodule --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index 6b78beb8a268..8eeffbad0a03 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 6b78beb8a268974362511fa1932b998cbe7b6a4d +Subproject commit 8eeffbad0a03e0f51f99d82be7e3e7cb08c36132 From 0c396095e008d9a33b7b3978658f097e03e7c11c Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 19 Aug 2024 12:03:30 -0300 Subject: [PATCH 18/76] Update contracts hash in config file --- etc/env/base/contracts.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index 47f1e57fea13..59200adb3c25 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -26,8 +26,8 @@ RECURSION_NODE_LEVEL_VK_HASH = "0x1186ec268d49f1905f8d9c1e9d39fc33e98c74f91d91a2 RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc8966504064f1f6ba3f1ba863210" RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" -GENESIS_ROOT = "0xf511c8e55095e444bd86bc2813689935b2098edda19aa7f9d080b506e2cfc69f" -GENESIS_BATCH_COMMITMENT = "0x7c46546a6d6268914e6ee58b51a38fa44dcc707efadf8af3e68e5f3b3a28e0af" +GENESIS_ROOT = "0xd2b1a071a2da0f92d65e58e7db4743273963c1b8fa6c6a7b565e04128b5441f3" +GENESIS_BATCH_COMMITMENT = "0x7721099ac60105b5ec00fced84f92cb61ec2103ab2248f7d223a705aaddc1da4" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "56" From 864a67e2a331f2683f2fc4cf45dc2c710c954faf Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 19 Aug 2024 12:04:19 -0300 Subject: [PATCH 19/76] Fix format --- core/lib/types/src/event/mod.rs | 9 ++++++++- .../state_keeper/src/updates/l2_block_updates.rs | 16 ++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/core/lib/types/src/event/mod.rs b/core/lib/types/src/event/mod.rs index 6e86b88b2ff3..6fc4c4444ed5 100644 --- a/core/lib/types/src/event/mod.rs +++ b/core/lib/types/src/event/mod.rs @@ -10,7 +10,14 @@ use zksync_utils::{ }; use crate::{ - api::Log, ethabi, l2_to_l1_log::L2ToL1Log, tokens::{TokenInfo, TokenMetadata}, web3::{Bytes, Index}, zk_evm_types::{LogQuery, Timestamp}, Address, L1BatchNumber, StorageLogQuery, CONTRACT_DEPLOYER_ADDRESS, H256, KNOWN_CODES_STORAGE_ADDRESS, L1_MESSENGER_ADDRESS, U256, U64 + api::Log, + ethabi, + l2_to_l1_log::L2ToL1Log, + tokens::{TokenInfo, TokenMetadata}, + web3::{Bytes, Index}, + zk_evm_types::{LogQuery, Timestamp}, + Address, L1BatchNumber, StorageLogQuery, CONTRACT_DEPLOYER_ADDRESS, H256, + KNOWN_CODES_STORAGE_ADDRESS, L1_MESSENGER_ADDRESS, U256, U64, }; #[cfg(test)] diff --git a/core/node/state_keeper/src/updates/l2_block_updates.rs b/core/node/state_keeper/src/updates/l2_block_updates.rs index 7db7f110e44c..f3ea48047926 100644 --- a/core/node/state_keeper/src/updates/l2_block_updates.rs +++ b/core/node/state_keeper/src/updates/l2_block_updates.rs @@ -5,7 +5,13 @@ use zksync_multivm::{ vm_latest::TransactionVmExt, }; use zksync_types::{ - block::{BlockGasCount, L2BlockHasher}, event::{convert_vm_events_to_log_queries, extract_bytecodes_marked_as_known}, l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log}, tx::{tx_execution_info::TxExecutionStatus, ExecutionMetrics, TransactionExecutionResult}, vm_trace::Call, L2BlockNumber, ProtocolVersionId, StorageLogKind, StorageLogQuery, StorageLogWithPreviousValue, Transaction, VmEvent, H256 + block::{BlockGasCount, L2BlockHasher}, + event::{convert_vm_events_to_log_queries, extract_bytecodes_marked_as_known}, + l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log}, + tx::{tx_execution_info::TxExecutionStatus, ExecutionMetrics, TransactionExecutionResult}, + vm_trace::Call, + L2BlockNumber, ProtocolVersionId, StorageLogKind, StorageLogQuery, StorageLogWithPreviousValue, + Transaction, VmEvent, H256, }; use zksync_utils::bytecode::{hash_bytecode, CompressedBytecodeInfo}; @@ -122,9 +128,11 @@ impl L2BlockUpdates { .iter() .map(|bytecode| (hash_bytecode(bytecode), bytecode.clone())) .collect(); - new_known_factory_deps.into_iter().for_each(|(hash, bytecode)| { - tx_factory_deps.insert(hash, bytecode); - }); + new_known_factory_deps + .into_iter() + .for_each(|(hash, bytecode)| { + tx_factory_deps.insert(hash, bytecode); + }); // Save all bytecodes that were marked as known on the bootloader let known_bytecodes = saved_factory_deps.into_iter().map(|bytecode_hash| { From d8cc2b4e93397fdb55a5cc10806266952fa90d89 Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Mon, 19 Aug 2024 12:08:55 -0300 Subject: [PATCH 20/76] Add inital integration reversioning --- contracts | 2 +- core/lib/types/src/event/mod.rs | 9 +- .../src/updates/l2_block_updates.rs | 16 +- .../evm-contracts/ConstructorRevert.sol | 13 + .../evm-contracts/CounterFallback.sol | 15 + .../evm-contracts/CounterWithParam.sol | 40 + .../ts-integration/evm-contracts/Creator.sol | 19 + .../evm-contracts/CreatorFallback.sol | 19 + .../ts-integration/evm-contracts/ERC20.sol | 76 ++ .../evm-contracts/GasCaller.sol | 16 + .../evm-contracts/OpcodeTest.sol | 125 +++ .../evm-contracts/OpcodeTestFallback.sol | 141 +++ .../evm-contracts/ProxyCaller.sol | 25 + .../evm-contracts/SelfDestruct.sol | 15 + .../evm-contracts/UniswapFallback.sol | 124 +++ core/tests/ts-integration/package.json | 5 +- core/tests/ts-integration/src/helpers.ts | 47 + .../tests/evm-contracts.test.ts | 894 ++++++++++++++++++ yarn.lock | 485 +++++++++- 19 files changed, 2042 insertions(+), 44 deletions(-) create mode 100644 core/tests/ts-integration/evm-contracts/ConstructorRevert.sol create mode 100644 core/tests/ts-integration/evm-contracts/CounterFallback.sol create mode 100644 core/tests/ts-integration/evm-contracts/CounterWithParam.sol create mode 100644 core/tests/ts-integration/evm-contracts/Creator.sol create mode 100644 core/tests/ts-integration/evm-contracts/CreatorFallback.sol create mode 100644 core/tests/ts-integration/evm-contracts/ERC20.sol create mode 100644 core/tests/ts-integration/evm-contracts/GasCaller.sol create mode 100644 core/tests/ts-integration/evm-contracts/OpcodeTest.sol create mode 100644 core/tests/ts-integration/evm-contracts/OpcodeTestFallback.sol create mode 100644 core/tests/ts-integration/evm-contracts/ProxyCaller.sol create mode 100644 core/tests/ts-integration/evm-contracts/SelfDestruct.sol create mode 100644 core/tests/ts-integration/evm-contracts/UniswapFallback.sol create mode 100644 core/tests/ts-integration/tests/evm-contracts.test.ts diff --git a/contracts b/contracts index 8eeffbad0a03..b6a629f9b55b 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 8eeffbad0a03e0f51f99d82be7e3e7cb08c36132 +Subproject commit b6a629f9b55b2b59409e086469c8cdff0c4bd56c diff --git a/core/lib/types/src/event/mod.rs b/core/lib/types/src/event/mod.rs index 6e86b88b2ff3..6fc4c4444ed5 100644 --- a/core/lib/types/src/event/mod.rs +++ b/core/lib/types/src/event/mod.rs @@ -10,7 +10,14 @@ use zksync_utils::{ }; use crate::{ - api::Log, ethabi, l2_to_l1_log::L2ToL1Log, tokens::{TokenInfo, TokenMetadata}, web3::{Bytes, Index}, zk_evm_types::{LogQuery, Timestamp}, Address, L1BatchNumber, StorageLogQuery, CONTRACT_DEPLOYER_ADDRESS, H256, KNOWN_CODES_STORAGE_ADDRESS, L1_MESSENGER_ADDRESS, U256, U64 + api::Log, + ethabi, + l2_to_l1_log::L2ToL1Log, + tokens::{TokenInfo, TokenMetadata}, + web3::{Bytes, Index}, + zk_evm_types::{LogQuery, Timestamp}, + Address, L1BatchNumber, StorageLogQuery, CONTRACT_DEPLOYER_ADDRESS, H256, + KNOWN_CODES_STORAGE_ADDRESS, L1_MESSENGER_ADDRESS, U256, U64, }; #[cfg(test)] diff --git a/core/node/state_keeper/src/updates/l2_block_updates.rs b/core/node/state_keeper/src/updates/l2_block_updates.rs index 7db7f110e44c..f3ea48047926 100644 --- a/core/node/state_keeper/src/updates/l2_block_updates.rs +++ b/core/node/state_keeper/src/updates/l2_block_updates.rs @@ -5,7 +5,13 @@ use zksync_multivm::{ vm_latest::TransactionVmExt, }; use zksync_types::{ - block::{BlockGasCount, L2BlockHasher}, event::{convert_vm_events_to_log_queries, extract_bytecodes_marked_as_known}, l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log}, tx::{tx_execution_info::TxExecutionStatus, ExecutionMetrics, TransactionExecutionResult}, vm_trace::Call, L2BlockNumber, ProtocolVersionId, StorageLogKind, StorageLogQuery, StorageLogWithPreviousValue, Transaction, VmEvent, H256 + block::{BlockGasCount, L2BlockHasher}, + event::{convert_vm_events_to_log_queries, extract_bytecodes_marked_as_known}, + l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log}, + tx::{tx_execution_info::TxExecutionStatus, ExecutionMetrics, TransactionExecutionResult}, + vm_trace::Call, + L2BlockNumber, ProtocolVersionId, StorageLogKind, StorageLogQuery, StorageLogWithPreviousValue, + Transaction, VmEvent, H256, }; use zksync_utils::bytecode::{hash_bytecode, CompressedBytecodeInfo}; @@ -122,9 +128,11 @@ impl L2BlockUpdates { .iter() .map(|bytecode| (hash_bytecode(bytecode), bytecode.clone())) .collect(); - new_known_factory_deps.into_iter().for_each(|(hash, bytecode)| { - tx_factory_deps.insert(hash, bytecode); - }); + new_known_factory_deps + .into_iter() + .for_each(|(hash, bytecode)| { + tx_factory_deps.insert(hash, bytecode); + }); // Save all bytecodes that were marked as known on the bootloader let known_bytecodes = saved_factory_deps.into_iter().map(|bytecode_hash| { diff --git a/core/tests/ts-integration/evm-contracts/ConstructorRevert.sol b/core/tests/ts-integration/evm-contracts/ConstructorRevert.sol new file mode 100644 index 000000000000..468b3395ce5b --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/ConstructorRevert.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity >=0.7.0; + +contract ConstructorRevert { + uint256 value; + + + constructor() { + revert('Failure string'); + } + +} diff --git a/core/tests/ts-integration/evm-contracts/CounterFallback.sol b/core/tests/ts-integration/evm-contracts/CounterFallback.sol new file mode 100644 index 000000000000..2535a05262bf --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/CounterFallback.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.0; + +contract CounterFallback { + + function performCall() external { + uint256 value = 0; + value += 1; + } + + fallback() external { + this.performCall(); + } +} diff --git a/core/tests/ts-integration/evm-contracts/CounterWithParam.sol b/core/tests/ts-integration/evm-contracts/CounterWithParam.sol new file mode 100644 index 000000000000..40211a746540 --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/CounterWithParam.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity >=0.7.0; + +contract CounterWithParam { + uint256 value; + + + constructor(uint256 _startingValue) { + value = _startingValue; + } + + function increment(uint256 x) public { + value += x; + } + + function incrementWithRevertPayable(uint256 x, bool shouldRevert) payable public returns (uint256) { + return incrementWithRevert(x, shouldRevert); + } + + function incrementWithRevert(uint256 x, bool shouldRevert) public returns (uint256) { + value += x; + if(shouldRevert) { + revert("This method always reverts"); + } + return value; + } + + function set(uint256 x) public { + value = x; + } + + function get() public view returns (uint256) { + return value; + } + + function getBytes() public returns (bytes memory) { + return "Testing"; + } +} \ No newline at end of file diff --git a/core/tests/ts-integration/evm-contracts/Creator.sol b/core/tests/ts-integration/evm-contracts/Creator.sol new file mode 100644 index 000000000000..516bce4cbe38 --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/Creator.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity >=0.7.0; + +contract Creation { + function blockNumber() external view returns (uint256) { + return block.number; + } +} + +contract Creator { + function create() external { + new Creation(); + } + + function getCreationRuntimeCode() external pure returns(bytes memory){ + return type(Creation).runtimeCode; + } +} diff --git a/core/tests/ts-integration/evm-contracts/CreatorFallback.sol b/core/tests/ts-integration/evm-contracts/CreatorFallback.sol new file mode 100644 index 000000000000..ce532aa69b7e --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/CreatorFallback.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity >=0.7.0; + +contract Creation { + function blockNumber() external view returns (uint256) { + return block.number; + } +} + +contract CreatorFallback { + function performCall() external { + new Creation(); + type(Creation).runtimeCode; + } + fallback() external { + this.performCall(); + } +} diff --git a/core/tests/ts-integration/evm-contracts/ERC20.sol b/core/tests/ts-integration/evm-contracts/ERC20.sol new file mode 100644 index 000000000000..5c1c89faf7ad --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/ERC20.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity >=0.7.0; + +contract ERC20{ + string public symbol; + string public name; + uint8 public decimals; + uint public totalSupply; + + mapping(address => uint) balances; + mapping(address => mapping(address => uint)) allowed; + + event Transfer(address indexed _from, address indexed _to, uint256 _value); + event Approval(address indexed _owner, address indexed _spender, uint256 _value); + + constructor() { + symbol = "TEST"; + name = "Test Coin"; + decimals = 18; + totalSupply = 1000000; + balances[msg.sender] = totalSupply; + emit Transfer(address(0), msg.sender, totalSupply); + } + + + function balanceOf(address tokenOwner) public view returns (uint balance) { + return balances[tokenOwner]; + } + + function transfer(address to, uint tokens) public returns (bool success) { + balances[msg.sender] = safeSub(balances[msg.sender], tokens); + balances[to] = safeAdd(balances[to], tokens); + emit Transfer(msg.sender, to, tokens); + return true; + } + + function approve(address spender, uint tokens) public returns (bool success) { + allowed[msg.sender][spender] = tokens; + emit Approval(msg.sender, spender, tokens); + return true; + } + + function transferFrom(address from, address to, uint tokens) public returns (bool success) { + balances[from] = safeSub(balances[from], tokens); + allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], tokens); + balances[to] = safeAdd(balances[to], tokens); + emit Transfer(from, to, tokens); + return true; + } + + function allowance(address tokenOwner, address spender) public view returns (uint remaining) { + return allowed[tokenOwner][spender]; + } + + function safeAdd(uint a, uint b) internal pure returns (uint c) { + c = a + b; + require(c >= a); + } + + function safeSub(uint a, uint b) internal pure returns (uint c) { + require(b <= a); + c = a - b; + } + + function safeMul(uint a, uint b) internal pure returns (uint c) { + c = a * b; + require(a == 0 || c / a == b); + } + + function safeDiv(uint a, uint b) internal pure returns (uint c) { + require(b > 0); + c = a / b; + } + +} diff --git a/core/tests/ts-integration/evm-contracts/GasCaller.sol b/core/tests/ts-integration/evm-contracts/GasCaller.sol new file mode 100644 index 000000000000..4fd43a235b5e --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/GasCaller.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.0; + +contract GasCaller { + uint256 _resultGas; + + function callAndGetGas(address _to) external returns (uint256){ + uint256 startGas = gasleft(); + // Just doing a call to an address + (bool success, ) = _to.call(""); + require(success); + _resultGas = startGas - gasleft(); + return _resultGas; + } +} diff --git a/core/tests/ts-integration/evm-contracts/OpcodeTest.sol b/core/tests/ts-integration/evm-contracts/OpcodeTest.sol new file mode 100644 index 000000000000..9c739846f334 --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/OpcodeTest.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.0; + +contract OpcodeTest { + + function execute() external { + uint256 loaded = 1; + uint256 tmp; + uint256 prevBlock = block.number - 1; + assembly { + loaded := add(loaded, 1) + loaded := mul(loaded, 2) + loaded := sub(loaded, 1) + loaded := div(loaded, 2) + loaded := sdiv(loaded, 2) + loaded := mod(loaded, 2) + // ADDMOD + // MULMOD + loaded := exp(loaded, 2) + loaded := signextend(loaded, 2) + tmp := lt(loaded, 2) + tmp := gt(loaded, 2) + tmp := slt(loaded, 2) + tmp := sgt(loaded, 2) + tmp := eq(loaded, 2) + tmp := iszero(tmp) + tmp := and(1,1) + tmp := or(1,1) + tmp := xor(1,1) + tmp := not(tmp) + tmp := byte(tmp,1) + tmp := shl(tmp,1) + tmp := shr(tmp,1) + tmp := sar(tmp,1) + tmp := keccak256(0, 0x40) + tmp := address() + tmp := balance(0x00) + tmp := origin() + tmp := caller() + tmp := callvalue() + // CALLDATALOAD + tmp := calldatasize() + // CALLDATACOPY + tmp := codesize() + // CODECOPY + tmp := gasprice() + // EXTCODESIZE + // EXTCODECOPY + tmp := returndatasize() + // RETURNDATACOPY + // EXTCODEHASH + tmp := blockhash(prevBlock) + tmp := coinbase() + tmp := timestamp() + tmp := number() + tmp := prevrandao() + tmp := gaslimit() + tmp := chainid() + tmp := selfbalance() + tmp := basefee() + // POP + tmp := mload(1) + mstore(1024,1) + mstore8(10242,1) + tmp := sload(0) + sstore(0,1) + // JUMP + // JUMPI + // PC + tmp := msize() + tmp := gas() + // JUMPDEST + // PUSH0...PUSH32 + // DUP1...DUP16 + // SWAP1...SWAP16 + // LOG0...LOG4 + // CREATE + // CALL + // CALLCODE + // RETURN + // DELEGATECALL + // CREATE2 + // STATICCALL + // REVERT + // INVALID + // selfdestruct(sender) + } + + // tmp = 0; + // tmp = 0x11; + // tmp = 0x2211; + // tmp = 0x332211; + // tmp = 0x44332211; + // tmp = 0x5544332211; + // tmp = 0x665544332211; + // tmp = 0x77665544332211; + // tmp = 0x8877665544332211; + // tmp = 0x998877665544332211; + // tmp = 0xaa998877665544332211; + // tmp = 0xbbaa998877665544332211; + // tmp = 0xccbbaa998877665544332211; + // tmp = 0xddccbbaa998877665544332211; + // tmp = 0xeeddccbbaa998877665544332211; + // tmp = 0xffeeddccbbaa998877665544332211; + // tmp = 0x11ffeeddccbbaa998877665544332211; + // tmp = 0x2211ffeeddccbbaa998877665544332211; + // tmp = 0x332211ffeeddccbbaa998877665544332211; + // tmp = 0x44332211ffeeddccbbaa998877665544332211; + // tmp = uint256(uint160(0x5544332211FFeeDDCcbbAa998877665544332211)); + // tmp = 0x665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x77665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x8877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0xff998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x11ff998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x2211ff998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x332211ff998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x44332211ff998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x5544332211ff998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x665544332211ff998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x77665544332211ff998877665544332211ffeeddccbbaa998877665544332211; + } + +} diff --git a/core/tests/ts-integration/evm-contracts/OpcodeTestFallback.sol b/core/tests/ts-integration/evm-contracts/OpcodeTestFallback.sol new file mode 100644 index 000000000000..68d64fc074d8 --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/OpcodeTestFallback.sol @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.0; + +contract OpcodeTestFallback { + + function performCall() external { + uint256 loaded = 1; + uint256 tmp; + uint256 prevBlock = block.number - 1; + assembly { + loaded := add(loaded, 1) + loaded := mul(loaded, 2) + loaded := sub(loaded, 1) + loaded := div(loaded, 2) + loaded := sdiv(loaded, 2) + loaded := mod(loaded, 2) + // ADDMOD + // MULMOD + loaded := exp(loaded, 2) + loaded := signextend(loaded, 2) + tmp := lt(loaded, 2) + tmp := gt(loaded, 2) + tmp := slt(loaded, 2) + tmp := sgt(loaded, 2) + tmp := eq(loaded, 2) + tmp := iszero(tmp) + tmp := and(1,1) + tmp := or(1,1) + tmp := xor(1,1) + tmp := not(tmp) + tmp := byte(tmp,1) + tmp := shl(tmp,1) + tmp := shr(tmp,1) + tmp := sar(tmp,1) + tmp := keccak256(0, 0x40) + tmp := address() + tmp := balance(0x00) + tmp := origin() + tmp := caller() + tmp := callvalue() + // CALLDATALOAD + tmp := calldatasize() + // CALLDATACOPY + tmp := codesize() + // CODECOPY + tmp := gasprice() + // EXTCODESIZE + // EXTCODECOPY + tmp := returndatasize() + // RETURNDATACOPY + // EXTCODEHASH + tmp := blockhash(prevBlock) + tmp := coinbase() + tmp := timestamp() + tmp := number() + tmp := prevrandao() + tmp := gaslimit() + tmp := chainid() + tmp := selfbalance() + tmp := basefee() + // POP + tmp := mload(1) + mstore(1024,1) + mstore8(10242,1) + tmp := sload(0) + sstore(0,1) + // JUMP + // JUMPI + // PC + tmp := msize() + tmp := gas() + // JUMPDEST + // PUSH0...PUSH32 + // DUP1...DUP16 + // SWAP1...SWAP16 + // LOG0...LOG4 + // CREATE + // CALL + // CALLCODE + // RETURN + // DELEGATECALL + // CREATE2 + // STATICCALL + // REVERT + // INVALID + // selfdestruct(sender) + tmp := calldataload(0) + calldatacopy(10,0,1) + codecopy(10,0,1) + tmp := extcodesize(0) + extcodecopy(address(),10,0,1) + returndatacopy(10,0,1) + pop(extcodehash(0)) + log0(0,30) + log1(0,30,30) + log2(0,30,30,30) + log3(0,30,30,30,30) + log4(0,30,30,30,30,30) + } + + // tmp = 0; + // tmp = 0x11; + // tmp = 0x2211; + // tmp = 0x332211; + // tmp = 0x44332211; + // tmp = 0x5544332211; + // tmp = 0x665544332211; + // tmp = 0x77665544332211; + // tmp = 0x8877665544332211; + // tmp = 0x998877665544332211; + // tmp = 0xaa998877665544332211; + // tmp = 0xbbaa998877665544332211; + // tmp = 0xccbbaa998877665544332211; + // tmp = 0xddccbbaa998877665544332211; + // tmp = 0xeeddccbbaa998877665544332211; + // tmp = 0xffeeddccbbaa998877665544332211; + // tmp = 0x11ffeeddccbbaa998877665544332211; + // tmp = 0x2211ffeeddccbbaa998877665544332211; + // tmp = 0x332211ffeeddccbbaa998877665544332211; + // tmp = 0x44332211ffeeddccbbaa998877665544332211; + // tmp = uint256(uint160(0x5544332211FFeeDDCcbbAa998877665544332211)); + // tmp = 0x665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x77665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x8877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0xff998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x11ff998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x2211ff998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x332211ff998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x44332211ff998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x5544332211ff998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x665544332211ff998877665544332211ffeeddccbbaa998877665544332211; + // tmp = 0x77665544332211ff998877665544332211ffeeddccbbaa998877665544332211; + } + + fallback() external { + this.performCall(); + } + +} diff --git a/core/tests/ts-integration/evm-contracts/ProxyCaller.sol b/core/tests/ts-integration/evm-contracts/ProxyCaller.sol new file mode 100644 index 000000000000..05200d06a31c --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/ProxyCaller.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity >=0.7.0; + +interface ICounterWithParam { + function increment(uint256 x) external; + + function get() external view returns (uint256); + + function getBytes() external returns (bytes memory); +} + +contract ProxyCaller { + function executeIncrememt(address dest, uint256 x) external{ + ICounterWithParam(dest).increment(x); + } + + function proxyGet(address dest) external view returns (uint256){ + return ICounterWithParam(dest).get(); + } + + function proxyGetBytes(address dest) external returns(bytes memory returnData){ + return ICounterWithParam(dest).getBytes(); + } +} \ No newline at end of file diff --git a/core/tests/ts-integration/evm-contracts/SelfDestruct.sol b/core/tests/ts-integration/evm-contracts/SelfDestruct.sol new file mode 100644 index 000000000000..3e3923de3369 --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/SelfDestruct.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity >=0.7.0; + +contract SelfDestruct { + + constructor() payable { + } + + function destroy(address recipient) external{ + assembly { + selfdestruct(recipient) + } + } +} \ No newline at end of file diff --git a/core/tests/ts-integration/evm-contracts/UniswapFallback.sol b/core/tests/ts-integration/evm-contracts/UniswapFallback.sol new file mode 100644 index 000000000000..b2d631d3551d --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/UniswapFallback.sol @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.0; + +interface IUniswapV2ERC20 { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external pure returns (string memory); + + function symbol() external pure returns (string memory); + + function decimals() external pure returns (uint8); + + function totalSupply() external returns (uint); + + function balanceOf(address owner) external returns (uint); + + function allowance(address owner, address spender) external returns (uint); + + function approve(address spender, uint value) external returns (bool); + + function transfer(address to, uint value) external returns (bool); + + function transferFrom( + address from, + address to, + uint value + ) external returns (bool); + + function DOMAIN_SEPARATOR() external returns (bytes32); + + function PERMIT_TYPEHASH() external pure returns (bytes32); + + function nonces(address owner) external returns (uint); + + function permit( + address owner, + address spender, + uint value, + uint deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; +} + +interface IUniswapV2Pair { + event Mint(address indexed sender, uint amount0, uint amount1); + event Burn( + address indexed sender, + uint amount0, + uint amount1, + address indexed to + ); + event Swap( + address indexed sender, + uint amount0In, + uint amount1In, + uint amount0Out, + uint amount1Out, + address indexed to + ); + event Sync(uint112 reserve0, uint112 reserve1); + + function MINIMUM_LIQUIDITY() external pure returns (uint); + + function factory() external returns (address); + + function token0() external returns (address); + + function token1() external returns (address); + + function getReserves() + external + returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); + + function price0CumulativeLast() external returns (uint); + + function price1CumulativeLast() external returns (uint); + + function kLast() external returns (uint); + + function mint(address to) external returns (uint liquidity); + + function burn(address to) external returns (uint amount0, uint amount1); + + function swap( + uint amount0Out, + uint amount1Out, + address to, + bytes calldata data + ) external; + + function skim(address to) external; + + function sync() external; + + function initialize(address, address) external; +} + +contract UniswapFallback { + IUniswapV2Pair public uniswapPair; + IUniswapV2ERC20 public uniswapPair2; + address public alice_address; + + function setUniswapAddress(address _uniswap_address) public { + uniswapPair = IUniswapV2Pair(_uniswap_address); + uniswapPair2 = IUniswapV2ERC20(_uniswap_address); + } + function setAliceAddress(address _alice_address) public { + alice_address = _alice_address; + } + // Fallback function + fallback() external { + // Implement any logic you want the contract to perform when it receives Ether + // This function will be called when the contract receives Ether and no other function matches the call data + uniswapPair.mint(alice_address); + uniswapPair.swap(0,5000,alice_address,"0x"); + uint balance = uniswapPair2.balanceOf(alice_address); + //uniswapPair2.transfer(address(uniswapPair),balance); + //uniswapPair.burn(alice_address); + } +} diff --git a/core/tests/ts-integration/package.json b/core/tests/ts-integration/package.json index 03bd84bb3f48..e6c414bbaafe 100644 --- a/core/tests/ts-integration/package.json +++ b/core/tests/ts-integration/package.json @@ -32,6 +32,9 @@ "typescript": "^4.3.5", "zksync-ethers": "^6.9.0", "elliptic": "^6.5.5", - "yaml": "^2.4.2" + "yaml": "^2.4.2", + "zksync-web3": "^0.15.5", + "csv-parser": "^3.0.0", + "csv-writer": "^1.6.0" } } diff --git a/core/tests/ts-integration/src/helpers.ts b/core/tests/ts-integration/src/helpers.ts index 8e31c1a691ff..327a4912a6c0 100644 --- a/core/tests/ts-integration/src/helpers.ts +++ b/core/tests/ts-integration/src/helpers.ts @@ -4,6 +4,8 @@ import * as ethers from 'ethers'; import * as hre from 'hardhat'; import { ZkSyncArtifact } from '@matterlabs/hardhat-zksync-solc/dist/src/types'; +const solc = require('solc'); + export const SYSTEM_CONTEXT_ADDRESS = '0x000000000000000000000000000000000000800b'; /** @@ -141,3 +143,48 @@ export function bigIntMax(...args: bigint[]) { return args.reduce((max, current) => (current > max ? current : max), args[0]); } + +/** Compiles and returns artifacts for a Solidity (EVM) contract + * + * @param contractPath The path of the contract relative to the contracts directory + * @param args Constructor arguments for the contract + * @returns The transaction data for the contract deployment + */ +export function getEVMArtifact(contractPath: string, contractName: string | undefined = undefined): any { + const compilerParams = { + language: 'Solidity', + sources: { + contract: { + content: getContractSource(contractPath) + } + }, + settings: { + outputSelection: { + '*': { + '*': ['*'] + } + } + } + } as any; + if (contractName === undefined) { + const splitPath = contractPath.split('/'); + contractName = splitPath[splitPath.length - 1]; + } + + const artifact = JSON.parse(solc.compile(JSON.stringify(compilerParams))).contracts['contract'][ + contractName.split('.')[0] + ]; + + return artifact; +} + +/** Gets the deployment transaction data for a given contract path and parameters + * + * @param initiator Wallet that should be used + * @param contractPath The path of the contract relative to the contracts directory + * @param args Constructor arguments for the contract + * @returns The transaction data for the contract deployment + */ +export function getEVMContractFactory(initiator: zksync.Wallet, artifact: any): ethers.ContractFactory { + return new ethers.ContractFactory(artifact.abi, '0x' + artifact.evm.bytecode.object, initiator); +} diff --git a/core/tests/ts-integration/tests/evm-contracts.test.ts b/core/tests/ts-integration/tests/evm-contracts.test.ts new file mode 100644 index 000000000000..57e2a61a2f0c --- /dev/null +++ b/core/tests/ts-integration/tests/evm-contracts.test.ts @@ -0,0 +1,894 @@ +/** + * Generic tests checking evm equivalence smart contract behavior. + * + * Note: if you are going to write multiple tests checking specific topic (e.g. `CREATE2` behavior or something like this), + * consider creating a separate suite. + * Let's try to keep only relatively simple and self-contained tests here. + */ + +import { TestMaster } from '../src'; +import { deployContract, getEVMArtifact, getEVMContractFactory, getTestContract } from '../src/helpers'; + +import * as ethers from 'ethers'; +import * as zksync from 'zksync-ethers'; + +import fs, { PathLike } from 'fs'; +import csv from 'csv-parser'; +import { createObjectCsvWriter } from 'csv-writer'; + +const contracts = { + tester: getTestContract('TestEVMCreate'), + erc20: getTestContract('ERC20'), + uniswapV2Pair: getTestContract('UniswapV2Pair'), + uniswapV2Factory: getTestContract('UniswapV2Factory') +}; + +const artifacts = { + counter: getEVMArtifact('../evm-contracts/CounterWithParam.sol'), + proxyCaller: getEVMArtifact('../evm-contracts/ProxyCaller.sol'), + creator: getEVMArtifact('../evm-contracts/Creator.sol'), + erc20: getEVMArtifact('../evm-contracts/ERC20.sol'), + constructorRevert: getEVMArtifact('../evm-contracts/ConstructorRevert.sol'), + uniswapV2Pair: getEVMArtifact('../contracts/uniswap-v2/UniswapV2Factory.sol', 'UniswapV2Pair.sol'), + uniswapV2Factory: getEVMArtifact('../contracts/uniswap-v2/UniswapV2Factory.sol', 'UniswapV2Factory.sol'), + opcodeTest: getEVMArtifact('../evm-contracts/OpcodeTest.sol'), + selfDestruct: getEVMArtifact('../evm-contracts/SelfDestruct.sol'), + gasCaller: getEVMArtifact('../evm-contracts/GasCaller.sol'), + counterFallback: getEVMArtifact('../evm-contracts/CounterFallback.sol'), + uniswapFallback: getEVMArtifact('../evm-contracts/UniswapFallback.sol'), + creatorFallback: getEVMArtifact('../evm-contracts/CreatorFallback.sol'), + opcodeTestFallback: getEVMArtifact('../evm-contracts/OpcodeTestFallback.sol') +}; + +const initBytecode = '0x69602a60005260206000f3600052600a6016f3'; +const runtimeBytecode = '0x602a60005260206000f3'; + +let gasLimit = '0x01ffffff'; + +const logGasCosts = false; +describe('EVM equivalence contract', () => { + let testMaster: TestMaster; + let alice: zksync.Wallet; + + // Contracts shared in several tests. + let evmCreateTester: zksync.Contract; + let deployer: zksync.Contract; + + beforeAll(async () => { + testMaster = TestMaster.getInstance(__filename); + alice = testMaster.mainAccount(); + + evmCreateTester = await deployContract(alice, contracts.tester, []); + deployer = new zksync.Contract(zksync.utils.CONTRACT_DEPLOYER_ADDRESS, zksync.utils.CONTRACT_DEPLOYER, alice); + }); + + describe('Gas consumption', () => { + test("Should compare gas against counter fallback contract's call", async () => { + const gasCallerContract = await deploygasCallerContract(alice, artifacts.gasCaller); + + const counterContract = await deploygasCallerContract(alice, artifacts.counterFallback); + + let result = (await gasCallerContract.callAndGetGas.staticCall(counterContract.address)).toString(); + + const expected_gas = '3617'; // Gas cost when run with solidity interpreter + expect(result).toEqual(expected_gas); + }); + + test("Should compare gas against creator fallback contract's call", async () => { + const gasCallerContract = await deploygasCallerContract(alice, artifacts.gasCaller); + + const creatorContract = await deploygasCallerContract(alice, artifacts.creatorFallback); + + let result = (await gasCallerContract.callStatic.callAndGetGas(creatorContract.address)).toString(); + + const expected_gas = '70601'; // Gas cost when run with solidity interpreter + expect(result).toEqual(expected_gas); + }); + + xtest("Should compare gas against opcode test fallback contract's call", async () => { + const gasCallerContract = await deploygasCallerContract(alice, artifacts.gasCaller); + + const counterContract = await deploygasCallerContract(alice, artifacts.opcodeTestFallback); + + let result = (await gasCallerContract.callStatic.callAndGetGas(counterContract.address)).toString(); + + const expected_gas = '34763'; // Gas cost when run with solidity interpreter + expect(result).toEqual(expected_gas); + }); + }); + + describe('Contract creation', () => { + describe('Create from EOA', () => { + test('Should create evm contract from EOA and allow view and non-view calls', async () => { + const args = [1]; + const factory = getEVMContractFactory(alice, artifacts.counter); + const contract = await factory.deploy(args); + await contract.deployTransaction.wait(); + const receipt = await alice.provider.getTransactionReceipt(contract.deployTransaction.hash); + + await assertCreatedCorrectly( + deployer, + contract.address, + '0x' + artifacts.counter.evm.deployedBytecode.object, + receipt.logs + ); + + expect((await contract.callStatic.get()).toString()).toEqual('1'); + await (await contract.increment(1)).wait(); + expect((await contract.callStatic.get()).toString()).toEqual('2'); + }); + + test('Should create2 evm contract from ZKEVM contract', async () => { + const salt = ethers.utils.randomBytes(32); + + const expectedAddress = ethers.utils.getCreate2Address( + evmCreateTester.address, + salt, + ethers.utils.keccak256(initBytecode) + ); + + const receipt = await (await evmCreateTester.create2(salt, initBytecode)).wait(); + + await assertCreatedCorrectly(deployer, expectedAddress, runtimeBytecode, receipt.logs); + + try { + await (await evmCreateTester.create2(salt, initBytecode, { gasLimit })).wait(); + } catch (e) { + // Should fail + return; + } + throw 'Should fail to create2 the same contract with same salt twice'; + }); + + test('Should propegate revert in constructor', async () => { + const factory = getEVMContractFactory(alice, artifacts.constructorRevert); + const contract = await factory.deploy({ gasLimit }); + + let failReason; + + try { + await contract.deployTransaction.wait(); + } catch (e: any) { + failReason = e.reason; + } + + expect(failReason).toBe('transaction failed'); + }); + + test('Should NOT create evm contract from EOA when `to` is address(0x0)', async () => { + const args = [1]; + + const factory = getEVMContractFactory(alice, artifacts.counter); + const transaction = await factory.getDeployTransaction(args); + transaction.to = '0x0000000000000000000000000000000000000000'; + + const result = await (await alice.sendTransaction(transaction)).wait(); + const expectedAddressCreate = ethers.utils.getContractAddress({ + from: alice.address, + nonce: await alice.getNonce() + }); + + await assertContractNotCreated(deployer, expectedAddressCreate); + }); + + // test('Should SENDALL', async () => { + // const salt = ethers.utils.randomBytes(32); + // const selfDestructBytecode = '0x' + artifacts.selfDestruct.evm.bytecode.object; + // const hash = ethers.utils.keccak256(selfDestructBytecode); + + // const selfDestructFactory = getEVMContractFactory(alice, artifacts.selfDestruct); + // const selfDestructAddress = ethers.utils.getCreate2Address(evmCreateTester.address, salt, hash); + // const selfDestruct = selfDestructFactory.attach(selfDestructAddress); + // const beneficiary = testMaster.newEmptyAccount(); + + // await (await evmCreateTester.create2(salt, selfDestructBytecode, { value: 1000 })).wait(); + // expect((await alice.provider.getBalance(selfDestructAddress)).toNumber()).toBe(1000); + + // await (await selfDestruct.destroy(beneficiary.address)).wait(); + // expect((await alice.provider.getBalance(beneficiary.address)).toNumber()).toBe(1000); + + // let failReason; + + // try { + // await (await evmCreateTester.create2(salt, selfDestructBytecode)).wait(); + // } catch (e: any) { + // failReason = e.error.reason; + // } + + // expect(failReason).toBe("execution reverted: Can't create on existing contract address"); + // }); + }); + }); + + describe('Inter-contract calls', () => { + test('Calls (read/write) between EVM contracts should work correctly', async () => { + const args = [1]; + + const counterFactory = getEVMContractFactory(alice, artifacts.counter); + const counterContract = await counterFactory.deploy(args); + await counterContract.deployTransaction.wait(); + await alice.provider.getTransactionReceipt(counterContract.deployTransaction.hash); + + const proxyCallerFactory = getEVMContractFactory(alice, artifacts.proxyCaller); + const proxyCallerContract = await proxyCallerFactory.deploy(); + await proxyCallerContract.deployTransaction.wait(); + await alice.provider.getTransactionReceipt(proxyCallerContract.deployTransaction.hash); + + expect((await proxyCallerContract.proxyGet(counterContract.address)).toString()).toEqual('1'); + + await (await proxyCallerContract.executeIncrememt(counterContract.address, 1)).wait(); + + expect((await proxyCallerContract.proxyGet(counterContract.address)).toString()).toEqual('2'); + + expect((await proxyCallerContract.callStatic.proxyGetBytes(counterContract.address)).toString()).toEqual( + '0x54657374696e67' + ); + }); + + test('Create opcode works correctly', async () => { + const creatorFactory = getEVMContractFactory(alice, artifacts.creator); + const creatorContract = await creatorFactory.deploy(); + await creatorContract.deployTransaction.wait(); + + dumpOpcodeLogs(creatorContract.deployTransaction.hash, alice.provider); + + const nonce = 1; + + const runtimeBytecode = await creatorContract.getCreationRuntimeCode(); + + const expectedAddress = ethers.utils.getContractAddress({ + from: creatorContract.address, + nonce + }); + + const result = await (await creatorContract.create()).wait(); + dumpOpcodeLogs(result.transactionHash, alice.provider); + + await assertCreatedCorrectly(deployer, expectedAddress, runtimeBytecode, result.logs); + }); + + test('Should revert correctly', async () => { + const args = [1]; + + const counterFactory = getEVMContractFactory(alice, artifacts.counter); + const counterContract = await counterFactory.deploy(args); + await counterContract.deployTransaction.wait(); + + dumpOpcodeLogs(counterContract.deployTransaction.hash, alice.provider); + + let errorString; + + try { + await counterContract.callStatic.incrementWithRevert(1, true); + } catch (e: any) { + errorString = e.reason; + } + expect(errorString).toEqual('This method always reverts'); + }); + }); + + // NOTE: Gas cost comparisons should be done on a *fresh* chain that doesn't have e.g. bytecodes already published + describe('ERC20', () => { + let evmToken: ethers.Contract; + let nativeToken: zksync.Contract; + let userAccount: zksync.Wallet; + let deployLogged: boolean = false; + + beforeEach(async () => { + const erc20Factory = getEVMContractFactory(alice, artifacts.erc20); + evmToken = await erc20Factory.deploy(); + await evmToken.deployTransaction.wait(); + nativeToken = await deployContract(alice, contracts.erc20, []); + + dumpOpcodeLogs(evmToken.deployTransaction.hash, alice.provider); + userAccount = testMaster.newEmptyAccount(); + // Only log the first deployment + if (logGasCosts && !deployLogged) { + console.log( + 'ERC20 native deploy gas: ' + + (await alice.provider.getTransactionReceipt(nativeToken.deployTransaction.hash)).gasUsed + ); + console.log( + 'ERC20 evm deploy gas: ' + + (await alice.provider.getTransactionReceipt(evmToken.deployTransaction.hash)).gasUsed + ); + deployLogged = true; + } + await ( + await alice.sendTransaction({ + to: userAccount.address, + value: ethers.BigNumber.from('0xffffffffffffff') + }) + ).wait(); + }); + + test('view functions should work', async () => { + const evmBalanceOfCost = await evmToken.estimateGas.balanceOf(alice.address); + const nativeBalanceOfCost = await nativeToken.estimateGas.balanceOf(alice.address); + if (logGasCosts) { + console.log('ERC20 native balanceOf gas: ' + nativeBalanceOfCost.toString()); + console.log('ERC20 evm balanceOf gas: ' + evmBalanceOfCost.toString()); + } + expect((await evmToken.balanceOf(alice.address)).toString()).toEqual('1000000'); + expect((await evmToken.totalSupply()).toString()).toEqual('1000000'); + expect((await evmToken.balanceOf(userAccount.address)).toString()).toEqual('0'); + }); + + test('transfer should work', async () => { + expect((await evmToken.balanceOf(alice.address)).toString()).toEqual('1000000'); + const evmTransferTx = await (await evmToken.transfer(userAccount.address, 100000)).wait(); + const nativeTransferTx = await (await nativeToken.transfer(userAccount.address, 100000)).wait(); + if (logGasCosts) { + console.log('ERC20 native transfer gas: ' + nativeTransferTx.gasUsed.toString()); + console.log('ERC20 evm transfer gas: ' + evmTransferTx.gasUsed.toString()); + } + dumpOpcodeLogs(evmTransferTx.transactionHash, alice.provider); + + expect((await evmToken.balanceOf(alice.address)).toString()).toEqual('900000'); + expect((await evmToken.balanceOf(userAccount.address)).toString()).toEqual('100000'); + }); + + test('approve & transferFrom should work', async () => { + expect((await evmToken.balanceOf(alice.address)).toString()).toEqual('1000000'); + const evmApproveTx = await (await evmToken.connect(alice).approve(userAccount.address, 100000)).wait(); + const nativeApproveTx = await ( + await nativeToken.connect(alice).approve(userAccount.address, 100000) + ).wait(); + if (logGasCosts) { + console.log('ERC20 native approve gas: ' + nativeApproveTx.gasUsed.toString()); + console.log('ERC20 evm approve gas: ' + evmApproveTx.gasUsed.toString()); + } + dumpOpcodeLogs(evmApproveTx.transactionHash, alice.provider); + + const evmTransferFromTx = await ( + await evmToken.connect(userAccount).transferFrom(alice.address, userAccount.address, 100000) + ).wait(); + const nativeTransferFromTx = await ( + await nativeToken.connect(userAccount).transferFrom(alice.address, userAccount.address, 100000) + ).wait(); + if (logGasCosts) { + console.log('ERC20 native transferFrom gas: ' + nativeTransferFromTx.gasUsed.toString()); + console.log('ERC20 evm transferFrom gas: ' + evmTransferFromTx.gasUsed.toString()); + } + dumpOpcodeLogs(evmTransferFromTx.transactionHash, alice.provider); + + expect((await evmToken.balanceOf(alice.address)).toString()).toEqual('900000'); + expect((await evmToken.balanceOf(userAccount.address)).toString()).toEqual('100000'); + }); + }); + + // NOTE: Gas cost comparisons should be done on a *fresh* chain that doesn't have e.g. bytecodes already published + describe('Uniswap-v2', () => { + let evmToken1: ethers.Contract; + let evmToken2: ethers.Contract; + let evmUniswapFactory: ethers.Contract; + let nativeUniswapFactory: ethers.Contract; + let evmUniswapPair: ethers.Contract; + let nativeUniswapPair: ethers.Contract; + + let deployLogged: boolean = false; + const NEW_PAIR_TOPIC = '0x0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9'; + + beforeEach(async () => { + const erc20Factory = getEVMContractFactory(alice, artifacts.erc20); + evmToken1 = await erc20Factory.deploy({ gasLimit }); + await evmToken1.deployTransaction.wait(); + evmToken2 = await erc20Factory.deploy(); + await evmToken2.deployTransaction.wait(); + + const evmUniswapFactoryFactory = getEVMContractFactory(alice, artifacts.uniswapV2Factory); + evmUniswapFactory = await evmUniswapFactoryFactory.deploy('0x0000000000000000000000000000000000000000'); + await evmUniswapFactory.deployTransaction.wait(); + + nativeUniswapFactory = await deployContract( + alice, + contracts.uniswapV2Factory, + ['0x0000000000000000000000000000000000000000'], + undefined, + { + customData: { + factoryDeps: [contracts.uniswapV2Pair.bytecode] + } + } + ); + + const evmPairReceipt = await ( + await evmUniswapFactory.createPair(evmToken1.address, evmToken2.address) + ).wait(); + + const nativePairReceipt = await ( + await nativeUniswapFactory.createPair(evmToken1.address, evmToken2.address) + ).wait(); + dumpOpcodeLogs(evmUniswapFactory.deployTransaction.hash, alice.provider); + dumpOpcodeLogs(evmPairReceipt.transactionHash, alice.provider); + + const evmUniswapPairFactory = getEVMContractFactory(alice, artifacts.uniswapV2Pair); + const nativeUniswapPairFactory = new zksync.ContractFactory( + contracts.uniswapV2Pair.abi, + contracts.uniswapV2Pair.bytecode, + alice + ); + evmUniswapPair = evmUniswapPairFactory.attach( + ethers.utils.defaultAbiCoder.decode( + ['address', 'uint256'], + evmPairReceipt.logs.find((log: any) => log.topics[0] === NEW_PAIR_TOPIC).data + )[0] + ); + nativeUniswapPair = nativeUniswapPairFactory.attach( + ethers.utils.defaultAbiCoder.decode( + ['address', 'uint256'], + nativePairReceipt.logs.find((log: any) => log.topics[0] === NEW_PAIR_TOPIC).data + )[0] + ); + const token1IsFirst = (await evmUniswapPair.token0()).toString() === evmToken1.address; + if (!token1IsFirst) { + [evmToken1, evmToken2] = [evmToken2, evmToken1]; + } + await (await evmToken1.transfer(evmUniswapPair.address, 100000)).wait(); + await (await evmToken1.transfer(nativeUniswapPair.address, 100000)).wait(); + await (await evmToken2.transfer(evmUniswapPair.address, 100000)).wait(); + await (await evmToken2.transfer(nativeUniswapPair.address, 100000)).wait(); + + // Only log the first deployment + if (logGasCosts && !deployLogged) { + console.log( + 'Uniswap Factory native deploy gas: ' + + (await alice.provider.getTransactionReceipt(nativeUniswapFactory.deployTransaction.hash)) + .gasUsed + ); + console.log( + 'Uniswap Factory evm deploy gas: ' + + (await alice.provider.getTransactionReceipt(evmUniswapFactory.deployTransaction.hash)).gasUsed + ); + console.log('Uniswap Pair native create gas: ' + nativePairReceipt.gasUsed); + console.log('Uniswap Pair evm create gas: ' + evmPairReceipt.gasUsed); + deployLogged = true; + } + }); + + test('mint, swap, and burn should work', async () => { + const evmMintReceipt = await (await evmUniswapPair.mint(alice.address)).wait(); + const nativeMintReceipt = await (await nativeUniswapPair.mint(alice.address)).wait(); + dumpOpcodeLogs(evmMintReceipt.transactionHash, alice.provider); + + await (await evmToken1.transfer(evmUniswapPair.address, 10000)).wait(); + await (await evmToken1.transfer(nativeUniswapPair.address, 10000)).wait(); + const evmSwapReceipt = await (await evmUniswapPair.swap(0, 5000, alice.address, '0x')).wait(); + const nativeSwapReceipt = await (await nativeUniswapPair.swap(0, 5000, alice.address, '0x')).wait(); + dumpOpcodeLogs(evmSwapReceipt.transactionHash, alice.provider); + + const evmLiquidityTransfer = await ( + await evmUniswapPair.transfer( + evmUniswapPair.address, + (await evmUniswapPair.balanceOf(alice.address)).toString() + ) + ).wait(); + await ( + await nativeUniswapPair.transfer( + nativeUniswapPair.address, + (await nativeUniswapPair.balanceOf(alice.address)).toString() + ) + ).wait(); + const evmBurnReceipt = await (await evmUniswapPair.burn(alice.address)).wait(); + const nativeBurnReceipt = await (await nativeUniswapPair.burn(alice.address)).wait(); + expect(Number((await evmToken1.balanceOf(alice.address)).toString())).toBeGreaterThanOrEqual(990000); + expect(Number((await evmToken2.balanceOf(alice.address)).toString())).toBeGreaterThanOrEqual(990000); + + if (logGasCosts) { + console.log('UniswapV2Pair native mint gas: ' + nativeMintReceipt.gasUsed); + console.log('UniswapV2Pair evm mint gas: ' + evmMintReceipt.gasUsed); + console.log('UniswapV2Pair native swap gas: ' + nativeSwapReceipt.gasUsed); + console.log('UniswapV2Pair evm swap gas: ' + evmSwapReceipt.gasUsed); + console.log('UniswapV2Pair native burn gas: ' + nativeBurnReceipt.gasUsed); + console.log('UniswapV2Pair evm burn gas: ' + evmBurnReceipt.gasUsed); + } + dumpOpcodeLogs(evmLiquidityTransfer.transactionHash, alice.provider); + dumpOpcodeLogs(evmBurnReceipt.transactionHash, alice.provider); + }); + + test("Should compare gas against uniswap fallback contract's call", async () => { + const gasCallerFactory = getEVMContractFactory(alice, artifacts.gasCaller); + const gasCallerContract = await gasCallerFactory.deploy(); + await gasCallerContract.deployTransaction.wait(); + await alice.provider.getTransactionReceipt(gasCallerContract.deployTransaction.hash); + + const uniswapContract = await deploygasCallerContract(alice, artifacts.uniswapFallback); + await (await uniswapContract.setUniswapAddress(evmUniswapPair.address)).wait(); + await (await uniswapContract.setAliceAddress(alice.address)).wait(); + + await (await evmToken1.transfer(evmUniswapPair.address, 10000)).wait(); + await (await evmToken1.transfer(uniswapContract.address, 10000)).wait(); + + let result = (await gasCallerContract.callStatic.callAndGetGas(uniswapContract.address)).toString(); + + const expected_gas = '165939'; // Gas cost when run with solidity interpreter + expect(result).toEqual(expected_gas); + }); + }); + + // NOTE: Gas cost comparisons should be done on a *fresh* chain that doesn't have e.g. bytecodes already published + // describe('Bulk opcode tests', () => { + // let opcodeTest: ethers.Contract; + // beforeEach(async () => { + // const opcodeTestFactory = getEVMContractFactory(alice, artifacts.opcodeTest); + // console.log(opcodeTestFactory.bytecode) + // opcodeTest = await opcodeTestFactory.deploy() + // }); + + // test('should successfully execute bulk opcode test', async () => { + // console.log(await deployer.evmCode(opcodeTest.address)) + // // const receipt = await (await opcodeTest.execute()).wait() + // // dumpOpcodeLogs(receipt.transactionHash, alice.provider); + // }); + // }); + + afterAll(async () => { + await testMaster.deinitialize(); + if (logGasCosts) { + printCostData(); + } + }); +}); + +type BenchmarkResult = { + name: string; + used_zkevm_ergs: string; + used_evm_gas: string; + used_circuits: string; +}; + +async function saveBenchmark(name: string, filename: string, result: string) { + try { + const resultWithName = { + name: name, + used_zkevm_ergs: result, + used_evm_gas: '0', + used_circuits: '0' + }; + + let results: BenchmarkResult[] = []; + + // Read existing CSV file + if (fs.existsSync(filename)) { + const existingResults: BenchmarkResult[] = await new Promise((resolve, reject) => { + const results: BenchmarkResult[] = []; + fs.createReadStream(filename) + .pipe(csv()) + .on('data', (data) => results.push(data)) + .on('end', () => resolve(results)) + .on('error', reject); + }); + results = existingResults.map((result) => ({ + name: result.name, + used_zkevm_ergs: result.used_zkevm_ergs, + used_evm_gas: result.used_evm_gas, + used_circuits: result.used_circuits + })); + } + + // Push the new result + results.push(resultWithName); + + // Write results back to CSV + const csvWriter = createObjectCsvWriter({ + path: filename, + header: [ + { id: 'name', title: 'name' }, + { id: 'used_zkevm_ergs', title: 'used_zkevm_ergs' }, + { id: 'used_evm_gas', title: 'used_evm_gas' }, + { id: 'used_circuits', title: 'used_circuits' } + ] + }); + await csvWriter.writeRecords(results); + + console.log('Benchmark saved successfully.'); + } catch (error) { + console.error('Error saving benchmark:', error); + } +} +function zeroPad(num: number, places: number): string { + return String(num).padStart(places, '0'); +} + +async function startBenchmark(): Promise { + try { + const now = new Date(); + const year = now.getUTCFullYear(); + const month = zeroPad(now.getUTCMonth() + 1, 2); // Months are zero-based, so add 1 + const day = zeroPad(now.getUTCDate(), 2); + const hour = zeroPad(now.getUTCHours(), 2); + const minute = zeroPad(now.getUTCMinutes(), 2); + const second = zeroPad(now.getUTCSeconds(), 2); + const formattedTime = `${year}-${month}-${day}-${hour}-${minute}-${second}`; + const directoryPath = 'benchmarks'; + + if (!fs.existsSync(directoryPath)) { + // If it doesn't exist, create it + fs.mkdirSync(directoryPath); + } + + const filename = `benchmarks/benchmark_integration_${formattedTime}.csv`; + return filename; + } catch (error) { + console.error('Error creating benchmark:', error); + return ''; + } +} + +async function deploygasCallerContract(alice: zksync.Wallet, contract: any, ...args: Array) { + const counterFactory = getEVMContractFactory(alice, contract); + const counterContract = await counterFactory.deploy(...args); + await counterContract.waitForDeployment(); + await counterContract.deploymentTransaction()?.wait(); + let hash = counterContract.deploymentTransaction()?.hash; + if (hash == undefined) { + throw new Error('Deployment transaction has failed'); + } + await alice.provider.getTransactionReceipt(hash); + + return counterContract; +} + +async function assertStoredBytecodeHash( + deployer: zksync.Contract, + deployedAddress: string, + expectedStoredHash: string +): Promise { + const ACCOUNT_CODE_STORAGE_ADDRESS = '0x0000000000000000000000000000000000008002'; + const storedCodeHash = await deployer.provider.getStorageAt( + ACCOUNT_CODE_STORAGE_ADDRESS, + ethers.utils.hexZeroPad(deployedAddress, 32) + ); + + expect(storedCodeHash).toEqual(expectedStoredHash); +} + +async function assertCreatedCorrectly( + deployer: zksync.Contract, + deployedAddress: string, + expectedEVMBytecode: string, + logs: Array +): Promise { + const expectedStoredHash = getSha256BlobHash(expectedEVMBytecode); + await assertStoredBytecodeHash(deployer, deployedAddress, expectedStoredHash); +} + +function getPaddedBytecode(bytes: ethers.BytesLike) { + const length = ethers.utils.arrayify(bytes).length; + + const encodedLength = ethers.utils.defaultAbiCoder.encode(['uint256'], [length]); + + let paddedBytecode = encodedLength + ethers.utils.hexlify(bytes).slice(2); + + // The length needs to be 32 mod 64. We use 64 mod 128, since + // we are dealing with a hexlified string + while ((paddedBytecode.length - 2) % 128 != 64) { + paddedBytecode += '0'; + } + + return paddedBytecode; +} + +// Returns the canonical code hash of +function getSha256BlobHash(bytes: ethers.BytesLike): string { + const paddedBytes = getPaddedBytecode(bytes); + + const hash = ethers.utils.arrayify(ethers.utils.sha256(paddedBytes)); + hash[0] = 2; + hash[1] = 0; + + // Length of the bytecode + const lengthInBytes = ethers.utils.arrayify(paddedBytes).length; + hash[2] = Math.floor(lengthInBytes / 256); + hash[3] = lengthInBytes % 256; + + return ethers.utils.hexlify(hash); +} + +async function assertContractNotCreated(deployer: zksync.Contract, deployedAddress: string): Promise { + assertStoredBytecodeHash(deployer, deployedAddress, ethers.constants.HashZero); +} + +function printCostData() { + let costsDataString = ''; + + const averageOverhead = + overheadDataDump.length === 0 + ? undefined + : Math.floor(overheadDataDump.reduce((a: number, c: number) => a + c) / overheadDataDump.length); + const minOverhead = overheadDataDump.length === 0 ? undefined : Math.min(...overheadDataDump); + const maxOverhead = overheadDataDump.length === 0 ? undefined : Math.max(...overheadDataDump); + + costsDataString += 'Overhead\t' + averageOverhead + '\t' + minOverhead + '\t' + maxOverhead + '\n'; + + Object.keys(opcodeDataDump).forEach((opcode) => { + const opcodeString = '0x' + Number(opcode).toString(16).padStart(2, '0'); + const values = opcodeDataDump[opcode.toString()]; + if (values.length === 0) { + costsDataString += opcodeString + '\n'; + return; + } + const average = Math.floor(values.reduce((a: number, c: number) => a + c) / values.length); + const min = Math.min(...values); + const max = Math.max(...values); + + costsDataString += + opcodeString + + '\t' + + average + + '\t' + + (min === average ? '' : min) + + '\t' + + (max === average ? '' : max) + + '\n'; + }); + console.log(costsDataString); +} + +const overheadDataDump: Array = []; +const opcodeDataDump: any = {}; +[ + '0x0', + '0x1', + '0x2', + '0x3', + '0x4', + '0x5', + '0x6', + '0x7', + '0x8', + '0x9', + '0x0A', + '0x0B', + '0x10', + '0x11', + '0x12', + '0x13', + '0x14', + '0x15', + '0x16', + '0x17', + '0x18', + '0x19', + '0x1A', + '0x1B', + '0x1C', + '0x1D', + '0x20', + '0x30', + '0x31', + '0x32', + '0x33', + '0x34', + '0x35', + '0x36', + '0x37', + '0x38', + '0x39', + '0x3A', + '0x3B', + '0x3C', + '0x3D', + '0x3E', + '0x3F', + '0x40', + '0x41', + '0x42', + '0x43', + '0x44', + '0x45', + '0x46', + '0x47', + '0x48', + '0x50', + '0x51', + '0x52', + '0x53', + '0x54', + '0x55', + '0x56', + '0x57', + '0x58', + '0x59', + '0x5A', + '0x5B', + '0x5F', + '0x60', + '0x61', + '0x62', + '0x63', + '0x64', + '0x65', + '0x66', + '0x67', + '0x68', + '0x69', + '0x6A', + '0x6B', + '0x6C', + '0x6D', + '0x6E', + '0x6F', + '0x70', + '0x71', + '0x72', + '0x73', + '0x74', + '0x75', + '0x76', + '0x77', + '0x78', + '0x79', + '0x7A', + '0x7B', + '0x7C', + '0x7D', + '0x7E', + '0x7F', + '0x80', + '0x81', + '0x82', + '0x83', + '0x84', + '0x85', + '0x86', + '0x87', + '0x88', + '0x89', + '0x8A', + '0x8B', + '0x8C', + '0x8D', + '0x8E', + '0x8F', + '0x90', + '0x91', + '0x92', + '0x93', + '0x94', + '0x95', + '0x96', + '0x97', + '0x98', + '0x99', + '0x9A', + '0x9B', + '0x9C', + '0x9D', + '0x9E', + '0x9F', + '0xA0', + '0xA1', + '0xA2', + '0xA3', + '0xA4', + '0xF0', + '0xF1', + '0xF2', + '0xF3', + '0xF4', + '0xF5', + '0xFA', + '0xFD', + '0xFE', + '0xFF' +].forEach((key) => { + opcodeDataDump[Number(key).toString()] = []; +}); + +async function dumpOpcodeLogs(hash: string, provider: zksync.Provider): Promise { + const logs = (await provider.getTransactionReceipt(hash)).logs; + logs.forEach((log) => { + if (log.topics[0] === '0x63307236653da06aaa7e128a306b128c594b4cf3b938ef212975ed10dad17515') { + //Overhead + overheadDataDump.push(Number(ethers.utils.defaultAbiCoder.decode(['uint256'], log.data).toString())); + } else if (log.topics[0] === '0xca5a69edf1b934943a56c00605317596b03e2f61c3f633e8657b150f102a3dfa') { + // Opcode + const parsed = ethers.utils.defaultAbiCoder.decode(['uint256', 'uint256'], log.data); + const opcode = Number(parsed[0].toString()); + const cost = Number(parsed[1].toString()); + + opcodeDataDump[opcode.toString()].push(cost); + } + }); +} diff --git a/yarn.lock b/yarn.lock index 173a06e631f6..be6687ce6ed8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1689,12 +1689,22 @@ resolved "https://registry.yarnpkg.com/@matterlabs/eslint-config-typescript/-/eslint-config-typescript-1.1.2.tgz#a9be4e56aedf298800f247c5049fc412f8b301a7" integrity sha512-AhiWJQr+MSE3RVfgp5XwGoMK7kNSKh6a18+T7hkNJtyycP0306I6IGmuFA5ZVbcakGb+K32fQWzepSkrNCTAGg== -"@matterlabs/hardhat-zksync-chai-matchers@^0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-chai-matchers/-/hardhat-zksync-chai-matchers-0.1.4.tgz#105cb0ec1367c8fcd3ce7e3773f747c71fff675b" - integrity sha512-eGQWiImg51fmayoQ7smIK/T6QZkSu38PK7xjp1RIrewGzw2ZgqFWGp40jb5oomkf8yOQPk52Hu4TwE3Ntp8CtA== +"@matterlabs/hardhat-zksync-chai-matchers@^0.2.0": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-chai-matchers/-/hardhat-zksync-chai-matchers-0.2.1.tgz#d05136d6cf9a53c30f5e7ee9bae95abb72c1000d" + integrity sha512-LXm5r53DLTQC/KXRXzSRmVp5mEJ4tsoKAKyGck2YLHQ9CBdPoC0paVjbyB2MaEuK/k8o4lZu4uaYKgWQNUXeyQ== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@matterlabs/hardhat-zksync-deploy" "^0.7.0" + "@matterlabs/hardhat-zksync-solc" "1.0.6" + chai "^4.3.7" + chai-as-promised "^7.1.1" + ethers "~5.7.2" + hardhat "^2.14.0" + ordinal "1.0.3" + zksync-ethers "^5.0.0" -"@matterlabs/hardhat-zksync-deploy@^0.6.1", "@matterlabs/hardhat-zksync-deploy@^0.6.5": +"@matterlabs/hardhat-zksync-deploy@^0.6.1": version "0.6.6" resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-deploy/-/hardhat-zksync-deploy-0.6.6.tgz#5c86cf7da859844167d62300528c3e6013ee0286" integrity sha512-QpkxK2wnyQCgaTVLdFATpfiySfr7073yPre9eq5LfKA8VxXWD4WZAuBMq700GL5UyfW9yyHkCdkSzaGigmZ4/Q== @@ -1703,6 +1713,15 @@ chalk "4.1.2" ts-morph "^19.0.0" +"@matterlabs/hardhat-zksync-deploy@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-deploy/-/hardhat-zksync-deploy-0.7.0.tgz#e56b73d8f8fbd0f809a779d0028418ea7d914017" + integrity sha512-PGZcuhKsVzZ2IWPt931pK2gA+HDxnCtye+7CwvoOnM6diHeO9tB1QHFX/ywR9ErOW9wpezhPYkVDx9myFrdoqQ== + dependencies: + "@matterlabs/hardhat-zksync-solc" "^1.0.5" + chalk "4.1.2" + ts-morph "^19.0.0" + "@matterlabs/hardhat-zksync-deploy@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-deploy/-/hardhat-zksync-deploy-1.3.0.tgz#5c2b723318ddf6c4d3929ec225401864ff54557a" @@ -1728,25 +1747,26 @@ chalk "4.1.2" fs-extra "^11.1.1" -"@matterlabs/hardhat-zksync-solc@0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-0.4.1.tgz#e8e67d947098d7bb8925f968544d34e522af5a9c" - integrity sha512-fdlGf/2yZR5ihVNc2ubea1R/nNFXRONL29Fgz5FwB3azB13rPb76fkQgcFIg9zSufHsEy6zUUT029NkxLNA9Sw== +"@matterlabs/hardhat-zksync-solc@0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-0.4.2.tgz#64121082e88c5ab22eb4e9594d120e504f6af499" + integrity sha512-6NFWPSZiOAoo7wNuhMg4ztj7mMEH+tLrx09WuCbcURrHPijj/KxYNsJD6Uw5lapKr7G8H7SQISGid1/MTXVmXQ== dependencies: "@nomiclabs/hardhat-docker" "^2.0.0" chalk "4.1.2" dockerode "^3.3.4" fs-extra "^11.1.1" + proper-lockfile "^4.1.2" semver "^7.5.1" -"@matterlabs/hardhat-zksync-solc@0.4.2": - version "0.4.2" - resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-0.4.2.tgz#64121082e88c5ab22eb4e9594d120e504f6af499" - integrity sha512-6NFWPSZiOAoo7wNuhMg4ztj7mMEH+tLrx09WuCbcURrHPijj/KxYNsJD6Uw5lapKr7G8H7SQISGid1/MTXVmXQ== +"@matterlabs/hardhat-zksync-solc@1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-1.0.6.tgz#7ef8438e6bb15244691600e2afa77aaff7dff9f0" + integrity sha512-0icYSufXba/Bbb7v2iXuZJ+IbYsiNpR4Wy6UizHnGuFw3OMHgh+saebQphuaN9yyRL2UPGZbPkQFHWBLZj5/xQ== dependencies: "@nomiclabs/hardhat-docker" "^2.0.0" chalk "4.1.2" - dockerode "^3.3.4" + dockerode "^4.0.0" fs-extra "^11.1.1" proper-lockfile "^4.1.2" semver "^7.5.1" @@ -1794,16 +1814,17 @@ sinon-chai "^3.7.0" undici "^6.18.2" -"@matterlabs/hardhat-zksync-verify@^0.2.0": - version "0.2.2" - resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-verify/-/hardhat-zksync-verify-0.2.2.tgz#daa34bc4404096ed0f44461ee366c1cb0e5a4f2f" - integrity sha512-WgcItoZGY702oJ708uCP5uLvmwzDLBfhMqq2D0Kh1U/3fCTlPza9zMGUFHxKMQYsITKTeQ5zKOjKoi8MXOeUdQ== +"@matterlabs/hardhat-zksync-verify@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-verify/-/hardhat-zksync-verify-0.4.0.tgz#f812c19950022fc36728f3796f6bdae5633e2fcd" + integrity sha512-GPZmAumFl3ZMPKbECX7Qw8CriwZKWd1DlCRhoG/6YYc6mFy4+MXkF1XsHLMs5r34N+GDOfbVZVMeftIlJC96Kg== dependencies: - "@matterlabs/hardhat-zksync-solc" "0.4.1" + "@matterlabs/hardhat-zksync-solc" "^1.0.5" "@nomicfoundation/hardhat-verify" "^1.0.2" axios "^1.4.0" chalk "4.1.2" dockerode "^3.3.4" + zksync-ethers "^5.0.0" "@matterlabs/hardhat-zksync-verify@^1.4.3": version "1.5.0" @@ -1925,6 +1946,11 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.4.0.tgz#bbb43f0e01f40839b0bd38c2c443cb6910ae955f" integrity sha512-7+rraFk9tCqvfemv9Ita5vTlSBAeO/S5aDKOgGRgYt0JEKZlrX161nDW6UfzMPxWl9GOLEDUzCEaYuNmXseUlg== +"@nomicfoundation/edr-darwin-arm64@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.5.2.tgz#72f7a826c9f0f2c91308edca562de3b9484ac079" + integrity sha512-Gm4wOPKhbDjGTIRyFA2QUAPfCXA1AHxYOKt3yLSGJkQkdy9a5WW+qtqKeEKHc/+4wpJSLtsGQfpzyIzggFfo/A== + "@nomicfoundation/edr-darwin-x64@0.3.4": version "0.3.4" resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.4.tgz#cbcc0a2dcda0a7c0a900a74efc6918cff134dc23" @@ -1935,6 +1961,11 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.4.0.tgz#b1ffcd9142418fd8498de34a7336b3f977907c86" integrity sha512-+Hrc0mP9L6vhICJSfyGo/2taOToy1AIzVZawO3lU8Lf7oDQXfhQ4UkZnkWAs9SVu1eUwHUGGGE0qB8644piYgg== +"@nomicfoundation/edr-darwin-x64@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.5.2.tgz#6d0fedb219d664631c6feddc596ab8c3bbc36fa8" + integrity sha512-ClyABq2dFCsrYEED3/UIO0c7p4H1/4vvlswFlqUyBpOkJccr75qIYvahOSJRM62WgUFRhbSS0OJXFRwc/PwmVg== + "@nomicfoundation/edr-linux-arm64-gnu@0.3.4": version "0.3.4" resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.4.tgz#12073f97d310176bb24ad7d48c25128ea8eff093" @@ -1945,6 +1976,11 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.4.0.tgz#8173d16d4f6f2b3e82ba7096d2a1ea3619d8bfa7" integrity sha512-4HUDMchNClQrVRfVTqBeSX92hM/3khCgpZkXP52qrnJPqgbdCxosOehlQYZ65wu0b/kaaZSyvACgvCLSQ5oSzQ== +"@nomicfoundation/edr-linux-arm64-gnu@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.5.2.tgz#60e4d52d963141bc2bb4a02639dc590a7fbdda2f" + integrity sha512-HWMTVk1iOabfvU2RvrKLDgtFjJZTC42CpHiw2h6rfpsgRqMahvIlx2jdjWYzFNy1jZKPTN1AStQ/91MRrg5KnA== + "@nomicfoundation/edr-linux-arm64-musl@0.3.4": version "0.3.4" resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.4.tgz#c9bc685d4d14bf21d9c3e326edd44e009e24492d" @@ -1955,6 +1991,11 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.4.0.tgz#b1ce293a7c3e0d9f70391e1aef1a82b83b997567" integrity sha512-D4J935ZRL8xfnP3zIFlCI9jXInJ0loDUkCTLeCEbOf2uuDumWDghKNQlF1itUS+EHaR1pFVBbuwqq8hVK0dASg== +"@nomicfoundation/edr-linux-arm64-musl@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.5.2.tgz#6676a09eab57c435a16ffc144658c896acca9baa" + integrity sha512-CwsQ10xFx/QAD5y3/g5alm9+jFVuhc7uYMhrZAu9UVF+KtVjeCvafj0PaVsZ8qyijjqVuVsJ8hD1x5ob7SMcGg== + "@nomicfoundation/edr-linux-x64-gnu@0.3.4": version "0.3.4" resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.4.tgz#37486cbe317b8caf7961e500fc0150c45c895a56" @@ -1965,6 +2006,11 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.4.0.tgz#4c12c4e4bfd3d837f5663ad7cbf7cb6d5634ef83" integrity sha512-6x7HPy+uN5Cb9N77e2XMmT6+QSJ+7mRbHnhkGJ8jm4cZvWuj2Io7npOaeHQ3YHK+TiQpTnlbkjoOIpEwpY3XZA== +"@nomicfoundation/edr-linux-x64-gnu@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.5.2.tgz#f558d9697ce961410e7a7468f9ab8c8a601b9df6" + integrity sha512-CWVCEdhWJ3fmUpzWHCRnC0/VLBDbqtqTGTR6yyY1Ep3S3BOrHEAvt7h5gx85r2vLcztisu2vlDq51auie4IU1A== + "@nomicfoundation/edr-linux-x64-musl@0.3.4": version "0.3.4" resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.4.tgz#399278807100a1833f6c8a39c17d5beaaf7a9223" @@ -1975,6 +2021,11 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.4.0.tgz#8842004aa1a47c504f10863687da28b65dca7baa" integrity sha512-3HFIJSXgyubOiaN4MWGXx2xhTnhwlJk0PiSYNf9+L/fjBtcRkb2nM910ZJHTvqCb6OT98cUnaKuAYdXIW2amgw== +"@nomicfoundation/edr-linux-x64-musl@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.5.2.tgz#c9c9cbb2997499f75c1d022be724b0551d44569f" + integrity sha512-+aJDfwhkddy2pP5u1ISg3IZVAm0dO836tRlDTFWtvvSMQ5hRGqPcWwlsbobhDQsIxhPJyT7phL0orCg5W3WMeA== + "@nomicfoundation/edr-win32-arm64-msvc@0.3.4": version "0.3.4" resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-arm64-msvc/-/edr-win32-arm64-msvc-0.3.4.tgz#879028e2708538fd54efc349c1a4de107a15abb4" @@ -1995,6 +2046,11 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.4.0.tgz#29d8bbb2edf9912a95f5453855cf17cdcb269957" integrity sha512-CP4GsllEfXEz+lidcGYxKe5rDJ60TM5/blB5z/04ELVvw6/CK9eLcYeku7HV0jvV7VE6dADYKSdQyUkvd0El+A== +"@nomicfoundation/edr-win32-x64-msvc@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.5.2.tgz#f16db88bf4fe09a996af0a25096e09deecb72bfa" + integrity sha512-CcvvuA3sAv7liFNPsIR/68YlH6rrybKzYttLlMr80d4GKJjwJ5OKb3YgE6FdZZnOfP19HEHhsLcE0DPLtY3r0w== + "@nomicfoundation/edr@^0.3.1": version "0.3.4" resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.3.4.tgz#e8eaf41963460139c47b0785f1a6a2a1c1b24ae0" @@ -2023,6 +2079,19 @@ "@nomicfoundation/edr-linux-x64-musl" "0.4.0" "@nomicfoundation/edr-win32-x64-msvc" "0.4.0" +"@nomicfoundation/edr@^0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.5.2.tgz#e8c7b3d3dd4a312432ab3930dec60f76dc5c4926" + integrity sha512-hW/iLvUQZNTVjFyX/I40rtKvvDOqUEyIi96T28YaLfmPL+3LW2lxmYLUXEJ6MI14HzqxDqrLyhf6IbjAa2r3Dw== + dependencies: + "@nomicfoundation/edr-darwin-arm64" "0.5.2" + "@nomicfoundation/edr-darwin-x64" "0.5.2" + "@nomicfoundation/edr-linux-arm64-gnu" "0.5.2" + "@nomicfoundation/edr-linux-arm64-musl" "0.5.2" + "@nomicfoundation/edr-linux-x64-gnu" "0.5.2" + "@nomicfoundation/edr-linux-x64-musl" "0.5.2" + "@nomicfoundation/edr-win32-x64-msvc" "0.5.2" + "@nomicfoundation/ethereumjs-common@4.0.4": version "4.0.4" resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz#9901f513af2d4802da87c66d6f255b510bef5acb" @@ -2239,6 +2308,27 @@ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== +"@pnpm/config.env-replace@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz#ab29da53df41e8948a00f2433f085f54de8b3a4c" + integrity sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w== + +"@pnpm/network.ca-file@^1.0.1": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz#2ab05e09c1af0cdf2fcf5035bea1484e222f7983" + integrity sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA== + dependencies: + graceful-fs "4.2.10" + +"@pnpm/npm-conf@^2.1.0": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz#bb375a571a0bd63ab0a23bece33033c683e9b6b0" + integrity sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw== + dependencies: + "@pnpm/config.env-replace" "^1.1.0" + "@pnpm/network.ca-file" "^1.0.1" + config-chain "^1.1.11" + "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" @@ -2441,6 +2531,11 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== +"@sindresorhus/is@^5.2.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-5.6.0.tgz#41dd6093d34652cddb5d5bdeee04eafc33826668" + integrity sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g== + "@sinonjs/commons@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3" @@ -2507,6 +2602,13 @@ resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.18.0.tgz#8e77a02a09ecce957255a2f48c9a7178ec191908" integrity sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA== +"@szmarczak/http-timer@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-5.0.1.tgz#c7c1bf1141cdd4751b0399c8fc7b8b664cd5be3a" + integrity sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw== + dependencies: + defer-to-connect "^2.0.1" + "@trufflesuite/bigint-buffer@1.1.10": version "1.1.10" resolved "https://registry.yarnpkg.com/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.10.tgz#a1d9ca22d3cad1a138b78baaf15543637a3e1692" @@ -2686,6 +2788,11 @@ dependencies: "@types/node" "*" +"@types/http-cache-semantics@^4.0.2": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" + integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" @@ -3242,6 +3349,11 @@ antlr4@^4.11.0: resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.13.1.tgz#1e0a1830a08faeb86217cb2e6c34716004e4253d" integrity sha512-kiXTspaRYvnIArgE97z5YVVf/cDVQABr3abFRR6mE7yesLMkgu4ujuyV/sgxafQ8wgve0DJQUJ38Z8tkgA2izA== +antlr4@^4.13.1-patch-1: + version "4.13.2" + resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.13.2.tgz#0d084ad0e32620482a9c3a0e2470c02e72e4006d" + integrity sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg== + antlr4ts@^0.5.0-alpha.4: version "0.5.0-alpha.4" resolved "https://registry.yarnpkg.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a" @@ -3812,6 +3924,24 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +cacheable-lookup@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz#3476a8215d046e5a3202a9209dd13fec1f933a27" + integrity sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w== + +cacheable-request@^10.2.8: + version "10.2.14" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-10.2.14.tgz#eb915b665fda41b79652782df3f553449c406b9d" + integrity sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ== + dependencies: + "@types/http-cache-semantics" "^4.0.2" + get-stream "^6.0.1" + http-cache-semantics "^4.1.1" + keyv "^4.5.3" + mimic-response "^4.0.0" + normalize-url "^8.0.0" + responselike "^3.0.0" + call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" @@ -3887,6 +4017,19 @@ chai@^4.3.10, chai@^4.3.4, chai@^4.3.6: pathval "^1.1.1" type-detect "^4.0.8" +chai@^4.3.7: + version "4.5.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8" + integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.1.0" + chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -4192,6 +4335,14 @@ concat-stream@^1.6.0, concat-stream@^1.6.2, concat-stream@~1.6.2: readable-stream "^2.2.2" typedarray "^0.0.6" +config-chain@^1.1.11: + version "1.1.13" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" + integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" @@ -4316,6 +4467,18 @@ crypto-js@^4.2.0: resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== +csv-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/csv-parser/-/csv-parser-3.0.0.tgz#b88a6256d79e090a97a1b56451f9327b01d710e7" + integrity sha512-s6OYSXAK3IdKqYO33y09jhypG/bSDHPuyCme/IdEHfWpLf/jKcpitVFyOC6UemgGk8v7Q5u2XE0vvwmanxhGlQ== + dependencies: + minimist "^1.2.0" + +csv-writer@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/csv-writer/-/csv-writer-1.6.0.tgz#d0cea44b6b4d7d3baa2ecc6f3f7209233514bcf9" + integrity sha512-NOx7YDFWEsM/fTRAJjRpPp8t+MKRVvniAg9wQlUKx20MFrPs73WLJhFf5iteqrxNYnsy924K3Iroh3yNHeYd2g== + dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -4395,6 +4558,13 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + dedent@^1.0.0: version "1.5.1" resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" @@ -4427,6 +4597,11 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== +defer-to-connect@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + deferred-leveldown@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz#27a997ad95408b61161aa69bd489b86c71b78058" @@ -4555,7 +4730,7 @@ dockerode@^3.3.4: docker-modem "^3.0.0" tar-fs "~2.0.1" -dockerode@^4.0.2: +dockerode@^4.0.0, dockerode@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/dockerode/-/dockerode-4.0.2.tgz#dedc8529a1db3ac46d186f5912389899bc309f7d" integrity sha512-9wM1BVpVMFr2Pw3eJNXrYYt6DT9k0xMcsSCjtPvyQ+xa1iPg/Mo3T/gUcwI0B2cczqCeCYRPF8yFYDwtFXT0+w== @@ -5236,7 +5411,7 @@ ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.3, ethereumjs-util@^7.1.4, ethereum ethereum-cryptography "^0.1.3" rlp "^2.2.4" -ethers@^5.0.2, ethers@^5.7.0, ethers@^5.7.2, ethers@~5.7.0: +ethers@^5.0.2, ethers@^5.7.0, ethers@^5.7.2, ethers@~5.7.0, ethers@~5.7.2: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -5647,6 +5822,11 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== +form-data-encoder@^2.1.2: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-2.1.4.tgz#261ea35d2a70d48d30ec7a9603130fa5515e9cd5" + integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw== + form-data@^2.2.0: version "2.5.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" @@ -5840,7 +6020,7 @@ get-stdin@~9.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575" integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA== -get-stream@^6.0.0: +get-stream@^6.0.0, get-stream@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== @@ -6038,6 +6218,28 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" +got@^12.1.0: + version "12.6.1" + resolved "https://registry.yarnpkg.com/got/-/got-12.6.1.tgz#8869560d1383353204b5a9435f782df9c091f549" + integrity sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ== + dependencies: + "@sindresorhus/is" "^5.2.0" + "@szmarczak/http-timer" "^5.0.1" + cacheable-lookup "^7.0.0" + cacheable-request "^10.2.8" + decompress-response "^6.0.0" + form-data-encoder "^2.1.2" + get-stream "^6.0.1" + http2-wrapper "^2.1.10" + lowercase-keys "^3.0.0" + p-cancelable "^3.0.0" + responselike "^3.0.0" + +graceful-fs@4.2.10: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" @@ -6155,6 +6357,55 @@ hardhat@=2.22.2: uuid "^8.3.2" ws "^7.4.6" +hardhat@^2.14.0: + version "2.22.8" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.8.tgz#348dcdb48c44648ae7723f6efb511785e2b220c5" + integrity sha512-hPh2feBGRswkXkoXUFW6NbxgiYtEzp/3uvVFjYROy6fA9LH8BobUyxStlyhSKj4+v1Y23ZoUBOVWL84IcLACrA== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@metamask/eth-sig-util" "^4.0.0" + "@nomicfoundation/edr" "^0.5.2" + "@nomicfoundation/ethereumjs-common" "4.0.4" + "@nomicfoundation/ethereumjs-tx" "5.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" + "@nomicfoundation/solidity-analyzer" "^0.1.0" + "@sentry/node" "^5.18.1" + "@types/bn.js" "^5.1.0" + "@types/lru-cache" "^5.1.0" + adm-zip "^0.4.16" + aggregate-error "^3.0.0" + ansi-escapes "^4.3.0" + boxen "^5.1.2" + chalk "^2.4.2" + chokidar "^3.4.0" + ci-info "^2.0.0" + debug "^4.1.1" + enquirer "^2.3.0" + env-paths "^2.2.0" + ethereum-cryptography "^1.0.3" + ethereumjs-abi "^0.6.8" + find-up "^2.1.0" + fp-ts "1.19.3" + fs-extra "^7.0.1" + glob "7.2.0" + immutable "^4.0.0-rc.12" + io-ts "1.10.4" + keccak "^3.0.2" + lodash "^4.17.11" + mnemonist "^0.38.0" + mocha "^10.0.0" + p-map "^4.0.0" + raw-body "^2.4.1" + resolve "1.17.0" + semver "^6.3.0" + solc "0.8.26" + source-map-support "^0.5.13" + stacktrace-parser "^0.1.10" + tsort "0.0.1" + undici "^5.14.0" + uuid "^8.3.2" + ws "^7.4.6" + hardhat@^2.22.5: version "2.22.5" resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.5.tgz#7e1a4311fa9e34a1cfe337784eae06706f6469a5" @@ -6311,6 +6562,11 @@ http-basic@^8.1.1: http-response-object "^3.0.1" parse-cache-control "^1.0.1" +http-cache-semantics@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + http-errors@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" @@ -6338,6 +6594,14 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" +http2-wrapper@^2.1.10: + version "2.2.1" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-2.2.1.tgz#310968153dcdedb160d8b72114363ef5fce1f64a" + integrity sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.2.0" + https-proxy-agent@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" @@ -6442,7 +6706,7 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== -ini@^1.3.5, ini@~1.3.0: +ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== @@ -7389,6 +7653,13 @@ kleur@^3.0.3: dependencies: dotenv "^16.0.3" +latest-version@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-7.0.0.tgz#843201591ea81a4d404932eeb61240fe04e9e5da" + integrity sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg== + dependencies: + package-json "^8.1.0" + level-codec@^9.0.0: version "9.0.2" resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.2.tgz#fd60df8c64786a80d44e63423096ffead63d8cbc" @@ -7658,6 +7929,11 @@ loupe@^2.3.6: dependencies: get-func-name "^2.0.1" +lowercase-keys@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" + integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== + lru-cache@^10.2.0: version "10.2.2" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878" @@ -7899,6 +8175,16 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + +mimic-response@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f" + integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg== + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -8228,6 +8514,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +normalize-url@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.1.tgz#9b7d96af9836577c58f5883e939365fa15623a4a" + integrity sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w== + npm-run-all@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" @@ -8371,7 +8662,7 @@ optionator@^0.9.1, optionator@^0.9.3: prelude-ls "^1.2.1" type-check "^0.4.0" -ordinal@^1.0.3: +ordinal@1.0.3, ordinal@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/ordinal/-/ordinal-1.0.3.tgz#1a3c7726a61728112f50944ad7c35c06ae3a0d4d" integrity sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ== @@ -8381,6 +8672,11 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== +p-cancelable@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" + integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== + p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -8447,6 +8743,16 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-json@^8.1.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-8.1.1.tgz#3e9948e43df40d1e8e78a85485f1070bf8f03dc8" + integrity sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA== + dependencies: + got "^12.1.0" + registry-auth-token "^5.0.1" + registry-url "^6.0.0" + semver "^7.3.7" + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -8852,6 +9158,11 @@ proper-lockfile@^4.1.2: retry "^0.12.0" signal-exit "^3.0.2" +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== + protobufjs@^7.2.5: version "7.2.6" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.6.tgz#4a0ccd79eb292717aacf07530a07e0ed20278215" @@ -8938,6 +9249,11 @@ queue-microtask@^1.2.2, queue-microtask@^1.2.3: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + railroad-diagrams@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" @@ -8968,7 +9284,7 @@ raw-body@^2.4.1: iconv-lite "0.4.24" unpipe "1.0.0" -rc@~1.2.7: +rc@1.2.8, rc@~1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -9070,6 +9386,20 @@ regexpp@^3.1.0: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== +registry-auth-token@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-5.0.2.tgz#8b026cc507c8552ebbe06724136267e63302f756" + integrity sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ== + dependencies: + "@pnpm/npm-conf" "^2.1.0" + +registry-url@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-6.0.1.tgz#056d9343680f2f64400032b1e199faa692286c58" + integrity sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q== + dependencies: + rc "1.2.8" + req-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/req-cwd/-/req-cwd-2.0.0.tgz#d4082b4d44598036640fb73ddea01ed53db49ebc" @@ -9120,6 +9450,11 @@ require-from-string@^2.0.0, require-from-string@^2.0.2: resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== +resolve-alpn@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== + resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -9173,6 +9508,13 @@ resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.20.0, resolve@^1.22 path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +responselike@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-3.0.0.tgz#20decb6c298aff0dbee1c355ca95461d42823626" + integrity sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg== + dependencies: + lowercase-keys "^3.0.0" + restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -9573,6 +9915,19 @@ solc@0.8.17: semver "^5.5.0" tmp "0.0.33" +solc@0.8.26: + version "0.8.26" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.26.tgz#afc78078953f6ab3e727c338a2fefcd80dd5b01a" + integrity sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g== + dependencies: + command-exists "^1.2.8" + commander "^8.1.0" + follow-redirects "^1.12.1" + js-sha3 "0.8.0" + memorystream "^0.3.1" + semver "^5.5.0" + tmp "0.0.33" + solhint-plugin-prettier@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/solhint-plugin-prettier/-/solhint-plugin-prettier-0.0.5.tgz#e3b22800ba435cd640a9eca805a7f8bc3e3e6a6b" @@ -9580,6 +9935,32 @@ solhint-plugin-prettier@^0.0.5: dependencies: prettier-linter-helpers "^1.0.0" +solhint@4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/solhint/-/solhint-4.5.4.tgz#171cf33f46c36b8499efe60c0e425f6883a54e50" + integrity sha512-Cu1XiJXub2q1eCr9kkJ9VPv1sGcmj3V7Zb76B0CoezDOB9bu3DxKIFFH7ggCl9fWpEPD6xBmRLfZrYijkVmujQ== + dependencies: + "@solidity-parser/parser" "^0.18.0" + ajv "^6.12.6" + antlr4 "^4.13.1-patch-1" + ast-parents "^0.0.1" + chalk "^4.1.2" + commander "^10.0.0" + cosmiconfig "^8.0.0" + fast-diff "^1.2.0" + glob "^8.0.3" + ignore "^5.2.4" + js-yaml "^4.1.0" + latest-version "^7.0.0" + lodash "^4.17.21" + pluralize "^8.0.0" + semver "^7.5.2" + strip-ansi "^6.0.1" + table "^6.8.1" + text-table "^0.2.0" + optionalDependencies: + prettier "^2.8.3" + solhint@^3.3.2, solhint@^3.6.2: version "3.6.2" resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.6.2.tgz#2b2acbec8fdc37b2c68206a71ba89c7f519943fe" @@ -9776,7 +10157,7 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -9793,6 +10174,15 @@ string-width@^2.1.0, string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -9859,7 +10249,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -9880,6 +10270,13 @@ strip-ansi@^5.1.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -9979,7 +10376,7 @@ synckit@^0.8.6: "system-contracts@link:contracts/system-contracts": version "0.1.0" dependencies: - "@matterlabs/hardhat-zksync-deploy" "^0.6.5" + "@matterlabs/hardhat-zksync-deploy" "^0.7.0" "@matterlabs/hardhat-zksync-solc" "^1.1.4" "@matterlabs/hardhat-zksync-verify" "^1.4.3" commander "^9.4.1" @@ -9990,7 +10387,6 @@ synckit@^0.8.6: fast-glob "^3.3.2" hardhat "=2.22.2" preprocess "^3.2.0" - zksync-ethers "https://github.com/zksync-sdk/zksync-ethers#ethers-v5-feat/bridgehub" table-layout@^1.0.2: version "1.0.2" @@ -10347,6 +10743,11 @@ type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.8: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== +type-detect@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" + integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== + type-fest@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" @@ -10725,7 +11126,16 @@ workerpool@6.2.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -10879,18 +11289,19 @@ zksync-ethers@5.8.0-beta.5: dependencies: ethers "~5.7.0" +zksync-ethers@^5.0.0, zksync-ethers@^5.9.0: + version "5.9.2" + resolved "https://registry.yarnpkg.com/zksync-ethers/-/zksync-ethers-5.9.2.tgz#1c5f34cb25ac0b040fd1a6118f2ba1c2c3bda090" + integrity sha512-Y2Mx6ovvxO6UdC2dePLguVzvNToOY8iLWeq5ne+jgGSJxAi/f4He/NF6FNsf6x1aWX0o8dy4Df8RcOQXAkj5qw== + dependencies: + ethers "~5.7.0" + zksync-ethers@^6.9.0: version "6.9.0" resolved "https://registry.yarnpkg.com/zksync-ethers/-/zksync-ethers-6.9.0.tgz#efaff1d59e2cff837eeda84c4ba59fdca4972a91" integrity sha512-2CppwvLHtz689L7E9EhevbFtsqVukKC/lVicwdeUS2yqV46ET4iBR11rYdEfGW2oEo1h6yJuuwIBDFm2SybkIA== -"zksync-ethers@https://github.com/zksync-sdk/zksync-ethers#ethers-v5-feat/bridgehub": - version "5.1.0" - resolved "https://github.com/zksync-sdk/zksync-ethers#28ccbe7d67b170c202b17475e06a82002e6e3acc" - dependencies: - ethers "~5.7.0" - -zksync-web3@^0.15.4: +zksync-web3@^0.15.5: version "0.15.5" resolved "https://registry.yarnpkg.com/zksync-web3/-/zksync-web3-0.15.5.tgz#aabe379464963ab573e15948660a709f409b5316" integrity sha512-97gB7OKJL4spegl8fGO54g6cvTd/75G6yFWZWEa2J09zhjTrfqabbwE/GwiUJkFQ5BbzoH4JaTlVz1hoYZI+DQ== From 4f28e859b90104f1ff8c0440e128e7eccea50ad5 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 19 Aug 2024 12:45:53 -0300 Subject: [PATCH 21/76] Remove old fix me comments --- core/node/genesis/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/node/genesis/src/lib.rs b/core/node/genesis/src/lib.rs index 1b9199e20421..68ac3fdccc98 100644 --- a/core/node/genesis/src/lib.rs +++ b/core/node/genesis/src/lib.rs @@ -105,7 +105,6 @@ impl GenesisParams { .evm_simulator_hash .ok_or(GenesisError::MalformedConfig("evm_simulator_hash"))?, }; - // FIXME: uncomment this and update hashes. if base_system_contracts_hashes != base_system_contracts.hashes() { return Err(GenesisError::BaseSystemContractsHashes(Box::new( BaseContractsHashError { @@ -311,7 +310,6 @@ pub async fn ensure_genesis_state( "expected_rollup_last_leaf_index", ))?; - // FIXME: uncomment this and update hashes. if expected_root_hash != root_hash { return Err(GenesisError::RootHash(expected_root_hash, root_hash)); } From c57862553cfc2c61f00771f9e79af28912cae155 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 19 Aug 2024 15:05:25 -0300 Subject: [PATCH 22/76] Fix format --- .../versions/vm_latest/tracers/evm_debug_tracer.rs | 14 +++++++------- .../vm_latest/tracers/evm_deploy_tracer.rs | 6 ++++-- core/lib/vm_interface/src/storage/in_memory.rs | 1 - core/lib/vm_utils/src/storage.rs | 4 +++- .../src/batch_executor/main_executor.rs | 4 +--- core/node/state_keeper/src/batch_executor/mod.rs | 4 ++-- .../state_keeper/src/updates/l2_block_updates.rs | 6 +++++- core/node/state_keeper/src/updates/mod.rs | 3 +-- 8 files changed, 23 insertions(+), 19 deletions(-) diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/evm_debug_tracer.rs b/core/lib/multivm/src/versions/vm_latest/tracers/evm_debug_tracer.rs index 9392d61f0650..341cc8783663 100644 --- a/core/lib/multivm/src/versions/vm_latest/tracers/evm_debug_tracer.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/evm_debug_tracer.rs @@ -9,15 +9,15 @@ use zk_evm_1_5_0::{ zkevm_opcode_defs::{FatPointer, Opcode, UMAOpcode}, }; use zksync_state::interface::{StoragePtr, WriteStorage}; -use zksync_types::{ - Address, StorageKey, U256, -}; +use zksync_types::{Address, StorageKey, U256}; use crate::{ - interface::tracer::TracerExecutionStatus, tracers::dynamic::vm_1_5_0::DynTracer, vm_latest::{ - old_vm::utils::heap_page_from_base, - BootloaderState, HistoryMode, SimpleMemory, VmTracer, ZkSyncVmState, - } + interface::tracer::TracerExecutionStatus, + tracers::dynamic::vm_1_5_0::DynTracer, + vm_latest::{ + old_vm::utils::heap_page_from_base, BootloaderState, HistoryMode, SimpleMemory, VmTracer, + ZkSyncVmState, + }, }; pub(crate) struct EvmDebugTracer { diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs b/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs index 6a8ded8f624e..e0eda1d2034c 100644 --- a/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs @@ -11,9 +11,11 @@ use zksync_utils::{bytes_to_be_words, h256_to_u256}; use super::{traits::VmTracer, utils::read_pointer}; use crate::{ - interface::tracer::TracerExecutionStatus, tracers::dynamic::vm_1_5_0::DynTracer, vm_latest::{ + interface::tracer::TracerExecutionStatus, + tracers::dynamic::vm_1_5_0::DynTracer, + vm_latest::{ utils::hash_evm_bytecode, BootloaderState, HistoryMode, SimpleMemory, ZkSyncVmState, - } + }, }; /// Tracer responsible for collecting information about EVM deploys and providing those diff --git a/core/lib/vm_interface/src/storage/in_memory.rs b/core/lib/vm_interface/src/storage/in_memory.rs index e754d47e417a..9d523fd3336a 100644 --- a/core/lib/vm_interface/src/storage/in_memory.rs +++ b/core/lib/vm_interface/src/storage/in_memory.rs @@ -6,7 +6,6 @@ use zksync_types::{ system_contracts::{get_evm_interpreter_hash, get_system_smart_contracts}, L2ChainId, StorageKey, StorageLog, StorageValue, H256, U256, }; - use zksync_utils::u256_to_h256; use super::ReadStorage; diff --git a/core/lib/vm_utils/src/storage.rs b/core/lib/vm_utils/src/storage.rs index f5ebb37962ab..52333ca46fa3 100644 --- a/core/lib/vm_utils/src/storage.rs +++ b/core/lib/vm_utils/src/storage.rs @@ -4,7 +4,9 @@ use anyhow::Context; use zksync_contracts::BaseSystemContracts; use zksync_dal::{Connection, Core, CoreDal, DalError}; use zksync_types::{ - block::L2BlockHeader, fee_model::BatchFeeInput, snapshots::SnapshotRecoveryStatus, web3::contract, Address, L1BatchNumber, L2BlockNumber, L2ChainId, ProtocolVersionId, H256, ZKPORTER_IS_AVAILABLE + block::L2BlockHeader, fee_model::BatchFeeInput, snapshots::SnapshotRecoveryStatus, + web3::contract, Address, L1BatchNumber, L2BlockNumber, L2ChainId, ProtocolVersionId, H256, + ZKPORTER_IS_AVAILABLE, }; use zksync_vm_interface::{L1BatchEnv, L2BlockEnv, SystemEnv, TxExecutionMode}; diff --git a/core/node/state_keeper/src/batch_executor/main_executor.rs b/core/node/state_keeper/src/batch_executor/main_executor.rs index 0b827be562e1..813d03edce0a 100644 --- a/core/node/state_keeper/src/batch_executor/main_executor.rs +++ b/core/node/state_keeper/src/batch_executor/main_executor.rs @@ -14,9 +14,7 @@ use zksync_multivm::{ MultiVMTracer, VmInstance, }; use zksync_shared_metrics::{InteractionType, TxStage, APP_METRICS}; -use zksync_types::{ - vm::FastVmMode, Transaction, -}; +use zksync_types::{vm::FastVmMode, Transaction}; use super::{BatchExecutor, BatchExecutorHandle, Command, TxExecutionResult}; use crate::{ diff --git a/core/node/state_keeper/src/batch_executor/mod.rs b/core/node/state_keeper/src/batch_executor/mod.rs index 116ee14d16a1..7512f1508be5 100644 --- a/core/node/state_keeper/src/batch_executor/mod.rs +++ b/core/node/state_keeper/src/batch_executor/mod.rs @@ -6,8 +6,8 @@ use tokio::{ task::JoinHandle, }; use zksync_multivm::interface::{ - Call, CompressedBytecodeInfo, FinishedL1Batch, Halt, L1BatchEnv, - L2BlockEnv, SystemEnv, VmExecutionResultAndLogs, + Call, CompressedBytecodeInfo, FinishedL1Batch, Halt, L1BatchEnv, L2BlockEnv, SystemEnv, + VmExecutionResultAndLogs, }; use zksync_state::{interface::StorageViewCache, OwnedStorage}; use zksync_types::{Transaction, H256}; diff --git a/core/node/state_keeper/src/updates/l2_block_updates.rs b/core/node/state_keeper/src/updates/l2_block_updates.rs index cb3b7c03ec94..7cdf99f1b55c 100644 --- a/core/node/state_keeper/src/updates/l2_block_updates.rs +++ b/core/node/state_keeper/src/updates/l2_block_updates.rs @@ -10,7 +10,11 @@ use zksync_multivm::{ }; use zksync_system_constants::KNOWN_CODES_STORAGE_ADDRESS; use zksync_types::{ - block::{BlockGasCount, L2BlockHasher}, ethabi, l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log}, L2BlockNumber, ProtocolVersionId, StorageLogKind, StorageLogQuery, StorageLogWithPreviousValue, Transaction, H256 + block::{BlockGasCount, L2BlockHasher}, + ethabi, + l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log}, + L2BlockNumber, ProtocolVersionId, StorageLogKind, StorageLogQuery, StorageLogWithPreviousValue, + Transaction, H256, }; use zksync_utils::bytecode::hash_bytecode; diff --git a/core/node/state_keeper/src/updates/mod.rs b/core/node/state_keeper/src/updates/mod.rs index b55dd310e6be..45bfebabeac0 100644 --- a/core/node/state_keeper/src/updates/mod.rs +++ b/core/node/state_keeper/src/updates/mod.rs @@ -7,8 +7,7 @@ use zksync_multivm::{ utils::{get_batch_base_fee, StorageWritesDeduplicator}, }; use zksync_types::{ - block::BlockGasCount, fee_model::BatchFeeInput, - Address, L1BatchNumber, L2BlockNumber, + block::BlockGasCount, fee_model::BatchFeeInput, Address, L1BatchNumber, L2BlockNumber, ProtocolVersionId, Transaction, H256, }; From e0940193e5b77d0ea418646d317db5a368a24b2c Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Mon, 19 Aug 2024 16:37:04 -0300 Subject: [PATCH 23/76] Make evm tests compile --- .../contracts/create/TestEVMCreate.sol | 30 + .../ts-integration/contracts/token/ERC20.sol | 76 ++ .../contracts/uniswap-v2/UniswapV2Factory.sol | 683 ++++++++++++++++++ .../tests/evm-contracts.test.ts | 242 ++++--- 4 files changed, 915 insertions(+), 116 deletions(-) create mode 100644 core/tests/ts-integration/contracts/create/TestEVMCreate.sol create mode 100644 core/tests/ts-integration/contracts/token/ERC20.sol create mode 100644 core/tests/ts-integration/contracts/uniswap-v2/UniswapV2Factory.sol diff --git a/core/tests/ts-integration/contracts/create/TestEVMCreate.sol b/core/tests/ts-integration/contracts/create/TestEVMCreate.sol new file mode 100644 index 000000000000..176790d14023 --- /dev/null +++ b/core/tests/ts-integration/contracts/create/TestEVMCreate.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +interface IContractDeployer { + function evmCodeHash(address key) external returns (bytes32); + + function createEVM( + bytes calldata _initCode + ) external payable returns (address newAddress); + + function create2EVM( + bytes32 _salt, + bytes calldata _initCode + ) external payable returns (address); +} + +/// @notice An example of a system contract that be used for local testing. +/// @dev It is not used anywhere except for testing +contract TestEVMCreate { + IContractDeployer deployer = IContractDeployer(address(0x8006)); + + function create(bytes calldata _code) external { + deployer.createEVM(_code); + } + + function create2(bytes32 _salt, bytes calldata _code) external payable { + deployer.create2EVM{value:msg.value}(_salt, _code); + } +} diff --git a/core/tests/ts-integration/contracts/token/ERC20.sol b/core/tests/ts-integration/contracts/token/ERC20.sol new file mode 100644 index 000000000000..ca3269c4ebd0 --- /dev/null +++ b/core/tests/ts-integration/contracts/token/ERC20.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.0; + +contract ERC20{ + string public symbol; + string public name; + uint8 public decimals; + uint public totalSupply; + + mapping(address => uint) balances; + mapping(address => mapping(address => uint)) allowed; + + event Transfer(address indexed _from, address indexed _to, uint256 _value); + event Approval(address indexed _owner, address indexed _spender, uint256 _value); + + constructor() { + symbol = "TEST"; + name = "Test Coin"; + decimals = 18; + totalSupply = 1000000; + balances[msg.sender] = totalSupply; + emit Transfer(address(0), msg.sender, totalSupply); + } + + + function balanceOf(address tokenOwner) public view returns (uint balance) { + return balances[tokenOwner]; + } + + function transfer(address to, uint tokens) public returns (bool success) { + balances[msg.sender] = safeSub(balances[msg.sender], tokens); + balances[to] = safeAdd(balances[to], tokens); + emit Transfer(msg.sender, to, tokens); + return true; + } + + function approve(address spender, uint tokens) public returns (bool success) { + allowed[msg.sender][spender] = tokens; + emit Approval(msg.sender, spender, tokens); + return true; + } + + function transferFrom(address from, address to, uint tokens) public returns (bool success) { + balances[from] = safeSub(balances[from], tokens); + allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], tokens); + balances[to] = safeAdd(balances[to], tokens); + emit Transfer(from, to, tokens); + return true; + } + + function allowance(address tokenOwner, address spender) public view returns (uint remaining) { + return allowed[tokenOwner][spender]; + } + + function safeAdd(uint a, uint b) internal pure returns (uint c) { + c = a + b; + require(c >= a); + } + + function safeSub(uint a, uint b) internal pure returns (uint c) { + require(b <= a); + c = a - b; + } + + function safeMul(uint a, uint b) internal pure returns (uint c) { + c = a * b; + require(a == 0 || c / a == b); + } + + function safeDiv(uint a, uint b) internal pure returns (uint c) { + require(b > 0); + c = a / b; + } + +} \ No newline at end of file diff --git a/core/tests/ts-integration/contracts/uniswap-v2/UniswapV2Factory.sol b/core/tests/ts-integration/contracts/uniswap-v2/UniswapV2Factory.sol new file mode 100644 index 000000000000..90b9429dc197 --- /dev/null +++ b/core/tests/ts-integration/contracts/uniswap-v2/UniswapV2Factory.sol @@ -0,0 +1,683 @@ +// NOTE: Flattened to make easier to deploy to both native/evm + +// File contracts/uniswap-v2/interfaces/IUniswapV2Factory.sol + +pragma solidity ^0.8.0; + +interface IUniswapV2Factory { + function feeTo() external returns (address); + + function feeToSetter() external returns (address); + + function getPair( + address tokenA, + address tokenB + ) external returns (address pair); + + function allPairs(uint) external returns (address pair); + + function allPairsLength() external returns (uint); + + function createPair( + address tokenA, + address tokenB + ) external returns (address pair); + + function setFeeTo(address) external; + + function setFeeToSetter(address) external; +} + +// File contracts/uniswap-v2/libraries/SafeMath.sol + +pragma solidity ^0.8.0; + +// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) + +library SafeMath { + function add(uint x, uint y) internal pure returns (uint z) { + require((z = x + y) >= x, "ds-math-add-overflow"); + } + + function sub(uint x, uint y) internal pure returns (uint z) { + require((z = x - y) <= x, "ds-math-sub-underflow"); + } + + function mul(uint x, uint y) internal pure returns (uint z) { + require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); + } +} + +// File contracts/uniswap-v2/interfaces/IUniswapV2ERC20.sol + +pragma solidity ^0.8.0; + +interface IUniswapV2ERC20 { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external pure returns (string memory); + + function symbol() external pure returns (string memory); + + function decimals() external pure returns (uint8); + + function totalSupply() external returns (uint); + + function balanceOf(address owner) external returns (uint); + + function allowance(address owner, address spender) external returns (uint); + + function approve(address spender, uint value) external returns (bool); + + function transfer(address to, uint value) external returns (bool); + + function transferFrom( + address from, + address to, + uint value + ) external returns (bool); + + function DOMAIN_SEPARATOR() external returns (bytes32); + + function PERMIT_TYPEHASH() external pure returns (bytes32); + + function nonces(address owner) external returns (uint); + + function permit( + address owner, + address spender, + uint value, + uint deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; +} + +// File contracts/uniswap-v2/UniswapV2ERC20.sol + +pragma solidity ^0.8.0; + +contract UniswapV2ERC20 is IUniswapV2ERC20 { + using SafeMath for uint; + + string public override constant name = "Uniswap V2"; + string public override constant symbol = "UNI-V2"; + uint8 public override constant decimals = 18; + uint public override totalSupply; + mapping(address => uint) public override balanceOf; + mapping(address => mapping(address => uint)) public override allowance; + + bytes32 public override DOMAIN_SEPARATOR; + // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + bytes32 public override constant PERMIT_TYPEHASH = + 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; + mapping(address => uint) public override nonces; + + constructor() { + uint chainId; + assembly { + chainId := chainid() + } + DOMAIN_SEPARATOR = keccak256( + abi.encode( + keccak256( + "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" + ), + keccak256(bytes(name)), + keccak256(bytes("1")), + chainId, + address(this) + ) + ); + } + + function _mint(address to, uint value) internal { + totalSupply = totalSupply.add(value); + balanceOf[to] = balanceOf[to].add(value); + emit Transfer(address(0), to, value); + } + + function _burn(address from, uint value) internal { + balanceOf[from] = balanceOf[from].sub(value); + totalSupply = totalSupply.sub(value); + emit Transfer(from, address(0), value); + } + + function _approve(address owner, address spender, uint value) private { + allowance[owner][spender] = value; + emit Approval(owner, spender, value); + } + + function _transfer(address from, address to, uint value) private { + balanceOf[from] = balanceOf[from].sub(value); + balanceOf[to] = balanceOf[to].add(value); + emit Transfer(from, to, value); + } + + function approve(address spender, uint value) external override returns (bool) { + _approve(msg.sender, spender, value); + return true; + } + + function transfer(address to, uint value) external override returns (bool) { + _transfer(msg.sender, to, value); + return true; + } + + function transferFrom( + address from, + address to, + uint value + ) external override returns (bool) { + if (allowance[from][msg.sender] != uint(int(-1))) { + allowance[from][msg.sender] = allowance[from][msg.sender].sub( + value + ); + } + _transfer(from, to, value); + return true; + } + + function permit( + address owner, + address spender, + uint value, + uint deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external override { + require(deadline >= block.timestamp, "UniswapV2: EXPIRED"); + bytes32 digest = keccak256( + abi.encodePacked( + "\x19\x01", + DOMAIN_SEPARATOR, + keccak256( + abi.encode( + PERMIT_TYPEHASH, + owner, + spender, + value, + nonces[owner]++, + deadline + ) + ) + ) + ); + address recoveredAddress = ecrecover(digest, v, r, s); + require( + recoveredAddress != address(0) && recoveredAddress == owner, + "UniswapV2: INVALID_SIGNATURE" + ); + _approve(owner, spender, value); + } +} + +// File contracts/uniswap-v2/libraries/Math.sol + +pragma solidity ^0.8.0; + +// a library for performing various math operations + +library Math { + function min(uint x, uint y) internal pure returns (uint z) { + z = x < y ? x : y; + } + + // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) + function sqrt(uint y) internal pure returns (uint z) { + if (y > 3) { + z = y; + uint x = y / 2 + 1; + while (x < z) { + z = x; + x = (y / x + x) / 2; + } + } else if (y != 0) { + z = 1; + } + } +} + +// File contracts/uniswap-v2/interfaces/IERC20.sol + +pragma solidity ^0.8.0; + +interface IERC20 { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external returns (string memory); + + function symbol() external returns (string memory); + + function decimals() external returns (uint8); + + function totalSupply() external returns (uint); + + function balanceOf(address owner) external returns (uint); + + function allowance(address owner, address spender) external returns (uint); + + function approve(address spender, uint value) external returns (bool); + + function transfer(address to, uint value) external returns (bool); + + function transferFrom( + address from, + address to, + uint value + ) external returns (bool); +} + +// File contracts/uniswap-v2/libraries/UQ112x112.sol + +pragma solidity ^0.8.0; + +// a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) + +// range: [0, 2**112 - 1] +// resolution: 1 / 2**112 + +library UQ112x112 { + uint224 constant Q112 = 2 ** 112; + + // encode a uint112 as a UQ112x112 + function encode(uint112 y) internal pure returns (uint224 z) { + z = uint224(y) * Q112; // never overflows + } + + // divide a UQ112x112 by a uint112, returning a UQ112x112 + function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) { + z = x / uint224(y); + } +} + +// File contracts/uniswap-v2/interfaces/IUniswapV2Pair.sol + +pragma solidity ^0.8.0; + +interface IUniswapV2Pair { + event Mint(address indexed sender, uint amount0, uint amount1); + event Burn( + address indexed sender, + uint amount0, + uint amount1, + address indexed to + ); + event Swap( + address indexed sender, + uint amount0In, + uint amount1In, + uint amount0Out, + uint amount1Out, + address indexed to + ); + event Sync(uint112 reserve0, uint112 reserve1); + + function MINIMUM_LIQUIDITY() external pure returns (uint); + + function factory() external returns (address); + + function token0() external returns (address); + + function token1() external returns (address); + + function getReserves() + external + returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); + + function price0CumulativeLast() external returns (uint); + + function price1CumulativeLast() external returns (uint); + + function kLast() external returns (uint); + + function mint(address to) external returns (uint liquidity); + + function burn(address to) external returns (uint amount0, uint amount1); + + function swap( + uint amount0Out, + uint amount1Out, + address to, + bytes calldata data + ) external; + + function skim(address to) external; + + function sync() external; + + function initialize(address, address) external; +} + +// File contracts/uniswap-v2/interfaces/IUniswapV2Callee.sol + +pragma solidity ^0.8.0; + +interface IUniswapV2Callee { + function uniswapV2Call( + address sender, + uint amount0, + uint amount1, + bytes calldata data + ) external; +} + +// File contracts/uniswap-v2/UniswapV2Pair.sol + +pragma solidity ^0.8.0; + +contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 { + using SafeMath for uint; + using UQ112x112 for uint224; + + uint public override constant MINIMUM_LIQUIDITY = 10 ** 3; + bytes4 private constant SELECTOR = + bytes4(keccak256(bytes("transfer(address,uint256)"))); + + address public override factory; + address public override token0; + address public override token1; + + uint112 private reserve0; // uses single storage slot, accessible via getReserves + uint112 private reserve1; // uses single storage slot, accessible via getReserves + uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves + + uint public override price0CumulativeLast; + uint public override price1CumulativeLast; + uint public override kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event + + uint private unlocked = 1; + modifier lock() { + require(unlocked == 1, "UniswapV2: LOCKED"); + unlocked = 0; + _; + unlocked = 1; + } + + function getReserves() + public + override + returns ( + uint112 _reserve0, + uint112 _reserve1, + uint32 _blockTimestampLast + ) + { + _reserve0 = reserve0; + _reserve1 = reserve1; + _blockTimestampLast = blockTimestampLast; + } + + function _safeTransfer(address token, address to, uint value) private { + IERC20(token).transfer(to, value); + } + + constructor() public { + factory = msg.sender; + } + + // called once by the factory at time of deployment + function initialize(address _token0, address _token1) external override { + require(msg.sender == factory, "UniswapV2: FORBIDDEN"); // sufficient check + token0 = _token0; + token1 = _token1; + } + + // update reserves and, on the first call per block, price accumulators + function _update( + uint balance0, + uint balance1, + uint112 _reserve0, + uint112 _reserve1 + ) private { + require( + balance0 <= uint112(int112(-1)) && balance1 <= uint112(int112(-1)), + "UniswapV2: OVERFLOW" + ); + uint32 blockTimestamp = uint32(block.timestamp % 2 ** 32); + uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired + if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) { + // * never overflows, and + overflow is desired + price0CumulativeLast += + uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * + timeElapsed; + price1CumulativeLast += + uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * + timeElapsed; + } + reserve0 = uint112(balance0); + reserve1 = uint112(balance1); + blockTimestampLast = blockTimestamp; + emit Sync(reserve0, reserve1); + } + + // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k) + function _mintFee( + uint112 _reserve0, + uint112 _reserve1 + ) private returns (bool feeOn) { + address feeTo = IUniswapV2Factory(factory).feeTo(); + feeOn = feeTo != address(0); + uint _kLast = kLast; // gas savings + if (feeOn) { + if (_kLast != 0) { + uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1)); + uint rootKLast = Math.sqrt(_kLast); + if (rootK > rootKLast) { + uint numerator = totalSupply.mul(rootK.sub(rootKLast)); + uint denominator = rootK.mul(5).add(rootKLast); + uint liquidity = numerator / denominator; + if (liquidity > 0) _mint(feeTo, liquidity); + } + } + } else if (_kLast != 0) { + kLast = 0; + } + } + + // this low-level function should be called from a contract which performs important safety checks + function mint(address to) external override lock returns (uint liquidity) { + (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings + uint balance0 = IERC20(token0).balanceOf(address(this)); + uint balance1 = IERC20(token1).balanceOf(address(this)); + uint amount0 = balance0.sub(_reserve0); + uint amount1 = balance1.sub(_reserve1); + + bool feeOn = _mintFee(_reserve0, _reserve1); + uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee + if (_totalSupply == 0) { + liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY); + _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens + } else { + liquidity = Math.min( + amount0.mul(_totalSupply) / _reserve0, + amount1.mul(_totalSupply) / _reserve1 + ); + } + require(liquidity > 0, "UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED"); + _mint(to, liquidity); + + _update(balance0, balance1, _reserve0, _reserve1); + if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date + emit Mint(msg.sender, amount0, amount1); + } + + // this low-level function should be called from a contract which performs important safety checks + function burn( + address to + ) external override lock returns (uint amount0, uint amount1) { + (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings + address _token0 = token0; // gas savings + address _token1 = token1; // gas savings + uint balance0 = IERC20(_token0).balanceOf(address(this)); + uint balance1 = IERC20(_token1).balanceOf(address(this)); + uint liquidity = balanceOf[address(this)]; + + bool feeOn = _mintFee(_reserve0, _reserve1); + uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee + amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution + amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution + require( + amount0 > 0 && amount1 > 0, + "UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED" + ); + _burn(address(this), liquidity); + _safeTransfer(_token0, to, amount0); + _safeTransfer(_token1, to, amount1); + balance0 = IERC20(_token0).balanceOf(address(this)); + balance1 = IERC20(_token1).balanceOf(address(this)); + + _update(balance0, balance1, _reserve0, _reserve1); + if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date + emit Burn(msg.sender, amount0, amount1, to); + } + + // this low-level function should be called from a contract which performs important safety checks + function swap( + uint amount0Out, + uint amount1Out, + address to, + bytes calldata data + ) external override lock { + // require( + // amount0Out > 0 || amount1Out > 0, + // "UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT" + // ); + // (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings + // require( + // amount0Out < _reserve0 && amount1Out < _reserve1, + // "UniswapV2: INSUFFICIENT_LIQUIDITY" + // ); + + // uint balance0; + // uint balance1; + // { + // // scope for _token{0,1}, avoids stack too deep errors + // address _token0 = token0; + // address _token1 = token1; + // require(to != _token0 && to != _token1, "UniswapV2: INVALID_TO"); + // if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens + // if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens + // if (data.length > 0) + // IUniswapV2Callee(to).uniswapV2Call( + // msg.sender, + // amount0Out, + // amount1Out, + // data + // ); + // balance0 = IERC20(_token0).balanceOf(address(this)); + // balance1 = IERC20(_token1).balanceOf(address(this)); + // } + // uint amount0In = balance0 > _reserve0 - amount0Out + // ? balance0 - (_reserve0 - amount0Out) + // : 0; + // uint amount1In = balance1 > _reserve1 - amount1Out + // ? balance1 - (_reserve1 - amount1Out) + // : 0; + // require( + // amount0In > 0 || amount1In > 0, + // "UniswapV2: INSUFFICIENT_INPUT_AMOUNT" + // ); + // { + // // scope for reserve{0,1}Adjusted, avoids stack too deep errors + // uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3)); + // uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3)); + // require( + // balance0Adjusted.mul(balance1Adjusted) >= + // uint(_reserve0).mul(_reserve1).mul(1000 ** 2), + // "UniswapV2: K" + // ); + // } + + // _update(balance0, balance1, _reserve0, _reserve1); + // emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to); + } + + // force balances to match reserves + function skim(address to) external override lock { + address _token0 = token0; // gas savings + address _token1 = token1; // gas savings + _safeTransfer( + _token0, + to, + IERC20(_token0).balanceOf(address(this)).sub(reserve0) + ); + _safeTransfer( + _token1, + to, + IERC20(_token1).balanceOf(address(this)).sub(reserve1) + ); + } + + // force reserves to match balances + function sync() external override lock { + _update( + IERC20(token0).balanceOf(address(this)), + IERC20(token1).balanceOf(address(this)), + reserve0, + reserve1 + ); + } +} + +// File contracts/uniswap-v2/UniswapV2Factory.sol + +pragma solidity ^0.8.0; + +contract UniswapV2Factory is IUniswapV2Factory { + address public override feeTo; + address public override feeToSetter; + + mapping(address => mapping(address => address)) public override getPair; + address[] public override allPairs; + + event PairCreated( + address indexed token0, + address indexed token1, + address pair, + uint + ); + + constructor(address _feeToSetter) public { + feeToSetter = _feeToSetter; + } + + function allPairsLength() external override returns (uint) { + return allPairs.length; + } + + function createPair( + address tokenA, + address tokenB + ) external override returns (address pair) { + require(tokenA != tokenB, "UniswapV2: IDENTICAL_ADDRESSES"); + (address token0, address token1) = tokenA < tokenB + ? (tokenA, tokenB) + : (tokenB, tokenA); + require(token0 != address(0), "UniswapV2: ZERO_ADDRESS"); + require( + getPair[token0][token1] == address(0), + "UniswapV2: PAIR_EXISTS" + ); // single check is sufficient + pair = address(new UniswapV2Pair()); + IUniswapV2Pair(pair).initialize(token0, token1); + getPair[token0][token1] = pair; + getPair[token1][token0] = pair; // populate mapping in the reverse direction + allPairs.push(pair); + emit PairCreated(token0, token1, pair, allPairs.length); + } + + function setFeeTo(address _feeTo) external override { + require(msg.sender == feeToSetter, "UniswapV2: FORBIDDEN"); + feeTo = _feeTo; + } + + function setFeeToSetter(address _feeToSetter) external override { + require(msg.sender == feeToSetter, "UniswapV2: FORBIDDEN"); + feeToSetter = _feeToSetter; + } +} \ No newline at end of file diff --git a/core/tests/ts-integration/tests/evm-contracts.test.ts b/core/tests/ts-integration/tests/evm-contracts.test.ts index 57e2a61a2f0c..316e65ce4bd6 100644 --- a/core/tests/ts-integration/tests/evm-contracts.test.ts +++ b/core/tests/ts-integration/tests/evm-contracts.test.ts @@ -68,7 +68,7 @@ describe('EVM equivalence contract', () => { const counterContract = await deploygasCallerContract(alice, artifacts.counterFallback); - let result = (await gasCallerContract.callAndGetGas.staticCall(counterContract.address)).toString(); + let result = (await gasCallerContract.getFunction("callAndGetGas").staticCall(counterContract.getAddress())).toString(); const expected_gas = '3617'; // Gas cost when run with solidity interpreter expect(result).toEqual(expected_gas); @@ -79,7 +79,7 @@ describe('EVM equivalence contract', () => { const creatorContract = await deploygasCallerContract(alice, artifacts.creatorFallback); - let result = (await gasCallerContract.callStatic.callAndGetGas(creatorContract.address)).toString(); + let result = (await gasCallerContract.getFunction("callAndGetGas").staticCall(creatorContract.getAddress())).toString(); const expected_gas = '70601'; // Gas cost when run with solidity interpreter expect(result).toEqual(expected_gas); @@ -90,7 +90,7 @@ describe('EVM equivalence contract', () => { const counterContract = await deploygasCallerContract(alice, artifacts.opcodeTestFallback); - let result = (await gasCallerContract.callStatic.callAndGetGas(counterContract.address)).toString(); + let result = (await gasCallerContract.getFunction("callAndGetGas").staticCall(counterContract.getAddress())).toString(); const expected_gas = '34763'; // Gas cost when run with solidity interpreter expect(result).toEqual(expected_gas); @@ -103,33 +103,32 @@ describe('EVM equivalence contract', () => { const args = [1]; const factory = getEVMContractFactory(alice, artifacts.counter); const contract = await factory.deploy(args); - await contract.deployTransaction.wait(); - const receipt = await alice.provider.getTransactionReceipt(contract.deployTransaction.hash); + await contract.deploymentTransaction()?.wait(); + const receipt = await alice.provider.getTransactionReceipt(contract.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })()); await assertCreatedCorrectly( deployer, - contract.address, + await contract.getAddress(), '0x' + artifacts.counter.evm.deployedBytecode.object, - receipt.logs ); - expect((await contract.callStatic.get()).toString()).toEqual('1'); - await (await contract.increment(1)).wait(); - expect((await contract.callStatic.get()).toString()).toEqual('2'); + expect((await contract.getFunction("get").staticCall()).toString()).toEqual('1'); + await (await contract.getFunction("increment")(1)).wait(); + expect((await contract.getFunction("get").staticCall()).toString()).toEqual('2'); }); test('Should create2 evm contract from ZKEVM contract', async () => { - const salt = ethers.utils.randomBytes(32); + const salt = ethers.randomBytes(32); - const expectedAddress = ethers.utils.getCreate2Address( - evmCreateTester.address, + const expectedAddress = ethers.getCreate2Address( + await evmCreateTester.getAddress(), salt, - ethers.utils.keccak256(initBytecode) + ethers.keccak256(initBytecode) ); const receipt = await (await evmCreateTester.create2(salt, initBytecode)).wait(); - await assertCreatedCorrectly(deployer, expectedAddress, runtimeBytecode, receipt.logs); + await assertCreatedCorrectly(deployer, expectedAddress, runtimeBytecode); try { await (await evmCreateTester.create2(salt, initBytecode, { gasLimit })).wait(); @@ -147,7 +146,7 @@ describe('EVM equivalence contract', () => { let failReason; try { - await contract.deployTransaction.wait(); + await contract.deploymentTransaction()?.wait(); } catch (e: any) { failReason = e.reason; } @@ -160,10 +159,11 @@ describe('EVM equivalence contract', () => { const factory = getEVMContractFactory(alice, artifacts.counter); const transaction = await factory.getDeployTransaction(args); - transaction.to = '0x0000000000000000000000000000000000000000'; + let dep_transaction = ethers.Transaction.from(transaction); + dep_transaction.to = '0x0000000000000000000000000000000000000000'; - const result = await (await alice.sendTransaction(transaction)).wait(); - const expectedAddressCreate = ethers.utils.getContractAddress({ + const result = await (await alice.sendTransaction(dep_transaction)).wait(); + const expectedAddressCreate = ethers.getCreateAddress({ from: alice.address, nonce: await alice.getNonce() }); @@ -206,21 +206,21 @@ describe('EVM equivalence contract', () => { const counterFactory = getEVMContractFactory(alice, artifacts.counter); const counterContract = await counterFactory.deploy(args); - await counterContract.deployTransaction.wait(); - await alice.provider.getTransactionReceipt(counterContract.deployTransaction.hash); + await counterContract.deploymentTransaction()?.wait(); + await alice.provider.getTransactionReceipt(counterContract.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })()); const proxyCallerFactory = getEVMContractFactory(alice, artifacts.proxyCaller); const proxyCallerContract = await proxyCallerFactory.deploy(); - await proxyCallerContract.deployTransaction.wait(); - await alice.provider.getTransactionReceipt(proxyCallerContract.deployTransaction.hash); + await proxyCallerContract.deploymentTransaction()?.wait(); + await alice.provider.getTransactionReceipt(proxyCallerContract.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })()); - expect((await proxyCallerContract.proxyGet(counterContract.address)).toString()).toEqual('1'); + expect((await proxyCallerContract.getFunction("proxyGet")(counterContract.getAddress())).toString()).toEqual('1'); - await (await proxyCallerContract.executeIncrememt(counterContract.address, 1)).wait(); + await (await proxyCallerContract.getFunction("executeIncrememt")(counterContract.getAddress(), 1)).wait(); - expect((await proxyCallerContract.proxyGet(counterContract.address)).toString()).toEqual('2'); + expect((await proxyCallerContract.getFunction("proxyGet")(counterContract.getAddress())).toString()).toEqual('2'); - expect((await proxyCallerContract.callStatic.proxyGetBytes(counterContract.address)).toString()).toEqual( + expect((await proxyCallerContract.getFunction("proxyGetBytes").staticCall(counterContract.getAddress())).toString()).toEqual( '0x54657374696e67' ); }); @@ -228,23 +228,23 @@ describe('EVM equivalence contract', () => { test('Create opcode works correctly', async () => { const creatorFactory = getEVMContractFactory(alice, artifacts.creator); const creatorContract = await creatorFactory.deploy(); - await creatorContract.deployTransaction.wait(); + await creatorContract.deploymentTransaction()?.wait(); - dumpOpcodeLogs(creatorContract.deployTransaction.hash, alice.provider); + dumpOpcodeLogs(creatorContract.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(), alice.provider); const nonce = 1; - const runtimeBytecode = await creatorContract.getCreationRuntimeCode(); + const runtimeBytecode = await creatorContract.getFunction("getCreationRuntimeCode")(); - const expectedAddress = ethers.utils.getContractAddress({ - from: creatorContract.address, + const expectedAddress = ethers.getCreateAddress({ + from: await creatorContract.getAddress(), nonce }); - const result = await (await creatorContract.create()).wait(); + const result = await (await creatorContract.getFunction("create")()).wait(); dumpOpcodeLogs(result.transactionHash, alice.provider); - await assertCreatedCorrectly(deployer, expectedAddress, runtimeBytecode, result.logs); + await assertCreatedCorrectly(deployer, expectedAddress, runtimeBytecode); }); test('Should revert correctly', async () => { @@ -252,14 +252,14 @@ describe('EVM equivalence contract', () => { const counterFactory = getEVMContractFactory(alice, artifacts.counter); const counterContract = await counterFactory.deploy(args); - await counterContract.deployTransaction.wait(); + await counterContract.deploymentTransaction()?.wait(); - dumpOpcodeLogs(counterContract.deployTransaction.hash, alice.provider); + dumpOpcodeLogs(counterContract.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(), alice.provider); let errorString; try { - await counterContract.callStatic.incrementWithRevert(1, true); + await counterContract.getFunction("incrementWithRevert").staticCall(1, true); } catch (e: any) { errorString = e.reason; } @@ -269,7 +269,7 @@ describe('EVM equivalence contract', () => { // NOTE: Gas cost comparisons should be done on a *fresh* chain that doesn't have e.g. bytecodes already published describe('ERC20', () => { - let evmToken: ethers.Contract; + let evmToken: ethers.BaseContract; let nativeToken: zksync.Contract; let userAccount: zksync.Wallet; let deployLogged: boolean = false; @@ -277,46 +277,50 @@ describe('EVM equivalence contract', () => { beforeEach(async () => { const erc20Factory = getEVMContractFactory(alice, artifacts.erc20); evmToken = await erc20Factory.deploy(); - await evmToken.deployTransaction.wait(); + await evmToken.deploymentTransaction()?.wait(); nativeToken = await deployContract(alice, contracts.erc20, []); - dumpOpcodeLogs(evmToken.deployTransaction.hash, alice.provider); + dumpOpcodeLogs(evmToken.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(), alice.provider); userAccount = testMaster.newEmptyAccount(); // Only log the first deployment if (logGasCosts && !deployLogged) { + let native_hash = nativeToken.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(); + let native_transanction_receipt = (await alice.provider.getTransactionReceipt(native_hash)) ?? (() => { throw new Error('Deployment transaction has failed'); })(); + let evm_hash = evmToken.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(); + let evm_transanction_receipt = (await alice.provider.getTransactionReceipt(evm_hash)) ?? (() => { throw new Error('Deployment transaction has failed'); })(); console.log( 'ERC20 native deploy gas: ' + - (await alice.provider.getTransactionReceipt(nativeToken.deployTransaction.hash)).gasUsed + native_transanction_receipt.gasUsed ); console.log( 'ERC20 evm deploy gas: ' + - (await alice.provider.getTransactionReceipt(evmToken.deployTransaction.hash)).gasUsed + evm_transanction_receipt.gasUsed ); deployLogged = true; } await ( await alice.sendTransaction({ to: userAccount.address, - value: ethers.BigNumber.from('0xffffffffffffff') + value: BigInt('0xffffffffffffff') }) ).wait(); }); test('view functions should work', async () => { - const evmBalanceOfCost = await evmToken.estimateGas.balanceOf(alice.address); - const nativeBalanceOfCost = await nativeToken.estimateGas.balanceOf(alice.address); + const evmBalanceOfCost = await evmToken.getFunction("balanceOf").estimateGas(alice.address); + const nativeBalanceOfCost = await nativeToken.getFunction("balanceOf").estimateGas(alice.address); if (logGasCosts) { console.log('ERC20 native balanceOf gas: ' + nativeBalanceOfCost.toString()); console.log('ERC20 evm balanceOf gas: ' + evmBalanceOfCost.toString()); } - expect((await evmToken.balanceOf(alice.address)).toString()).toEqual('1000000'); - expect((await evmToken.totalSupply()).toString()).toEqual('1000000'); - expect((await evmToken.balanceOf(userAccount.address)).toString()).toEqual('0'); + expect((await evmToken.getFunction("balanceOf")(alice.address)).toString()).toEqual('1000000'); + expect((await evmToken.getFunction("totalSupply")()).toString()).toEqual('1000000'); + expect((await evmToken.getFunction("balanceOf")(userAccount.address)).toString()).toEqual('0'); }); test('transfer should work', async () => { - expect((await evmToken.balanceOf(alice.address)).toString()).toEqual('1000000'); - const evmTransferTx = await (await evmToken.transfer(userAccount.address, 100000)).wait(); + expect((await evmToken.getFunction("balanceOf")(alice.address)).toString()).toEqual('1000000'); + const evmTransferTx = await (await evmToken.getFunction("transfer")(userAccount.address, 100000)).wait(); const nativeTransferTx = await (await nativeToken.transfer(userAccount.address, 100000)).wait(); if (logGasCosts) { console.log('ERC20 native transfer gas: ' + nativeTransferTx.gasUsed.toString()); @@ -324,15 +328,15 @@ describe('EVM equivalence contract', () => { } dumpOpcodeLogs(evmTransferTx.transactionHash, alice.provider); - expect((await evmToken.balanceOf(alice.address)).toString()).toEqual('900000'); - expect((await evmToken.balanceOf(userAccount.address)).toString()).toEqual('100000'); + expect((await evmToken.getFunction("balanceOf")(alice.address)).toString()).toEqual('900000'); + expect((await evmToken.getFunction("balanceOf")(userAccount.address)).toString()).toEqual('100000'); }); test('approve & transferFrom should work', async () => { - expect((await evmToken.balanceOf(alice.address)).toString()).toEqual('1000000'); - const evmApproveTx = await (await evmToken.connect(alice).approve(userAccount.address, 100000)).wait(); + expect((await evmToken.getFunction("balanceOf")(alice.address)).toString()).toEqual('1000000'); + const evmApproveTx = await (await evmToken.connect(alice).getFunction("approve")(userAccount.getAddress(), 100000)).wait(); const nativeApproveTx = await ( - await nativeToken.connect(alice).approve(userAccount.address, 100000) + await nativeToken.connect(alice).getFunction("approve")(userAccount.address, 100000) ).wait(); if (logGasCosts) { console.log('ERC20 native approve gas: ' + nativeApproveTx.gasUsed.toString()); @@ -341,10 +345,10 @@ describe('EVM equivalence contract', () => { dumpOpcodeLogs(evmApproveTx.transactionHash, alice.provider); const evmTransferFromTx = await ( - await evmToken.connect(userAccount).transferFrom(alice.address, userAccount.address, 100000) + await evmToken.connect(userAccount).getFunction("transferFrom")(alice.address, userAccount.address, 100000) ).wait(); const nativeTransferFromTx = await ( - await nativeToken.connect(userAccount).transferFrom(alice.address, userAccount.address, 100000) + await nativeToken.connect(userAccount).getFunction("transferFrom")(alice.address, userAccount.address, 100000) ).wait(); if (logGasCosts) { console.log('ERC20 native transferFrom gas: ' + nativeTransferFromTx.gasUsed.toString()); @@ -352,19 +356,19 @@ describe('EVM equivalence contract', () => { } dumpOpcodeLogs(evmTransferFromTx.transactionHash, alice.provider); - expect((await evmToken.balanceOf(alice.address)).toString()).toEqual('900000'); - expect((await evmToken.balanceOf(userAccount.address)).toString()).toEqual('100000'); + expect((await evmToken.getFunction("balanceOf")(alice.address)).toString()).toEqual('900000'); + expect((await evmToken.getFunction("balanceOf")(userAccount.address)).toString()).toEqual('100000'); }); }); // NOTE: Gas cost comparisons should be done on a *fresh* chain that doesn't have e.g. bytecodes already published describe('Uniswap-v2', () => { - let evmToken1: ethers.Contract; - let evmToken2: ethers.Contract; - let evmUniswapFactory: ethers.Contract; - let nativeUniswapFactory: ethers.Contract; - let evmUniswapPair: ethers.Contract; - let nativeUniswapPair: ethers.Contract; + let evmToken1: ethers.BaseContract; + let evmToken2: ethers.BaseContract; + let evmUniswapFactory: ethers.BaseContract; + let nativeUniswapFactory: ethers.BaseContract; + let evmUniswapPair: ethers.BaseContract; + let nativeUniswapPair: ethers.BaseContract; let deployLogged: boolean = false; const NEW_PAIR_TOPIC = '0x0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9'; @@ -372,13 +376,13 @@ describe('EVM equivalence contract', () => { beforeEach(async () => { const erc20Factory = getEVMContractFactory(alice, artifacts.erc20); evmToken1 = await erc20Factory.deploy({ gasLimit }); - await evmToken1.deployTransaction.wait(); + await evmToken1.deploymentTransaction()?.wait(); evmToken2 = await erc20Factory.deploy(); - await evmToken2.deployTransaction.wait(); + await evmToken2.deploymentTransaction()?.wait(); const evmUniswapFactoryFactory = getEVMContractFactory(alice, artifacts.uniswapV2Factory); evmUniswapFactory = await evmUniswapFactoryFactory.deploy('0x0000000000000000000000000000000000000000'); - await evmUniswapFactory.deployTransaction.wait(); + await evmUniswapFactory.deploymentTransaction()?.wait(); nativeUniswapFactory = await deployContract( alice, @@ -393,13 +397,13 @@ describe('EVM equivalence contract', () => { ); const evmPairReceipt = await ( - await evmUniswapFactory.createPair(evmToken1.address, evmToken2.address) + await evmUniswapFactory.getFunction("createPair")(evmToken1.getAddress(), evmToken2.getAddress()) ).wait(); const nativePairReceipt = await ( - await nativeUniswapFactory.createPair(evmToken1.address, evmToken2.address) + await nativeUniswapFactory.getFunction("createPair")(evmToken1.getAddress(), evmToken2.getAddress()) ).wait(); - dumpOpcodeLogs(evmUniswapFactory.deployTransaction.hash, alice.provider); + dumpOpcodeLogs(evmUniswapFactory.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(), alice.provider); dumpOpcodeLogs(evmPairReceipt.transactionHash, alice.provider); const evmUniswapPairFactory = getEVMContractFactory(alice, artifacts.uniswapV2Pair); @@ -409,36 +413,40 @@ describe('EVM equivalence contract', () => { alice ); evmUniswapPair = evmUniswapPairFactory.attach( - ethers.utils.defaultAbiCoder.decode( + ethers.AbiCoder.defaultAbiCoder().decode( ['address', 'uint256'], evmPairReceipt.logs.find((log: any) => log.topics[0] === NEW_PAIR_TOPIC).data )[0] ); nativeUniswapPair = nativeUniswapPairFactory.attach( - ethers.utils.defaultAbiCoder.decode( + ethers.AbiCoder.defaultAbiCoder().decode( ['address', 'uint256'], nativePairReceipt.logs.find((log: any) => log.topics[0] === NEW_PAIR_TOPIC).data )[0] ); - const token1IsFirst = (await evmUniswapPair.token0()).toString() === evmToken1.address; + const token1IsFirst = (await evmUniswapPair.getFunction("token0")()).toString() === evmToken1.getAddress(); if (!token1IsFirst) { [evmToken1, evmToken2] = [evmToken2, evmToken1]; } - await (await evmToken1.transfer(evmUniswapPair.address, 100000)).wait(); - await (await evmToken1.transfer(nativeUniswapPair.address, 100000)).wait(); - await (await evmToken2.transfer(evmUniswapPair.address, 100000)).wait(); - await (await evmToken2.transfer(nativeUniswapPair.address, 100000)).wait(); + await (await evmToken1.getFunction("transfer")(evmUniswapPair.getAddress(), 100000)).wait(); + await (await evmToken1.getFunction("transfer")(nativeUniswapPair.getAddress(), 100000)).wait(); + await (await evmToken2.getFunction("transfer")(evmUniswapPair.getAddress(), 100000)).wait(); + await (await evmToken2.getFunction("transfer")(nativeUniswapPair.getAddress(), 100000)).wait(); // Only log the first deployment if (logGasCosts && !deployLogged) { + let native_hash = nativeUniswapFactory.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(); + let native_transanction_receipt = (await alice.provider.getTransactionReceipt(native_hash)) ?? (() => { throw new Error('Deployment transaction has failed'); })(); + let evm_hash = evmUniswapFactory.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(); + let evm_transanction_receipt = (await alice.provider.getTransactionReceipt(evm_hash)) ?? (() => { throw new Error('Deployment transaction has failed'); })(); console.log( 'Uniswap Factory native deploy gas: ' + - (await alice.provider.getTransactionReceipt(nativeUniswapFactory.deployTransaction.hash)) + native_transanction_receipt .gasUsed ); console.log( 'Uniswap Factory evm deploy gas: ' + - (await alice.provider.getTransactionReceipt(evmUniswapFactory.deployTransaction.hash)).gasUsed + evm_transanction_receipt.gasUsed ); console.log('Uniswap Pair native create gas: ' + nativePairReceipt.gasUsed); console.log('Uniswap Pair evm create gas: ' + evmPairReceipt.gasUsed); @@ -447,32 +455,32 @@ describe('EVM equivalence contract', () => { }); test('mint, swap, and burn should work', async () => { - const evmMintReceipt = await (await evmUniswapPair.mint(alice.address)).wait(); - const nativeMintReceipt = await (await nativeUniswapPair.mint(alice.address)).wait(); + const evmMintReceipt = await (await evmUniswapPair.getFunction("mint")(alice.address)).wait(); + const nativeMintReceipt = await (await nativeUniswapPair.getFunction("mint")(alice.address)).wait(); dumpOpcodeLogs(evmMintReceipt.transactionHash, alice.provider); - await (await evmToken1.transfer(evmUniswapPair.address, 10000)).wait(); - await (await evmToken1.transfer(nativeUniswapPair.address, 10000)).wait(); - const evmSwapReceipt = await (await evmUniswapPair.swap(0, 5000, alice.address, '0x')).wait(); - const nativeSwapReceipt = await (await nativeUniswapPair.swap(0, 5000, alice.address, '0x')).wait(); + await (await evmToken1.getFunction("transfer")(evmUniswapPair.getAddress(), 10000)).wait(); + await (await evmToken1.getFunction("transfer")(nativeUniswapPair.getAddress(), 10000)).wait(); + const evmSwapReceipt = await (await evmUniswapPair.getFunction("swap")(0, 5000, alice.address, '0x')).wait(); + const nativeSwapReceipt = await (await nativeUniswapPair.getFunction("swap")(0, 5000, alice.address, '0x')).wait(); dumpOpcodeLogs(evmSwapReceipt.transactionHash, alice.provider); const evmLiquidityTransfer = await ( - await evmUniswapPair.transfer( - evmUniswapPair.address, - (await evmUniswapPair.balanceOf(alice.address)).toString() + await evmUniswapPair.getFunction("transfer")( + evmUniswapPair.getAddress(), + (await evmUniswapPair.getFunction("balanceOf")(alice.address)).toString() ) ).wait(); await ( - await nativeUniswapPair.transfer( - nativeUniswapPair.address, - (await nativeUniswapPair.balanceOf(alice.address)).toString() + await nativeUniswapPair.getFunction("transfer")( + nativeUniswapPair.getAddress(), + (await nativeUniswapPair.getFunction("balanceOf")(alice.address)).toString() ) ).wait(); - const evmBurnReceipt = await (await evmUniswapPair.burn(alice.address)).wait(); - const nativeBurnReceipt = await (await nativeUniswapPair.burn(alice.address)).wait(); - expect(Number((await evmToken1.balanceOf(alice.address)).toString())).toBeGreaterThanOrEqual(990000); - expect(Number((await evmToken2.balanceOf(alice.address)).toString())).toBeGreaterThanOrEqual(990000); + const evmBurnReceipt = await (await evmUniswapPair.getFunction("burn")(alice.address)).wait(); + const nativeBurnReceipt = await (await nativeUniswapPair.getFunction("burn")(alice.address)).wait(); + expect(Number((await evmToken1.getFunction("balanceOf")(alice.address)).toString())).toBeGreaterThanOrEqual(990000); + expect(Number((await evmToken2.getFunction("balanceOf")(alice.address)).toString())).toBeGreaterThanOrEqual(990000); if (logGasCosts) { console.log('UniswapV2Pair native mint gas: ' + nativeMintReceipt.gasUsed); @@ -489,17 +497,17 @@ describe('EVM equivalence contract', () => { test("Should compare gas against uniswap fallback contract's call", async () => { const gasCallerFactory = getEVMContractFactory(alice, artifacts.gasCaller); const gasCallerContract = await gasCallerFactory.deploy(); - await gasCallerContract.deployTransaction.wait(); - await alice.provider.getTransactionReceipt(gasCallerContract.deployTransaction.hash); + await gasCallerContract.deploymentTransaction()?.wait(); + await alice.provider.getTransactionReceipt(gasCallerContract.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })()); const uniswapContract = await deploygasCallerContract(alice, artifacts.uniswapFallback); - await (await uniswapContract.setUniswapAddress(evmUniswapPair.address)).wait(); - await (await uniswapContract.setAliceAddress(alice.address)).wait(); + await (await uniswapContract.getFunction("setUniswapAddress")(evmUniswapPair.getAddress())).wait(); + await (await uniswapContract.getFunction("setAliceAddress")(alice.address)).wait(); - await (await evmToken1.transfer(evmUniswapPair.address, 10000)).wait(); - await (await evmToken1.transfer(uniswapContract.address, 10000)).wait(); + await (await evmToken1.getFunction("transfer")(evmUniswapPair.getAddress(), 10000)).wait(); + await (await evmToken1.getFunction("transfer")(uniswapContract.getAddress(), 10000)).wait(); - let result = (await gasCallerContract.callStatic.callAndGetGas(uniswapContract.address)).toString(); + let result = (await gasCallerContract.getFunction("callAndGetGas").staticCall(uniswapContract.getAddress())).toString(); const expected_gas = '165939'; // Gas cost when run with solidity interpreter expect(result).toEqual(expected_gas); @@ -635,9 +643,11 @@ async function assertStoredBytecodeHash( expectedStoredHash: string ): Promise { const ACCOUNT_CODE_STORAGE_ADDRESS = '0x0000000000000000000000000000000000008002'; - const storedCodeHash = await deployer.provider.getStorageAt( + let runner = deployer.runner ?? (() => { throw new Error('Runner get failed'); })(); + let provider = runner.provider ?? (() => { throw new Error('Provider get failed'); })(); + const storedCodeHash = await provider.getStorage( ACCOUNT_CODE_STORAGE_ADDRESS, - ethers.utils.hexZeroPad(deployedAddress, 32) + ethers.zeroPadValue(deployedAddress, 32) ); expect(storedCodeHash).toEqual(expectedStoredHash); @@ -647,18 +657,17 @@ async function assertCreatedCorrectly( deployer: zksync.Contract, deployedAddress: string, expectedEVMBytecode: string, - logs: Array ): Promise { const expectedStoredHash = getSha256BlobHash(expectedEVMBytecode); await assertStoredBytecodeHash(deployer, deployedAddress, expectedStoredHash); } function getPaddedBytecode(bytes: ethers.BytesLike) { - const length = ethers.utils.arrayify(bytes).length; + const length = ethers.getBytes(bytes).length; - const encodedLength = ethers.utils.defaultAbiCoder.encode(['uint256'], [length]); + const encodedLength = ethers.AbiCoder.defaultAbiCoder().encode(['uint256'], [length]); - let paddedBytecode = encodedLength + ethers.utils.hexlify(bytes).slice(2); + let paddedBytecode = encodedLength + ethers.toBeHex(ethers.toBigInt(bytes)).slice(2); // The length needs to be 32 mod 64. We use 64 mod 128, since // we are dealing with a hexlified string @@ -673,20 +682,20 @@ function getPaddedBytecode(bytes: ethers.BytesLike) { function getSha256BlobHash(bytes: ethers.BytesLike): string { const paddedBytes = getPaddedBytecode(bytes); - const hash = ethers.utils.arrayify(ethers.utils.sha256(paddedBytes)); + const hash = ethers.getBytes(ethers.sha256(paddedBytes)); hash[0] = 2; hash[1] = 0; // Length of the bytecode - const lengthInBytes = ethers.utils.arrayify(paddedBytes).length; + const lengthInBytes = ethers.getBytes(paddedBytes).length; hash[2] = Math.floor(lengthInBytes / 256); hash[3] = lengthInBytes % 256; - return ethers.utils.hexlify(hash); + return ethers.toBeHex(ethers.toBigInt(hash)); } async function assertContractNotCreated(deployer: zksync.Contract, deployedAddress: string): Promise { - assertStoredBytecodeHash(deployer, deployedAddress, ethers.constants.HashZero); + assertStoredBytecodeHash(deployer, deployedAddress, ethers.ZeroHash); } function printCostData() { @@ -877,14 +886,15 @@ const opcodeDataDump: any = {}; }); async function dumpOpcodeLogs(hash: string, provider: zksync.Provider): Promise { - const logs = (await provider.getTransactionReceipt(hash)).logs; + let tx_receipt = (await provider.getTransactionReceipt(hash)) ?? (() => { throw new Error('Get Transaction Receipt has failed'); })(); + const logs = tx_receipt.logs; logs.forEach((log) => { if (log.topics[0] === '0x63307236653da06aaa7e128a306b128c594b4cf3b938ef212975ed10dad17515') { //Overhead - overheadDataDump.push(Number(ethers.utils.defaultAbiCoder.decode(['uint256'], log.data).toString())); + overheadDataDump.push(Number(ethers.AbiCoder.defaultAbiCoder().decode(['uint256'], log.data).toString())); } else if (log.topics[0] === '0xca5a69edf1b934943a56c00605317596b03e2f61c3f633e8657b150f102a3dfa') { // Opcode - const parsed = ethers.utils.defaultAbiCoder.decode(['uint256', 'uint256'], log.data); + const parsed = ethers.AbiCoder.defaultAbiCoder().decode(['uint256', 'uint256'], log.data); const opcode = Number(parsed[0].toString()); const cost = Number(parsed[1].toString()); From 3561a5ba03c9a70d0a55123b09edd2f2c77e9ea3 Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Mon, 19 Aug 2024 16:37:33 -0300 Subject: [PATCH 24/76] Format code --- .../tests/evm-contracts.test.ts | 297 ++++++++++++------ 1 file changed, 202 insertions(+), 95 deletions(-) diff --git a/core/tests/ts-integration/tests/evm-contracts.test.ts b/core/tests/ts-integration/tests/evm-contracts.test.ts index 316e65ce4bd6..8c876a1b76b4 100644 --- a/core/tests/ts-integration/tests/evm-contracts.test.ts +++ b/core/tests/ts-integration/tests/evm-contracts.test.ts @@ -68,7 +68,9 @@ describe('EVM equivalence contract', () => { const counterContract = await deploygasCallerContract(alice, artifacts.counterFallback); - let result = (await gasCallerContract.getFunction("callAndGetGas").staticCall(counterContract.getAddress())).toString(); + let result = ( + await gasCallerContract.getFunction('callAndGetGas').staticCall(counterContract.getAddress()) + ).toString(); const expected_gas = '3617'; // Gas cost when run with solidity interpreter expect(result).toEqual(expected_gas); @@ -79,7 +81,9 @@ describe('EVM equivalence contract', () => { const creatorContract = await deploygasCallerContract(alice, artifacts.creatorFallback); - let result = (await gasCallerContract.getFunction("callAndGetGas").staticCall(creatorContract.getAddress())).toString(); + let result = ( + await gasCallerContract.getFunction('callAndGetGas').staticCall(creatorContract.getAddress()) + ).toString(); const expected_gas = '70601'; // Gas cost when run with solidity interpreter expect(result).toEqual(expected_gas); @@ -90,7 +94,9 @@ describe('EVM equivalence contract', () => { const counterContract = await deploygasCallerContract(alice, artifacts.opcodeTestFallback); - let result = (await gasCallerContract.getFunction("callAndGetGas").staticCall(counterContract.getAddress())).toString(); + let result = ( + await gasCallerContract.getFunction('callAndGetGas').staticCall(counterContract.getAddress()) + ).toString(); const expected_gas = '34763'; // Gas cost when run with solidity interpreter expect(result).toEqual(expected_gas); @@ -104,17 +110,22 @@ describe('EVM equivalence contract', () => { const factory = getEVMContractFactory(alice, artifacts.counter); const contract = await factory.deploy(args); await contract.deploymentTransaction()?.wait(); - const receipt = await alice.provider.getTransactionReceipt(contract.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })()); + const receipt = await alice.provider.getTransactionReceipt( + contract.deploymentTransaction()?.hash ?? + (() => { + throw new Error('Deployment transaction has failed'); + })() + ); await assertCreatedCorrectly( deployer, await contract.getAddress(), - '0x' + artifacts.counter.evm.deployedBytecode.object, + '0x' + artifacts.counter.evm.deployedBytecode.object ); - expect((await contract.getFunction("get").staticCall()).toString()).toEqual('1'); - await (await contract.getFunction("increment")(1)).wait(); - expect((await contract.getFunction("get").staticCall()).toString()).toEqual('2'); + expect((await contract.getFunction('get').staticCall()).toString()).toEqual('1'); + await (await contract.getFunction('increment')(1)).wait(); + expect((await contract.getFunction('get').staticCall()).toString()).toEqual('2'); }); test('Should create2 evm contract from ZKEVM contract', async () => { @@ -207,22 +218,38 @@ describe('EVM equivalence contract', () => { const counterFactory = getEVMContractFactory(alice, artifacts.counter); const counterContract = await counterFactory.deploy(args); await counterContract.deploymentTransaction()?.wait(); - await alice.provider.getTransactionReceipt(counterContract.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })()); + await alice.provider.getTransactionReceipt( + counterContract.deploymentTransaction()?.hash ?? + (() => { + throw new Error('Deployment transaction has failed'); + })() + ); const proxyCallerFactory = getEVMContractFactory(alice, artifacts.proxyCaller); const proxyCallerContract = await proxyCallerFactory.deploy(); await proxyCallerContract.deploymentTransaction()?.wait(); - await alice.provider.getTransactionReceipt(proxyCallerContract.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })()); + await alice.provider.getTransactionReceipt( + proxyCallerContract.deploymentTransaction()?.hash ?? + (() => { + throw new Error('Deployment transaction has failed'); + })() + ); - expect((await proxyCallerContract.getFunction("proxyGet")(counterContract.getAddress())).toString()).toEqual('1'); + expect( + (await proxyCallerContract.getFunction('proxyGet')(counterContract.getAddress())).toString() + ).toEqual('1'); - await (await proxyCallerContract.getFunction("executeIncrememt")(counterContract.getAddress(), 1)).wait(); + await (await proxyCallerContract.getFunction('executeIncrememt')(counterContract.getAddress(), 1)).wait(); - expect((await proxyCallerContract.getFunction("proxyGet")(counterContract.getAddress())).toString()).toEqual('2'); + expect( + (await proxyCallerContract.getFunction('proxyGet')(counterContract.getAddress())).toString() + ).toEqual('2'); - expect((await proxyCallerContract.getFunction("proxyGetBytes").staticCall(counterContract.getAddress())).toString()).toEqual( - '0x54657374696e67' - ); + expect( + ( + await proxyCallerContract.getFunction('proxyGetBytes').staticCall(counterContract.getAddress()) + ).toString() + ).toEqual('0x54657374696e67'); }); test('Create opcode works correctly', async () => { @@ -230,18 +257,24 @@ describe('EVM equivalence contract', () => { const creatorContract = await creatorFactory.deploy(); await creatorContract.deploymentTransaction()?.wait(); - dumpOpcodeLogs(creatorContract.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(), alice.provider); + dumpOpcodeLogs( + creatorContract.deploymentTransaction()?.hash ?? + (() => { + throw new Error('Deployment transaction has failed'); + })(), + alice.provider + ); const nonce = 1; - const runtimeBytecode = await creatorContract.getFunction("getCreationRuntimeCode")(); + const runtimeBytecode = await creatorContract.getFunction('getCreationRuntimeCode')(); const expectedAddress = ethers.getCreateAddress({ from: await creatorContract.getAddress(), nonce }); - const result = await (await creatorContract.getFunction("create")()).wait(); + const result = await (await creatorContract.getFunction('create')()).wait(); dumpOpcodeLogs(result.transactionHash, alice.provider); await assertCreatedCorrectly(deployer, expectedAddress, runtimeBytecode); @@ -254,12 +287,18 @@ describe('EVM equivalence contract', () => { const counterContract = await counterFactory.deploy(args); await counterContract.deploymentTransaction()?.wait(); - dumpOpcodeLogs(counterContract.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(), alice.provider); + dumpOpcodeLogs( + counterContract.deploymentTransaction()?.hash ?? + (() => { + throw new Error('Deployment transaction has failed'); + })(), + alice.provider + ); let errorString; try { - await counterContract.getFunction("incrementWithRevert").staticCall(1, true); + await counterContract.getFunction('incrementWithRevert').staticCall(1, true); } catch (e: any) { errorString = e.reason; } @@ -280,22 +319,38 @@ describe('EVM equivalence contract', () => { await evmToken.deploymentTransaction()?.wait(); nativeToken = await deployContract(alice, contracts.erc20, []); - dumpOpcodeLogs(evmToken.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(), alice.provider); + dumpOpcodeLogs( + evmToken.deploymentTransaction()?.hash ?? + (() => { + throw new Error('Deployment transaction has failed'); + })(), + alice.provider + ); userAccount = testMaster.newEmptyAccount(); // Only log the first deployment if (logGasCosts && !deployLogged) { - let native_hash = nativeToken.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(); - let native_transanction_receipt = (await alice.provider.getTransactionReceipt(native_hash)) ?? (() => { throw new Error('Deployment transaction has failed'); })(); - let evm_hash = evmToken.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(); - let evm_transanction_receipt = (await alice.provider.getTransactionReceipt(evm_hash)) ?? (() => { throw new Error('Deployment transaction has failed'); })(); - console.log( - 'ERC20 native deploy gas: ' + - native_transanction_receipt.gasUsed - ); - console.log( - 'ERC20 evm deploy gas: ' + - evm_transanction_receipt.gasUsed - ); + let native_hash = + nativeToken.deploymentTransaction()?.hash ?? + (() => { + throw new Error('Deployment transaction has failed'); + })(); + let native_transanction_receipt = + (await alice.provider.getTransactionReceipt(native_hash)) ?? + (() => { + throw new Error('Deployment transaction has failed'); + })(); + let evm_hash = + evmToken.deploymentTransaction()?.hash ?? + (() => { + throw new Error('Deployment transaction has failed'); + })(); + let evm_transanction_receipt = + (await alice.provider.getTransactionReceipt(evm_hash)) ?? + (() => { + throw new Error('Deployment transaction has failed'); + })(); + console.log('ERC20 native deploy gas: ' + native_transanction_receipt.gasUsed); + console.log('ERC20 evm deploy gas: ' + evm_transanction_receipt.gasUsed); deployLogged = true; } await ( @@ -307,20 +362,20 @@ describe('EVM equivalence contract', () => { }); test('view functions should work', async () => { - const evmBalanceOfCost = await evmToken.getFunction("balanceOf").estimateGas(alice.address); - const nativeBalanceOfCost = await nativeToken.getFunction("balanceOf").estimateGas(alice.address); + const evmBalanceOfCost = await evmToken.getFunction('balanceOf').estimateGas(alice.address); + const nativeBalanceOfCost = await nativeToken.getFunction('balanceOf').estimateGas(alice.address); if (logGasCosts) { console.log('ERC20 native balanceOf gas: ' + nativeBalanceOfCost.toString()); console.log('ERC20 evm balanceOf gas: ' + evmBalanceOfCost.toString()); } - expect((await evmToken.getFunction("balanceOf")(alice.address)).toString()).toEqual('1000000'); - expect((await evmToken.getFunction("totalSupply")()).toString()).toEqual('1000000'); - expect((await evmToken.getFunction("balanceOf")(userAccount.address)).toString()).toEqual('0'); + expect((await evmToken.getFunction('balanceOf')(alice.address)).toString()).toEqual('1000000'); + expect((await evmToken.getFunction('totalSupply')()).toString()).toEqual('1000000'); + expect((await evmToken.getFunction('balanceOf')(userAccount.address)).toString()).toEqual('0'); }); test('transfer should work', async () => { - expect((await evmToken.getFunction("balanceOf")(alice.address)).toString()).toEqual('1000000'); - const evmTransferTx = await (await evmToken.getFunction("transfer")(userAccount.address, 100000)).wait(); + expect((await evmToken.getFunction('balanceOf')(alice.address)).toString()).toEqual('1000000'); + const evmTransferTx = await (await evmToken.getFunction('transfer')(userAccount.address, 100000)).wait(); const nativeTransferTx = await (await nativeToken.transfer(userAccount.address, 100000)).wait(); if (logGasCosts) { console.log('ERC20 native transfer gas: ' + nativeTransferTx.gasUsed.toString()); @@ -328,15 +383,17 @@ describe('EVM equivalence contract', () => { } dumpOpcodeLogs(evmTransferTx.transactionHash, alice.provider); - expect((await evmToken.getFunction("balanceOf")(alice.address)).toString()).toEqual('900000'); - expect((await evmToken.getFunction("balanceOf")(userAccount.address)).toString()).toEqual('100000'); + expect((await evmToken.getFunction('balanceOf')(alice.address)).toString()).toEqual('900000'); + expect((await evmToken.getFunction('balanceOf')(userAccount.address)).toString()).toEqual('100000'); }); test('approve & transferFrom should work', async () => { - expect((await evmToken.getFunction("balanceOf")(alice.address)).toString()).toEqual('1000000'); - const evmApproveTx = await (await evmToken.connect(alice).getFunction("approve")(userAccount.getAddress(), 100000)).wait(); + expect((await evmToken.getFunction('balanceOf')(alice.address)).toString()).toEqual('1000000'); + const evmApproveTx = await ( + await evmToken.connect(alice).getFunction('approve')(userAccount.getAddress(), 100000) + ).wait(); const nativeApproveTx = await ( - await nativeToken.connect(alice).getFunction("approve")(userAccount.address, 100000) + await nativeToken.connect(alice).getFunction('approve')(userAccount.address, 100000) ).wait(); if (logGasCosts) { console.log('ERC20 native approve gas: ' + nativeApproveTx.gasUsed.toString()); @@ -345,10 +402,18 @@ describe('EVM equivalence contract', () => { dumpOpcodeLogs(evmApproveTx.transactionHash, alice.provider); const evmTransferFromTx = await ( - await evmToken.connect(userAccount).getFunction("transferFrom")(alice.address, userAccount.address, 100000) + await evmToken.connect(userAccount).getFunction('transferFrom')( + alice.address, + userAccount.address, + 100000 + ) ).wait(); const nativeTransferFromTx = await ( - await nativeToken.connect(userAccount).getFunction("transferFrom")(alice.address, userAccount.address, 100000) + await nativeToken.connect(userAccount).getFunction('transferFrom')( + alice.address, + userAccount.address, + 100000 + ) ).wait(); if (logGasCosts) { console.log('ERC20 native transferFrom gas: ' + nativeTransferFromTx.gasUsed.toString()); @@ -356,8 +421,8 @@ describe('EVM equivalence contract', () => { } dumpOpcodeLogs(evmTransferFromTx.transactionHash, alice.provider); - expect((await evmToken.getFunction("balanceOf")(alice.address)).toString()).toEqual('900000'); - expect((await evmToken.getFunction("balanceOf")(userAccount.address)).toString()).toEqual('100000'); + expect((await evmToken.getFunction('balanceOf')(alice.address)).toString()).toEqual('900000'); + expect((await evmToken.getFunction('balanceOf')(userAccount.address)).toString()).toEqual('100000'); }); }); @@ -397,13 +462,19 @@ describe('EVM equivalence contract', () => { ); const evmPairReceipt = await ( - await evmUniswapFactory.getFunction("createPair")(evmToken1.getAddress(), evmToken2.getAddress()) + await evmUniswapFactory.getFunction('createPair')(evmToken1.getAddress(), evmToken2.getAddress()) ).wait(); const nativePairReceipt = await ( - await nativeUniswapFactory.getFunction("createPair")(evmToken1.getAddress(), evmToken2.getAddress()) + await nativeUniswapFactory.getFunction('createPair')(evmToken1.getAddress(), evmToken2.getAddress()) ).wait(); - dumpOpcodeLogs(evmUniswapFactory.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(), alice.provider); + dumpOpcodeLogs( + evmUniswapFactory.deploymentTransaction()?.hash ?? + (() => { + throw new Error('Deployment transaction has failed'); + })(), + alice.provider + ); dumpOpcodeLogs(evmPairReceipt.transactionHash, alice.provider); const evmUniswapPairFactory = getEVMContractFactory(alice, artifacts.uniswapV2Pair); @@ -424,30 +495,39 @@ describe('EVM equivalence contract', () => { nativePairReceipt.logs.find((log: any) => log.topics[0] === NEW_PAIR_TOPIC).data )[0] ); - const token1IsFirst = (await evmUniswapPair.getFunction("token0")()).toString() === evmToken1.getAddress(); + const token1IsFirst = (await evmUniswapPair.getFunction('token0')()).toString() === evmToken1.getAddress(); if (!token1IsFirst) { [evmToken1, evmToken2] = [evmToken2, evmToken1]; } - await (await evmToken1.getFunction("transfer")(evmUniswapPair.getAddress(), 100000)).wait(); - await (await evmToken1.getFunction("transfer")(nativeUniswapPair.getAddress(), 100000)).wait(); - await (await evmToken2.getFunction("transfer")(evmUniswapPair.getAddress(), 100000)).wait(); - await (await evmToken2.getFunction("transfer")(nativeUniswapPair.getAddress(), 100000)).wait(); + await (await evmToken1.getFunction('transfer')(evmUniswapPair.getAddress(), 100000)).wait(); + await (await evmToken1.getFunction('transfer')(nativeUniswapPair.getAddress(), 100000)).wait(); + await (await evmToken2.getFunction('transfer')(evmUniswapPair.getAddress(), 100000)).wait(); + await (await evmToken2.getFunction('transfer')(nativeUniswapPair.getAddress(), 100000)).wait(); // Only log the first deployment if (logGasCosts && !deployLogged) { - let native_hash = nativeUniswapFactory.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(); - let native_transanction_receipt = (await alice.provider.getTransactionReceipt(native_hash)) ?? (() => { throw new Error('Deployment transaction has failed'); })(); - let evm_hash = evmUniswapFactory.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })(); - let evm_transanction_receipt = (await alice.provider.getTransactionReceipt(evm_hash)) ?? (() => { throw new Error('Deployment transaction has failed'); })(); - console.log( - 'Uniswap Factory native deploy gas: ' + - native_transanction_receipt - .gasUsed - ); - console.log( - 'Uniswap Factory evm deploy gas: ' + - evm_transanction_receipt.gasUsed - ); + let native_hash = + nativeUniswapFactory.deploymentTransaction()?.hash ?? + (() => { + throw new Error('Deployment transaction has failed'); + })(); + let native_transanction_receipt = + (await alice.provider.getTransactionReceipt(native_hash)) ?? + (() => { + throw new Error('Deployment transaction has failed'); + })(); + let evm_hash = + evmUniswapFactory.deploymentTransaction()?.hash ?? + (() => { + throw new Error('Deployment transaction has failed'); + })(); + let evm_transanction_receipt = + (await alice.provider.getTransactionReceipt(evm_hash)) ?? + (() => { + throw new Error('Deployment transaction has failed'); + })(); + console.log('Uniswap Factory native deploy gas: ' + native_transanction_receipt.gasUsed); + console.log('Uniswap Factory evm deploy gas: ' + evm_transanction_receipt.gasUsed); console.log('Uniswap Pair native create gas: ' + nativePairReceipt.gasUsed); console.log('Uniswap Pair evm create gas: ' + evmPairReceipt.gasUsed); deployLogged = true; @@ -455,32 +535,40 @@ describe('EVM equivalence contract', () => { }); test('mint, swap, and burn should work', async () => { - const evmMintReceipt = await (await evmUniswapPair.getFunction("mint")(alice.address)).wait(); - const nativeMintReceipt = await (await nativeUniswapPair.getFunction("mint")(alice.address)).wait(); + const evmMintReceipt = await (await evmUniswapPair.getFunction('mint')(alice.address)).wait(); + const nativeMintReceipt = await (await nativeUniswapPair.getFunction('mint')(alice.address)).wait(); dumpOpcodeLogs(evmMintReceipt.transactionHash, alice.provider); - await (await evmToken1.getFunction("transfer")(evmUniswapPair.getAddress(), 10000)).wait(); - await (await evmToken1.getFunction("transfer")(nativeUniswapPair.getAddress(), 10000)).wait(); - const evmSwapReceipt = await (await evmUniswapPair.getFunction("swap")(0, 5000, alice.address, '0x')).wait(); - const nativeSwapReceipt = await (await nativeUniswapPair.getFunction("swap")(0, 5000, alice.address, '0x')).wait(); + await (await evmToken1.getFunction('transfer')(evmUniswapPair.getAddress(), 10000)).wait(); + await (await evmToken1.getFunction('transfer')(nativeUniswapPair.getAddress(), 10000)).wait(); + const evmSwapReceipt = await ( + await evmUniswapPair.getFunction('swap')(0, 5000, alice.address, '0x') + ).wait(); + const nativeSwapReceipt = await ( + await nativeUniswapPair.getFunction('swap')(0, 5000, alice.address, '0x') + ).wait(); dumpOpcodeLogs(evmSwapReceipt.transactionHash, alice.provider); const evmLiquidityTransfer = await ( - await evmUniswapPair.getFunction("transfer")( + await evmUniswapPair.getFunction('transfer')( evmUniswapPair.getAddress(), - (await evmUniswapPair.getFunction("balanceOf")(alice.address)).toString() + (await evmUniswapPair.getFunction('balanceOf')(alice.address)).toString() ) ).wait(); await ( - await nativeUniswapPair.getFunction("transfer")( + await nativeUniswapPair.getFunction('transfer')( nativeUniswapPair.getAddress(), - (await nativeUniswapPair.getFunction("balanceOf")(alice.address)).toString() + (await nativeUniswapPair.getFunction('balanceOf')(alice.address)).toString() ) ).wait(); - const evmBurnReceipt = await (await evmUniswapPair.getFunction("burn")(alice.address)).wait(); - const nativeBurnReceipt = await (await nativeUniswapPair.getFunction("burn")(alice.address)).wait(); - expect(Number((await evmToken1.getFunction("balanceOf")(alice.address)).toString())).toBeGreaterThanOrEqual(990000); - expect(Number((await evmToken2.getFunction("balanceOf")(alice.address)).toString())).toBeGreaterThanOrEqual(990000); + const evmBurnReceipt = await (await evmUniswapPair.getFunction('burn')(alice.address)).wait(); + const nativeBurnReceipt = await (await nativeUniswapPair.getFunction('burn')(alice.address)).wait(); + expect(Number((await evmToken1.getFunction('balanceOf')(alice.address)).toString())).toBeGreaterThanOrEqual( + 990000 + ); + expect(Number((await evmToken2.getFunction('balanceOf')(alice.address)).toString())).toBeGreaterThanOrEqual( + 990000 + ); if (logGasCosts) { console.log('UniswapV2Pair native mint gas: ' + nativeMintReceipt.gasUsed); @@ -498,16 +586,23 @@ describe('EVM equivalence contract', () => { const gasCallerFactory = getEVMContractFactory(alice, artifacts.gasCaller); const gasCallerContract = await gasCallerFactory.deploy(); await gasCallerContract.deploymentTransaction()?.wait(); - await alice.provider.getTransactionReceipt(gasCallerContract.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); })()); + await alice.provider.getTransactionReceipt( + gasCallerContract.deploymentTransaction()?.hash ?? + (() => { + throw new Error('Deployment transaction has failed'); + })() + ); const uniswapContract = await deploygasCallerContract(alice, artifacts.uniswapFallback); - await (await uniswapContract.getFunction("setUniswapAddress")(evmUniswapPair.getAddress())).wait(); - await (await uniswapContract.getFunction("setAliceAddress")(alice.address)).wait(); + await (await uniswapContract.getFunction('setUniswapAddress')(evmUniswapPair.getAddress())).wait(); + await (await uniswapContract.getFunction('setAliceAddress')(alice.address)).wait(); - await (await evmToken1.getFunction("transfer")(evmUniswapPair.getAddress(), 10000)).wait(); - await (await evmToken1.getFunction("transfer")(uniswapContract.getAddress(), 10000)).wait(); + await (await evmToken1.getFunction('transfer')(evmUniswapPair.getAddress(), 10000)).wait(); + await (await evmToken1.getFunction('transfer')(uniswapContract.getAddress(), 10000)).wait(); - let result = (await gasCallerContract.getFunction("callAndGetGas").staticCall(uniswapContract.getAddress())).toString(); + let result = ( + await gasCallerContract.getFunction('callAndGetGas').staticCall(uniswapContract.getAddress()) + ).toString(); const expected_gas = '165939'; // Gas cost when run with solidity interpreter expect(result).toEqual(expected_gas); @@ -643,8 +738,16 @@ async function assertStoredBytecodeHash( expectedStoredHash: string ): Promise { const ACCOUNT_CODE_STORAGE_ADDRESS = '0x0000000000000000000000000000000000008002'; - let runner = deployer.runner ?? (() => { throw new Error('Runner get failed'); })(); - let provider = runner.provider ?? (() => { throw new Error('Provider get failed'); })(); + let runner = + deployer.runner ?? + (() => { + throw new Error('Runner get failed'); + })(); + let provider = + runner.provider ?? + (() => { + throw new Error('Provider get failed'); + })(); const storedCodeHash = await provider.getStorage( ACCOUNT_CODE_STORAGE_ADDRESS, ethers.zeroPadValue(deployedAddress, 32) @@ -656,7 +759,7 @@ async function assertStoredBytecodeHash( async function assertCreatedCorrectly( deployer: zksync.Contract, deployedAddress: string, - expectedEVMBytecode: string, + expectedEVMBytecode: string ): Promise { const expectedStoredHash = getSha256BlobHash(expectedEVMBytecode); await assertStoredBytecodeHash(deployer, deployedAddress, expectedStoredHash); @@ -886,7 +989,11 @@ const opcodeDataDump: any = {}; }); async function dumpOpcodeLogs(hash: string, provider: zksync.Provider): Promise { - let tx_receipt = (await provider.getTransactionReceipt(hash)) ?? (() => { throw new Error('Get Transaction Receipt has failed'); })(); + let tx_receipt = + (await provider.getTransactionReceipt(hash)) ?? + (() => { + throw new Error('Get Transaction Receipt has failed'); + })(); const logs = tx_receipt.logs; logs.forEach((log) => { if (log.topics[0] === '0x63307236653da06aaa7e128a306b128c594b4cf3b938ef212975ed10dad17515') { From 0e95d8d7a2884d1a8d9e1e2c38ccddb48e884728 Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Mon, 19 Aug 2024 18:49:22 -0300 Subject: [PATCH 25/76] Fix some tests --- core/tests/ts-integration/package.json | 3 ++- .../tests/evm-contracts.test.ts | 18 +++++++++++------- etc/env/base/chain.toml | 2 +- etc/env/base/contracts.toml | 4 ++-- .../fee_estimate.yul/fee_estimate.yul.zbin | Bin 76256 -> 76064 bytes .../gas_test.yul/gas_test.yul.zbin | Bin 72352 -> 72160 bytes .../playground_batch.yul.zbin | Bin 76448 -> 76256 bytes .../proved_batch.yul/proved_batch.yul.zbin | Bin 72864 -> 72672 bytes yarn.lock | 13 +++++++++++++ 9 files changed, 29 insertions(+), 11 deletions(-) diff --git a/core/tests/ts-integration/package.json b/core/tests/ts-integration/package.json index e6c414bbaafe..2f438a920cb0 100644 --- a/core/tests/ts-integration/package.json +++ b/core/tests/ts-integration/package.json @@ -35,6 +35,7 @@ "yaml": "^2.4.2", "zksync-web3": "^0.15.5", "csv-parser": "^3.0.0", - "csv-writer": "^1.6.0" + "csv-writer": "^1.6.0", + "solc": "0.8.20" } } diff --git a/core/tests/ts-integration/tests/evm-contracts.test.ts b/core/tests/ts-integration/tests/evm-contracts.test.ts index 8c876a1b76b4..3f188bc459fd 100644 --- a/core/tests/ts-integration/tests/evm-contracts.test.ts +++ b/core/tests/ts-integration/tests/evm-contracts.test.ts @@ -85,7 +85,7 @@ describe('EVM equivalence contract', () => { await gasCallerContract.getFunction('callAndGetGas').staticCall(creatorContract.getAddress()) ).toString(); - const expected_gas = '70601'; // Gas cost when run with solidity interpreter + const expected_gas = '70598'; // Gas cost when run with solidity interpreter - 3 (We have some changes that are needed) expect(result).toEqual(expected_gas); }); @@ -106,7 +106,7 @@ describe('EVM equivalence contract', () => { describe('Contract creation', () => { describe('Create from EOA', () => { test('Should create evm contract from EOA and allow view and non-view calls', async () => { - const args = [1]; + const args = 1; const factory = getEVMContractFactory(alice, artifacts.counter); const contract = await factory.deploy(args); await contract.deploymentTransaction()?.wait(); @@ -162,16 +162,18 @@ describe('EVM equivalence contract', () => { failReason = e.reason; } - expect(failReason).toBe('transaction failed'); + expect(failReason).toBe(null); }); test('Should NOT create evm contract from EOA when `to` is address(0x0)', async () => { - const args = [1]; + const args = 1; const factory = getEVMContractFactory(alice, artifacts.counter); const transaction = await factory.getDeployTransaction(args); + console.log(transaction); let dep_transaction = ethers.Transaction.from(transaction); dep_transaction.to = '0x0000000000000000000000000000000000000000'; + console.log(dep_transaction); const result = await (await alice.sendTransaction(dep_transaction)).wait(); const expectedAddressCreate = ethers.getCreateAddress({ @@ -213,7 +215,7 @@ describe('EVM equivalence contract', () => { describe('Inter-contract calls', () => { test('Calls (read/write) between EVM contracts should work correctly', async () => { - const args = [1]; + const args = 1; const counterFactory = getEVMContractFactory(alice, artifacts.counter); const counterContract = await counterFactory.deploy(args); @@ -281,7 +283,7 @@ describe('EVM equivalence contract', () => { }); test('Should revert correctly', async () => { - const args = [1]; + const args = 1; const counterFactory = getEVMContractFactory(alice, artifacts.counter); const counterContract = await counterFactory.deploy(args); @@ -294,7 +296,7 @@ describe('EVM equivalence contract', () => { })(), alice.provider ); - + let errorString; try { @@ -302,6 +304,8 @@ describe('EVM equivalence contract', () => { } catch (e: any) { errorString = e.reason; } + console.log(errorString); + expect(errorString).toEqual('This method always reverts'); }); }); diff --git a/etc/env/base/chain.toml b/etc/env/base/chain.toml index 58fca8eff96e..5f1a9a1603d2 100644 --- a/etc/env/base/chain.toml +++ b/etc/env/base/chain.toml @@ -90,7 +90,7 @@ fee_model_version = "V2" validation_computational_gas_limit = 300000 save_call_traces = true -bootloader_hash = "0x010008e54ed4ed2784197a39309255faa062e7f130424f0075bfd7ff11eb22d6" +bootloader_hash = "0x010008df0ef90cb578022657652c9ac6339748e080ea22d185ba9a07e0238a28" default_aa_hash = "0x0100058deb36e1f2eeb48bf3846d0e8eb38e9176754b73116bb41a472459a4dd" evm_simulator_hash = "0x01000f197081a9906cc411d0698c4961aeb5c74877f37f7071681da6e8ef3f31" diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index 47f1e57fea13..65c18b320687 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -26,8 +26,8 @@ RECURSION_NODE_LEVEL_VK_HASH = "0x1186ec268d49f1905f8d9c1e9d39fc33e98c74f91d91a2 RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc8966504064f1f6ba3f1ba863210" RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" -GENESIS_ROOT = "0xf511c8e55095e444bd86bc2813689935b2098edda19aa7f9d080b506e2cfc69f" -GENESIS_BATCH_COMMITMENT = "0x7c46546a6d6268914e6ee58b51a38fa44dcc707efadf8af3e68e5f3b3a28e0af" +GENESIS_ROOT = "0xd2b1a071a2da0f92d65e58e7db4743273963c1b8fa6c6a7b565e04128b5441f3" +GENESIS_BATCH_COMMITMENT = "0x300898d4ff7fb555d3ab3eb669e1d0d75efdd32e68a5a61dd4198b1ea3a1e53b" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "56" diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin index 785b3b1fc1768b9dc0d9cca3605b7e7b001f9470..a48d89ebe7ff2c5640d3c15271298e7689b7a370 100644 GIT binary patch literal 76064 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 diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/gas_test.yul/gas_test.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/gas_test.yul/gas_test.yul.zbin index 76009d66d53fc019df60971cf1614aaf85d07a04..5c325c1ce13b4190a2613e3f85744804d315ed13 100644 GIT binary patch literal 72160 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 Drv`(VLPEsH=T3c&J*p_5T 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 diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/playground_batch.yul/playground_batch.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/playground_batch.yul/playground_batch.yul.zbin index 286052468b316f596234fc492881b0bc0087229a..60749b415b87a731d7f7a937c28b9fd6b68a1c18 100644 GIT binary patch literal 76256 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 diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/proved_batch.yul/proved_batch.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/proved_batch.yul/proved_batch.yul.zbin index 56c5f67812c8874f08130f68645bb4fb84b04f8a..ca866fc73665a8b3fbfbc1fe83e859690793ca3c 100644 GIT binary patch literal 72672 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 VUUPGP|BLTmcgqc@zVI{m|9^8+93%h$ diff --git a/yarn.lock b/yarn.lock index be6687ce6ed8..fb00befa2ade 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9915,6 +9915,19 @@ solc@0.8.17: semver "^5.5.0" tmp "0.0.33" +solc@0.8.20: + version "0.8.20" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.20.tgz#b49151cf5ecc8de088d3d32b0afb607b3522ba8d" + integrity sha512-fPRnGspIEqmhu63RFO3pc79sLA7ZmzO0Uy0L5l6hEt2wAsq0o7UV6pXkAp3Mfv9IBhg7Px/oTu3a+y4gs3BWrQ== + dependencies: + command-exists "^1.2.8" + commander "^8.1.0" + follow-redirects "^1.12.1" + js-sha3 "0.8.0" + memorystream "^0.3.1" + semver "^5.5.0" + tmp "0.0.33" + solc@0.8.26: version "0.8.26" resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.26.tgz#afc78078953f6ab3e727c338a2fefcd80dd5b01a" From 0c939090e0b2e6d0677dd4eab960c915f2a7b4c9 Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Mon, 19 Aug 2024 18:53:08 -0300 Subject: [PATCH 26/76] Format code --- contracts | 2 +- core/tests/ts-integration/tests/evm-contracts.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts b/contracts index b6a629f9b55b..af2a2c9113f9 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit b6a629f9b55b2b59409e086469c8cdff0c4bd56c +Subproject commit af2a2c9113f9d6510f45ee2ae08d29d623d03c99 diff --git a/core/tests/ts-integration/tests/evm-contracts.test.ts b/core/tests/ts-integration/tests/evm-contracts.test.ts index 3f188bc459fd..af012119b9ec 100644 --- a/core/tests/ts-integration/tests/evm-contracts.test.ts +++ b/core/tests/ts-integration/tests/evm-contracts.test.ts @@ -296,7 +296,7 @@ describe('EVM equivalence contract', () => { })(), alice.provider ); - + let errorString; try { From 167c58132c0d2d56b4274945dfd0661368242c11 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 20 Aug 2024 00:42:12 -0300 Subject: [PATCH 27/76] Use EVM simulator name for consistency --- core/lib/contracts/src/lib.rs | 2 +- core/lib/multivm/src/versions/vm_fast/vm.rs | 8 +++++++- core/lib/types/src/commitment/mod.rs | 8 -------- core/lib/types/src/system_contracts.rs | 8 ++++---- core/lib/vm_interface/src/storage/in_memory.rs | 4 ++-- 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index 8c93cd277a99..792ba24558f9 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -288,7 +288,7 @@ fn read_zbin_bytecode_from_path(bytecode_path: PathBuf) -> Vec { .unwrap_or_else(|err| panic!("Can't read .zbin bytecode at {:?}: {}", bytecode_path, err)) } /// Hash of code and code which consists of 32 bytes words -#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct SystemContractCode { pub code: Vec, pub hash: H256, diff --git a/core/lib/multivm/src/versions/vm_fast/vm.rs b/core/lib/multivm/src/versions/vm_fast/vm.rs index a9b2fcd605c9..d996f062aedb 100644 --- a/core/lib/multivm/src/versions/vm_fast/vm.rs +++ b/core/lib/multivm/src/versions/vm_fast/vm.rs @@ -357,6 +357,12 @@ impl Vm { .hash .into(); + let evm_simulator_code_hash = system_env + .base_system_smart_contracts + .evm_simulator + .hash + .into(); + let program_cache = HashMap::from([convert_system_contract_code( &system_env.base_system_smart_contracts.default_aa, false, @@ -375,7 +381,7 @@ impl Vm { Settings { default_aa_code_hash, // this will change after 1.5 - evm_interpreter_code_hash: default_aa_code_hash, + evm_interpreter_code_hash: evm_simulator_code_hash, hook_address: get_vm_hook_position(VM_VERSION) * 32, }, ); diff --git a/core/lib/types/src/commitment/mod.rs b/core/lib/types/src/commitment/mod.rs index b35a2cb11f80..e0c51925c694 100644 --- a/core/lib/types/src/commitment/mod.rs +++ b/core/lib/types/src/commitment/mod.rs @@ -478,15 +478,7 @@ impl L1BatchMetaParameters { result.push(self.zkporter_is_available as u8); result.extend(self.bootloader_code_hash.as_bytes()); result.extend(self.default_aa_code_hash.as_bytes()); - // result.extend(self.evm_simulator_code_hash.as_bytes()); - - // if self - // .protocol_version - // .map_or(false, |ver| ver.is_post_1_5_0()) - // { - // EVM simulator hash for now is the same as the default AA hash. result.extend(self.evm_simulator_code_hash.as_bytes()); - // } result } diff --git a/core/lib/types/src/system_contracts.rs b/core/lib/types/src/system_contracts.rs index ed6e0c879901..74a91b29f241 100644 --- a/core/lib/types/src/system_contracts.rs +++ b/core/lib/types/src/system_contracts.rs @@ -1,4 +1,4 @@ -use std::{env, path::PathBuf}; +use std::path::PathBuf; use once_cell::sync::Lazy; use zksync_basic_types::{AccountTreeId, Address, H256, U256}; @@ -178,7 +178,7 @@ static SYSTEM_CONTRACT_LIST: [(&str, &str, Address, ContractLanguage); 26] = [ ), ]; -static EVM_INTERPRETER_HASH: Lazy = Lazy::new(|| { +static EVM_SIMULATOR_HASH: Lazy = Lazy::new(|| { hash_bytecode(&read_sys_contract_bytecode( "", "EvmInterpreter", @@ -186,8 +186,8 @@ static EVM_INTERPRETER_HASH: Lazy = Lazy::new(|| { )) }); -pub fn get_evm_interpreter_hash() -> H256 { - EVM_INTERPRETER_HASH.clone() +pub fn get_evm_simulator_hash() -> H256 { + EVM_SIMULATOR_HASH.clone() } static SYSTEM_CONTRACTS: Lazy> = Lazy::new(|| { diff --git a/core/lib/vm_interface/src/storage/in_memory.rs b/core/lib/vm_interface/src/storage/in_memory.rs index 9d523fd3336a..cf7cf0a85a13 100644 --- a/core/lib/vm_interface/src/storage/in_memory.rs +++ b/core/lib/vm_interface/src/storage/in_memory.rs @@ -3,7 +3,7 @@ use std::collections::{hash_map::Entry, BTreeMap, HashMap}; use zksync_types::{ block::DeployedContract, get_code_key, get_deployer_key, get_known_code_key, get_system_context_init_logs, - system_contracts::{get_evm_interpreter_hash, get_system_smart_contracts}, + system_contracts::{get_evm_simulator_hash, get_system_smart_contracts}, L2ChainId, StorageKey, StorageLog, StorageValue, H256, U256, }; use zksync_utils::u256_to_h256; @@ -66,7 +66,7 @@ impl InMemoryStorage { .chain(system_context_init_log) .chain(vec![StorageLog::new_write_log( get_deployer_key(u256_to_h256(1.into())), - get_evm_interpreter_hash(), + get_evm_simulator_hash(), )]) .filter_map(|log| (log.is_write()).then_some((log.key, log.value))) .collect(); From cdcf570a4f6f221239c2285ae507ff698347654c Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Tue, 20 Aug 2024 10:53:56 -0300 Subject: [PATCH 28/76] Fix remaining tests --- .../tests/evm-contracts.test.ts | 101 ++---------------- 1 file changed, 11 insertions(+), 90 deletions(-) diff --git a/core/tests/ts-integration/tests/evm-contracts.test.ts b/core/tests/ts-integration/tests/evm-contracts.test.ts index af012119b9ec..75ed265094b2 100644 --- a/core/tests/ts-integration/tests/evm-contracts.test.ts +++ b/core/tests/ts-integration/tests/evm-contracts.test.ts @@ -88,19 +88,6 @@ describe('EVM equivalence contract', () => { const expected_gas = '70598'; // Gas cost when run with solidity interpreter - 3 (We have some changes that are needed) expect(result).toEqual(expected_gas); }); - - xtest("Should compare gas against opcode test fallback contract's call", async () => { - const gasCallerContract = await deploygasCallerContract(alice, artifacts.gasCaller); - - const counterContract = await deploygasCallerContract(alice, artifacts.opcodeTestFallback); - - let result = ( - await gasCallerContract.getFunction('callAndGetGas').staticCall(counterContract.getAddress()) - ).toString(); - - const expected_gas = '34763'; // Gas cost when run with solidity interpreter - expect(result).toEqual(expected_gas); - }); }); describe('Contract creation', () => { @@ -169,12 +156,14 @@ describe('EVM equivalence contract', () => { const args = 1; const factory = getEVMContractFactory(alice, artifacts.counter); - const transaction = await factory.getDeployTransaction(args); - console.log(transaction); - let dep_transaction = ethers.Transaction.from(transaction); - dep_transaction.to = '0x0000000000000000000000000000000000000000'; + const { data, ...rest } = await factory.getDeployTransaction(args); + const dep_transaction = { + ...rest, + to: '0x0000000000000000000000000000000000000000', + chainId: alice.provider._network.chainId, + data + }; console.log(dep_transaction); - const result = await (await alice.sendTransaction(dep_transaction)).wait(); const expectedAddressCreate = ethers.getCreateAddress({ from: alice.address, @@ -183,33 +172,6 @@ describe('EVM equivalence contract', () => { await assertContractNotCreated(deployer, expectedAddressCreate); }); - - // test('Should SENDALL', async () => { - // const salt = ethers.utils.randomBytes(32); - // const selfDestructBytecode = '0x' + artifacts.selfDestruct.evm.bytecode.object; - // const hash = ethers.utils.keccak256(selfDestructBytecode); - - // const selfDestructFactory = getEVMContractFactory(alice, artifacts.selfDestruct); - // const selfDestructAddress = ethers.utils.getCreate2Address(evmCreateTester.address, salt, hash); - // const selfDestruct = selfDestructFactory.attach(selfDestructAddress); - // const beneficiary = testMaster.newEmptyAccount(); - - // await (await evmCreateTester.create2(salt, selfDestructBytecode, { value: 1000 })).wait(); - // expect((await alice.provider.getBalance(selfDestructAddress)).toNumber()).toBe(1000); - - // await (await selfDestruct.destroy(beneficiary.address)).wait(); - // expect((await alice.provider.getBalance(beneficiary.address)).toNumber()).toBe(1000); - - // let failReason; - - // try { - // await (await evmCreateTester.create2(salt, selfDestructBytecode)).wait(); - // } catch (e: any) { - // failReason = e.error.reason; - // } - - // expect(failReason).toBe("execution reverted: Can't create on existing contract address"); - // }); }); }); @@ -238,18 +200,18 @@ describe('EVM equivalence contract', () => { ); expect( - (await proxyCallerContract.getFunction('proxyGet')(counterContract.getAddress())).toString() + (await proxyCallerContract.getFunction('proxyGet')(await counterContract.getAddress())).toString() ).toEqual('1'); - await (await proxyCallerContract.getFunction('executeIncrememt')(counterContract.getAddress(), 1)).wait(); + await (await proxyCallerContract.getFunction('executeIncrememt')(await counterContract.getAddress(), 1)).wait(); expect( - (await proxyCallerContract.getFunction('proxyGet')(counterContract.getAddress())).toString() + (await proxyCallerContract.getFunction('proxyGet')(await counterContract.getAddress())).toString() ).toEqual('2'); expect( ( - await proxyCallerContract.getFunction('proxyGetBytes').staticCall(counterContract.getAddress()) + await proxyCallerContract.getFunction('proxyGetBytes').staticCall(await counterContract.getAddress()) ).toString() ).toEqual('0x54657374696e67'); }); @@ -259,14 +221,6 @@ describe('EVM equivalence contract', () => { const creatorContract = await creatorFactory.deploy(); await creatorContract.deploymentTransaction()?.wait(); - dumpOpcodeLogs( - creatorContract.deploymentTransaction()?.hash ?? - (() => { - throw new Error('Deployment transaction has failed'); - })(), - alice.provider - ); - const nonce = 1; const runtimeBytecode = await creatorContract.getFunction('getCreationRuntimeCode')(); @@ -277,7 +231,6 @@ describe('EVM equivalence contract', () => { }); const result = await (await creatorContract.getFunction('create')()).wait(); - dumpOpcodeLogs(result.transactionHash, alice.provider); await assertCreatedCorrectly(deployer, expectedAddress, runtimeBytecode); }); @@ -289,14 +242,6 @@ describe('EVM equivalence contract', () => { const counterContract = await counterFactory.deploy(args); await counterContract.deploymentTransaction()?.wait(); - dumpOpcodeLogs( - counterContract.deploymentTransaction()?.hash ?? - (() => { - throw new Error('Deployment transaction has failed'); - })(), - alice.provider - ); - let errorString; try { @@ -304,7 +249,6 @@ describe('EVM equivalence contract', () => { } catch (e: any) { errorString = e.reason; } - console.log(errorString); expect(errorString).toEqual('This method always reverts'); }); @@ -323,13 +267,6 @@ describe('EVM equivalence contract', () => { await evmToken.deploymentTransaction()?.wait(); nativeToken = await deployContract(alice, contracts.erc20, []); - dumpOpcodeLogs( - evmToken.deploymentTransaction()?.hash ?? - (() => { - throw new Error('Deployment transaction has failed'); - })(), - alice.provider - ); userAccount = testMaster.newEmptyAccount(); // Only log the first deployment if (logGasCosts && !deployLogged) { @@ -385,7 +322,6 @@ describe('EVM equivalence contract', () => { console.log('ERC20 native transfer gas: ' + nativeTransferTx.gasUsed.toString()); console.log('ERC20 evm transfer gas: ' + evmTransferTx.gasUsed.toString()); } - dumpOpcodeLogs(evmTransferTx.transactionHash, alice.provider); expect((await evmToken.getFunction('balanceOf')(alice.address)).toString()).toEqual('900000'); expect((await evmToken.getFunction('balanceOf')(userAccount.address)).toString()).toEqual('100000'); @@ -403,7 +339,6 @@ describe('EVM equivalence contract', () => { console.log('ERC20 native approve gas: ' + nativeApproveTx.gasUsed.toString()); console.log('ERC20 evm approve gas: ' + evmApproveTx.gasUsed.toString()); } - dumpOpcodeLogs(evmApproveTx.transactionHash, alice.provider); const evmTransferFromTx = await ( await evmToken.connect(userAccount).getFunction('transferFrom')( @@ -423,7 +358,6 @@ describe('EVM equivalence contract', () => { console.log('ERC20 native transferFrom gas: ' + nativeTransferFromTx.gasUsed.toString()); console.log('ERC20 evm transferFrom gas: ' + evmTransferFromTx.gasUsed.toString()); } - dumpOpcodeLogs(evmTransferFromTx.transactionHash, alice.provider); expect((await evmToken.getFunction('balanceOf')(alice.address)).toString()).toEqual('900000'); expect((await evmToken.getFunction('balanceOf')(userAccount.address)).toString()).toEqual('100000'); @@ -472,14 +406,6 @@ describe('EVM equivalence contract', () => { const nativePairReceipt = await ( await nativeUniswapFactory.getFunction('createPair')(evmToken1.getAddress(), evmToken2.getAddress()) ).wait(); - dumpOpcodeLogs( - evmUniswapFactory.deploymentTransaction()?.hash ?? - (() => { - throw new Error('Deployment transaction has failed'); - })(), - alice.provider - ); - dumpOpcodeLogs(evmPairReceipt.transactionHash, alice.provider); const evmUniswapPairFactory = getEVMContractFactory(alice, artifacts.uniswapV2Pair); const nativeUniswapPairFactory = new zksync.ContractFactory( @@ -541,7 +467,6 @@ describe('EVM equivalence contract', () => { test('mint, swap, and burn should work', async () => { const evmMintReceipt = await (await evmUniswapPair.getFunction('mint')(alice.address)).wait(); const nativeMintReceipt = await (await nativeUniswapPair.getFunction('mint')(alice.address)).wait(); - dumpOpcodeLogs(evmMintReceipt.transactionHash, alice.provider); await (await evmToken1.getFunction('transfer')(evmUniswapPair.getAddress(), 10000)).wait(); await (await evmToken1.getFunction('transfer')(nativeUniswapPair.getAddress(), 10000)).wait(); @@ -551,7 +476,6 @@ describe('EVM equivalence contract', () => { const nativeSwapReceipt = await ( await nativeUniswapPair.getFunction('swap')(0, 5000, alice.address, '0x') ).wait(); - dumpOpcodeLogs(evmSwapReceipt.transactionHash, alice.provider); const evmLiquidityTransfer = await ( await evmUniswapPair.getFunction('transfer')( @@ -582,8 +506,6 @@ describe('EVM equivalence contract', () => { console.log('UniswapV2Pair native burn gas: ' + nativeBurnReceipt.gasUsed); console.log('UniswapV2Pair evm burn gas: ' + evmBurnReceipt.gasUsed); } - dumpOpcodeLogs(evmLiquidityTransfer.transactionHash, alice.provider); - dumpOpcodeLogs(evmBurnReceipt.transactionHash, alice.provider); }); test("Should compare gas against uniswap fallback contract's call", async () => { @@ -625,7 +547,6 @@ describe('EVM equivalence contract', () => { // test('should successfully execute bulk opcode test', async () => { // console.log(await deployer.evmCode(opcodeTest.address)) // // const receipt = await (await opcodeTest.execute()).wait() - // // dumpOpcodeLogs(receipt.transactionHash, alice.provider); // }); // }); From 91bf9ca1a05b5d01c0421398472731bd8a8b0b3f Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Tue, 20 Aug 2024 10:54:16 -0300 Subject: [PATCH 29/76] Format code --- core/tests/ts-integration/tests/evm-contracts.test.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/tests/ts-integration/tests/evm-contracts.test.ts b/core/tests/ts-integration/tests/evm-contracts.test.ts index 75ed265094b2..279fdd87bbb0 100644 --- a/core/tests/ts-integration/tests/evm-contracts.test.ts +++ b/core/tests/ts-integration/tests/evm-contracts.test.ts @@ -203,7 +203,9 @@ describe('EVM equivalence contract', () => { (await proxyCallerContract.getFunction('proxyGet')(await counterContract.getAddress())).toString() ).toEqual('1'); - await (await proxyCallerContract.getFunction('executeIncrememt')(await counterContract.getAddress(), 1)).wait(); + await ( + await proxyCallerContract.getFunction('executeIncrememt')(await counterContract.getAddress(), 1) + ).wait(); expect( (await proxyCallerContract.getFunction('proxyGet')(await counterContract.getAddress())).toString() @@ -211,7 +213,9 @@ describe('EVM equivalence contract', () => { expect( ( - await proxyCallerContract.getFunction('proxyGetBytes').staticCall(await counterContract.getAddress()) + await proxyCallerContract + .getFunction('proxyGetBytes') + .staticCall(await counterContract.getAddress()) ).toString() ).toEqual('0x54657374696e67'); }); From c40ac2d566ec1801d950716e96d18b68e92ff9a9 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 20 Aug 2024 11:16:09 -0300 Subject: [PATCH 30/76] Remove evm debug tracer --- .../vm_latest/tracers/default_tracers.rs | 8 +- .../vm_latest/tracers/evm_debug_tracer.rs | 117 ------------------ .../src/versions/vm_latest/tracers/mod.rs | 2 - core/node/eth_watch/src/client.rs | 1 - 4 files changed, 2 insertions(+), 126 deletions(-) delete mode 100644 core/lib/multivm/src/versions/vm_latest/tracers/evm_debug_tracer.rs diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs b/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs index 8fcbc83da7cd..661ae5bc2ecf 100755 --- a/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs @@ -13,7 +13,7 @@ use zk_evm_1_5_0::{ zkevm_opcode_defs::{decoding::EncodingModeProduction, Opcode, RetOpcode}, }; -use super::{EvmDebugTracer, EvmDeployTracer, PubdataTracer}; +use super::{EvmDeployTracer, PubdataTracer}; use crate::{ glue::GlueInto, interface::{ @@ -64,7 +64,7 @@ pub struct DefaultExecutionTracer { // take into account e.g circuits produced by the initial bootloader memory commitment. pub(crate) circuits_tracer: CircuitsTracer, - pub(crate) evm_tracer: Option>, + // This tracer is responsible for handling EVM deployments and providing the data to the code decommitter. pub(crate) evm_deploy_tracer: EvmDeployTracer, subversion: MultiVMSubversion, @@ -98,7 +98,6 @@ impl DefaultExecutionTracer { circuits_tracer: CircuitsTracer::new(), evm_deploy_tracer: EvmDeployTracer::new(), storage, - evm_tracer: None, _phantom: PhantomData, } } @@ -177,9 +176,6 @@ macro_rules! dispatch_tracers { if let Some(tracer) = &mut $self.pubdata_tracer { tracer.$function($( $params ),*); } - if let Some(tracer) = &mut $self.evm_tracer { - tracer.$function($( $params ),*); - } $self.circuits_tracer.$function($( $params ),*); $self.evm_deploy_tracer.$function($( $params ),*); }; diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/evm_debug_tracer.rs b/core/lib/multivm/src/versions/vm_latest/tracers/evm_debug_tracer.rs deleted file mode 100644 index 341cc8783663..000000000000 --- a/core/lib/multivm/src/versions/vm_latest/tracers/evm_debug_tracer.rs +++ /dev/null @@ -1,117 +0,0 @@ -use std::{marker::PhantomData, str::FromStr}; - -use circuit_sequencer_api_1_4_2::sort_storage_access::sort_storage_access_queries; -use itertools::Itertools; -use zk_evm_1_4_1::aux_structures::LogQuery as LogQuery_1_4_1; -use zk_evm_1_5_0::{ - aux_structures::{LogQuery, Timestamp}, - tracing::{BeforeExecutionData, VmLocalStateData}, - zkevm_opcode_defs::{FatPointer, Opcode, UMAOpcode}, -}; -use zksync_state::interface::{StoragePtr, WriteStorage}; -use zksync_types::{Address, StorageKey, U256}; - -use crate::{ - interface::tracer::TracerExecutionStatus, - tracers::dynamic::vm_1_5_0::DynTracer, - vm_latest::{ - old_vm::utils::heap_page_from_base, BootloaderState, HistoryMode, SimpleMemory, VmTracer, - ZkSyncVmState, - }, -}; - -pub(crate) struct EvmDebugTracer { - counter: u32, - - _storage: PhantomData, - _history: PhantomData, -} - -impl EvmDebugTracer { - pub fn new() -> Self { - Self { - counter: 0, - _storage: PhantomData, - _history: PhantomData, - } - } -} - -impl DynTracer> for EvmDebugTracer { - fn before_execution( - &mut self, - state: VmLocalStateData<'_>, - data: BeforeExecutionData, - memory: &SimpleMemory, - storage: StoragePtr, - ) { - // FIXME: this catches not only Evm contracts - - let opcode_variant = data.opcode.variant; - let heap_page = - heap_page_from_base(state.vm_local_state.callstack.current.base_memory_page).0; - - let src0_value = data.src0_value.value; - - let fat_ptr = FatPointer::from_u256(src0_value); - - let value = data.src1_value.value; - - const DEBUG_SLOT: u32 = 32 * 32; - - let debug_magic = U256::from_dec_str( - "33509158800074003487174289148292687789659295220513886355337449724907776218753", - ) - .unwrap(); - - // Only `UMA` opcodes in the bootloader serve for vm hooks - if !matches!(opcode_variant.opcode, Opcode::UMA(UMAOpcode::HeapWrite)) - || fat_ptr.offset != DEBUG_SLOT - || value != debug_magic - { - // println!("I tried"); - return; - } - - let how_to_print_value = memory.read_slot(heap_page as usize, 32 + 1).value; - let value_to_print = memory.read_slot(heap_page as usize, 32 + 2).value; - - let print_as_hex_value = - U256::from_str("0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebde") - .unwrap(); - let print_as_string_value = - U256::from_str("0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdf") - .unwrap(); - - if how_to_print_value == print_as_hex_value { - print!("PRINTED: "); - println!("0x{:02x}", value_to_print); - } - - if how_to_print_value == print_as_string_value { - print!("PRINTED: "); - let mut value = value_to_print.0; - value.reverse(); - for limb in value { - print!( - "{}", - String::from_utf8(limb.to_be_bytes().to_vec()).unwrap() - ); - } - println!(""); - } - - self.counter += 1; - } -} - -impl VmTracer for EvmDebugTracer { - // fn finish_cycle( - // &mut self, - // _state: &mut ZkSyncVmState, - // _bootloader_state: &mut BootloaderState, - // ) -> TracerExecutionStatus { - // let contract = _state.local_state.callstack.current.code_address; - - // } -} diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs b/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs index 8f660df7ac1f..82721a322640 100755 --- a/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs @@ -1,6 +1,5 @@ pub(crate) use circuits_tracer::CircuitsTracer; pub(crate) use default_tracers::DefaultExecutionTracer; -pub(crate) use evm_debug_tracer::EvmDebugTracer; pub(crate) use evm_deploy_tracer::EvmDeployTracer; pub(crate) use pubdata_tracer::PubdataTracer; pub(crate) use refunds::RefundsTracer; @@ -8,7 +7,6 @@ pub(crate) use result_tracer::ResultTracer; pub(crate) mod circuits_tracer; pub(crate) mod default_tracers; -pub(crate) mod evm_debug_tracer; pub(crate) mod evm_deploy_tracer; pub(crate) mod pubdata_tracer; pub(crate) mod refunds; diff --git a/core/node/eth_watch/src/client.rs b/core/node/eth_watch/src/client.rs index 51b156d58e91..8be556b42889 100644 --- a/core/node/eth_watch/src/client.rs +++ b/core/node/eth_watch/src/client.rs @@ -70,7 +70,6 @@ impl EthHttpQueryClient { diamond_proxy_addr, governance_address ); - dbg!(&state_transition_manager_contract()); Self { client: client.for_component("watch"), topics: Vec::new(), From 43aa7c6e445e4d45adf165835df027f2be8f8450 Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Tue, 20 Aug 2024 11:58:11 -0300 Subject: [PATCH 31/76] Change hashes --- contracts | 2 +- .../tests/evm-contracts.test.ts | 1 - etc/env/base/chain.toml | 6 +++--- etc/env/base/contracts.toml | 4 ++-- .../fee_estimate.yul/fee_estimate.yul.zbin | Bin 76064 -> 76064 bytes .../gas_test.yul/gas_test.yul.zbin | Bin 72160 -> 72160 bytes .../playground_batch.yul.zbin | Bin 76256 -> 76256 bytes .../proved_batch.yul/proved_batch.yul.zbin | Bin 72672 -> 72672 bytes 8 files changed, 6 insertions(+), 7 deletions(-) diff --git a/contracts b/contracts index af2a2c9113f9..127ae1af133b 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit af2a2c9113f9d6510f45ee2ae08d29d623d03c99 +Subproject commit 127ae1af133bbd1c94c46d81ee47a8457b1062f9 diff --git a/core/tests/ts-integration/tests/evm-contracts.test.ts b/core/tests/ts-integration/tests/evm-contracts.test.ts index 279fdd87bbb0..145975b3af05 100644 --- a/core/tests/ts-integration/tests/evm-contracts.test.ts +++ b/core/tests/ts-integration/tests/evm-contracts.test.ts @@ -163,7 +163,6 @@ describe('EVM equivalence contract', () => { chainId: alice.provider._network.chainId, data }; - console.log(dep_transaction); const result = await (await alice.sendTransaction(dep_transaction)).wait(); const expectedAddressCreate = ethers.getCreateAddress({ from: alice.address, diff --git a/etc/env/base/chain.toml b/etc/env/base/chain.toml index 5f1a9a1603d2..297fe2838c3e 100644 --- a/etc/env/base/chain.toml +++ b/etc/env/base/chain.toml @@ -90,9 +90,9 @@ fee_model_version = "V2" validation_computational_gas_limit = 300000 save_call_traces = true -bootloader_hash = "0x010008df0ef90cb578022657652c9ac6339748e080ea22d185ba9a07e0238a28" -default_aa_hash = "0x0100058deb36e1f2eeb48bf3846d0e8eb38e9176754b73116bb41a472459a4dd" -evm_simulator_hash = "0x01000f197081a9906cc411d0698c4961aeb5c74877f37f7071681da6e8ef3f31" +bootloader_hash = "0x010008df4033788c2a544809ba3d727dcbd9487c8379a9f94e109d245a6390bb" +default_aa_hash = "0x0100058d6621a738ecdb4f523fb46ba9eb04e897c5313c9e17369350a1d664e0" +evm_simulator_hash = "0x01000f19ffd06646d0e66ed6f38d889c329dbabd347b52e3ff93563878a9874d" protective_reads_persistence_enabled = false diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index 59200adb3c25..19517e85d4ef 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -26,8 +26,8 @@ RECURSION_NODE_LEVEL_VK_HASH = "0x1186ec268d49f1905f8d9c1e9d39fc33e98c74f91d91a2 RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc8966504064f1f6ba3f1ba863210" RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" -GENESIS_ROOT = "0xd2b1a071a2da0f92d65e58e7db4743273963c1b8fa6c6a7b565e04128b5441f3" -GENESIS_BATCH_COMMITMENT = "0x7721099ac60105b5ec00fced84f92cb61ec2103ab2248f7d223a705aaddc1da4" +GENESIS_ROOT = "0x6f51a4b123e59b6e06f522eb50fdb67bd0f47f00a3815b3581e85f22abfd14b5" +GENESIS_BATCH_COMMITMENT = "0xa087446fafeafdc8b4b6dc3813f5a313fa41af3327b5086e53d279ed0df3c283" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "56" diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin index a48d89ebe7ff2c5640d3c15271298e7689b7a370..71eb88b4e93b2042650726f2740a3acf6bd2b634 100644 GIT binary patch delta 77 zcmV-T0J8s}(gdK=1c0;whx@KpHVrC>d delta 77 zcmV-T0J8s}(gdK=1c0;w&kd>&gr22~5R&558Fg&IK2&pfc_XYAJj&i9fIC6E9B delta 75 zcmV-R0JQ($vjpI?1hAy{97(H};O30^i=4ScBN-a61{w05&jdN{pS|s$#G}CXA|OLn hMn#^o{1p88QLIJpoqlgOS21hRjFjJRZb_QD>YfS~D763p diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/playground_batch.yul/playground_batch.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/playground_batch.yul/playground_batch.yul.zbin index 60749b415b87a731d7f7a937c28b9fd6b68a1c18..c01f5f8383a616eed1671923456fc9bc6932fef9 100644 GIT binary patch delta 79 zcmV-V0I>hy(*)qt1c0;wLhy(*)qt1c0;wLDDKnt)OxkprdN@ZI&tv)zwn{e*Q)nHhtWF!Ot From 4e1df208dd87b2f1a627aa714d0912b3605dc08d Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Tue, 20 Aug 2024 12:50:25 -0300 Subject: [PATCH 32/76] Modify hashes --- contracts | 2 +- etc/env/base/chain.toml | 4 ++-- etc/env/base/contracts.toml | 4 ++-- .../fee_estimate.yul/fee_estimate.yul.zbin | Bin 76064 -> 76064 bytes .../gas_test.yul/gas_test.yul.zbin | Bin 72160 -> 72160 bytes .../playground_batch.yul.zbin | Bin 76256 -> 76256 bytes .../proved_batch.yul/proved_batch.yul.zbin | Bin 72672 -> 72672 bytes 7 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts b/contracts index 127ae1af133b..6a0fe1a1bea2 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 127ae1af133bbd1c94c46d81ee47a8457b1062f9 +Subproject commit 6a0fe1a1bea2eacf798c8fffb19729046d1ce7b8 diff --git a/etc/env/base/chain.toml b/etc/env/base/chain.toml index 297fe2838c3e..aca6f4f7f68c 100644 --- a/etc/env/base/chain.toml +++ b/etc/env/base/chain.toml @@ -90,8 +90,8 @@ fee_model_version = "V2" validation_computational_gas_limit = 300000 save_call_traces = true -bootloader_hash = "0x010008df4033788c2a544809ba3d727dcbd9487c8379a9f94e109d245a6390bb" -default_aa_hash = "0x0100058d6621a738ecdb4f523fb46ba9eb04e897c5313c9e17369350a1d664e0" +bootloader_hash = "0x010008dfcd3aa2beca1745f437e42b55a1657712bc063e2d52aeb2dee138c399" +default_aa_hash = "0x0100058d8dede04786d92d2dd62bbbf8b696f62c5db1d4b2601ac6276f5dcad9" evm_simulator_hash = "0x01000f19ffd06646d0e66ed6f38d889c329dbabd347b52e3ff93563878a9874d" protective_reads_persistence_enabled = false diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index 19517e85d4ef..7e7b5cf3ca51 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -26,8 +26,8 @@ RECURSION_NODE_LEVEL_VK_HASH = "0x1186ec268d49f1905f8d9c1e9d39fc33e98c74f91d91a2 RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc8966504064f1f6ba3f1ba863210" RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" -GENESIS_ROOT = "0x6f51a4b123e59b6e06f522eb50fdb67bd0f47f00a3815b3581e85f22abfd14b5" -GENESIS_BATCH_COMMITMENT = "0xa087446fafeafdc8b4b6dc3813f5a313fa41af3327b5086e53d279ed0df3c283" +GENESIS_ROOT = "0x45f206478fac785d68ae8217999e8caf66c4e67fea1db90139422e5c4eb5cc51" +GENESIS_BATCH_COMMITMENT = "0x9e598e2b5784e62dec66ce37d92bfa4407d7441fb77c003d09856221e286eb95" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "56" diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin index 71eb88b4e93b2042650726f2740a3acf6bd2b634..6f86e6f1ae0b37cb9e2749be246f52ad066e3b16 100644 GIT binary patch delta 77 zcmV-T0J8s}(gdK=1c0;whx@KpHVrC>d diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/gas_test.yul/gas_test.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/gas_test.yul/gas_test.yul.zbin index 86f867d37b38895bad3ea6bee34db0e5f425a1e3..57a8573e08eb9df117f50b22c2999d8f6c974e83 100644 GIT binary patch delta 75 zcmV-R0JQ($vjpI?1hAy{9G-endWvRY5Ufb1}MHbZul>cf^G`J=%1A|Uwb h%vV&i6JGsZ<($r8!ed6ykK(xy+@gV4kx;!xRP87~DYyUt delta 75 zcmV-R0JQ($vjpI?1hAy{9Bo%-0^HFT#FmF$-9lePl%QgiD_!~A{jxLzf}_CqA|RA} hyi>&kd>&gr22~5R&558Fg&IK2&pfc_XYAJj&i9fIC6E9B diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/playground_batch.yul/playground_batch.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/playground_batch.yul/playground_batch.yul.zbin index c01f5f8383a616eed1671923456fc9bc6932fef9..e8ca1c721a3006074301b1c538fcb73a54e14b66 100644 GIT binary patch delta 79 zcmV-V0I>hy(*)qt1c0;wL;{3{%Uq_v-T#C)WS~ delta 79 zcmV-V0I>hy(*)qt1c0;wLendWvRY5Ufb1}MHbZul>cf^G`LjUzfFdA+ i%QMlx7RR!(V`i4DHlx Date: Tue, 20 Aug 2024 12:54:34 -0300 Subject: [PATCH 33/76] Add newlines --- core/tests/ts-integration/contracts/token/ERC20.sol | 2 +- core/tests/ts-integration/evm-contracts/CounterWithParam.sol | 2 +- core/tests/ts-integration/evm-contracts/ProxyCaller.sol | 2 +- core/tests/ts-integration/evm-contracts/SelfDestruct.sol | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/tests/ts-integration/contracts/token/ERC20.sol b/core/tests/ts-integration/contracts/token/ERC20.sol index ca3269c4ebd0..514e2358624f 100644 --- a/core/tests/ts-integration/contracts/token/ERC20.sol +++ b/core/tests/ts-integration/contracts/token/ERC20.sol @@ -73,4 +73,4 @@ contract ERC20{ c = a / b; } -} \ No newline at end of file +} diff --git a/core/tests/ts-integration/evm-contracts/CounterWithParam.sol b/core/tests/ts-integration/evm-contracts/CounterWithParam.sol index 40211a746540..1261e2f9fa06 100644 --- a/core/tests/ts-integration/evm-contracts/CounterWithParam.sol +++ b/core/tests/ts-integration/evm-contracts/CounterWithParam.sol @@ -37,4 +37,4 @@ contract CounterWithParam { function getBytes() public returns (bytes memory) { return "Testing"; } -} \ No newline at end of file +} diff --git a/core/tests/ts-integration/evm-contracts/ProxyCaller.sol b/core/tests/ts-integration/evm-contracts/ProxyCaller.sol index 05200d06a31c..926d2a944d41 100644 --- a/core/tests/ts-integration/evm-contracts/ProxyCaller.sol +++ b/core/tests/ts-integration/evm-contracts/ProxyCaller.sol @@ -22,4 +22,4 @@ contract ProxyCaller { function proxyGetBytes(address dest) external returns(bytes memory returnData){ return ICounterWithParam(dest).getBytes(); } -} \ No newline at end of file +} diff --git a/core/tests/ts-integration/evm-contracts/SelfDestruct.sol b/core/tests/ts-integration/evm-contracts/SelfDestruct.sol index 3e3923de3369..b28a25968e3e 100644 --- a/core/tests/ts-integration/evm-contracts/SelfDestruct.sol +++ b/core/tests/ts-integration/evm-contracts/SelfDestruct.sol @@ -12,4 +12,4 @@ contract SelfDestruct { selfdestruct(recipient) } } -} \ No newline at end of file +} From db04c02938f6275dcd236cbfec9295d20e0c059f Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 20 Aug 2024 13:05:23 -0300 Subject: [PATCH 34/76] Update contracts submodule --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index 6a0fe1a1bea2..cb3ad25f27a6 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 6a0fe1a1bea2eacf798c8fffb19729046d1ce7b8 +Subproject commit cb3ad25f27a65c2d9a6e0c03c8717f482017ca15 From 9ab61718c13ac2e3c44117a891d2cbc4524f4f30 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 22 Aug 2024 10:07:06 -0300 Subject: [PATCH 35/76] Update contracts submodule --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index cb3ad25f27a6..cd2babb79aea 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit cb3ad25f27a65c2d9a6e0c03c8717f482017ca15 +Subproject commit cd2babb79aeacd63e5873d46fdf7c9ba732d0925 From 2275e75ef3f8a2c436feaa9fcef81a0070d385c5 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 22 Aug 2024 10:19:10 -0300 Subject: [PATCH 36/76] Update contracts submodule after merge with dev --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index cd2babb79aea..0dd4a0b04778 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit cd2babb79aeacd63e5873d46fdf7c9ba732d0925 +Subproject commit 0dd4a0b04778ac09059895563c361d114d4d3c9b From 6513092ba6540ea37e7799f5d460d1d21311f574 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 23 Aug 2024 18:39:06 -0300 Subject: [PATCH 37/76] Update contracts submodule --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index 0dd4a0b04778..2579d6893efc 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 0dd4a0b04778ac09059895563c361d114d4d3c9b +Subproject commit 2579d6893efcdc7172953abb7f5a83bff58ed920 From a049e935c833c88d2050df2eb1bfcbaf9516e5e8 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 23 Aug 2024 18:48:47 -0300 Subject: [PATCH 38/76] Update outdated comment --- .../multivm/src/versions/vm_latest/types/internals/vm_state.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/lib/multivm/src/versions/vm_latest/types/internals/vm_state.rs b/core/lib/multivm/src/versions/vm_latest/types/internals/vm_state.rs index 765cd3a56db2..16353f5c2f7e 100644 --- a/core/lib/multivm/src/versions/vm_latest/types/internals/vm_state.rs +++ b/core/lib/multivm/src/versions/vm_latest/types/internals/vm_state.rs @@ -140,8 +140,6 @@ pub(crate) fn new_vm_state( default_aa_code_hash: h256_to_u256( system_env.base_system_smart_contracts.default_aa.hash, ), - // For now, the default account hash is used as the code hash for the EVM simulator. - // In the 1.5.0 version, it is not possible to instantiate EVM bytecode. evm_simulator_code_hash: h256_to_u256( system_env.base_system_smart_contracts.evm_simulator.hash, ), From 2aaedaa0b9b6c4683a3a88cfd404b20c6a346be3 Mon Sep 17 00:00:00 2001 From: Javier Chatruc Date: Mon, 26 Aug 2024 11:26:39 -0300 Subject: [PATCH 39/76] Update toml hashes and multivm_bootloaders --- etc/env/base/chain.toml | 6 +++--- etc/env/base/contracts.toml | 4 ++-- .../fee_estimate.yul/fee_estimate.yul.zbin | Bin 76064 -> 76000 bytes .../gas_test.yul/gas_test.yul.zbin | Bin 72160 -> 72096 bytes .../playground_batch.yul.zbin | Bin 76256 -> 76192 bytes .../proved_batch.yul/proved_batch.yul.zbin | Bin 72672 -> 72608 bytes 6 files changed, 5 insertions(+), 5 deletions(-) diff --git a/etc/env/base/chain.toml b/etc/env/base/chain.toml index aca6f4f7f68c..6eb1557a56c2 100644 --- a/etc/env/base/chain.toml +++ b/etc/env/base/chain.toml @@ -90,9 +90,9 @@ fee_model_version = "V2" validation_computational_gas_limit = 300000 save_call_traces = true -bootloader_hash = "0x010008dfcd3aa2beca1745f437e42b55a1657712bc063e2d52aeb2dee138c399" -default_aa_hash = "0x0100058d8dede04786d92d2dd62bbbf8b696f62c5db1d4b2601ac6276f5dcad9" -evm_simulator_hash = "0x01000f19ffd06646d0e66ed6f38d889c329dbabd347b52e3ff93563878a9874d" +bootloader_hash = "0x010008ddf6824c3f8778b86a85d568ddfb45c29bf23b604fad20b91e6d8d458b" +default_aa_hash = "0x0100058d7a6e6d8f0ba29e37f30a89475ae789f5058004af7df75868f46b7705" +evm_simulator_hash = "0x01000f196acd122635a752fcb275be0cc95fd3bba348c1d0908a517fe316418e" protective_reads_persistence_enabled = false diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index 7e7b5cf3ca51..b34ca5046b84 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -26,8 +26,8 @@ RECURSION_NODE_LEVEL_VK_HASH = "0x1186ec268d49f1905f8d9c1e9d39fc33e98c74f91d91a2 RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc8966504064f1f6ba3f1ba863210" RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" -GENESIS_ROOT = "0x45f206478fac785d68ae8217999e8caf66c4e67fea1db90139422e5c4eb5cc51" -GENESIS_BATCH_COMMITMENT = "0x9e598e2b5784e62dec66ce37d92bfa4407d7441fb77c003d09856221e286eb95" +GENESIS_ROOT = "0xcb36c2f9065392206dd4aa019208c0b36484a35ce5a77af13054c51526c7714f" +GENESIS_BATCH_COMMITMENT = "0xb4a4e83cc5264fec1f41762433c59f3b8f57da49bc222d4214cbdf7cee8f852d" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "56" diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin index 6f86e6f1ae0b37cb9e2749be246f52ad066e3b16..fd5cc89b1239f7267729d9ba53a9b434650924a6 100644 GIT binary patch delta 15688 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 GW&Z~i`bww( delta 15256 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 JGT+lS`5*OCz2*P_ diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/gas_test.yul/gas_test.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/gas_test.yul/gas_test.yul.zbin index 57a8573e08eb9df117f50b22c2999d8f6c974e83..42f7be1e0a89eb73f3c6dd77e9f496b39957090a 100644 GIT binary patch delta 15422 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 KVAaP9hW{TKatiPO delta 15040 zcmcgTeOy#k+V>1|nIT6R@Pm&Tm_daJMTbd~NDNRD6>LyREb%KfD%hWzzS*m6U{Y*B zsrz8IMdlj2?r){Eu4xG=m|w5*`jNC+u%)i0CcD+hrbg(B4)0R_qlxWQMEPoXT-hJWiq9pn#i2>+gg&QM3f z`H(CsG1D(NZY@fTyAZZalo%hTABEJOhtUQH`BW$}Y}b(vL4U_iUD%%tyO^9VLz8Jc zDxfJcjVhq;d_um5u6~=zU!gXNC%h(&JX)qm&(vy zft3SyI{w}RyBxlc5yhrrcjchWB{y|uii_iPI%K0C{lUc{JOA(*M|F6{|LHSsmdAfY zgJO6HK|IkoP8gnBlsY(VweZpSD;e_REO6aw9;jBD3|4QRN#h1F=?SjDzI#5jN3fB|P!@#nKoLR6i_Jtm z2{jfQ;X@bvso+GRaW6V`L~KtZYn@&e#`4 zx1RKa*1>Mx%mA~7SYYfBGnC+G&JZ&KmJa!e{8cC&DvN^BwIfl+rM3c(C>Zrfxrcg0 zl#xV5u{$Y^kC2z@hRFmYORd9fe5_2SmQXA*RLO8z zD9I{Q<_4jUCZkPQ$#>K?!Z(O<$`}V3lM>%u5pdH=9WArW-A0nqp8ZZv=4eOi{5v62PD(ucrQT?GlgSu+#;5Z=ThVcU!HTmN#kUP!{Yw%Mtjz*liL?`TE zznaF`NMGm}N7b8hpF3z@Qv}B0YT5KdoQzPhiQt~xohbMWc3n#$P@m0K=QRp9tyT<4EMYwzhOS4?bWI4+r&Gi$U3aKjsu^$F+gj3i+ zjEWdKB{YtGW@VitqjSPQet|TjNAoGkU&MJ8ZbS2uPbmJFUqdbvy zx)@ohwiB=dWRbO;pAkTprW_}YxH-LvxC+`)ZgRv$X$DH*GrNsTc}Srsg$gtj)i_lq&Y}`GN1c?;qTTd)1w7b-cb^lgqq97=)!TSwBs-)>+EDRKIu8TJ`?P&;ppww z2MYP&vV0Vkm!Eu6pzVSAWCVq=guLiaM|sQ@atb-Xnx_p&B8gz#mcBp0jmOB zH0~vP3yuKkPA*6=-7TI`h#g52{+$g2W)>pdr8C{VNPwOdJvCWIL7JauQ31xFG#`eV z0w-S?>y4acz{D+71m}pr2EPElACrLTE3#2Q^?VD&$wo zlt}UxilWtXjccHzC=F+n>fK>&VmEI%4yAK#`D7h5&08AtJ~2~IH0;6eqbPG}Ct)uXopHJ@iTER?p)zRq zj4GjJltFve#h_=UJm!QI^P@GWsX>VLM|*-8TigSLYkbhOHNEY0Wd}XW`i|3eBj{O0 zZ;ye87e;8vp$Q@OX+o5}GX_>a67i5nN5)4)&4yp^UWdkE+V8uujLs!CVuPWJ9U62Z zOg61J>F!h_?oMT*HLeI+9-UPq;kDuzjdk*#8yRnC^Fd5QhqxPZhK@t(5(^ApVunWi z2wX5~Q^gEY0U1xnL>5ap*7LSDYO0-yPc+?4J7ik%`sn`jySPP;Q zA#Q0pM{BXuwK8bx(Q#d$2R(~AGc3@ew-X_L(1gf)+zF#JAsQZc4*b%WHiOq9`aBWP zB8%9D_=5uVQfvSov!wvXJJf-_Q(6h z(5$NunTeG&$Az#BzyG1QBHgS@aeKNHw^VtnyA*>5T7IwYQs~Z7GGY_=d~Y8Q+b;Y+ zz{7f95zmP9$bj_t$^9qc(9gn&qev7^Kz1=L;$AIdHyHHBxiE3*O>!7Amf11`rc}B% z3nVOvay&j`l^&idhI1noQFi1crnpH|;Bao4RU=@UmOEkHis&#YJuHNx>Eom!~V>R0WCH>_turh$j@+NmsmA&sP-~#(}c=*YST0E}B z=<#zcr!y_LL7&I56#mbC>9jPZ&On`lIfHQ|lg6}wTtwmf0B z?Is`|wOJaSU|pXCKd$`DwTDuQ)-X%7229rM+5D96Gjb*#5bcG|D(Aw#iBM8mC(p|F zon;#9`)r;lKI7k>%D~#Ew2A}MTBnQ35Gj{v=mkzX>(1MmRqhCOmI#k*iauw@XDnpQ z87g@^(K~tQ40{2SxJwr-89)=|*+;Yt8S}ujAAIr3>MWAT(|Ob-cHM?O_$}7@c6R=^ z*V8=^){Sp{%mS9x(dklvSQ2!7NDG!xngt8;l^qs<>SraYdo(iS9j>p_l8$u^Qc@ma z_7#9}DwM9dGX1bffZ;Hn%hjQWa3Q3Ewyz6FDxQ{ch9kHYn$2>TOCD zp4Cu+HmaShFrDSDiNGk-L-SpVHc}Wg0j-E0Gzp-!cD1&nRZfc4*cHH192zU5hM8aP zwR6`zo1>B8Q!p@E)(QX`QWefp z%_8`WC7*_TP0u@BRYA`xecl=Oyw5CJ0`aUL*hR;CY@K(@P+F~X&-7y?PyWD%5-o1A zgo$hNfu>|;J=6w%#6t$jc*lwuz+K~=u_h3-S3e}R_kT`$-)OtWr}bHqa;b$DBb z6%d9G#b;04ijt{ieH8Sxx9Nq_;>io8;K^^F)C+aOvjcj)I=V;Be}bVk-zItzCKtud zVYu*W=FHx*nYBrb8)@eg_bhwDjZKhsy#r3Xbb&9Ebr;P1p9|LY2Etd~*5v0{CB1LM z8B}Y{MlH1-+UO+BaAV__xVhf;OT3W<*4nhbt2wTP9x92)G!?b%n5M4Q2Cvsjd+c9A z1_PG&*lTeoz83eW@gqXv9y|XFM*esB?mCWJHsOiGCW^tj$w^*-yiGZH1F3cs-ax8` z8?Vp}_^!G*2&)?mu-UFwvav>#MXiO$nuUvjt%w$v(tzuaaLFFH@JP=|8^_uCR9g7r zDMsb1OUX;ZjaS3zEgAi5X*#4Wqb?_6J(fyXJPj)J2%;Kl>xvn9ZhnKzQ^_0A3ZClU zD91B}p3IqA%R=HA`jt2YWp7;- zx_)b*!}{MjO2$(MDwhCB3tuP{X~k zbd@%d2Yue_Y^K;m4q}#K6FG=kMQ>|m&L+*bW$)Z~hv9u)7CjR%zKCUVJZ#%}CZUdM z619vs0J}Q}FisU}cNvH*`>9a>E)A4*@7a>2QtoB3l=GtStI50e*dRnWuPyuOuX#ub zAbTUPUZ=;Z2{oFqQ5&nFLpZeCNy7Bw?5n=x##c!e z?Z_nI7&nX0XryA>?x}l+1yT578ggl;A;hlIK`nIcxsuRhUj+IOmhx{T>14I`#uA9Q|zN0dU!hZxifpk^ONIOu4R&MTXnSt#vj zwn2NdbmIMN;}o(5S{tum4BFjvg?R3hH1EedfBW(3A%5ETQ{aYXEDsORUnvLD99TGW z+0okrZs*XOe96(<#qAsgoT?rW?`A08t9Ly^y?FYjE8vixt4VNg^Fq)4jOJzw+@kb0 zBfX5d&gM-1O^-lr;BGO&nw9}noXA00iw)(&gykb2HICAQT9vLMY(>|1@5SA;a*D7O z#4JVF3Sw5nL9MW5`dI62tL9s*jw1$B>7vEU6&a))o{zUtY7U!coh8_ec}Ld{FdT~y%x}pSh9`1Cfbn#PHjhQvo-eXfOrhJPIBzm z6wkDD1)K^GC&C4$huUMhk`8ulM0YY<^oZEc0#d*{BK9*6Ctf%e1)@i2;1MZgc>1O* z-~_mFQo60Q^%NE-r|`lnei~0vpKU#*m4Gu&qi?rqbzXI+ovz-(I#hqE#e81d zeS>?kOkJDSGF@%=MM~R~a&p^Cw>e#`;S5S)bk@$`<$!7~IjzMh#rw0{!JAzw&hiEs z@i~aBjiHJR7MlJLPWX4}WccnJb_C}zSF~eCaGrWc$9Wsv!jatb@~B^7FL>tKVCQ+0 zG}jMG?B3}L3S54-MG7GAGn$(_KTqpB*{9vfZ^s;T5wC?IZ6)oLHrmO&-`(1NSpNg+ zKNqn|eNlcpX1;dJd_LINfkrn{=xom`&J7rDS>a%vOT%s7bOjt+hDB#p< zC$O~x<6((J#Dko9;gE`pQUdTdqm)Z-jV_@3bl!F;({X@Nvmzi@EJ0gWP_9O#TfJ~9 zu2^DCx2}}&VEg;0D$*>NE}x?9Z^u_Qo#$Gi{VE=oT*YP{KVz@@ci2omV83dE@~b8Z z3U$zMwaURR>&ESsS5cRfEP2N56|F)6htyotN{}>uu?;Sci`&)f^hYl$4Ed&~xHz6l zI4Hb|5;6#C6eVO3vl_n9NFic!8JyU~%z^NZ2AnRs-`Yp8nxI5ndk87=k1w#LM|C;wz-N}Uq7fm{~{?do$j%{ma MZ_NK_Qo*197leMN(EtDd diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/playground_batch.yul/playground_batch.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/playground_batch.yul/playground_batch.yul.zbin index e8ca1c721a3006074301b1c538fcb73a54e14b66..4e88417fabb5d36ecb5758d386f3d83519de76fd 100644 GIT binary patch delta 15932 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 diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/proved_batch.yul/proved_batch.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/proved_batch.yul/proved_batch.yul.zbin index 89adea2da47c73b32983732aee74081de5845ec3..931d11b2d46180893fbe47bde1c1b5275ba1f476 100644 GIT binary patch delta 14779 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 Date: Mon, 26 Aug 2024 12:10:39 -0300 Subject: [PATCH 40/76] Fix lint errors --- .../src/versions/vm_latest/old_vm/oracles/decommitter.rs | 8 +++----- .../src/versions/vm_latest/tracers/evm_deploy_tracer.rs | 4 ++-- core/lib/types/src/system_contracts.rs | 2 +- core/lib/vm_utils/src/storage.rs | 5 ++--- core/tests/vm-benchmark/harness/src/lib.rs | 6 +++--- 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs b/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs index 678520dbfa00..6debe874d6c3 100644 --- a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs +++ b/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs @@ -5,9 +5,7 @@ use zk_evm_1_5_0::{ aux_structures::{ DecommittmentQuery, MemoryIndex, MemoryLocation, MemoryPage, MemoryQuery, Timestamp, }, - zkevm_opcode_defs::{ - ContractCodeSha256, VersionedHashDef, VersionedHashHeader, VersionedHashNormalizedPreimage, - }, + zkevm_opcode_defs::{VersionedHashHeader, VersionedHashNormalizedPreimage}, }; use zksync_types::{H256, U256}; use zksync_utils::{bytes_to_be_words, h256_to_u256, u256_to_h256}; @@ -267,8 +265,8 @@ impl VersionedCodeHash { }; let mut hash = [0u8; 32]; - &mut hash[0..4].copy_from_slice(&header.0); - &mut hash[4..32].copy_from_slice(&preimage.0); + let _ = hash[0..4].copy_from_slice(&header.0); + let _ = hash[4..32].copy_from_slice(&preimage.0); // Hash[1] is used in both of the versions to denote whether the bytecode is being constructed. // We ignore this param. diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs b/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs index e0eda1d2034c..7cd32cea96fa 100644 --- a/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs @@ -6,7 +6,7 @@ use zk_evm_1_5_0::{ }; use zksync_contracts::known_codes_contract; use zksync_state::interface::WriteStorage; -use zksync_types::{CONTRACT_DEPLOYER_ADDRESS, KNOWN_CODES_STORAGE_ADDRESS, U256}; +use zksync_types::{CONTRACT_DEPLOYER_ADDRESS, KNOWN_CODES_STORAGE_ADDRESS}; use zksync_utils::{bytes_to_be_words, h256_to_u256}; use super::{traits::VmTracer, utils::read_pointer}; @@ -39,7 +39,7 @@ impl VmTracer for EvmDeployTracer { fn finish_cycle( &mut self, state: &mut ZkSyncVmState, - bootloader_state: &mut BootloaderState, + _bootloader_state: &mut BootloaderState, ) -> TracerExecutionStatus { // We check if ContractDeployer was called with provided evm bytecode. // It is assumed that by that time the user has already paid for its size. diff --git a/core/lib/types/src/system_contracts.rs b/core/lib/types/src/system_contracts.rs index 74a91b29f241..57ca0150f7f4 100644 --- a/core/lib/types/src/system_contracts.rs +++ b/core/lib/types/src/system_contracts.rs @@ -187,7 +187,7 @@ static EVM_SIMULATOR_HASH: Lazy = Lazy::new(|| { }); pub fn get_evm_simulator_hash() -> H256 { - EVM_SIMULATOR_HASH.clone() + *EVM_SIMULATOR_HASH } static SYSTEM_CONTRACTS: Lazy> = Lazy::new(|| { diff --git a/core/lib/vm_utils/src/storage.rs b/core/lib/vm_utils/src/storage.rs index 52333ca46fa3..bcb559510fa7 100644 --- a/core/lib/vm_utils/src/storage.rs +++ b/core/lib/vm_utils/src/storage.rs @@ -4,9 +4,8 @@ use anyhow::Context; use zksync_contracts::BaseSystemContracts; use zksync_dal::{Connection, Core, CoreDal, DalError}; use zksync_types::{ - block::L2BlockHeader, fee_model::BatchFeeInput, snapshots::SnapshotRecoveryStatus, - web3::contract, Address, L1BatchNumber, L2BlockNumber, L2ChainId, ProtocolVersionId, H256, - ZKPORTER_IS_AVAILABLE, + block::L2BlockHeader, fee_model::BatchFeeInput, snapshots::SnapshotRecoveryStatus, Address, + L1BatchNumber, L2BlockNumber, L2ChainId, ProtocolVersionId, H256, ZKPORTER_IS_AVAILABLE, }; use zksync_vm_interface::{L1BatchEnv, L2BlockEnv, SystemEnv, TxExecutionMode}; diff --git a/core/tests/vm-benchmark/harness/src/lib.rs b/core/tests/vm-benchmark/harness/src/lib.rs index 6594951fa786..2450937b90a1 100644 --- a/core/tests/vm-benchmark/harness/src/lib.rs +++ b/core/tests/vm-benchmark/harness/src/lib.rs @@ -277,7 +277,7 @@ fn tx_fee(gas_limit: u32) -> Fee { pub fn get_transfer_tx(nonce: u32) -> Transaction { let mut signed = L2Tx::new_signed( - PRIVATE_KEY.address(), + Some(PRIVATE_KEY.address()), vec![], // calldata Nonce(nonce), tx_fee(1_000_000), @@ -310,7 +310,7 @@ pub fn get_load_test_deploy_tx() -> Transaction { factory_deps.push(LOAD_TEST_CONTRACT.bytecode.clone()); let mut signed = L2Tx::new_signed( - CONTRACT_DEPLOYER_ADDRESS, + Some(CONTRACT_DEPLOYER_ADDRESS), create_calldata, Nonce(0), tx_fee(100_000_000), @@ -348,7 +348,7 @@ pub fn get_load_test_tx(nonce: u32, gas_limit: u32, params: LoadTestParams) -> T .expect("cannot encode `execute` inputs"); let mut signed = L2Tx::new_signed( - *LOAD_TEST_CONTRACT_ADDRESS, + Some(*LOAD_TEST_CONTRACT_ADDRESS), calldata, Nonce(nonce), tx_fee(gas_limit), From 469131d83877cb8417590e2afc622367f507cbe3 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 26 Aug 2024 12:11:03 -0300 Subject: [PATCH 41/76] Update contracts submodule --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index 2579d6893efc..0ac46175e091 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 2579d6893efcdc7172953abb7f5a83bff58ed920 +Subproject commit 0ac46175e091586e6e23dcafda12b15009cbec7d From 4d9d0d2c9988f1637f93a0d9afb9ba270b0c56c0 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 26 Aug 2024 12:38:08 -0300 Subject: [PATCH 42/76] Remove unused import --- core/lib/vm_interface/src/storage/in_memory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/vm_interface/src/storage/in_memory.rs b/core/lib/vm_interface/src/storage/in_memory.rs index cf7cf0a85a13..5dfb3ba156e1 100644 --- a/core/lib/vm_interface/src/storage/in_memory.rs +++ b/core/lib/vm_interface/src/storage/in_memory.rs @@ -4,7 +4,7 @@ use zksync_types::{ block::DeployedContract, get_code_key, get_deployer_key, get_known_code_key, get_system_context_init_logs, system_contracts::{get_evm_simulator_hash, get_system_smart_contracts}, - L2ChainId, StorageKey, StorageLog, StorageValue, H256, U256, + L2ChainId, StorageKey, StorageLog, StorageValue, H256, }; use zksync_utils::u256_to_h256; From 1c747dd6ce356ddb05cf3fce2f22909936ef555a Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 26 Aug 2024 13:09:05 -0300 Subject: [PATCH 43/76] Update base system contracts hashes and commitment hash --- etc/env/base/chain.toml | 2 +- etc/env/base/contracts.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/env/base/chain.toml b/etc/env/base/chain.toml index 6eb1557a56c2..b987cc75623d 100644 --- a/etc/env/base/chain.toml +++ b/etc/env/base/chain.toml @@ -91,7 +91,7 @@ validation_computational_gas_limit = 300000 save_call_traces = true bootloader_hash = "0x010008ddf6824c3f8778b86a85d568ddfb45c29bf23b604fad20b91e6d8d458b" -default_aa_hash = "0x0100058d7a6e6d8f0ba29e37f30a89475ae789f5058004af7df75868f46b7705" +default_aa_hash = "0x0100058d69da9a1ba9e97d8d26a67967a39e1a9d50d55a4b6aace7d98877a485" evm_simulator_hash = "0x01000f196acd122635a752fcb275be0cc95fd3bba348c1d0908a517fe316418e" protective_reads_persistence_enabled = false diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index b34ca5046b84..21614ee63125 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -27,7 +27,7 @@ RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc896650406 RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" GENESIS_ROOT = "0xcb36c2f9065392206dd4aa019208c0b36484a35ce5a77af13054c51526c7714f" -GENESIS_BATCH_COMMITMENT = "0xb4a4e83cc5264fec1f41762433c59f3b8f57da49bc222d4214cbdf7cee8f852d" +GENESIS_BATCH_COMMITMENT = "0x45d4f53e451df9bcb5dc00a86f64bd6b4e8ab991d970919b6127e214f5d38550" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "56" From d3b259863a36c00a2219eb0403a550371b54b703 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 26 Aug 2024 13:10:57 -0300 Subject: [PATCH 44/76] Remove unused imports --- core/node/state_keeper/src/updates/l2_block_updates.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/node/state_keeper/src/updates/l2_block_updates.rs b/core/node/state_keeper/src/updates/l2_block_updates.rs index 7cdf99f1b55c..a448f38a6b31 100644 --- a/core/node/state_keeper/src/updates/l2_block_updates.rs +++ b/core/node/state_keeper/src/updates/l2_block_updates.rs @@ -13,8 +13,7 @@ use zksync_types::{ block::{BlockGasCount, L2BlockHasher}, ethabi, l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log}, - L2BlockNumber, ProtocolVersionId, StorageLogKind, StorageLogQuery, StorageLogWithPreviousValue, - Transaction, H256, + L2BlockNumber, ProtocolVersionId, StorageLogWithPreviousValue, Transaction, H256, }; use zksync_utils::bytecode::hash_bytecode; From 7dc510d54de0ac40a201af223cb8345e9d6f9309 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 26 Aug 2024 13:53:25 -0300 Subject: [PATCH 45/76] Fix lint for all core components --- .../lib/dal/src/models/storage_transaction.rs | 6 +- .../vm_latest/old_vm/oracles/decommitter.rs | 12 +- .../src/versions/vm_latest/utils/mod.rs | 2 +- .../src/updates/l2_block_updates.rs | 1 + core/node/state_keeper/src/updates/mod.rs | 1 + .../tests/evm-contracts.test.ts | 121 +----------------- 6 files changed, 16 insertions(+), 127 deletions(-) diff --git a/core/lib/dal/src/models/storage_transaction.rs b/core/lib/dal/src/models/storage_transaction.rs index 49a5937cfd13..746026af73e5 100644 --- a/core/lib/dal/src/models/storage_transaction.rs +++ b/core/lib/dal/src/models/storage_transaction.rs @@ -364,12 +364,10 @@ impl From for TransactionReceipt { to: storage_receipt .transfer_to .or(storage_receipt.execute_contract_address) - .map(|addr| { + .and_then(|addr| { serde_json::from_value::>(addr) .expect("invalid address value in the database") - }) - // For better compatibility with various clients, we never return null. - .flatten(), + }), cumulative_gas_used: Default::default(), // TODO: Should be actually calculated (SMA-1183). gas_used: { let refunded_gas: U256 = storage_receipt.refunded_gas.into(); diff --git a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs b/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs index 6debe874d6c3..0f31031d3723 100644 --- a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs +++ b/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs @@ -245,14 +245,14 @@ impl DecommittmentProcess // TODO: consider moving this to the zk-evm crate enum VersionedCodeHash { ZkEVM(VersionedHashHeader, VersionedHashNormalizedPreimage), - EVM(VersionedHashHeader, VersionedHashNormalizedPreimage), + Evm(VersionedHashHeader, VersionedHashNormalizedPreimage), } impl VersionedCodeHash { fn from_query(query: &DecommittmentQuery) -> Self { match query.header.0[0] { 1 => Self::ZkEVM(query.header, query.normalized_preimage), - 2 => Self::EVM(query.header, query.normalized_preimage), + 2 => Self::Evm(query.header, query.normalized_preimage), _ => panic!("Unsupported hash version"), } } @@ -261,12 +261,12 @@ impl VersionedCodeHash { fn to_stored_hash(&self) -> U256 { let (header, preimage) = match self { Self::ZkEVM(header, preimage) => (header, preimage), - Self::EVM(header, preimage) => (header, preimage), + Self::Evm(header, preimage) => (header, preimage), }; let mut hash = [0u8; 32]; - let _ = hash[0..4].copy_from_slice(&header.0); - let _ = hash[4..32].copy_from_slice(&preimage.0); + hash[0..4].copy_from_slice(&header.0); + hash[4..32].copy_from_slice(&preimage.0); // Hash[1] is used in both of the versions to denote whether the bytecode is being constructed. // We ignore this param. @@ -283,7 +283,7 @@ impl VersionedCodeHash { let length_in_words = header.0[2] as u32 * 256 + header.0[3] as u32; length_in_words * 32 } - Self::EVM(header, _) => header.0[2] as u32 * 256 + header.0[3] as u32, + Self::Evm(header, _) => header.0[2] as u32 * 256 + header.0[3] as u32, } } } diff --git a/core/lib/multivm/src/versions/vm_latest/utils/mod.rs b/core/lib/multivm/src/versions/vm_latest/utils/mod.rs index 84bc99cc620d..313947f048c2 100644 --- a/core/lib/multivm/src/versions/vm_latest/utils/mod.rs +++ b/core/lib/multivm/src/versions/vm_latest/utils/mod.rs @@ -21,7 +21,7 @@ pub(crate) fn hash_evm_bytecode(bytecode: &[u8]) -> H256 { let result = hasher.finalize(); let mut output = [0u8; 32]; - output[..].copy_from_slice(&result.as_slice()); + output[..].copy_from_slice(result.as_slice()); output[0] = BlobSha256Format::VERSION_BYTE; output[1] = 0; output[2..4].copy_from_slice(&len.to_be_bytes()); diff --git a/core/node/state_keeper/src/updates/l2_block_updates.rs b/core/node/state_keeper/src/updates/l2_block_updates.rs index a448f38a6b31..33b435d9db01 100644 --- a/core/node/state_keeper/src/updates/l2_block_updates.rs +++ b/core/node/state_keeper/src/updates/l2_block_updates.rs @@ -104,6 +104,7 @@ impl L2BlockUpdates { self.block_execution_metrics += execution_metrics; } + #[allow(clippy::too_many_arguments)] pub(crate) fn extend_from_executed_transaction( &mut self, tx: Transaction, diff --git a/core/node/state_keeper/src/updates/mod.rs b/core/node/state_keeper/src/updates/mod.rs index 45bfebabeac0..59267b976dbe 100644 --- a/core/node/state_keeper/src/updates/mod.rs +++ b/core/node/state_keeper/src/updates/mod.rs @@ -104,6 +104,7 @@ impl UpdatesManager { self.protocol_version } + #[allow(clippy::too_many_arguments)] pub fn extend_from_executed_transaction( &mut self, tx: Transaction, diff --git a/core/tests/ts-integration/tests/evm-contracts.test.ts b/core/tests/ts-integration/tests/evm-contracts.test.ts index 145975b3af05..90eb0975f021 100644 --- a/core/tests/ts-integration/tests/evm-contracts.test.ts +++ b/core/tests/ts-integration/tests/evm-contracts.test.ts @@ -12,10 +12,6 @@ import { deployContract, getEVMArtifact, getEVMContractFactory, getTestContract import * as ethers from 'ethers'; import * as zksync from 'zksync-ethers'; -import fs, { PathLike } from 'fs'; -import csv from 'csv-parser'; -import { createObjectCsvWriter } from 'csv-writer'; - const contracts = { tester: getTestContract('TestEVMCreate'), erc20: getTestContract('ERC20'), @@ -97,7 +93,7 @@ describe('EVM equivalence contract', () => { const factory = getEVMContractFactory(alice, artifacts.counter); const contract = await factory.deploy(args); await contract.deploymentTransaction()?.wait(); - const receipt = await alice.provider.getTransactionReceipt( + await alice.provider.getTransactionReceipt( contract.deploymentTransaction()?.hash ?? (() => { throw new Error('Deployment transaction has failed'); @@ -124,7 +120,7 @@ describe('EVM equivalence contract', () => { ethers.keccak256(initBytecode) ); - const receipt = await (await evmCreateTester.create2(salt, initBytecode)).wait(); + await (await evmCreateTester.create2(salt, initBytecode)).wait(); await assertCreatedCorrectly(deployer, expectedAddress, runtimeBytecode); @@ -163,7 +159,7 @@ describe('EVM equivalence contract', () => { chainId: alice.provider._network.chainId, data }; - const result = await (await alice.sendTransaction(dep_transaction)).wait(); + await (await alice.sendTransaction(dep_transaction)).wait(); const expectedAddressCreate = ethers.getCreateAddress({ from: alice.address, nonce: await alice.getNonce() @@ -233,7 +229,7 @@ describe('EVM equivalence contract', () => { nonce }); - const result = await (await creatorContract.getFunction('create')()).wait(); + await (await creatorContract.getFunction('create')()).wait(); await assertCreatedCorrectly(deployer, expectedAddress, runtimeBytecode); }); @@ -480,7 +476,7 @@ describe('EVM equivalence contract', () => { await nativeUniswapPair.getFunction('swap')(0, 5000, alice.address, '0x') ).wait(); - const evmLiquidityTransfer = await ( + await ( await evmUniswapPair.getFunction('transfer')( evmUniswapPair.getAddress(), (await evmUniswapPair.getFunction('balanceOf')(alice.address)).toString() @@ -561,91 +557,6 @@ describe('EVM equivalence contract', () => { }); }); -type BenchmarkResult = { - name: string; - used_zkevm_ergs: string; - used_evm_gas: string; - used_circuits: string; -}; - -async function saveBenchmark(name: string, filename: string, result: string) { - try { - const resultWithName = { - name: name, - used_zkevm_ergs: result, - used_evm_gas: '0', - used_circuits: '0' - }; - - let results: BenchmarkResult[] = []; - - // Read existing CSV file - if (fs.existsSync(filename)) { - const existingResults: BenchmarkResult[] = await new Promise((resolve, reject) => { - const results: BenchmarkResult[] = []; - fs.createReadStream(filename) - .pipe(csv()) - .on('data', (data) => results.push(data)) - .on('end', () => resolve(results)) - .on('error', reject); - }); - results = existingResults.map((result) => ({ - name: result.name, - used_zkevm_ergs: result.used_zkevm_ergs, - used_evm_gas: result.used_evm_gas, - used_circuits: result.used_circuits - })); - } - - // Push the new result - results.push(resultWithName); - - // Write results back to CSV - const csvWriter = createObjectCsvWriter({ - path: filename, - header: [ - { id: 'name', title: 'name' }, - { id: 'used_zkevm_ergs', title: 'used_zkevm_ergs' }, - { id: 'used_evm_gas', title: 'used_evm_gas' }, - { id: 'used_circuits', title: 'used_circuits' } - ] - }); - await csvWriter.writeRecords(results); - - console.log('Benchmark saved successfully.'); - } catch (error) { - console.error('Error saving benchmark:', error); - } -} -function zeroPad(num: number, places: number): string { - return String(num).padStart(places, '0'); -} - -async function startBenchmark(): Promise { - try { - const now = new Date(); - const year = now.getUTCFullYear(); - const month = zeroPad(now.getUTCMonth() + 1, 2); // Months are zero-based, so add 1 - const day = zeroPad(now.getUTCDate(), 2); - const hour = zeroPad(now.getUTCHours(), 2); - const minute = zeroPad(now.getUTCMinutes(), 2); - const second = zeroPad(now.getUTCSeconds(), 2); - const formattedTime = `${year}-${month}-${day}-${hour}-${minute}-${second}`; - const directoryPath = 'benchmarks'; - - if (!fs.existsSync(directoryPath)) { - // If it doesn't exist, create it - fs.mkdirSync(directoryPath); - } - - const filename = `benchmarks/benchmark_integration_${formattedTime}.csv`; - return filename; - } catch (error) { - console.error('Error creating benchmark:', error); - return ''; - } -} - async function deploygasCallerContract(alice: zksync.Wallet, contract: any, ...args: Array) { const counterFactory = getEVMContractFactory(alice, contract); const counterContract = await counterFactory.deploy(...args); @@ -915,25 +826,3 @@ const opcodeDataDump: any = {}; ].forEach((key) => { opcodeDataDump[Number(key).toString()] = []; }); - -async function dumpOpcodeLogs(hash: string, provider: zksync.Provider): Promise { - let tx_receipt = - (await provider.getTransactionReceipt(hash)) ?? - (() => { - throw new Error('Get Transaction Receipt has failed'); - })(); - const logs = tx_receipt.logs; - logs.forEach((log) => { - if (log.topics[0] === '0x63307236653da06aaa7e128a306b128c594b4cf3b938ef212975ed10dad17515') { - //Overhead - overheadDataDump.push(Number(ethers.AbiCoder.defaultAbiCoder().decode(['uint256'], log.data).toString())); - } else if (log.topics[0] === '0xca5a69edf1b934943a56c00605317596b03e2f61c3f633e8657b150f102a3dfa') { - // Opcode - const parsed = ethers.AbiCoder.defaultAbiCoder().decode(['uint256', 'uint256'], log.data); - const opcode = Number(parsed[0].toString()); - const cost = Number(parsed[1].toString()); - - opcodeDataDump[opcode.toString()].push(cost); - } - }); -} From 8a687eb063e38e1c785b884c6634de75fa53efd2 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 26 Aug 2024 15:36:21 -0300 Subject: [PATCH 46/76] Update genesis proto message to mantain compatibility with older version --- .../protobuf_config/src/proto/config/genesis.proto | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/lib/protobuf_config/src/proto/config/genesis.proto b/core/lib/protobuf_config/src/proto/config/genesis.proto index 34d65d8258e7..8a2890331173 100644 --- a/core/lib/protobuf_config/src/proto/config/genesis.proto +++ b/core/lib/protobuf_config/src/proto/config/genesis.proto @@ -21,12 +21,12 @@ message Genesis { optional uint64 genesis_protocol_version = 4; // optional; optional string default_aa_hash = 5; // required; h256 optional string bootloader_hash = 6; // required; h256 - optional string evm_simulator_hash = 7; // required; h256 - optional uint64 l1_chain_id = 8; // required; - optional uint64 l2_chain_id = 9; // required; - optional string fee_account = 10; // h160 - optional Prover prover = 11; + optional uint64 l1_chain_id = 7; // required; + optional uint64 l2_chain_id = 8; // required; + optional string fee_account = 9; // h160 + optional Prover prover = 10; optional L1BatchCommitDataGeneratorMode l1_batch_commit_data_generator_mode = 29; // optional, default to rollup - optional string genesis_protocol_semantic_version = 13; // optional; - reserved 12; reserved "shared_bridge"; + optional string genesis_protocol_semantic_version = 12; // optional; + optional string evm_simulator_hash = 13; // required; h256 + reserved 11; reserved "shared_bridge"; } From 4f1b3aad8c80ce08d841924ca7b121ab7282008d Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 26 Aug 2024 16:17:36 -0300 Subject: [PATCH 47/76] Update system contracts hashes for state keeper test --- core/lib/env_config/src/chain.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/lib/env_config/src/chain.rs b/core/lib/env_config/src/chain.rs index 973268c0a838..0bfcd957c56e 100644 --- a/core/lib/env_config/src/chain.rs +++ b/core/lib/env_config/src/chain.rs @@ -97,13 +97,13 @@ mod tests { validation_computational_gas_limit: 10_000_000, save_call_traces: false, bootloader_hash: Some(hash( - "0x010007ede999d096c84553fb514d3d6ca76fbf39789dda76bfeda9f3ae06236e", + "0x010008ddf6824c3f8778b86a85d568ddfb45c29bf23b604fad20b91e6d8d458b", )), default_aa_hash: Some(hash( - "0x0100055b041eb28aff6e3a6e0f37c31fd053fc9ef142683b05e5f0aee6934066", + "0x0100058d69da9a1ba9e97d8d26a67967a39e1a9d50d55a4b6aace7d98877a485", )), evm_simulator_hash: Some(hash( - "0x01000f197081a9906cc411d0698c4961aeb5c74877f37f7071681da6e8ef3f31", + "0x01000f196acd122635a752fcb275be0cc95fd3bba348c1d0908a517fe316418e", )), l1_batch_commit_data_generator_mode, max_circuits_per_batch: 24100, @@ -138,8 +138,8 @@ mod tests { CHAIN_STATE_KEEPER_FEE_MODEL_VERSION="V2" CHAIN_STATE_KEEPER_VALIDATION_COMPUTATIONAL_GAS_LIMIT="10000000" CHAIN_STATE_KEEPER_SAVE_CALL_TRACES="false" - CHAIN_STATE_KEEPER_BOOTLOADER_HASH=0x010007ede999d096c84553fb514d3d6ca76fbf39789dda76bfeda9f3ae06236e - CHAIN_STATE_KEEPER_DEFAULT_AA_HASH=0x0100055b041eb28aff6e3a6e0f37c31fd053fc9ef142683b05e5f0aee6934066 + CHAIN_STATE_KEEPER_BOOTLOADER_HASH=0x010008ddf6824c3f8778b86a85d568ddfb45c29bf23b604fad20b91e6d8d458b + CHAIN_STATE_KEEPER_DEFAULT_AA_HASH=0x0100058d69da9a1ba9e97d8d26a67967a39e1a9d50d55a4b6aace7d98877a485 CHAIN_STATE_KEEPER_PROTECTIVE_READS_PERSISTENCE_ENABLED=true CHAIN_STATE_KEEPER_L1_BATCH_COMMIT_DATA_GENERATOR_MODE="{l1_batch_commit_data_generator_mode}" "# From ce520c0c56692aedb623597aee2ada0adad72500 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 26 Aug 2024 18:45:17 -0300 Subject: [PATCH 48/76] Increase timeout for ts tests --- core/tests/ts-integration/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/tests/ts-integration/package.json b/core/tests/ts-integration/package.json index 2f438a920cb0..e74fbfa83e2b 100644 --- a/core/tests/ts-integration/package.json +++ b/core/tests/ts-integration/package.json @@ -4,7 +4,7 @@ "license": "MIT", "private": true, "scripts": { - "test": "zk f jest --forceExit --testTimeout 60000", + "test": "zk f jest --forceExit --testTimeout 600000", "long-running-test": "zk f jest", "fee-test": "RUN_FEE_TEST=1 zk f jest -- fees.test.ts", "api-test": "zk f jest -- api/web3.test.ts api/debug.test.ts", From cf92e7b002db89ede924339ec8e29c0a68aff993 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 27 Aug 2024 16:52:58 -0300 Subject: [PATCH 49/76] Update contracts submodule --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index 0ac46175e091..0922be90563c 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 0ac46175e091586e6e23dcafda12b15009cbec7d +Subproject commit 0922be90563c6fd251a9a3ec67aa0de91f2539b5 From 97cdba8f0179f7749200dd2ae926a0f62fac60e3 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 27 Aug 2024 17:09:15 -0300 Subject: [PATCH 50/76] Fix rust lints --- core/tests/vm-benchmark/src/transaction.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/tests/vm-benchmark/src/transaction.rs b/core/tests/vm-benchmark/src/transaction.rs index 90e1c6360b81..d5fedfa4df94 100644 --- a/core/tests/vm-benchmark/src/transaction.rs +++ b/core/tests/vm-benchmark/src/transaction.rs @@ -47,7 +47,7 @@ pub fn get_deploy_tx_with_gas_limit(code: &[u8], gas_limit: u32, nonce: u32) -> .collect(); let mut signed = L2Tx::new_signed( - CONTRACT_DEPLOYER_ADDRESS, + Some(CONTRACT_DEPLOYER_ADDRESS), calldata, Nonce(nonce), tx_fee(gas_limit), @@ -76,7 +76,7 @@ fn tx_fee(gas_limit: u32) -> Fee { pub fn get_transfer_tx(nonce: u32) -> Transaction { let mut signed = L2Tx::new_signed( - PRIVATE_KEY.address(), + Some(PRIVATE_KEY.address()), vec![], // calldata Nonce(nonce), tx_fee(1_000_000), @@ -109,7 +109,7 @@ pub fn get_load_test_deploy_tx() -> Transaction { factory_deps.push(LOAD_TEST_CONTRACT.bytecode.clone()); let mut signed = L2Tx::new_signed( - CONTRACT_DEPLOYER_ADDRESS, + Some(CONTRACT_DEPLOYER_ADDRESS), create_calldata, Nonce(0), tx_fee(100_000_000), @@ -147,7 +147,7 @@ pub fn get_load_test_tx(nonce: u32, gas_limit: u32, params: LoadTestParams) -> T .expect("cannot encode `execute` inputs"); let mut signed = L2Tx::new_signed( - *LOAD_TEST_CONTRACT_ADDRESS, + Some(*LOAD_TEST_CONTRACT_ADDRESS), calldata, Nonce(nonce), tx_fee(gas_limit), From 7a8ca0ae77922c87c90c63b1506221cfcde2ede9 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 27 Aug 2024 17:48:17 -0300 Subject: [PATCH 51/76] Fix format for sol files --- .../evm-contracts/ConstructorRevert.sol | 4 +- .../evm-contracts/CounterFallback.sol | 1 - .../evm-contracts/CounterWithParam.sol | 7 +- .../ts-integration/evm-contracts/Creator.sol | 2 +- .../evm-contracts/CreatorFallback.sol | 1 + .../ts-integration/evm-contracts/ERC20.sol | 34 +++++----- .../evm-contracts/GasCaller.sol | 2 +- .../evm-contracts/OpcodeTest.sol | 30 ++++----- .../evm-contracts/OpcodeTestFallback.sol | 48 +++++++------ .../evm-contracts/ProxyCaller.sol | 6 +- .../evm-contracts/SelfDestruct.sol | 6 +- .../evm-contracts/UniswapFallback.sol | 67 ++++++++++--------- 12 files changed, 101 insertions(+), 107 deletions(-) diff --git a/core/tests/ts-integration/evm-contracts/ConstructorRevert.sol b/core/tests/ts-integration/evm-contracts/ConstructorRevert.sol index 468b3395ce5b..868e57edca79 100644 --- a/core/tests/ts-integration/evm-contracts/ConstructorRevert.sol +++ b/core/tests/ts-integration/evm-contracts/ConstructorRevert.sol @@ -5,9 +5,7 @@ pragma solidity >=0.7.0; contract ConstructorRevert { uint256 value; - constructor() { - revert('Failure string'); + revert("Failure string"); } - } diff --git a/core/tests/ts-integration/evm-contracts/CounterFallback.sol b/core/tests/ts-integration/evm-contracts/CounterFallback.sol index 2535a05262bf..c67dfec9459e 100644 --- a/core/tests/ts-integration/evm-contracts/CounterFallback.sol +++ b/core/tests/ts-integration/evm-contracts/CounterFallback.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.0; contract CounterFallback { - function performCall() external { uint256 value = 0; value += 1; diff --git a/core/tests/ts-integration/evm-contracts/CounterWithParam.sol b/core/tests/ts-integration/evm-contracts/CounterWithParam.sol index 1261e2f9fa06..714b4d665ae3 100644 --- a/core/tests/ts-integration/evm-contracts/CounterWithParam.sol +++ b/core/tests/ts-integration/evm-contracts/CounterWithParam.sol @@ -5,7 +5,6 @@ pragma solidity >=0.7.0; contract CounterWithParam { uint256 value; - constructor(uint256 _startingValue) { value = _startingValue; } @@ -13,14 +12,14 @@ contract CounterWithParam { function increment(uint256 x) public { value += x; } - - function incrementWithRevertPayable(uint256 x, bool shouldRevert) payable public returns (uint256) { + + function incrementWithRevertPayable(uint256 x, bool shouldRevert) public payable returns (uint256) { return incrementWithRevert(x, shouldRevert); } function incrementWithRevert(uint256 x, bool shouldRevert) public returns (uint256) { value += x; - if(shouldRevert) { + if (shouldRevert) { revert("This method always reverts"); } return value; diff --git a/core/tests/ts-integration/evm-contracts/Creator.sol b/core/tests/ts-integration/evm-contracts/Creator.sol index 516bce4cbe38..63a6f7e3b1d7 100644 --- a/core/tests/ts-integration/evm-contracts/Creator.sol +++ b/core/tests/ts-integration/evm-contracts/Creator.sol @@ -13,7 +13,7 @@ contract Creator { new Creation(); } - function getCreationRuntimeCode() external pure returns(bytes memory){ + function getCreationRuntimeCode() external pure returns (bytes memory) { return type(Creation).runtimeCode; } } diff --git a/core/tests/ts-integration/evm-contracts/CreatorFallback.sol b/core/tests/ts-integration/evm-contracts/CreatorFallback.sol index ce532aa69b7e..30ebabd7cc7a 100644 --- a/core/tests/ts-integration/evm-contracts/CreatorFallback.sol +++ b/core/tests/ts-integration/evm-contracts/CreatorFallback.sol @@ -13,6 +13,7 @@ contract CreatorFallback { new Creation(); type(Creation).runtimeCode; } + fallback() external { this.performCall(); } diff --git a/core/tests/ts-integration/evm-contracts/ERC20.sol b/core/tests/ts-integration/evm-contracts/ERC20.sol index 5c1c89faf7ad..1b65e6541804 100644 --- a/core/tests/ts-integration/evm-contracts/ERC20.sol +++ b/core/tests/ts-integration/evm-contracts/ERC20.sol @@ -2,14 +2,14 @@ pragma solidity >=0.7.0; -contract ERC20{ +contract ERC20 { string public symbol; - string public name; + string public name; uint8 public decimals; - uint public totalSupply; + uint256 public totalSupply; - mapping(address => uint) balances; - mapping(address => mapping(address => uint)) allowed; + mapping(address => uint256) balances; + mapping(address => mapping(address => uint256)) allowed; event Transfer(address indexed _from, address indexed _to, uint256 _value); event Approval(address indexed _owner, address indexed _spender, uint256 _value); @@ -23,25 +23,28 @@ contract ERC20{ emit Transfer(address(0), msg.sender, totalSupply); } - - function balanceOf(address tokenOwner) public view returns (uint balance) { + function balanceOf(address tokenOwner) public view returns (uint256 balance) { return balances[tokenOwner]; } - function transfer(address to, uint tokens) public returns (bool success) { + function transfer(address to, uint256 tokens) public returns (bool success) { balances[msg.sender] = safeSub(balances[msg.sender], tokens); balances[to] = safeAdd(balances[to], tokens); emit Transfer(msg.sender, to, tokens); return true; } - function approve(address spender, uint tokens) public returns (bool success) { + function approve(address spender, uint256 tokens) public returns (bool success) { allowed[msg.sender][spender] = tokens; emit Approval(msg.sender, spender, tokens); return true; } - function transferFrom(address from, address to, uint tokens) public returns (bool success) { + function transferFrom( + address from, + address to, + uint256 tokens + ) public returns (bool success) { balances[from] = safeSub(balances[from], tokens); allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], tokens); balances[to] = safeAdd(balances[to], tokens); @@ -49,28 +52,27 @@ contract ERC20{ return true; } - function allowance(address tokenOwner, address spender) public view returns (uint remaining) { + function allowance(address tokenOwner, address spender) public view returns (uint256 remaining) { return allowed[tokenOwner][spender]; } - function safeAdd(uint a, uint b) internal pure returns (uint c) { + function safeAdd(uint256 a, uint256 b) internal pure returns (uint256 c) { c = a + b; require(c >= a); } - function safeSub(uint a, uint b) internal pure returns (uint c) { + function safeSub(uint256 a, uint256 b) internal pure returns (uint256 c) { require(b <= a); c = a - b; } - function safeMul(uint a, uint b) internal pure returns (uint c) { + function safeMul(uint256 a, uint256 b) internal pure returns (uint256 c) { c = a * b; require(a == 0 || c / a == b); } - function safeDiv(uint a, uint b) internal pure returns (uint c) { + function safeDiv(uint256 a, uint256 b) internal pure returns (uint256 c) { require(b > 0); c = a / b; } - } diff --git a/core/tests/ts-integration/evm-contracts/GasCaller.sol b/core/tests/ts-integration/evm-contracts/GasCaller.sol index 4fd43a235b5e..25b56aa744d6 100644 --- a/core/tests/ts-integration/evm-contracts/GasCaller.sol +++ b/core/tests/ts-integration/evm-contracts/GasCaller.sol @@ -5,7 +5,7 @@ pragma solidity ^0.8.0; contract GasCaller { uint256 _resultGas; - function callAndGetGas(address _to) external returns (uint256){ + function callAndGetGas(address _to) external returns (uint256) { uint256 startGas = gasleft(); // Just doing a call to an address (bool success, ) = _to.call(""); diff --git a/core/tests/ts-integration/evm-contracts/OpcodeTest.sol b/core/tests/ts-integration/evm-contracts/OpcodeTest.sol index 9c739846f334..721339bd7ae8 100644 --- a/core/tests/ts-integration/evm-contracts/OpcodeTest.sol +++ b/core/tests/ts-integration/evm-contracts/OpcodeTest.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.0; contract OpcodeTest { - function execute() external { uint256 loaded = 1; uint256 tmp; @@ -19,20 +18,20 @@ contract OpcodeTest { // MULMOD loaded := exp(loaded, 2) loaded := signextend(loaded, 2) - tmp := lt(loaded, 2) - tmp := gt(loaded, 2) - tmp := slt(loaded, 2) - tmp := sgt(loaded, 2) + tmp := lt(loaded, 2) + tmp := gt(loaded, 2) + tmp := slt(loaded, 2) + tmp := sgt(loaded, 2) tmp := eq(loaded, 2) tmp := iszero(tmp) - tmp := and(1,1) - tmp := or(1,1) - tmp := xor(1,1) + tmp := and(1, 1) + tmp := or(1, 1) + tmp := xor(1, 1) tmp := not(tmp) - tmp := byte(tmp,1) - tmp := shl(tmp,1) - tmp := shr(tmp,1) - tmp := sar(tmp,1) + tmp := byte(tmp, 1) + tmp := shl(tmp, 1) + tmp := shr(tmp, 1) + tmp := sar(tmp, 1) tmp := keccak256(0, 0x40) tmp := address() tmp := balance(0x00) @@ -61,10 +60,10 @@ contract OpcodeTest { tmp := basefee() // POP tmp := mload(1) - mstore(1024,1) - mstore8(10242,1) + mstore(1024, 1) + mstore8(10242, 1) tmp := sload(0) - sstore(0,1) + sstore(0, 1) // JUMP // JUMPI // PC @@ -121,5 +120,4 @@ contract OpcodeTest { // tmp = 0x665544332211ff998877665544332211ffeeddccbbaa998877665544332211; // tmp = 0x77665544332211ff998877665544332211ffeeddccbbaa998877665544332211; } - } diff --git a/core/tests/ts-integration/evm-contracts/OpcodeTestFallback.sol b/core/tests/ts-integration/evm-contracts/OpcodeTestFallback.sol index 68d64fc074d8..47f427a27333 100644 --- a/core/tests/ts-integration/evm-contracts/OpcodeTestFallback.sol +++ b/core/tests/ts-integration/evm-contracts/OpcodeTestFallback.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.0; contract OpcodeTestFallback { - function performCall() external { uint256 loaded = 1; uint256 tmp; @@ -19,20 +18,20 @@ contract OpcodeTestFallback { // MULMOD loaded := exp(loaded, 2) loaded := signextend(loaded, 2) - tmp := lt(loaded, 2) - tmp := gt(loaded, 2) - tmp := slt(loaded, 2) - tmp := sgt(loaded, 2) + tmp := lt(loaded, 2) + tmp := gt(loaded, 2) + tmp := slt(loaded, 2) + tmp := sgt(loaded, 2) tmp := eq(loaded, 2) tmp := iszero(tmp) - tmp := and(1,1) - tmp := or(1,1) - tmp := xor(1,1) + tmp := and(1, 1) + tmp := or(1, 1) + tmp := xor(1, 1) tmp := not(tmp) - tmp := byte(tmp,1) - tmp := shl(tmp,1) - tmp := shr(tmp,1) - tmp := sar(tmp,1) + tmp := byte(tmp, 1) + tmp := shl(tmp, 1) + tmp := shr(tmp, 1) + tmp := sar(tmp, 1) tmp := keccak256(0, 0x40) tmp := address() tmp := balance(0x00) @@ -61,10 +60,10 @@ contract OpcodeTestFallback { tmp := basefee() // POP tmp := mload(1) - mstore(1024,1) - mstore8(10242,1) + mstore(1024, 1) + mstore8(10242, 1) tmp := sload(0) - sstore(0,1) + sstore(0, 1) // JUMP // JUMPI // PC @@ -86,17 +85,17 @@ contract OpcodeTestFallback { // INVALID // selfdestruct(sender) tmp := calldataload(0) - calldatacopy(10,0,1) - codecopy(10,0,1) + calldatacopy(10, 0, 1) + codecopy(10, 0, 1) tmp := extcodesize(0) - extcodecopy(address(),10,0,1) - returndatacopy(10,0,1) + extcodecopy(address(), 10, 0, 1) + returndatacopy(10, 0, 1) pop(extcodehash(0)) - log0(0,30) - log1(0,30,30) - log2(0,30,30,30) - log3(0,30,30,30,30) - log4(0,30,30,30,30,30) + log0(0, 30) + log1(0, 30, 30) + log2(0, 30, 30, 30) + log3(0, 30, 30, 30, 30) + log4(0, 30, 30, 30, 30, 30) } // tmp = 0; @@ -137,5 +136,4 @@ contract OpcodeTestFallback { fallback() external { this.performCall(); } - } diff --git a/core/tests/ts-integration/evm-contracts/ProxyCaller.sol b/core/tests/ts-integration/evm-contracts/ProxyCaller.sol index 926d2a944d41..379d7c7addcd 100644 --- a/core/tests/ts-integration/evm-contracts/ProxyCaller.sol +++ b/core/tests/ts-integration/evm-contracts/ProxyCaller.sol @@ -11,15 +11,15 @@ interface ICounterWithParam { } contract ProxyCaller { - function executeIncrememt(address dest, uint256 x) external{ + function executeIncrememt(address dest, uint256 x) external { ICounterWithParam(dest).increment(x); } - function proxyGet(address dest) external view returns (uint256){ + function proxyGet(address dest) external view returns (uint256) { return ICounterWithParam(dest).get(); } - function proxyGetBytes(address dest) external returns(bytes memory returnData){ + function proxyGetBytes(address dest) external returns (bytes memory returnData) { return ICounterWithParam(dest).getBytes(); } } diff --git a/core/tests/ts-integration/evm-contracts/SelfDestruct.sol b/core/tests/ts-integration/evm-contracts/SelfDestruct.sol index b28a25968e3e..12fec9555908 100644 --- a/core/tests/ts-integration/evm-contracts/SelfDestruct.sol +++ b/core/tests/ts-integration/evm-contracts/SelfDestruct.sol @@ -3,11 +3,9 @@ pragma solidity >=0.7.0; contract SelfDestruct { + constructor() payable {} - constructor() payable { - } - - function destroy(address recipient) external{ + function destroy(address recipient) external { assembly { selfdestruct(recipient) } diff --git a/core/tests/ts-integration/evm-contracts/UniswapFallback.sol b/core/tests/ts-integration/evm-contracts/UniswapFallback.sol index b2d631d3551d..0237b4be1ba5 100644 --- a/core/tests/ts-integration/evm-contracts/UniswapFallback.sol +++ b/core/tests/ts-integration/evm-contracts/UniswapFallback.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.0; interface IUniswapV2ERC20 { - event Approval(address indexed owner, address indexed spender, uint value); - event Transfer(address indexed from, address indexed to, uint value); + event Approval(address indexed owner, address indexed spender, uint256 value); + event Transfer(address indexed from, address indexed to, uint256 value); function name() external pure returns (string memory); @@ -12,33 +12,33 @@ interface IUniswapV2ERC20 { function decimals() external pure returns (uint8); - function totalSupply() external returns (uint); + function totalSupply() external returns (uint256); - function balanceOf(address owner) external returns (uint); + function balanceOf(address owner) external returns (uint256); - function allowance(address owner, address spender) external returns (uint); + function allowance(address owner, address spender) external returns (uint256); - function approve(address spender, uint value) external returns (bool); + function approve(address spender, uint256 value) external returns (bool); - function transfer(address to, uint value) external returns (bool); + function transfer(address to, uint256 value) external returns (bool); function transferFrom( address from, address to, - uint value + uint256 value ) external returns (bool); function DOMAIN_SEPARATOR() external returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); - function nonces(address owner) external returns (uint); + function nonces(address owner) external returns (uint256); function permit( address owner, address spender, - uint value, - uint deadline, + uint256 value, + uint256 deadline, uint8 v, bytes32 r, bytes32 s @@ -46,24 +46,19 @@ interface IUniswapV2ERC20 { } interface IUniswapV2Pair { - event Mint(address indexed sender, uint amount0, uint amount1); - event Burn( - address indexed sender, - uint amount0, - uint amount1, - address indexed to - ); + event Mint(address indexed sender, uint256 amount0, uint256 amount1); + event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to); event Swap( address indexed sender, - uint amount0In, - uint amount1In, - uint amount0Out, - uint amount1Out, + uint256 amount0In, + uint256 amount1In, + uint256 amount0Out, + uint256 amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); - function MINIMUM_LIQUIDITY() external pure returns (uint); + function MINIMUM_LIQUIDITY() external pure returns (uint256); function factory() external returns (address); @@ -73,21 +68,25 @@ interface IUniswapV2Pair { function getReserves() external - returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); + returns ( + uint112 reserve0, + uint112 reserve1, + uint32 blockTimestampLast + ); - function price0CumulativeLast() external returns (uint); + function price0CumulativeLast() external returns (uint256); - function price1CumulativeLast() external returns (uint); + function price1CumulativeLast() external returns (uint256); - function kLast() external returns (uint); + function kLast() external returns (uint256); - function mint(address to) external returns (uint liquidity); + function mint(address to) external returns (uint256 liquidity); - function burn(address to) external returns (uint amount0, uint amount1); + function burn(address to) external returns (uint256 amount0, uint256 amount1); function swap( - uint amount0Out, - uint amount1Out, + uint256 amount0Out, + uint256 amount1Out, address to, bytes calldata data ) external; @@ -108,16 +107,18 @@ contract UniswapFallback { uniswapPair = IUniswapV2Pair(_uniswap_address); uniswapPair2 = IUniswapV2ERC20(_uniswap_address); } + function setAliceAddress(address _alice_address) public { alice_address = _alice_address; } + // Fallback function fallback() external { // Implement any logic you want the contract to perform when it receives Ether // This function will be called when the contract receives Ether and no other function matches the call data uniswapPair.mint(alice_address); - uniswapPair.swap(0,5000,alice_address,"0x"); - uint balance = uniswapPair2.balanceOf(alice_address); + uniswapPair.swap(0, 5000, alice_address, "0x"); + uint256 balance = uniswapPair2.balanceOf(alice_address); //uniswapPair2.transfer(address(uniswapPair),balance); //uniswapPair.burn(alice_address); } From 77d66b445692ef392d61520566f84b3fb280c45f Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 28 Aug 2024 10:55:17 -0300 Subject: [PATCH 52/76] Fix errors from merge adding execute address as Option --- .../multivm/src/versions/vm_fast/tests/get_used_contracts.rs | 2 +- .../multivm/src/versions/vm_latest/tests/get_used_contracts.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs b/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs index a3afedab956b..27ccf13e2f8c 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs @@ -144,7 +144,7 @@ fn execute_proxy_counter(gas: u32) -> (VmTester, U256, VmExecutionResultAndLogs) let increment = proxy_counter_abi.function("increment").unwrap(); let increment_tx = account.get_l2_tx_for_execute( Execute { - contract_address: deploy_tx.address, + contract_address: Some(deploy_tx.address), calldata: increment .encode_input(&[Token::Uint(1.into()), Token::Uint(gas.into())]) .unwrap(), diff --git a/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs b/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs index 38b884310d4d..ca2000f8fd54 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs @@ -207,7 +207,7 @@ fn execute_proxy_counter(gas: u32) -> (VmTester, U256, VmExecut let increment = proxy_counter_abi.function("increment").unwrap(); let increment_tx = account.get_l2_tx_for_execute( Execute { - contract_address: deploy_tx.address, + contract_address: Some(deploy_tx.address), calldata: increment .encode_input(&[Token::Uint(1.into()), Token::Uint(gas.into())]) .unwrap(), From caf6c58b72921830978bfb2e0e7402224a81f69c Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 28 Aug 2024 11:32:46 -0300 Subject: [PATCH 53/76] Fix mocked multicall response for tests --- core/node/eth_sender/src/tests.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/node/eth_sender/src/tests.rs b/core/node/eth_sender/src/tests.rs index d259e086d9fa..4ddadf400e3e 100644 --- a/core/node/eth_sender/src/tests.rs +++ b/core/node/eth_sender/src/tests.rs @@ -41,8 +41,9 @@ pub(crate) fn mock_multicall_response() -> Token { Token::Array(vec![ Token::Tuple(vec![Token::Bool(true), Token::Bytes(vec![1u8; 32])]), Token::Tuple(vec![Token::Bool(true), Token::Bytes(vec![2u8; 32])]), - Token::Tuple(vec![Token::Bool(true), Token::Bytes(vec![3u8; 96])]), - Token::Tuple(vec![Token::Bool(true), Token::Bytes(vec![4u8; 32])]), + Token::Tuple(vec![Token::Bool(true), Token::Bytes(vec![3u8; 32])]), + Token::Tuple(vec![Token::Bool(true), Token::Bytes(vec![4u8; 96])]), + Token::Tuple(vec![Token::Bool(true), Token::Bytes(vec![5u8; 32])]), Token::Tuple(vec![ Token::Bool(true), Token::Bytes( From 80ad08a264087e31e1e7ad53cfa4671cbf73052a Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 28 Aug 2024 12:20:35 -0300 Subject: [PATCH 54/76] Fix proposed upgrades tests --- core/lib/types/src/abi.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/lib/types/src/abi.rs b/core/lib/types/src/abi.rs index c2013dbdbe40..c1c0efa66e4c 100644 --- a/core/lib/types/src/abi.rs +++ b/core/lib/types/src/abi.rs @@ -258,6 +258,7 @@ impl ProposedUpgrade { ParamType::Array(ParamType::Bytes.into()), // factory deps ParamType::FixedBytes(32), // bootloader code hash ParamType::FixedBytes(32), // default account code hash + ParamType::FixedBytes(32), // evm simulator code hash ParamType::Address, // verifier address VerifierParams::schema(), // verifier params ParamType::Bytes, // l1 custom data @@ -279,6 +280,7 @@ impl ProposedUpgrade { ), Token::FixedBytes(self.bootloader_hash.into()), Token::FixedBytes(self.default_account_hash.into()), + Token::FixedBytes(self.evm_simulator_hash.into()), Token::Address(self.verifier), self.verifier_params.encode(), Token::Bytes(self.l1_contracts_upgrade_calldata.clone()), @@ -292,7 +294,7 @@ impl ProposedUpgrade { /// Returns an error if token doesn't match the `schema()`. pub fn decode(token: Token) -> anyhow::Result { let tokens = token.into_tuple().context("not a tuple")?; - anyhow::ensure!(tokens.len() == 10); + anyhow::ensure!(tokens.len() == 11); let mut t = tokens.into_iter(); let mut next = || t.next().unwrap(); Ok(Self { From 58f1dd50aacbbc7a33421b481be5868620a057dd Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 28 Aug 2024 13:46:02 -0300 Subject: [PATCH 55/76] Update tests for latest and fast vm --- .../versions/vm_fast/tests/l1_tx_execution.rs | 7 +- .../versions/vm_fast/tests/nonce_holder.rs | 11 +-- .../src/versions/vm_fast/tests/rollbacks.rs | 47 +++++++++--- .../tests/tester/transaction_test_info.rs | 73 ++++++++----------- .../vm_latest/tests/l1_tx_execution.rs | 7 +- .../versions/vm_latest/tests/nonce_holder.rs | 11 +-- .../src/versions/vm_latest/tests/rollbacks.rs | 47 +++++++++--- .../tests/tester/transaction_test_info.rs | 72 +++++++++--------- 8 files changed, 159 insertions(+), 116 deletions(-) diff --git a/core/lib/multivm/src/versions/vm_fast/tests/l1_tx_execution.rs b/core/lib/multivm/src/versions/vm_fast/tests/l1_tx_execution.rs index 84208328c72e..1a652fc59087 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/l1_tx_execution.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/l1_tx_execution.rs @@ -117,9 +117,8 @@ fn test_l1_tx_execution() { let res = vm.vm.execute(VmExecutionMode::OneTx); let storage_logs = res.logs.storage_logs; let res = StorageWritesDeduplicator::apply_on_empty_state(&storage_logs); - // We changed one slot inside contract. However, the rewrite of the `basePubdataSpent` didn't happen, since it was the same - // as the start of the previous tx. Thus we have `+1` slot for the changed counter and `-1` slot for base pubdata spent - assert_eq!(res.initial_storage_writes, basic_initial_writes); + // We changed one slot inside contract. + assert_eq!(res.initial_storage_writes - basic_initial_writes, 1); // No repeated writes let repeated_writes = res.repeated_storage_writes; @@ -146,7 +145,7 @@ fn test_l1_tx_execution() { assert!(result.result.is_failed(), "The transaction should fail"); let res = StorageWritesDeduplicator::apply_on_empty_state(&result.logs.storage_logs); - assert_eq!(res.initial_storage_writes, basic_initial_writes); + assert_eq!(res.initial_storage_writes, basic_initial_writes + 1); assert_eq!(res.repeated_storage_writes, 1); } diff --git a/core/lib/multivm/src/versions/vm_fast/tests/nonce_holder.rs b/core/lib/multivm/src/versions/vm_fast/tests/nonce_holder.rs index 6e3d507555cf..db54f0c8224a 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/nonce_holder.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/nonce_holder.rs @@ -36,6 +36,7 @@ impl From for u8 { #[test] fn test_nonce_holder() { let mut account = Account::random(); + let hex_addr = hex::encode(account.address.to_fixed_bytes()); let mut vm = VmTesterBuilder::new() .with_empty_in_memory_storage() @@ -92,7 +93,7 @@ fn test_nonce_holder() { run_nonce_test( 1u32, NonceHolderTestMode::SetValueUnderNonce, - Some("Previous nonce has not been used".to_string()), + Some("Error function_selector = 0x13595475, data = 0x13595475".to_string()), "Allowed to set value under non sequential value", ); @@ -133,7 +134,7 @@ fn test_nonce_holder() { run_nonce_test( 10u32, NonceHolderTestMode::IncreaseMinNonceBy5, - Some("Reusing the same nonce twice".to_string()), + Some(format!("Error function_selector = 0xe90aded4, data = 0xe90aded4000000000000000000000000{hex_addr}000000000000000000000000000000000000000000000000000000000000000a")), "Allowed to reuse nonce below the minimal one", ); @@ -149,7 +150,7 @@ fn test_nonce_holder() { run_nonce_test( 13u32, NonceHolderTestMode::IncreaseMinNonceBy5, - Some("Reusing the same nonce twice".to_string()), + Some(format!("Error function_selector = 0xe90aded4, data = 0xe90aded4000000000000000000000000{hex_addr}000000000000000000000000000000000000000000000000000000000000000d")), "Allowed to reuse the same nonce twice", ); @@ -165,7 +166,7 @@ fn test_nonce_holder() { run_nonce_test( 16u32, NonceHolderTestMode::IncreaseMinNonceTooMuch, - Some("The value for incrementing the nonce is too high".to_string()), + Some("Error function_selector = 0x45ac24a6, data = 0x45ac24a600000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000040000000000000000000000".to_string()), "Allowed for incrementing min nonce too much", ); @@ -173,7 +174,7 @@ fn test_nonce_holder() { run_nonce_test( 16u32, NonceHolderTestMode::LeaveNonceUnused, - Some("The nonce was not set as used".to_string()), + Some(format!("Error function_selector = 0x1f2f8478, data = 0x1f2f8478000000000000000000000000{hex_addr}0000000000000000000000000000000000000000000000000000000000000010")), "Allowed to leave nonce as unused", ); } diff --git a/core/lib/multivm/src/versions/vm_fast/tests/rollbacks.rs b/core/lib/multivm/src/versions/vm_fast/tests/rollbacks.rs index 4419aaeedfaa..f041d5ee96ca 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/rollbacks.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/rollbacks.rs @@ -1,6 +1,6 @@ use ethabi::Token; use zksync_contracts::{get_loadnext_contract, test_contracts::LoadnextContractExecutionParams}; -use zksync_types::{Execute, U256}; +use zksync_types::{Execute, Nonce, U256}; use crate::{ interface::TxExecutionMode, @@ -38,22 +38,40 @@ fn test_vm_rollbacks() { TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::WrongMagicValue.into()), TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::WrongSignature.into()), // The correct nonce is 0, this tx will fail - TransactionTestInfo::new_rejected(tx_2.clone(), TxModifier::WrongNonce.into()), + TransactionTestInfo::new_rejected( + tx_2.clone(), + TxModifier::WrongNonce(tx_2.nonce().unwrap(), Nonce(0)).into(), + ), // This tx will succeed TransactionTestInfo::new_processed(tx_0.clone(), false), // The correct nonce is 1, this tx will fail - TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::NonceReused.into()), + TransactionTestInfo::new_rejected( + tx_0.clone(), + TxModifier::NonceReused(tx_0.initiator_account(), tx_0.nonce().unwrap()).into(), + ), // The correct nonce is 1, this tx will fail - TransactionTestInfo::new_rejected(tx_2.clone(), TxModifier::WrongNonce.into()), + TransactionTestInfo::new_rejected( + tx_2.clone(), + TxModifier::WrongNonce(tx_2.nonce().unwrap(), Nonce(1)).into(), + ), // This tx will succeed TransactionTestInfo::new_processed(tx_1, false), // The correct nonce is 2, this tx will fail - TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::NonceReused.into()), + TransactionTestInfo::new_rejected( + tx_0.clone(), + TxModifier::NonceReused(tx_0.initiator_account(), tx_0.nonce().unwrap()).into(), + ), // This tx will succeed TransactionTestInfo::new_processed(tx_2.clone(), false), // This tx will fail - TransactionTestInfo::new_rejected(tx_2, TxModifier::NonceReused.into()), - TransactionTestInfo::new_rejected(tx_0, TxModifier::NonceReused.into()), + TransactionTestInfo::new_rejected( + tx_2.clone(), + TxModifier::NonceReused(tx_2.initiator_account(), tx_2.nonce().unwrap()).into(), + ), + TransactionTestInfo::new_rejected( + tx_0.clone(), + TxModifier::NonceReused(tx_0.initiator_account(), tx_0.nonce().unwrap()).into(), + ), ]); assert_eq!(result_without_rollbacks, result_with_rollbacks); @@ -131,12 +149,23 @@ fn test_vm_loadnext_rollbacks() { TransactionTestInfo::new_processed(loadnext_tx_1.clone(), true), TransactionTestInfo::new_rejected( loadnext_deploy_tx.clone(), - TxModifier::NonceReused.into(), + TxModifier::NonceReused( + loadnext_deploy_tx.initiator_account(), + loadnext_deploy_tx.nonce().unwrap(), + ) + .into(), ), TransactionTestInfo::new_processed(loadnext_tx_1, false), TransactionTestInfo::new_processed(loadnext_tx_2.clone(), true), TransactionTestInfo::new_processed(loadnext_tx_2.clone(), true), - TransactionTestInfo::new_rejected(loadnext_deploy_tx, TxModifier::NonceReused.into()), + TransactionTestInfo::new_rejected( + loadnext_deploy_tx.clone(), + TxModifier::NonceReused( + loadnext_deploy_tx.initiator_account(), + loadnext_deploy_tx.nonce().unwrap(), + ) + .into(), + ), TransactionTestInfo::new_processed(loadnext_tx_2, false), ]); diff --git a/core/lib/multivm/src/versions/vm_fast/tests/tester/transaction_test_info.rs b/core/lib/multivm/src/versions/vm_fast/tests/tester/transaction_test_info.rs index 562a8a6a6bdd..c3c1736902c9 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/tester/transaction_test_info.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/tester/transaction_test_info.rs @@ -1,4 +1,4 @@ -use zksync_types::{ExecuteTransactionCommon, Transaction, H160, U256}; +use zksync_types::{ExecuteTransactionCommon, Nonce, Transaction, H160, U256}; use super::VmTester; use crate::{ @@ -15,8 +15,8 @@ pub(crate) enum TxModifier { WrongSignatureLength, WrongSignature, WrongMagicValue, - WrongNonce, - NonceReused, + WrongNonce(Nonce, Nonce), + NonceReused(H160, Nonce), } #[derive(Debug, Clone)] @@ -41,15 +41,9 @@ impl From for ExpectedError { fn from(value: TxModifier) -> Self { let revert_reason = match value { TxModifier::WrongSignatureLength => { - Halt::ValidationFailed(VmRevertReason::General { - msg: "Signature length is incorrect".to_string(), - data: vec![ - 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 83, 105, 103, 110, 97, 116, 117, 114, 101, 32, - 108, 101, 110, 103, 116, 104, 32, 105, 115, 32, 105, 110, 99, 111, 114, 114, 101, 99, - 116, 0, 0, 0, - ], + Halt::ValidationFailed(VmRevertReason::Unknown { + function_selector: vec![144, 240, 73, 201], + data: vec![144, 240, 73, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45], }) } TxModifier::WrongSignature => { @@ -59,38 +53,35 @@ impl From for ExpectedError { }) } TxModifier::WrongMagicValue => { - Halt::ValidationFailed(VmRevertReason::General { - msg: "v is neither 27 nor 28".to_string(), - data: vec![ - 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 118, 32, 105, 115, 32, 110, 101, 105, 116, 104, - 101, 114, 32, 50, 55, 32, 110, 111, 114, 32, 50, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], + Halt::ValidationFailed(VmRevertReason::Unknown { + function_selector: vec![144, 240, 73, 201], + data: vec![144, 240, 73, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], }) } - TxModifier::WrongNonce => { - Halt::ValidationFailed(VmRevertReason::General { - msg: "Incorrect nonce".to_string(), - data: vec![ - 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 73, 110, 99, 111, 114, 114, 101, 99, 116, 32, 110, - 111, 110, 99, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], + TxModifier::WrongNonce(expected, actual) => { + let function_selector = vec![98, 106, 222, 48]; + let expected_nonce_bytes = expected.0.to_be_bytes().to_vec(); + let actual_nonce_bytes = actual.0.to_be_bytes().to_vec(); + // padding is 28 because an address takes up 4 bytes and we need it to fill a 32 byte field + let nonce_padding = vec![0u8; 28]; + let data = [function_selector.clone(), nonce_padding.clone(), expected_nonce_bytes, nonce_padding.clone(), actual_nonce_bytes].concat(); + Halt::ValidationFailed(VmRevertReason::Unknown { + function_selector, + data }) } - TxModifier::NonceReused => { - Halt::ValidationFailed(VmRevertReason::General { - msg: "Reusing the same nonce twice".to_string(), - data: vec![ - 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 82, 101, 117, 115, 105, 110, 103, 32, 116, 104, - 101, 32, 115, 97, 109, 101, 32, 110, 111, 110, 99, 101, 32, 116, 119, 105, 99, 101, 0, - 0, 0, 0, - ], + TxModifier::NonceReused(addr, nonce) => { + let function_selector = vec![233, 10, 222, 212]; + let addr = addr.as_bytes().to_vec(); + // padding is 12 because an address takes up 20 bytes and we need it to fill a 32 byte field + let addr_padding = vec![0u8; 12]; + // padding is 28 because an address takes up 4 bytes and we need it to fill a 32 byte field + let nonce_padding = vec![0u8; 28]; + let data = [function_selector.clone(), addr_padding, addr, nonce_padding, nonce.0.to_be_bytes().to_vec()].concat(); + Halt::ValidationFailed(VmRevertReason::Unknown { + function_selector, + data, }) } }; @@ -116,10 +107,10 @@ impl TransactionTestInfo { } TxModifier::WrongSignature => data.signature = vec![27u8; 65], TxModifier::WrongMagicValue => data.signature = vec![1u8; 65], - TxModifier::WrongNonce => { + TxModifier::WrongNonce(_, _) => { // Do not need to modify signature for nonce error } - TxModifier::NonceReused => { + TxModifier::NonceReused(_, _) => { // Do not need to modify signature for nonce error } } diff --git a/core/lib/multivm/src/versions/vm_latest/tests/l1_tx_execution.rs b/core/lib/multivm/src/versions/vm_latest/tests/l1_tx_execution.rs index dd06c99dd363..02199a360e94 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/l1_tx_execution.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/l1_tx_execution.rs @@ -112,9 +112,8 @@ fn test_l1_tx_execution() { let res = vm.vm.execute(VmExecutionMode::OneTx); let storage_logs = res.logs.storage_logs; let res = StorageWritesDeduplicator::apply_on_empty_state(&storage_logs); - // We changed one slot inside contract. However, the rewrite of the `basePubdataSpent` didn't happen, since it was the same - // as the start of the previous tx. Thus we have `+1` slot for the changed counter and `-1` slot for base pubdata spent - assert_eq!(res.initial_storage_writes - basic_initial_writes, 0); + // We changed one slot inside contract. + assert_eq!(res.initial_storage_writes - basic_initial_writes, 1); // No repeated writes let repeated_writes = res.repeated_storage_writes; @@ -142,7 +141,7 @@ fn test_l1_tx_execution() { let res = StorageWritesDeduplicator::apply_on_empty_state(&result.logs.storage_logs); // There are only basic initial writes - assert_eq!(res.initial_storage_writes - basic_initial_writes, 1); + assert_eq!(res.initial_storage_writes - basic_initial_writes, 2); } #[test] diff --git a/core/lib/multivm/src/versions/vm_latest/tests/nonce_holder.rs b/core/lib/multivm/src/versions/vm_latest/tests/nonce_holder.rs index ea11dd01818e..5e11ae358db5 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/nonce_holder.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/nonce_holder.rs @@ -40,6 +40,7 @@ impl From for u8 { #[test] fn test_nonce_holder() { let mut account = Account::random(); + let hex_addr = hex::encode(account.address.to_fixed_bytes()); let mut vm = VmTesterBuilder::new(HistoryEnabled) .with_empty_in_memory_storage() @@ -101,7 +102,7 @@ fn test_nonce_holder() { run_nonce_test( 1u32, NonceHolderTestMode::SetValueUnderNonce, - Some("Previous nonce has not been used".to_string()), + Some("Error function_selector = 0x13595475, data = 0x13595475".to_string()), "Allowed to set value under non sequential value", ); @@ -142,7 +143,7 @@ fn test_nonce_holder() { run_nonce_test( 10u32, NonceHolderTestMode::IncreaseMinNonceBy5, - Some("Reusing the same nonce twice".to_string()), + Some(format!("Error function_selector = 0xe90aded4, data = 0xe90aded4000000000000000000000000{hex_addr}000000000000000000000000000000000000000000000000000000000000000a")), "Allowed to reuse nonce below the minimal one", ); @@ -158,7 +159,7 @@ fn test_nonce_holder() { run_nonce_test( 13u32, NonceHolderTestMode::IncreaseMinNonceBy5, - Some("Reusing the same nonce twice".to_string()), + Some(format!("Error function_selector = 0xe90aded4, data = 0xe90aded4000000000000000000000000{hex_addr}000000000000000000000000000000000000000000000000000000000000000d")), "Allowed to reuse the same nonce twice", ); @@ -174,7 +175,7 @@ fn test_nonce_holder() { run_nonce_test( 16u32, NonceHolderTestMode::IncreaseMinNonceTooMuch, - Some("The value for incrementing the nonce is too high".to_string()), + Some("Error function_selector = 0x45ac24a6, data = 0x45ac24a600000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000040000000000000000000000".to_string()), "Allowed for incrementing min nonce too much", ); @@ -182,7 +183,7 @@ fn test_nonce_holder() { run_nonce_test( 16u32, NonceHolderTestMode::LeaveNonceUnused, - Some("The nonce was not set as used".to_string()), + Some(format!("Error function_selector = 0x1f2f8478, data = 0x1f2f8478000000000000000000000000{hex_addr}0000000000000000000000000000000000000000000000000000000000000010")), "Allowed to leave nonce as unused", ); } diff --git a/core/lib/multivm/src/versions/vm_latest/tests/rollbacks.rs b/core/lib/multivm/src/versions/vm_latest/tests/rollbacks.rs index 31f0d7f68718..c92105eeff23 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/rollbacks.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/rollbacks.rs @@ -1,6 +1,6 @@ use ethabi::Token; use zksync_contracts::{get_loadnext_contract, test_contracts::LoadnextContractExecutionParams}; -use zksync_types::{get_nonce_key, Execute, U256}; +use zksync_types::{get_nonce_key, Execute, Nonce, U256}; use crate::{ interface::{ @@ -47,22 +47,40 @@ fn test_vm_rollbacks() { TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::WrongMagicValue.into()), TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::WrongSignature.into()), // The correct nonce is 0, this tx will fail - TransactionTestInfo::new_rejected(tx_2.clone(), TxModifier::WrongNonce.into()), + TransactionTestInfo::new_rejected( + tx_2.clone(), + TxModifier::WrongNonce(tx_2.nonce().unwrap(), Nonce(0)).into(), + ), // This tx will succeed TransactionTestInfo::new_processed(tx_0.clone(), false), // The correct nonce is 1, this tx will fail - TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::NonceReused.into()), + TransactionTestInfo::new_rejected( + tx_0.clone(), + TxModifier::NonceReused(tx_0.initiator_account(), tx_0.nonce().unwrap()).into(), + ), // The correct nonce is 1, this tx will fail - TransactionTestInfo::new_rejected(tx_2.clone(), TxModifier::WrongNonce.into()), + TransactionTestInfo::new_rejected( + tx_2.clone(), + TxModifier::WrongNonce(tx_2.nonce().unwrap(), Nonce(1)).into(), + ), // This tx will succeed TransactionTestInfo::new_processed(tx_1, false), // The correct nonce is 2, this tx will fail - TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::NonceReused.into()), + TransactionTestInfo::new_rejected( + tx_0.clone(), + TxModifier::NonceReused(tx_0.initiator_account(), tx_0.nonce().unwrap()).into(), + ), // This tx will succeed TransactionTestInfo::new_processed(tx_2.clone(), false), // This tx will fail - TransactionTestInfo::new_rejected(tx_2, TxModifier::NonceReused.into()), - TransactionTestInfo::new_rejected(tx_0, TxModifier::NonceReused.into()), + TransactionTestInfo::new_rejected( + tx_2.clone(), + TxModifier::NonceReused(tx_2.initiator_account(), tx_2.nonce().unwrap()).into(), + ), + TransactionTestInfo::new_rejected( + tx_0.clone(), + TxModifier::NonceReused(tx_0.initiator_account(), tx_0.nonce().unwrap()).into(), + ), ]); assert_eq!(result_without_rollbacks, result_with_rollbacks); @@ -140,12 +158,23 @@ fn test_vm_loadnext_rollbacks() { TransactionTestInfo::new_processed(loadnext_tx_1.clone(), true), TransactionTestInfo::new_rejected( loadnext_deploy_tx.clone(), - TxModifier::NonceReused.into(), + TxModifier::NonceReused( + loadnext_deploy_tx.initiator_account(), + loadnext_deploy_tx.nonce().unwrap(), + ) + .into(), ), TransactionTestInfo::new_processed(loadnext_tx_1, false), TransactionTestInfo::new_processed(loadnext_tx_2.clone(), true), TransactionTestInfo::new_processed(loadnext_tx_2.clone(), true), - TransactionTestInfo::new_rejected(loadnext_deploy_tx, TxModifier::NonceReused.into()), + TransactionTestInfo::new_rejected( + loadnext_deploy_tx.clone(), + TxModifier::NonceReused( + loadnext_deploy_tx.initiator_account(), + loadnext_deploy_tx.nonce().unwrap(), + ) + .into(), + ), TransactionTestInfo::new_processed(loadnext_tx_2, false), ]); diff --git a/core/lib/multivm/src/versions/vm_latest/tests/tester/transaction_test_info.rs b/core/lib/multivm/src/versions/vm_latest/tests/tester/transaction_test_info.rs index 114f80d1a217..ccaab547c20c 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/tester/transaction_test_info.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/tester/transaction_test_info.rs @@ -1,4 +1,4 @@ -use zksync_types::{ExecuteTransactionCommon, Transaction}; +use zksync_types::{ExecuteTransactionCommon, Nonce, Transaction, H160}; use crate::{ interface::{ @@ -13,8 +13,8 @@ pub(crate) enum TxModifier { WrongSignatureLength, WrongSignature, WrongMagicValue, - WrongNonce, - NonceReused, + WrongNonce(Nonce, Nonce), + NonceReused(H160, Nonce), } #[derive(Debug, Clone)] @@ -39,14 +39,11 @@ impl From for ExpectedError { fn from(value: TxModifier) -> Self { let revert_reason = match value { TxModifier::WrongSignatureLength => { - Halt::ValidationFailed(VmRevertReason::General { - msg: "Signature length is incorrect".to_string(), + Halt::ValidationFailed(VmRevertReason::Unknown { + function_selector: vec![144, 240, 73, 201], data: vec![ - 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 83, 105, 103, 110, 97, 116, 117, 114, 101, 32, - 108, 101, 110, 103, 116, 104, 32, 105, 115, 32, 105, 110, 99, 111, 114, 114, 101, 99, - 116, 0, 0, 0, + 144, 240, 73, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45 ], }) } @@ -57,38 +54,35 @@ impl From for ExpectedError { }) } TxModifier::WrongMagicValue => { - Halt::ValidationFailed(VmRevertReason::General { - msg: "v is neither 27 nor 28".to_string(), - data: vec![ - 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 118, 32, 105, 115, 32, 110, 101, 105, 116, 104, - 101, 114, 32, 50, 55, 32, 110, 111, 114, 32, 50, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], + Halt::ValidationFailed(VmRevertReason::Unknown { + function_selector: vec![144, 240, 73, 201], + data: vec![144, 240, 73, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], }) } - TxModifier::WrongNonce => { - Halt::ValidationFailed(VmRevertReason::General { - msg: "Incorrect nonce".to_string(), - data: vec![ - 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 73, 110, 99, 111, 114, 114, 101, 99, 116, 32, 110, - 111, 110, 99, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], + TxModifier::WrongNonce(expected, actual) => { + let function_selector = vec![98, 106, 222, 48]; + let expected_nonce_bytes = expected.0.to_be_bytes().to_vec(); + let actual_nonce_bytes = actual.0.to_be_bytes().to_vec(); + // padding is 28 because an address takes up 4 bytes and we need it to fill a 32 byte field + let nonce_padding = vec![0u8; 28]; + let data = [function_selector.clone(), nonce_padding.clone(), expected_nonce_bytes, nonce_padding.clone(), actual_nonce_bytes].concat(); + Halt::ValidationFailed(VmRevertReason::Unknown { + function_selector, + data }) } - TxModifier::NonceReused => { - Halt::ValidationFailed(VmRevertReason::General { - msg: "Reusing the same nonce twice".to_string(), - data: vec![ - 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 82, 101, 117, 115, 105, 110, 103, 32, 116, 104, - 101, 32, 115, 97, 109, 101, 32, 110, 111, 110, 99, 101, 32, 116, 119, 105, 99, 101, 0, - 0, 0, 0, - ], + TxModifier::NonceReused(addr, nonce) => { + let function_selector = vec![233, 10, 222, 212]; + let addr = addr.as_bytes().to_vec(); + // padding is 12 because an address takes up 20 bytes and we need it to fill a 32 byte field + let addr_padding = vec![0u8; 12]; + // padding is 28 because an address takes up 4 bytes and we need it to fill a 32 byte field + let nonce_padding = vec![0u8; 28]; + let data = [function_selector.clone(), addr_padding, addr, nonce_padding, nonce.0.to_be_bytes().to_vec()].concat(); + Halt::ValidationFailed(VmRevertReason::Unknown { + function_selector, + data, }) } }; @@ -114,10 +108,10 @@ impl TransactionTestInfo { } TxModifier::WrongSignature => data.signature = vec![27u8; 65], TxModifier::WrongMagicValue => data.signature = vec![1u8; 65], - TxModifier::WrongNonce => { + TxModifier::WrongNonce(_, _) => { // Do not need to modify signature for nonce error } - TxModifier::NonceReused => { + TxModifier::NonceReused(_, _) => { // Do not need to modify signature for nonce error } } From 61c31b17314cac60d8a4f54998519be3d23288d7 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 29 Aug 2024 13:01:32 -0300 Subject: [PATCH 56/76] Update prepare to decommit function and test circuits expected values --- core/lib/multivm/src/versions/vm_1_4_2/tests/circuits.rs | 2 +- .../src/versions/vm_latest/old_vm/oracles/decommitter.rs | 9 +++++++++ .../lib/multivm/src/versions/vm_latest/tests/circuits.rs | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/core/lib/multivm/src/versions/vm_1_4_2/tests/circuits.rs b/core/lib/multivm/src/versions/vm_1_4_2/tests/circuits.rs index 7d0dfd1ed0ea..3e2b23999182 100644 --- a/core/lib/multivm/src/versions/vm_1_4_2/tests/circuits.rs +++ b/core/lib/multivm/src/versions/vm_1_4_2/tests/circuits.rs @@ -33,7 +33,7 @@ fn test_circuits() { let s = res.statistics.circuit_statistic; // Check `circuit_statistic`. const EXPECTED: [f32; 11] = [ - 1.1979, 0.1390, 1.5455, 0.0031, 1.0573, 0.00059, 0.003438, 0.00077, 0.1195, 0.1429, 0.0, + 1.1979, 0.1390, 1.5455, 0.0031, 1.1799649, 0.00059, 0.003438, 0.00077, 0.1195, 0.1429, 0.0, ]; let actual = [ (s.main_vm, "main_vm"), diff --git a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs b/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs index 0f31031d3723..d91fbfdb24df 100644 --- a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs +++ b/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs @@ -180,6 +180,15 @@ impl DecommittmentProcess Ok(partial_query) } else { + if self + .decommitted_code_hashes + .inner() + .get(&stored_hash) + .is_none() + { + self.decommitted_code_hashes + .insert(stored_hash, None, partial_query.timestamp); + }; partial_query.is_fresh = true; partial_query.decommitted_length = versioned_hash.get_preimage_length() as u16; diff --git a/core/lib/multivm/src/versions/vm_latest/tests/circuits.rs b/core/lib/multivm/src/versions/vm_latest/tests/circuits.rs index 35412ee4d1bd..74d77484d682 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/circuits.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/circuits.rs @@ -35,7 +35,7 @@ fn test_circuits() { let s = res.statistics.circuit_statistic; // Check `circuit_statistic`. const EXPECTED: [f32; 13] = [ - 1.34935, 0.15026, 1.66666, 0.00315, 1.0594, 0.00058, 0.00348, 0.00076, 0.11945, 0.14285, + 1.34935, 0.15026, 1.66666, 0.00315, 1.1799649, 0.00058, 0.00348, 0.00076, 0.11945, 0.14285, 0.0, 0.0, 0.0, ]; let actual = [ From f97e26f42b62842ec1aeda5c2a363acd0a82fc7e Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 29 Aug 2024 13:02:57 -0300 Subject: [PATCH 57/76] Update test aux function to get known bytecodes without base system contracts --- .../vm_1_4_1/tests/get_used_contracts.rs | 18 +++++++++++------- .../vm_1_4_2/tests/get_used_contracts.rs | 18 +++++++++++------- .../tests/get_used_contracts.rs | 18 +++++++++++------- .../vm_fast/tests/get_used_contracts.rs | 17 ++++++++++------- .../vm_latest/tests/get_used_contracts.rs | 18 +++++++++++------- .../tests/get_used_contracts.rs | 18 +++++++++++------- .../tests/get_used_contracts.rs | 18 +++++++++++------- 7 files changed, 76 insertions(+), 49 deletions(-) diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/get_used_contracts.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/get_used_contracts.rs index a7cbcd8e2953..e10c498fd4ff 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/tests/get_used_contracts.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/get_used_contracts.rs @@ -26,7 +26,7 @@ fn test_get_used_contracts() { .with_execution_mode(TxExecutionMode::VerifyExecute) .build(); - assert!(known_bytecodes_without_aa_code(&vm.vm).is_empty()); + assert!(known_bytecodes_without_base_system_contracts(&vm.vm).is_empty()); // create and push and execute some not-empty factory deps transaction with success status // to check that `get_used_contracts()` updates @@ -48,7 +48,7 @@ fn test_get_used_contracts() { .get_used_contracts() .into_iter() .collect::>(), - known_bytecodes_without_aa_code(&vm.vm) + known_bytecodes_without_base_system_contracts(&vm.vm) .keys() .cloned() .collect::>() @@ -84,26 +84,30 @@ fn test_get_used_contracts() { for factory_dep in tx2.execute.factory_deps.unwrap() { let hash = hash_bytecode(&factory_dep); let hash_to_u256 = h256_to_u256(hash); - assert!(known_bytecodes_without_aa_code(&vm.vm) + assert!(known_bytecodes_without_base_system_contracts(&vm.vm) .keys() .contains(&hash_to_u256)); assert!(!vm.vm.get_used_contracts().contains(&hash_to_u256)); } } -fn known_bytecodes_without_aa_code( +fn known_bytecodes_without_base_system_contracts( vm: &Vm, ) -> HashMap> { - let mut known_bytecodes_without_aa_code = vm + let mut known_bytecodes_without_base_system_contracts = vm .state .decommittment_processor .known_bytecodes .inner() .clone(); - known_bytecodes_without_aa_code + known_bytecodes_without_base_system_contracts .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.default_aa.hash)) .unwrap(); - known_bytecodes_without_aa_code + known_bytecodes_without_base_system_contracts + .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.evm_simulator.hash)) + .unwrap(); + + known_bytecodes_without_base_system_contracts } diff --git a/core/lib/multivm/src/versions/vm_1_4_2/tests/get_used_contracts.rs b/core/lib/multivm/src/versions/vm_1_4_2/tests/get_used_contracts.rs index cfe3e1bfc235..4aff9c6e240f 100644 --- a/core/lib/multivm/src/versions/vm_1_4_2/tests/get_used_contracts.rs +++ b/core/lib/multivm/src/versions/vm_1_4_2/tests/get_used_contracts.rs @@ -26,7 +26,7 @@ fn test_get_used_contracts() { .with_execution_mode(TxExecutionMode::VerifyExecute) .build(); - assert!(known_bytecodes_without_aa_code(&vm.vm).is_empty()); + assert!(known_bytecodes_without_base_system_contracts(&vm.vm).is_empty()); // create and push and execute some not-empty factory deps transaction with success status // to check that `get_used_contracts()` updates @@ -48,7 +48,7 @@ fn test_get_used_contracts() { .get_used_contracts() .into_iter() .collect::>(), - known_bytecodes_without_aa_code(&vm.vm) + known_bytecodes_without_base_system_contracts(&vm.vm) .keys() .cloned() .collect::>() @@ -84,26 +84,30 @@ fn test_get_used_contracts() { for factory_dep in tx2.execute.factory_deps.unwrap() { let hash = hash_bytecode(&factory_dep); let hash_to_u256 = h256_to_u256(hash); - assert!(known_bytecodes_without_aa_code(&vm.vm) + assert!(known_bytecodes_without_base_system_contracts(&vm.vm) .keys() .contains(&hash_to_u256)); assert!(!vm.vm.get_used_contracts().contains(&hash_to_u256)); } } -fn known_bytecodes_without_aa_code( +fn known_bytecodes_without_base_system_contracts( vm: &Vm, ) -> HashMap> { - let mut known_bytecodes_without_aa_code = vm + let mut known_bytecodes_without_base_system_contracts = vm .state .decommittment_processor .known_bytecodes .inner() .clone(); - known_bytecodes_without_aa_code + known_bytecodes_without_base_system_contracts .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.default_aa.hash)) .unwrap(); - known_bytecodes_without_aa_code + known_bytecodes_without_base_system_contracts + .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.evm_simulator.hash)) + .unwrap(); + + known_bytecodes_without_base_system_contracts } diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/get_used_contracts.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/get_used_contracts.rs index 658bcd75b059..ad26db9f9a78 100644 --- a/core/lib/multivm/src/versions/vm_boojum_integration/tests/get_used_contracts.rs +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/get_used_contracts.rs @@ -26,7 +26,7 @@ fn test_get_used_contracts() { .with_execution_mode(TxExecutionMode::VerifyExecute) .build(); - assert!(known_bytecodes_without_aa_code(&vm.vm).is_empty()); + assert!(known_bytecodes_without_base_system_contracts(&vm.vm).is_empty()); // create and push and execute some not-empty factory deps transaction with success status // to check that get_used_contracts() updates @@ -48,7 +48,7 @@ fn test_get_used_contracts() { .get_used_contracts() .into_iter() .collect::>(), - known_bytecodes_without_aa_code(&vm.vm) + known_bytecodes_without_base_system_contracts(&vm.vm) .keys() .cloned() .collect::>() @@ -84,26 +84,30 @@ fn test_get_used_contracts() { for factory_dep in tx2.execute.factory_deps.unwrap() { let hash = hash_bytecode(&factory_dep); let hash_to_u256 = h256_to_u256(hash); - assert!(known_bytecodes_without_aa_code(&vm.vm) + assert!(known_bytecodes_without_base_system_contracts(&vm.vm) .keys() .contains(&hash_to_u256)); assert!(!vm.vm.get_used_contracts().contains(&hash_to_u256)); } } -fn known_bytecodes_without_aa_code( +fn known_bytecodes_without_base_system_contracts( vm: &Vm, ) -> HashMap> { - let mut known_bytecodes_without_aa_code = vm + let mut known_bytecodes_without_base_system_contracts = vm .state .decommittment_processor .known_bytecodes .inner() .clone(); - known_bytecodes_without_aa_code + known_bytecodes_without_base_system_contracts .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.default_aa.hash)) .unwrap(); - known_bytecodes_without_aa_code + known_bytecodes_without_base_system_contracts + .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.evm_simulator.hash)) + .unwrap(); + + known_bytecodes_without_base_system_contracts } diff --git a/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs b/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs index 27ccf13e2f8c..4ae2b1073fad 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs @@ -30,7 +30,7 @@ fn test_get_used_contracts() { .with_execution_mode(TxExecutionMode::VerifyExecute) .build(); - assert!(known_bytecodes_without_aa_code(&vm.vm).is_empty()); + assert!(known_bytecodes_without_base_system_contracts(&vm.vm).is_empty()); // create and push and execute some not-empty factory deps transaction with success status // to check that `get_decommitted_hashes()` updates @@ -49,7 +49,7 @@ fn test_get_used_contracts() { // Note: `Default_AA` will be in the list of used contracts if L2 tx is used assert_eq!( vm.vm.decommitted_hashes().collect::>(), - known_bytecodes_without_aa_code(&vm.vm) + known_bytecodes_without_base_system_contracts(&vm.vm) ); // create push and execute some non-empty factory deps transaction that fails @@ -82,20 +82,23 @@ fn test_get_used_contracts() { for factory_dep in tx2.execute.factory_deps { let hash = hash_bytecode(&factory_dep); let hash_to_u256 = h256_to_u256(hash); - assert!(known_bytecodes_without_aa_code(&vm.vm).contains(&hash_to_u256)); + assert!(known_bytecodes_without_base_system_contracts(&vm.vm).contains(&hash_to_u256)); assert!(!vm.vm.decommitted_hashes().contains(&hash_to_u256)); } } -fn known_bytecodes_without_aa_code(vm: &Vm) -> HashSet { - let mut known_bytecodes_without_aa_code = vm +fn known_bytecodes_without_base_system_contracts(vm: &Vm) -> HashSet { + let mut known_bytecodes_without_base_system_contracts = vm .world .bytecode_cache .keys() .cloned() .collect::>(); - known_bytecodes_without_aa_code.remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.default_aa.hash)); - known_bytecodes_without_aa_code + known_bytecodes_without_base_system_contracts + .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.default_aa.hash)); + known_bytecodes_without_base_system_contracts + .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.evm_simulator.hash)); + known_bytecodes_without_base_system_contracts } /// Counter test contract bytecode inflated by appending lots of `NOP` opcodes at the end. This leads to non-trivial diff --git a/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs b/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs index ca2000f8fd54..5f1dfed13a60 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs @@ -40,7 +40,7 @@ fn test_get_used_contracts() { .with_execution_mode(TxExecutionMode::VerifyExecute) .build(); - assert!(known_bytecodes_without_aa_code(&vm.vm).is_empty()); + assert!(known_bytecodes_without_base_system_contracts(&vm.vm).is_empty()); // create and push and execute some not-empty factory deps transaction with success status // to check that `get_used_contracts()` updates @@ -62,7 +62,7 @@ fn test_get_used_contracts() { .get_used_contracts() .into_iter() .collect::>(), - known_bytecodes_without_aa_code(&vm.vm) + known_bytecodes_without_base_system_contracts(&vm.vm) .keys() .cloned() .collect::>() @@ -98,7 +98,7 @@ fn test_get_used_contracts() { for factory_dep in tx2.execute.factory_deps { let hash = hash_bytecode(&factory_dep); let hash_to_u256 = h256_to_u256(hash); - assert!(known_bytecodes_without_aa_code(&vm.vm) + assert!(known_bytecodes_without_base_system_contracts(&vm.vm) .keys() .contains(&hash_to_u256)); assert!(!vm.vm.get_used_contracts().contains(&hash_to_u256)); @@ -146,19 +146,23 @@ fn test_contract_is_used_right_after_prepare_to_decommit() { assert_eq!(vm.vm.get_used_contracts(), vec![bytecode_hash]); } -fn known_bytecodes_without_aa_code( +fn known_bytecodes_without_base_system_contracts( vm: &Vm, ) -> HashMap> { - let mut known_bytecodes_without_aa_code = vm + let mut known_bytecodes_without_base_system_contracts = vm .state .decommittment_processor .known_bytecodes .inner() .clone(); - known_bytecodes_without_aa_code + known_bytecodes_without_base_system_contracts .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.default_aa.hash)) .unwrap(); - known_bytecodes_without_aa_code + + known_bytecodes_without_base_system_contracts + .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.evm_simulator.hash)) + .unwrap(); + known_bytecodes_without_base_system_contracts } /// Counter test contract bytecode inflated by appending lots of `NOP` opcodes at the end. This leads to non-trivial diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/tests/get_used_contracts.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/tests/get_used_contracts.rs index 8c121db3e43e..1098f5854400 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/tests/get_used_contracts.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/tests/get_used_contracts.rs @@ -21,7 +21,7 @@ fn test_get_used_contracts() { .with_execution_mode(TxExecutionMode::VerifyExecute) .build(); - assert!(known_bytecodes_without_aa_code(&vm.vm).is_empty()); + assert!(known_bytecodes_without_base_system_contracts(&vm.vm).is_empty()); // create and push and execute some not-empty factory deps transaction with success status // to check that get_used_contracts() updates @@ -43,7 +43,7 @@ fn test_get_used_contracts() { .get_used_contracts() .into_iter() .collect::>(), - known_bytecodes_without_aa_code(&vm.vm) + known_bytecodes_without_base_system_contracts(&vm.vm) .keys() .cloned() .collect::>() @@ -79,26 +79,30 @@ fn test_get_used_contracts() { for factory_dep in tx2.execute.factory_deps.unwrap() { let hash = hash_bytecode(&factory_dep); let hash_to_u256 = h256_to_u256(hash); - assert!(known_bytecodes_without_aa_code(&vm.vm) + assert!(known_bytecodes_without_base_system_contracts(&vm.vm) .keys() .contains(&hash_to_u256)); assert!(!vm.vm.get_used_contracts().contains(&hash_to_u256)); } } -fn known_bytecodes_without_aa_code( +fn known_bytecodes_without_base_system_contracts( vm: &Vm, ) -> HashMap> { - let mut known_bytecodes_without_aa_code = vm + let mut known_bytecodes_without_base_system_contracts = vm .state .decommittment_processor .known_bytecodes .inner() .clone(); - known_bytecodes_without_aa_code + known_bytecodes_without_base_system_contracts .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.default_aa.hash)) .unwrap(); - known_bytecodes_without_aa_code + known_bytecodes_without_base_system_contracts + .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.evm_simulator.hash)) + .unwrap(); + + known_bytecodes_without_base_system_contracts } diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/tests/get_used_contracts.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/tests/get_used_contracts.rs index 06d8191310bc..c4fe148d7ad6 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/tests/get_used_contracts.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/tests/get_used_contracts.rs @@ -23,7 +23,7 @@ fn test_get_used_contracts() { .with_execution_mode(TxExecutionMode::VerifyExecute) .build(); - assert!(known_bytecodes_without_aa_code(&vm.vm).is_empty()); + assert!(known_bytecodes_without_base_system_contracts(&vm.vm).is_empty()); // create and push and execute some not-empty factory deps transaction with success status // to check that get_used_contracts() updates @@ -45,7 +45,7 @@ fn test_get_used_contracts() { .get_used_contracts() .into_iter() .collect::>(), - known_bytecodes_without_aa_code(&vm.vm) + known_bytecodes_without_base_system_contracts(&vm.vm) .keys() .cloned() .collect::>() @@ -81,26 +81,30 @@ fn test_get_used_contracts() { for factory_dep in tx2.execute.factory_deps.unwrap() { let hash = hash_bytecode(&factory_dep); let hash_to_u256 = h256_to_u256(hash); - assert!(known_bytecodes_without_aa_code(&vm.vm) + assert!(known_bytecodes_without_base_system_contracts(&vm.vm) .keys() .contains(&hash_to_u256)); assert!(!vm.vm.get_used_contracts().contains(&hash_to_u256)); } } -fn known_bytecodes_without_aa_code( +fn known_bytecodes_without_base_system_contracts( vm: &Vm, ) -> HashMap> { - let mut known_bytecodes_without_aa_code = vm + let mut known_bytecodes_without_base_system_contracts = vm .state .decommittment_processor .known_bytecodes .inner() .clone(); - known_bytecodes_without_aa_code + known_bytecodes_without_base_system_contracts .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.default_aa.hash)) .unwrap(); - known_bytecodes_without_aa_code + known_bytecodes_without_base_system_contracts + .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.evm_simulator.hash)) + .unwrap(); + + known_bytecodes_without_base_system_contracts } From f964da1c3137d84d0ea884421f77d70e3412d0fe Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 29 Aug 2024 14:42:45 -0300 Subject: [PATCH 58/76] Update system contracts, root and commitment hashes --- core/lib/env_config/src/chain.rs | 10 +++++----- etc/env/base/chain.toml | 6 +++--- etc/env/base/contracts.toml | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/lib/env_config/src/chain.rs b/core/lib/env_config/src/chain.rs index 0bfcd957c56e..ca2c51803ba2 100644 --- a/core/lib/env_config/src/chain.rs +++ b/core/lib/env_config/src/chain.rs @@ -97,13 +97,13 @@ mod tests { validation_computational_gas_limit: 10_000_000, save_call_traces: false, bootloader_hash: Some(hash( - "0x010008ddf6824c3f8778b86a85d568ddfb45c29bf23b604fad20b91e6d8d458b", + "0x010008bbde6fc402ea3a3d6cb15cb97e70245d3d4e48fb74362d4961b74c16b1", )), default_aa_hash: Some(hash( - "0x0100058d69da9a1ba9e97d8d26a67967a39e1a9d50d55a4b6aace7d98877a485", + "0x0100058d9eee51f4b9e9a9ecb7fd7e8301e90bef018c2bd913ed36e583fec8c2", )), evm_simulator_hash: Some(hash( - "0x01000f196acd122635a752fcb275be0cc95fd3bba348c1d0908a517fe316418e", + "0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91", )), l1_batch_commit_data_generator_mode, max_circuits_per_batch: 24100, @@ -138,8 +138,8 @@ mod tests { CHAIN_STATE_KEEPER_FEE_MODEL_VERSION="V2" CHAIN_STATE_KEEPER_VALIDATION_COMPUTATIONAL_GAS_LIMIT="10000000" CHAIN_STATE_KEEPER_SAVE_CALL_TRACES="false" - CHAIN_STATE_KEEPER_BOOTLOADER_HASH=0x010008ddf6824c3f8778b86a85d568ddfb45c29bf23b604fad20b91e6d8d458b - CHAIN_STATE_KEEPER_DEFAULT_AA_HASH=0x0100058d69da9a1ba9e97d8d26a67967a39e1a9d50d55a4b6aace7d98877a485 + CHAIN_STATE_KEEPER_BOOTLOADER_HASH=0x010008bbde6fc402ea3a3d6cb15cb97e70245d3d4e48fb74362d4961b74c16b1 + CHAIN_STATE_KEEPER_DEFAULT_AA_HASH=0x0100058d9eee51f4b9e9a9ecb7fd7e8301e90bef018c2bd913ed36e583fec8c2 CHAIN_STATE_KEEPER_PROTECTIVE_READS_PERSISTENCE_ENABLED=true CHAIN_STATE_KEEPER_L1_BATCH_COMMIT_DATA_GENERATOR_MODE="{l1_batch_commit_data_generator_mode}" "# diff --git a/etc/env/base/chain.toml b/etc/env/base/chain.toml index b987cc75623d..106ad503e7f5 100644 --- a/etc/env/base/chain.toml +++ b/etc/env/base/chain.toml @@ -90,9 +90,9 @@ fee_model_version = "V2" validation_computational_gas_limit = 300000 save_call_traces = true -bootloader_hash = "0x010008ddf6824c3f8778b86a85d568ddfb45c29bf23b604fad20b91e6d8d458b" -default_aa_hash = "0x0100058d69da9a1ba9e97d8d26a67967a39e1a9d50d55a4b6aace7d98877a485" -evm_simulator_hash = "0x01000f196acd122635a752fcb275be0cc95fd3bba348c1d0908a517fe316418e" +bootloader_hash = "0x010008bbde6fc402ea3a3d6cb15cb97e70245d3d4e48fb74362d4961b74c16b1" +default_aa_hash = "0x0100058d9eee51f4b9e9a9ecb7fd7e8301e90bef018c2bd913ed36e583fec8c2" +evm_simulator_hash = "0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91" protective_reads_persistence_enabled = false diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index 21614ee63125..46492304b3d0 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -26,8 +26,8 @@ RECURSION_NODE_LEVEL_VK_HASH = "0x1186ec268d49f1905f8d9c1e9d39fc33e98c74f91d91a2 RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc8966504064f1f6ba3f1ba863210" RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" -GENESIS_ROOT = "0xcb36c2f9065392206dd4aa019208c0b36484a35ce5a77af13054c51526c7714f" -GENESIS_BATCH_COMMITMENT = "0x45d4f53e451df9bcb5dc00a86f64bd6b4e8ab991d970919b6127e214f5d38550" +GENESIS_ROOT = "0xadcaa4f5e2230c8b77973034975c6d541551f2831d58317550528e7761a6960a" +GENESIS_BATCH_COMMITMENT = "0x94f1ef45aa30f5c10be838bb91a1dd9ee2d03445a10aeaac4c611c1228930368" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "56" From 3d8eb6d694ed20957c160a84640003b6e71255ec Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 29 Aug 2024 14:43:27 -0300 Subject: [PATCH 59/76] Update cached multivm bootloaders for vm 1.5.0 --- .../fee_estimate.yul/fee_estimate.yul.zbin | Bin 76000 -> 74912 bytes .../gas_test.yul/gas_test.yul.zbin | Bin 72096 -> 71008 bytes .../playground_batch.yul.zbin | Bin 76192 -> 75104 bytes .../proved_batch.yul/proved_batch.yul.zbin | Bin 72608 -> 71520 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/fee_estimate.yul/fee_estimate.yul.zbin index fd5cc89b1239f7267729d9ba53a9b434650924a6..ad45ddb49571509167df6fd155d50130db9b6afb 100644 GIT binary patch literal 74912 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%0ADQ!e*z8W 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 diff --git a/etc/multivm_bootloaders/vm_1_5_0_increased_memory/gas_test.yul/gas_test.yul.zbin b/etc/multivm_bootloaders/vm_1_5_0_increased_memory/gas_test.yul/gas_test.yul.zbin index 42f7be1e0a89eb73f3c6dd77e9f496b39957090a..fe6ca94b1503cbb9e61bf0290cea973f5bc31b0c 100644 GIT binary patch literal 71008 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 literal 72096 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 From eb83e9fb68a17fcfcdd16546e3f68f235993eb04 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 29 Aug 2024 14:43:48 -0300 Subject: [PATCH 60/76] Update contracts submodule --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index 0922be90563c..dc1a608842dc 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 0922be90563c6fd251a9a3ec67aa0de91f2539b5 +Subproject commit dc1a608842dc7d429d856ffaaf6f5bf339fb1eee From 4c11c21fa0b9f05b99a9a17bcd892727c283452e Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 29 Aug 2024 18:11:15 -0300 Subject: [PATCH 61/76] Delete migration module --- .../src/versions/vm_latest/tests/migration.rs | 51 ------------------- .../src/versions/vm_latest/tests/mod.rs | 1 - 2 files changed, 52 deletions(-) delete mode 100644 core/lib/multivm/src/versions/vm_latest/tests/migration.rs diff --git a/core/lib/multivm/src/versions/vm_latest/tests/migration.rs b/core/lib/multivm/src/versions/vm_latest/tests/migration.rs deleted file mode 100644 index 6bd0e87615ed..000000000000 --- a/core/lib/multivm/src/versions/vm_latest/tests/migration.rs +++ /dev/null @@ -1,51 +0,0 @@ -use zksync_types::{get_code_key, H256, SYSTEM_CONTEXT_ADDRESS}; - -use crate::{ - interface::{TxExecutionMode, VmExecutionMode, VmInterface}, - vm_latest::{ - tests::{ - tester::{get_empty_storage, DeployContractsTx, TxType, VmTesterBuilder}, - utils::read_test_contract, - }, - HistoryEnabled, - }, -}; - -/// This test checks that the new bootloader will work fine even if the previous system context contract is not -/// compatible with it, i.e. the bootloader will upgrade it before starting any transaction. -#[test] -fn test_migration_for_system_context_aa_interaction() { - let mut storage = get_empty_storage(); - // We will set the system context bytecode to zero. - storage.set_value(get_code_key(&SYSTEM_CONTEXT_ADDRESS), H256::zero()); - - // In this test, we aim to test whether a simple account interaction (without any fee logic) - // will work. The account will try to deploy a simple contract from integration tests. - let mut vm = VmTesterBuilder::new(HistoryEnabled) - .with_storage(storage) - .with_execution_mode(TxExecutionMode::VerifyExecute) - .with_random_rich_accounts(1) - .build(); - - // Now, we will just proceed with standard transaction execution. - // The bootloader should be able to update system context regardless of whether - // the upgrade transaction is there or not. - let account = &mut vm.rich_accounts[0]; - let counter = read_test_contract(); - let DeployContractsTx { tx, .. } = account.get_deploy_tx(&counter, None, TxType::L2); - - vm.vm.push_transaction(tx); - let result = vm.vm.execute(VmExecutionMode::OneTx); - assert!( - !result.result.is_failed(), - "Transaction wasn't successful {:#?}", - result.result - ); - - let batch_result = vm.vm.execute(VmExecutionMode::Batch); - assert!( - !batch_result.result.is_failed(), - "Batch transaction wasn't successful {:#?}", - batch_result.result - ); -} diff --git a/core/lib/multivm/src/versions/vm_latest/tests/mod.rs b/core/lib/multivm/src/versions/vm_latest/tests/mod.rs index 1203d61b80b7..bc6d5b0144f1 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/mod.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/mod.rs @@ -13,7 +13,6 @@ mod get_used_contracts; mod is_write_initial; mod l1_tx_execution; mod l2_blocks; -mod migration; mod nonce_holder; mod precompiles; mod prestate_tracer; From f927c2673266746064596e050d6aa734d997eee7 Mon Sep 17 00:00:00 2001 From: Nacho Avecilla Date: Fri, 30 Aug 2024 12:08:15 -0300 Subject: [PATCH 62/76] EVM Simulator code hash in witness data (#249) * Add evm simulator bytecode hash to the witness input data * Add evm simulator code hash to the test harness run * Fix error message for evm simulator not present in witness data --- core/lib/prover_interface/src/inputs.rs | 1 + core/node/vm_runner/src/impls/bwip.rs | 18 ++++++++++++++++++ .../witness_generator/src/basic_circuits.rs | 3 +-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/core/lib/prover_interface/src/inputs.rs b/core/lib/prover_interface/src/inputs.rs index 22a20223c8b4..776ca516aa3b 100644 --- a/core/lib/prover_interface/src/inputs.rs +++ b/core/lib/prover_interface/src/inputs.rs @@ -144,6 +144,7 @@ pub struct VMRunWitnessInputData { pub protocol_version: ProtocolVersionId, pub bootloader_code: Vec<[u8; 32]>, pub default_account_code_hash: U256, + pub evm_simulator_code_hash: U256, pub storage_refunds: Vec, pub pubdata_costs: Vec, pub witness_block_state: WitnessStorageState, diff --git a/core/node/vm_runner/src/impls/bwip.rs b/core/node/vm_runner/src/impls/bwip.rs index f7f8c099609f..4eedba275a9e 100644 --- a/core/node/vm_runner/src/impls/bwip.rs +++ b/core/node/vm_runner/src/impls/bwip.rs @@ -205,6 +205,7 @@ async fn get_updates_manager_witness_input_data( let initial_heap_content = finished_batch.final_bootloader_memory.unwrap(); // might be just empty let default_aa = updates_manager.base_system_contract_hashes().default_aa; let bootloader = updates_manager.base_system_contract_hashes().bootloader; + let evm_simulator = updates_manager.base_system_contract_hashes().evm_simulator; let bootloader_code_bytes = connection .factory_deps_dal() .get_sealed_factory_dep(bootloader) @@ -220,6 +221,14 @@ async fn get_updates_manager_witness_input_data( .ok_or_else(|| anyhow!("Default account bytecode should exist"))?; let account_bytecode = bytes_to_chunks(&account_bytecode_bytes); + let evm_simulator_code_hash = h256_to_u256(evm_simulator); + let simulator_bytecode_bytes = connection + .factory_deps_dal() + .get_sealed_factory_dep(evm_simulator) + .await? + .ok_or_else(|| anyhow!("EVM Simulator bytecode should exist"))?; + let evm_simulator_bytecode = bytes_to_chunks(&simulator_bytecode_bytes); + let hashes: HashSet = finished_batch .final_execution_state .used_contract_hashes @@ -240,6 +249,14 @@ async fn get_updates_manager_witness_input_data( used_bytecodes.insert(account_code_hash, account_bytecode); } + if finished_batch + .final_execution_state + .used_contract_hashes + .contains(&evm_simulator_code_hash) + { + used_bytecodes.insert(evm_simulator_code_hash, evm_simulator_bytecode); + } + let storage_refunds = finished_batch.final_execution_state.storage_refunds; let pubdata_costs = finished_batch.final_execution_state.pubdata_costs; @@ -261,6 +278,7 @@ async fn get_updates_manager_witness_input_data( bootloader_code, default_account_code_hash: account_code_hash, + evm_simulator_code_hash: evm_simulator_code_hash, storage_refunds, pubdata_costs, witness_block_state, diff --git a/prover/crates/bin/witness_generator/src/basic_circuits.rs b/prover/crates/bin/witness_generator/src/basic_circuits.rs index 00a4d99ba9a9..a1adfed438a6 100644 --- a/prover/crates/bin/witness_generator/src/basic_circuits.rs +++ b/prover/crates/bin/witness_generator/src/basic_circuits.rs @@ -491,8 +491,7 @@ async fn generate_witness( bootloader_contents, false, input.vm_run_data.default_account_code_hash, - // NOTE: this will be evm_simulator_code_hash in future releases - input.vm_run_data.default_account_code_hash, + input.vm_run_data.evm_simulator_code_hash, input.vm_run_data.used_bytecodes, Vec::default(), MAX_CYCLES_FOR_TX as usize, From 808df908a6f270bf0994491107494dfed5119863 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 30 Aug 2024 12:33:03 -0300 Subject: [PATCH 63/76] Fix format --- core/node/external_proof_integration_api/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/node/external_proof_integration_api/src/lib.rs b/core/node/external_proof_integration_api/src/lib.rs index 4ad8e2595a01..4355896e2a2e 100644 --- a/core/node/external_proof_integration_api/src/lib.rs +++ b/core/node/external_proof_integration_api/src/lib.rs @@ -4,8 +4,6 @@ mod middleware; mod processor; mod types; -pub use crate::processor::Processor; - use std::net::SocketAddr; use anyhow::Context; @@ -20,6 +18,7 @@ use tokio::sync::watch; use types::{ExternalProof, ProofGenerationDataResponse}; use zksync_basic_types::L1BatchNumber; +pub use crate::processor::Processor; use crate::{ metrics::{CallOutcome, Method}, middleware::MetricsMiddleware, From 06b88c65a7a494661f31c0b88b17c470d504a215 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 30 Aug 2024 18:41:46 -0300 Subject: [PATCH 64/76] Add evm simulator hash to dummy snapshot used for tests --- core/bin/genesis_generator/src/main.rs | 1 + core/node/test_utils/src/lib.rs | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/core/bin/genesis_generator/src/main.rs b/core/bin/genesis_generator/src/main.rs index abdd6091ed73..c90daac46b1c 100644 --- a/core/bin/genesis_generator/src/main.rs +++ b/core/bin/genesis_generator/src/main.rs @@ -91,6 +91,7 @@ async fn generate_new_config( genesis_commitment: None, bootloader_hash: Some(base_system_contracts.bootloader), default_aa_hash: Some(base_system_contracts.default_aa), + evm_simulator_hash: Some(base_system_contracts.evm_simulator), ..genesis_config }; diff --git a/core/node/test_utils/src/lib.rs b/core/node/test_utils/src/lib.rs index 0fc9c4478df9..92b8b02462be 100644 --- a/core/node/test_utils/src/lib.rs +++ b/core/node/test_utils/src/lib.rs @@ -217,10 +217,14 @@ impl Snapshot { Snapshot { l1_batch, l2_block, - factory_deps: [&contracts.bootloader, &contracts.default_aa] - .into_iter() - .map(|c| (c.hash, zksync_utils::be_words_to_bytes(&c.code))) - .collect(), + factory_deps: [ + &contracts.bootloader, + &contracts.default_aa, + &contracts.evm_simulator, + ] + .into_iter() + .map(|c| (c.hash, zksync_utils::be_words_to_bytes(&c.code))) + .collect(), storage_logs, } } From 35440d7611851808ca936270816c2038c5d33c42 Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Fri, 30 Aug 2024 18:58:31 -0300 Subject: [PATCH 65/76] EVM Simulator Flag (#244) * Add initial use evm interpreter flag * Add use evm simulator flag to toml * Update hashes * Delete Storage.sol * Update hashes * Change hashes --- Cargo.lock | 2 ++ core/lib/config/src/configs/mod.rs | 1 + core/lib/config/src/configs/use_evm_simulator.rs | 7 +++++++ core/lib/contracts/Cargo.toml | 2 ++ core/lib/contracts/src/lib.rs | 13 ++++++++++++- core/lib/env_config/src/lib.rs | 1 + core/lib/env_config/src/use_evm_simulator.rs | 9 +++++++++ etc/env/base/use_evm_simulator.toml | 2 ++ prover/Cargo.lock | 2 ++ 9 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 core/lib/config/src/configs/use_evm_simulator.rs create mode 100644 core/lib/env_config/src/use_evm_simulator.rs create mode 100644 etc/env/base/use_evm_simulator.toml diff --git a/Cargo.lock b/Cargo.lock index 49cfc23a845b..955b2f580133 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8468,6 +8468,8 @@ dependencies = [ "once_cell", "serde", "serde_json", + "zksync_config", + "zksync_env_config", "zksync_utils", ] diff --git a/core/lib/config/src/configs/mod.rs b/core/lib/config/src/configs/mod.rs index b213060f7ced..e3b216e4cdcc 100644 --- a/core/lib/config/src/configs/mod.rs +++ b/core/lib/config/src/configs/mod.rs @@ -63,6 +63,7 @@ pub mod pruning; pub mod secrets; pub mod snapshot_recovery; pub mod snapshots_creator; +pub mod use_evm_simulator; pub mod utils; pub mod vm_runner; pub mod wallets; diff --git a/core/lib/config/src/configs/use_evm_simulator.rs b/core/lib/config/src/configs/use_evm_simulator.rs new file mode 100644 index 000000000000..76113613a17d --- /dev/null +++ b/core/lib/config/src/configs/use_evm_simulator.rs @@ -0,0 +1,7 @@ +use serde::Deserialize; + +/// Configuration for the use evm simulator +#[derive(Debug, Deserialize, Clone, PartialEq)] +pub struct UseEvmSimulator { + pub use_evm_simulator: bool, +} diff --git a/core/lib/contracts/Cargo.toml b/core/lib/contracts/Cargo.toml index 2b80295cf440..26372a02a096 100644 --- a/core/lib/contracts/Cargo.toml +++ b/core/lib/contracts/Cargo.toml @@ -12,6 +12,8 @@ categories.workspace = true [dependencies] zksync_utils.workspace = true +zksync_config.workspace = true +zksync_env_config.workspace = true ethabi.workspace = true serde_json.workspace = true diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index 685ae5d1a4d2..2b678f991d4e 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -16,6 +16,11 @@ use ethabi::{ }; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; +use zksync_config::configs::{ + house_keeper::HouseKeeperConfig, + use_evm_simulator::{self, UseEvmSimulator}, +}; +use zksync_env_config::FromEnv; use zksync_utils::{bytecode::hash_bytecode, bytes_to_be_words, workspace_dir_or_current_dir}; pub mod test_contracts; @@ -342,10 +347,16 @@ impl BaseSystemContracts { hash, }; - let evm_simulator_bytecode = + let mut evm_simulator_bytecode = read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); let evm_simulator_hash = hash_bytecode(&evm_simulator_bytecode); + let use_evm_simulator = + UseEvmSimulator::from_env().expect("USE EVM SIMULATOR FLAG SHOULD BE SET"); + if !use_evm_simulator.use_evm_simulator { + evm_simulator_bytecode = vec![]; + } + let evm_simulator = SystemContractCode { code: bytes_to_be_words(evm_simulator_bytecode), hash: evm_simulator_hash, diff --git a/core/lib/env_config/src/lib.rs b/core/lib/env_config/src/lib.rs index 8cfa7b58a31c..0a8b35735059 100644 --- a/core/lib/env_config/src/lib.rs +++ b/core/lib/env_config/src/lib.rs @@ -29,6 +29,7 @@ mod genesis; mod prover_job_monitor; #[cfg(test)] mod test_utils; +mod use_evm_simulator; mod vm_runner; mod wallets; diff --git a/core/lib/env_config/src/use_evm_simulator.rs b/core/lib/env_config/src/use_evm_simulator.rs new file mode 100644 index 000000000000..c2a58387e62f --- /dev/null +++ b/core/lib/env_config/src/use_evm_simulator.rs @@ -0,0 +1,9 @@ +use zksync_config::configs::use_evm_simulator::UseEvmSimulator; + +use crate::{envy_load, FromEnv}; + +impl FromEnv for UseEvmSimulator { + fn from_env() -> anyhow::Result { + envy_load("use_evm_simulator", "USE_EVM_SIMULATOR_") + } +} diff --git a/etc/env/base/use_evm_simulator.toml b/etc/env/base/use_evm_simulator.toml new file mode 100644 index 000000000000..f0e222033464 --- /dev/null +++ b/etc/env/base/use_evm_simulator.toml @@ -0,0 +1,2 @@ +[use_evm_simulator] +use_evm_simulator = true diff --git a/prover/Cargo.lock b/prover/Cargo.lock index 5696addcf688..67065fbd0db4 100644 --- a/prover/Cargo.lock +++ b/prover/Cargo.lock @@ -7858,6 +7858,8 @@ dependencies = [ "once_cell", "serde", "serde_json", + "zksync_config", + "zksync_env_config", "zksync_utils", ] From 00f2325274988d3fe43f319b2fab7aa2e0e406bd Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 30 Aug 2024 19:08:56 -0300 Subject: [PATCH 66/76] Fix lints --- core/lib/contracts/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index 2b678f991d4e..192f228207c4 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -16,10 +16,7 @@ use ethabi::{ }; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; -use zksync_config::configs::{ - house_keeper::HouseKeeperConfig, - use_evm_simulator::{self, UseEvmSimulator}, -}; +use zksync_config::configs::use_evm_simulator::UseEvmSimulator; use zksync_env_config::FromEnv; use zksync_utils::{bytecode::hash_bytecode, bytes_to_be_words, workspace_dir_or_current_dir}; From c248a714aaa027e48f738676e7c25a8a4be290d6 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Sat, 31 Aug 2024 00:35:53 -0300 Subject: [PATCH 67/76] Add evm simulator to aux protocol version used for tests --- core/lib/types/src/api/mod.rs | 4 ++-- core/node/node_sync/src/external_io.rs | 2 +- core/node/node_sync/src/tests.rs | 7 +++++++ core/node/vm_runner/src/tests/mod.rs | 4 ++++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/core/lib/types/src/api/mod.rs b/core/lib/types/src/api/mod.rs index 4c0b1e69439c..e72884340252 100644 --- a/core/lib/types/src/api/mod.rs +++ b/core/lib/types/src/api/mod.rs @@ -638,7 +638,7 @@ pub struct ProtocolVersion { /// Verifier configuration #[deprecated] pub verification_keys_hashes: Option, - /// Hashes of base system contracts (bootloader and default account) + /// Hashes of base system contracts (bootloader, default account and evm simulator) #[deprecated] pub base_system_contracts: Option, /// Bootloader code hash @@ -696,7 +696,7 @@ impl ProtocolVersion { .or_else(|| self.base_system_contracts.map(|hashes| hashes.default_aa)) } - pub fn default_evm_simulator_code_hash(&self) -> Option { + pub fn evm_simulator_code_hash(&self) -> Option { self.evm_simulator_code_hash.or_else(|| { self.base_system_contracts .map(|hashes| hashes.evm_simulator) diff --git a/core/node/node_sync/src/external_io.rs b/core/node/node_sync/src/external_io.rs index 2fc04ba60bba..d05c011da4ef 100644 --- a/core/node/node_sync/src/external_io.rs +++ b/core/node/node_sync/src/external_io.rs @@ -346,7 +346,7 @@ impl StateKeeperIO for ExternalIO { .default_account_code_hash() .context("Missing default account code hash")?; let evm_simulator_code_hash = protocol_version - .default_evm_simulator_code_hash() + .evm_simulator_code_hash() .context("Missing evm simulator code hash")?; let l2_system_upgrade_tx_hash = protocol_version.l2_system_upgrade_tx_hash(); self.pool diff --git a/core/node/node_sync/src/tests.rs b/core/node/node_sync/src/tests.rs index edd8306e72e0..fc6fd292c091 100644 --- a/core/node/node_sync/src/tests.rs +++ b/core/node/node_sync/src/tests.rs @@ -304,6 +304,7 @@ async fn external_io_works_without_local_protocol_version(snapshot_recovery: boo timestamp: snapshot.l2_block_timestamp + 1, bootloader_code_hash: Some(H256::repeat_byte(1)), default_account_code_hash: Some(H256::repeat_byte(1)), + evm_simulator_code_hash: Some(H256::repeat_byte(1)), ..api::ProtocolVersion::default() }; client.insert_protocol_version(next_protocol_version.clone()); @@ -344,6 +345,12 @@ async fn external_io_works_without_local_protocol_version(snapshot_recovery: boo .default_aa, next_protocol_version.default_account_code_hash.unwrap() ); + assert_eq!( + persisted_protocol_version + .base_system_contracts_hashes + .evm_simulator, + next_protocol_version.evm_simulator_code_hash.unwrap() + ); let l2_block = storage .blocks_dal() diff --git a/core/node/vm_runner/src/tests/mod.rs b/core/node/vm_runner/src/tests/mod.rs index 30061954c180..cd225c0725bc 100644 --- a/core/node/vm_runner/src/tests/mod.rs +++ b/core/node/vm_runner/src/tests/mod.rs @@ -321,6 +321,10 @@ async fn store_l1_batches( .iter() .map(|contract| hash_bytecode(&contract.bytecode)) .chain([genesis_params.base_system_contracts().hashes().default_aa]) + .chain([genesis_params + .base_system_contracts() + .hashes() + .evm_simulator]) .map(h256_to_u256) .collect(); From 2f92e1d313792ed419b4be6e7e9f38fca973d1a0 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Sat, 31 Aug 2024 01:10:17 -0300 Subject: [PATCH 68/76] Add simulator code hash to genesis yaml file --- etc/env/file_based/genesis.yaml | 5 +++-- .../config/src/forge_interface/deploy_ecosystem/input.rs | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/etc/env/file_based/genesis.yaml b/etc/env/file_based/genesis.yaml index 6d7a6ba3c338..687e87290593 100644 --- a/etc/env/file_based/genesis.yaml +++ b/etc/env/file_based/genesis.yaml @@ -4,8 +4,8 @@ genesis_batch_commitment: 0x2d00e5f8d77afcebf58a6b82ae56ba967566fe7dfbcb6760319f genesis_protocol_semantic_version: '0.24.1' # deprecated genesis_protocol_version: 24 -default_aa_hash: 0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32 -bootloader_hash: 0x010008e742608b21bf7eb23c1a9d0602047e3618b464c9b59c0fba3b3d7ab66e +default_aa_hash: 0x0100058d9eee51f4b9e9a9ecb7fd7e8301e90bef018c2bd913ed36e583fec8c2 +bootloader_hash: 0x010008bbde6fc402ea3a3d6cb15cb97e70245d3d4e48fb74362d4961b74c16b1 l1_chain_id: 9 l2_chain_id: 270 fee_account: '0x0000000000000000000000000000000000000001' @@ -13,3 +13,4 @@ prover: recursion_scheduler_level_vk_hash: 0x14f97b81e54b35fe673d8708cc1a19e1ea5b5e348e12d31e39824ed4f42bbca2 dummy_verifier: true l1_batch_commit_data_generator_mode: Rollup +evm_simulator_hash: 0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91 diff --git a/zk_toolbox/crates/config/src/forge_interface/deploy_ecosystem/input.rs b/zk_toolbox/crates/config/src/forge_interface/deploy_ecosystem/input.rs index 30ec0eeb9c48..a205f640331b 100644 --- a/zk_toolbox/crates/config/src/forge_interface/deploy_ecosystem/input.rs +++ b/zk_toolbox/crates/config/src/forge_interface/deploy_ecosystem/input.rs @@ -146,6 +146,7 @@ impl DeployL1Config { .diamond_init_minimal_l2_gas_price, bootloader_hash: genesis_config.bootloader_hash.unwrap(), default_aa_hash: genesis_config.default_aa_hash.unwrap(), + evm_simulator_hash: genesis_config.evm_simulator_hash.unwrap(), diamond_init_priority_tx_max_pubdata: initial_deployment_config .diamond_init_priority_tx_max_pubdata, diamond_init_pubdata_pricing_mode: initial_deployment_config @@ -194,6 +195,7 @@ pub struct ContractsDeployL1Config { pub diamond_init_minimal_l2_gas_price: u64, pub bootloader_hash: H256, pub default_aa_hash: H256, + pub evm_simulator_hash: H256, } #[derive(Debug, Deserialize, Serialize, Clone)] From 9a807e60ccbd1333668b2760fdbc30ed256e46fa Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Sat, 31 Aug 2024 02:04:03 -0300 Subject: [PATCH 69/76] Remove panic for older vms and return empty vec for decommiter instead --- core/lib/multivm/src/vm_instance.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/multivm/src/vm_instance.rs b/core/lib/multivm/src/vm_instance.rs index 1a21fb7d87d9..e12bc9a55f87 100644 --- a/core/lib/multivm/src/vm_instance.rs +++ b/core/lib/multivm/src/vm_instance.rs @@ -241,7 +241,7 @@ impl VmInstance { let vm = if let VmInstance::Vm1_5_0(vm) = &self { vm } else { - panic!("No supported for old VMs"); + return vec![]; }; let mut result = vec![]; From feb47f9f5e705be2e2e0bdc918f46de7999150dd Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 2 Sep 2024 11:22:00 -0300 Subject: [PATCH 70/76] Add evm simulator code hash to metaparameters in json test files --- .../types/src/commitment/tests/post_boojum_1_4_1_test.json | 6 ++++-- .../types/src/commitment/tests/post_boojum_1_4_2_test.json | 6 ++++-- .../types/src/commitment/tests/post_boojum_1_5_0_test.json | 6 ++++-- core/lib/types/src/commitment/tests/pre_boojum_test.json | 6 ++++-- core/node/vm_runner/src/impls/bwip.rs | 2 +- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/core/lib/types/src/commitment/tests/post_boojum_1_4_1_test.json b/core/lib/types/src/commitment/tests/post_boojum_1_4_1_test.json index c5eccbce038a..74af90ce98f6 100644 --- a/core/lib/types/src/commitment/tests/post_boojum_1_4_1_test.json +++ b/core/lib/types/src/commitment/tests/post_boojum_1_4_1_test.json @@ -16,6 +16,7 @@ "rollup_root_hash": "0xe47f013d1ecd4ce53b6872f6b762670b393815e7ddacdf2b0886af9c7f3a555b", "bootloader_code_hash": "0x010007ed0e328b940e241f7666a6303b7ffd4e3fd7e8c154d6e7556befe6cd6d", "default_aa_code_hash": "0x0100055b7a8be90522251be8be1a186464d056462973502ac8a0437c85e4d2a9", + "evm_simulator_code_hash": "0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91", "protocol_version": "Version20" }, "system_logs": [ @@ -212,6 +213,7 @@ "zkporter_is_available": false, "bootloader_code_hash": "0x010007ed0e328b940e241f7666a6303b7ffd4e3fd7e8c154d6e7556befe6cd6d", "default_aa_code_hash": "0x0100055b7a8be90522251be8be1a186464d056462973502ac8a0437c85e4d2a9", + "evm_simulator_code_hash": "0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91", "protocol_version": "Version20" }, "auxiliary_output": { @@ -261,7 +263,7 @@ "hashes": { "pass_through_data": "0x6a3ffc0f55d4abce9498b8bcb01a3018bc2b83d96acb27e23772fe9347954725", "aux_output": "0x1759d3eff5b7f03b5207418548d2735fd8f70930c2726812f0b077581eb0832f", - "meta_parameters": "0x3fec00ec17ecaff24bbbcbc15850ca3528ce1c287d3a35fee97a6c65655866c1", - "commitment": "0xde52fb0a4b41aa857b0b18a8e5932846a955f60e0921fb99974a9786369e8503" + "meta_parameters": "0x02531e5cc22688523a4ac9317e5097743771f6914015cf1152491cf22084bd58", + "commitment": "0xfe674b8b0ca1602cf37cedd7bc1fd88ea36fd7a69eeda94c5ee13b2cf3496662" } } diff --git a/core/lib/types/src/commitment/tests/post_boojum_1_4_2_test.json b/core/lib/types/src/commitment/tests/post_boojum_1_4_2_test.json index 4983bbeca143..17744c562fc2 100644 --- a/core/lib/types/src/commitment/tests/post_boojum_1_4_2_test.json +++ b/core/lib/types/src/commitment/tests/post_boojum_1_4_2_test.json @@ -16,6 +16,7 @@ "rollup_root_hash": "0xe47f013d1ecd4ce53b6872f6b762670b393815e7ddacdf2b0886af9c7f3a555b", "bootloader_code_hash": "0x010007ed0e328b940e241f7666a6303b7ffd4e3fd7e8c154d6e7556befe6cd6d", "default_aa_code_hash": "0x0100055b7a8be90522251be8be1a186464d056462973502ac8a0437c85e4d2a9", + "evm_simulator_code_hash": "0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91", "protocol_version": "Version21" }, "system_logs": [ @@ -228,6 +229,7 @@ "zkporter_is_available": false, "bootloader_code_hash": "0x010007ed0e328b940e241f7666a6303b7ffd4e3fd7e8c154d6e7556befe6cd6d", "default_aa_code_hash": "0x0100055b7a8be90522251be8be1a186464d056462973502ac8a0437c85e4d2a9", + "evm_simulator_code_hash": "0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91", "protocol_version": "Version21" }, "auxiliary_output": { @@ -277,7 +279,7 @@ "hashes": { "pass_through_data": "0x6a3ffc0f55d4abce9498b8bcb01a3018bc2b83d96acb27e23772fe9347954725", "aux_output": "0xa6410b9d726740cc0e3309565816ed7a929fb2ad7ab69b46cde006e7ea60dd5b", - "meta_parameters": "0x3fec00ec17ecaff24bbbcbc15850ca3528ce1c287d3a35fee97a6c65655866c1", - "commitment": "0x3b2e443dd853fb0c15c5956db1deb2527661c2b2b64011ab345120c620bc5faa" + "meta_parameters": "0x02531e5cc22688523a4ac9317e5097743771f6914015cf1152491cf22084bd58", + "commitment": "0x5885a3c69a01beb06a795f78269c2cc092919e3202f38ac57c2bd498cb1c3f74" } } diff --git a/core/lib/types/src/commitment/tests/post_boojum_1_5_0_test.json b/core/lib/types/src/commitment/tests/post_boojum_1_5_0_test.json index 59a24b7c90ce..15d34a21b0f7 100644 --- a/core/lib/types/src/commitment/tests/post_boojum_1_5_0_test.json +++ b/core/lib/types/src/commitment/tests/post_boojum_1_5_0_test.json @@ -16,6 +16,7 @@ "rollup_root_hash": "0xe47f013d1ecd4ce53b6872f6b762670b393815e7ddacdf2b0886af9c7f3a555b", "bootloader_code_hash": "0x010007ed0e328b940e241f7666a6303b7ffd4e3fd7e8c154d6e7556befe6cd6d", "default_aa_code_hash": "0x0100055b7a8be90522251be8be1a186464d056462973502ac8a0437c85e4d2a9", + "evm_simulator_code_hash": "0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91", "protocol_version": "Version23" }, "system_logs": [ @@ -274,6 +275,7 @@ "zkporter_is_available": false, "bootloader_code_hash": "0x010007ed0e328b940e241f7666a6303b7ffd4e3fd7e8c154d6e7556befe6cd6d", "default_aa_code_hash": "0x0100055b7a8be90522251be8be1a186464d056462973502ac8a0437c85e4d2a9", + "evm_simulator_code_hash": "0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91", "protocol_version": "Version23" }, "auxiliary_output": { @@ -351,7 +353,7 @@ "hashes": { "pass_through_data": "0x6a3ffc0f55d4abce9498b8bcb01a3018bc2b83d96acb27e23772fe9347954725", "aux_output": "0xadc63d9c45f85598f3e3c232970315d1f6ac96222e379e16ced7a204524a4061", - "meta_parameters": "0xffdee3e679310760e0320a3f9dea3fa863b0771e4424193752ed803fc2d53d20", - "commitment": "0xbbac3e74f007f28453294acb27e3b5c85e67be1208203bb31db9065fe4305dea" + "meta_parameters": "0x02531e5cc22688523a4ac9317e5097743771f6914015cf1152491cf22084bd58", + "commitment": "0x4fdd8c5b231dfc9fc81aba744a90fbec78627f529ac29f9fc758a7b9e62fa321" } } diff --git a/core/lib/types/src/commitment/tests/pre_boojum_test.json b/core/lib/types/src/commitment/tests/pre_boojum_test.json index 3aa163830330..eccd843c08a3 100644 --- a/core/lib/types/src/commitment/tests/pre_boojum_test.json +++ b/core/lib/types/src/commitment/tests/pre_boojum_test.json @@ -16,6 +16,7 @@ "rollup_root_hash": "0xe47f013d1ecd4ce53b6872f6b762670b393815e7ddacdf2b0886af9c7f3a555b", "bootloader_code_hash": "0x010007ed0e328b940e241f7666a6303b7ffd4e3fd7e8c154d6e7556befe6cd6d", "default_aa_code_hash": "0x0100055b7a8be90522251be8be1a186464d056462973502ac8a0437c85e4d2a9", + "evm_simulator_code_hash": "0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91", "protocol_version": "Version17" }, "initial_writes": [ @@ -80,6 +81,7 @@ "zkporter_is_available": false, "bootloader_code_hash": "0x010007ed0e328b940e241f7666a6303b7ffd4e3fd7e8c154d6e7556befe6cd6d", "default_aa_code_hash": "0x0100055b7a8be90522251be8be1a186464d056462973502ac8a0437c85e4d2a9", + "evm_simulator_code_hash": "0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91", "protocol_version": "Version17" }, "auxiliary_output": { @@ -564,7 +566,7 @@ "hashes": { "pass_through_data": "0x6a3ffc0f55d4abce9498b8bcb01a3018bc2b83d96acb27e23772fe9347954725", "aux_output": "0x688566b1fe957584256b3bbdc9f9862a7c98cd0a3fa542b3e73600e7bfcd63a3", - "meta_parameters": "0x3fec00ec17ecaff24bbbcbc15850ca3528ce1c287d3a35fee97a6c65655866c1", - "commitment": "0x8e0a1f1f866df7d53f0648dc6e642eabd452a1319e4acae8cdf58d364d25ee59" + "meta_parameters": "0x02531e5cc22688523a4ac9317e5097743771f6914015cf1152491cf22084bd58", + "commitment": "0xebf93d8addf13e664e78fc287468b8783954d9d92572a734f96f0aa63c536da2" } } diff --git a/core/node/vm_runner/src/impls/bwip.rs b/core/node/vm_runner/src/impls/bwip.rs index 4eedba275a9e..bee4f0465b41 100644 --- a/core/node/vm_runner/src/impls/bwip.rs +++ b/core/node/vm_runner/src/impls/bwip.rs @@ -278,7 +278,7 @@ async fn get_updates_manager_witness_input_data( bootloader_code, default_account_code_hash: account_code_hash, - evm_simulator_code_hash: evm_simulator_code_hash, + evm_simulator_code_hash, storage_refunds, pubdata_costs, witness_block_state, From 8e9a05d918844e6f457e639aea487fda97d6ac04 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 4 Sep 2024 17:40:14 -0300 Subject: [PATCH 71/76] Update new rust tests for evm simulator changes --- core/lib/multivm/src/versions/vm_fast/tests/block_tip.rs | 2 +- core/lib/multivm/src/versions/vm_fast/tests/circuits.rs | 2 +- .../src/versions/vm_fast/tests/get_used_contracts.rs | 2 +- core/lib/multivm/src/versions/vm_fast/tests/precompiles.rs | 6 +++--- core/node/api_server/src/execution_sandbox/testonly.rs | 1 + core/node/api_server/src/web3/tests/vm.rs | 1 + core/node/state_keeper/src/tests/mod.rs | 1 + 7 files changed, 9 insertions(+), 6 deletions(-) diff --git a/core/lib/multivm/src/versions/vm_fast/tests/block_tip.rs b/core/lib/multivm/src/versions/vm_fast/tests/block_tip.rs index 15af9d868adc..a96045141380 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/block_tip.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/block_tip.rs @@ -147,7 +147,7 @@ fn execute_test(test_data: L1MessengerTestData) -> TestStatistics { for (i, data) in txs_data.into_iter().enumerate() { let tx = account.get_l2_tx_for_execute( Execute { - contract_address: CONTRACT_FORCE_DEPLOYER_ADDRESS, + contract_address: Some(CONTRACT_FORCE_DEPLOYER_ADDRESS), calldata: data, value: U256::zero(), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_fast/tests/circuits.rs b/core/lib/multivm/src/versions/vm_fast/tests/circuits.rs index 0270ac35475b..a119a31618e9 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/circuits.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/circuits.rs @@ -21,7 +21,7 @@ fn test_circuits() { let account = &mut vm.rich_accounts[0]; let tx = account.get_l2_tx_for_execute( Execute { - contract_address: Address::random(), + contract_address: Some(Address::random()), calldata: Vec::new(), value: U256::from(1u8), factory_deps: vec![], diff --git a/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs b/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs index fc493e292286..50ee14a2f56c 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/get_used_contracts.rs @@ -200,7 +200,7 @@ fn get_used_contracts_with_out_of_gas_far_call() { let increment = proxy_counter_abi.function("increment").unwrap(); let increment_tx = account.get_l2_tx_for_execute( Execute { - contract_address: data.proxy_counter_address, + contract_address: Some(data.proxy_counter_address), calldata: increment .encode_input(&[Token::Uint(1.into()), Token::Uint(u64::MAX.into())]) .unwrap(), diff --git a/core/lib/multivm/src/versions/vm_fast/tests/precompiles.rs b/core/lib/multivm/src/versions/vm_fast/tests/precompiles.rs index f77eeb4f126e..28d3ea82da31 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/precompiles.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/precompiles.rs @@ -28,7 +28,7 @@ fn test_keccak() { let account = &mut vm.rich_accounts[0]; let tx = account.get_l2_tx_for_execute( Execute { - contract_address: address, + contract_address: Some(address), calldata: hex::decode(keccak1000_calldata).unwrap(), value: 0.into(), factory_deps: vec![], @@ -65,7 +65,7 @@ fn test_sha256() { let account = &mut vm.rich_accounts[0]; let tx = account.get_l2_tx_for_execute( Execute { - contract_address: address, + contract_address: Some(address), calldata: hex::decode(sha1000_calldata).unwrap(), value: 0.into(), factory_deps: vec![], @@ -95,7 +95,7 @@ fn test_ecrecover() { let account = &mut vm.rich_accounts[0]; let tx = account.get_l2_tx_for_execute( Execute { - contract_address: account.address, + contract_address: Some(account.address), calldata: vec![], value: 0.into(), factory_deps: vec![], diff --git a/core/node/api_server/src/execution_sandbox/testonly.rs b/core/node/api_server/src/execution_sandbox/testonly.rs index d9d60f52415a..9cba5e716bc1 100644 --- a/core/node/api_server/src/execution_sandbox/testonly.rs +++ b/core/node/api_server/src/execution_sandbox/testonly.rs @@ -71,6 +71,7 @@ impl MockOneshotExecutor { logs: Default::default(), statistics: Default::default(), refunds: Default::default(), + new_known_factory_deps: Default::default(), } }, ) diff --git a/core/node/api_server/src/web3/tests/vm.rs b/core/node/api_server/src/web3/tests/vm.rs index 5b04250eebf4..6c076f51d5ad 100644 --- a/core/node/api_server/src/web3/tests/vm.rs +++ b/core/node/api_server/src/web3/tests/vm.rs @@ -336,6 +336,7 @@ impl HttpTest for SendTransactionWithDetailedOutputTest { logs: vm_execution_logs.clone(), statistics: Default::default(), refunds: Default::default(), + new_known_factory_deps: Default::default(), } }); tx_executor diff --git a/core/node/state_keeper/src/tests/mod.rs b/core/node/state_keeper/src/tests/mod.rs index 80de0f0beff9..10c42c7857bd 100644 --- a/core/node/state_keeper/src/tests/mod.rs +++ b/core/node/state_keeper/src/tests/mod.rs @@ -138,6 +138,7 @@ pub(super) fn create_execution_result( circuit_statistic: Default::default(), }, refunds: Refunds::default(), + new_known_factory_deps: Default::default(), } } From 7e77047dc26f86013916549489543518e55fa81a Mon Sep 17 00:00:00 2001 From: Javier Chatruc Date: Tue, 10 Sep 2024 15:22:12 -0300 Subject: [PATCH 72/76] Update commitment and contract hashes in configs --- etc/env/base/chain.toml | 2 +- etc/env/base/contracts.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/etc/env/base/chain.toml b/etc/env/base/chain.toml index 106ad503e7f5..b5a4e4b2e75c 100644 --- a/etc/env/base/chain.toml +++ b/etc/env/base/chain.toml @@ -92,7 +92,7 @@ save_call_traces = true bootloader_hash = "0x010008bbde6fc402ea3a3d6cb15cb97e70245d3d4e48fb74362d4961b74c16b1" default_aa_hash = "0x0100058d9eee51f4b9e9a9ecb7fd7e8301e90bef018c2bd913ed36e583fec8c2" -evm_simulator_hash = "0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91" +evm_simulator_hash = "0x01000ccb740e2345754450eda583f59b31a346920a22f968dfcfc63feae303ee" protective_reads_persistence_enabled = false diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index 46492304b3d0..c16a9c16592f 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -26,8 +26,8 @@ RECURSION_NODE_LEVEL_VK_HASH = "0x1186ec268d49f1905f8d9c1e9d39fc33e98c74f91d91a2 RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc8966504064f1f6ba3f1ba863210" RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" -GENESIS_ROOT = "0xadcaa4f5e2230c8b77973034975c6d541551f2831d58317550528e7761a6960a" -GENESIS_BATCH_COMMITMENT = "0x94f1ef45aa30f5c10be838bb91a1dd9ee2d03445a10aeaac4c611c1228930368" +GENESIS_ROOT = "0x50f5b5668514d2f373fccb031f317a368f4212992da8373a3e5fe993532c5dbd" +GENESIS_BATCH_COMMITMENT = "0x1459a405ed2ef80cf2f106421b211a8a754211b284c362e1fcb6ddf946efb597" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "56" From d863e9f1bd697fb57a7c405207e2490cb53fb602 Mon Sep 17 00:00:00 2001 From: Javier Chatruc Date: Tue, 10 Sep 2024 16:00:27 -0300 Subject: [PATCH 73/76] Fix compilation for all targets --- core/node/api_server/src/execution_sandbox/tests.rs | 2 +- core/node/consensus/src/registry/testonly.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/node/api_server/src/execution_sandbox/tests.rs b/core/node/api_server/src/execution_sandbox/tests.rs index 35103779a49e..79c5a7330384 100644 --- a/core/node/api_server/src/execution_sandbox/tests.rs +++ b/core/node/api_server/src/execution_sandbox/tests.rs @@ -236,7 +236,7 @@ fn create_transfer(fee_per_gas: u64, gas_per_pubdata: u64) -> L2Tx { gas_per_pubdata_limit: gas_per_pubdata.into(), }; L2Tx::new_signed( - Address::random(), + Some(Address::random()), vec![], Nonce(0), fee, diff --git a/core/node/consensus/src/registry/testonly.rs b/core/node/consensus/src/registry/testonly.rs index a0c55a557feb..07a87e3b676e 100644 --- a/core/node/consensus/src/registry/testonly.rs +++ b/core/node/consensus/src/registry/testonly.rs @@ -13,7 +13,7 @@ pub(crate) fn make_tx( ) -> Transaction { account.get_l2_tx_for_execute( Execute { - contract_address: *address, + contract_address: Some(*address), calldata: call.calldata().unwrap(), value: U256::zero(), factory_deps: vec![], From 539c1fda86b29f450aaa536633640f4de11d2a76 Mon Sep 17 00:00:00 2001 From: Javier Chatruc Date: Wed, 11 Sep 2024 10:53:28 -0300 Subject: [PATCH 74/76] Update submodule and genesis/root commitments --- contracts | 2 +- etc/env/base/contracts.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts b/contracts index 99bcbb4b4152..0f1383aef117 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 99bcbb4b4152c7bd3ec6574b312b3d30a060c978 +Subproject commit 0f1383aef1173d5971a67c9af6811036e8e9bfcd diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index a0de65f93239..fab072c07cec 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -26,8 +26,8 @@ RECURSION_NODE_LEVEL_VK_HASH = "0x1186ec268d49f1905f8d9c1e9d39fc33e98c74f91d91a2 RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc8966504064f1f6ba3f1ba863210" RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" -GENESIS_ROOT = "0x2f66751f814c73299b8e615d541b938fc328d9113787d3e2205710933e5b5c83" -GENESIS_BATCH_COMMITMENT = "0x2a302934edac3f6f252310105c9008a0cf6e8c8d40866af32303d51091777aa5" +GENESIS_ROOT = "0xbfa72908d61bf6e208a1140eb8b66a8e9fc0cc3ecd76f73d994fa75c49778530" +GENESIS_BATCH_COMMITMENT = "0xeac224ce2445688015b7b88a168332657fb1de5ccb3c55407d6107fbd483459e" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "56" From 4c6f40b6c40fca617a8e6fb1c0ad940cc4c69e62 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 16 Sep 2024 11:16:27 -0300 Subject: [PATCH 75/76] Update contracts submodule --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index 0f1383aef117..172240266b7f 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 0f1383aef1173d5971a67c9af6811036e8e9bfcd +Subproject commit 172240266b7f6fe572e768224dae44a96517dbf8 From 08606d3a4f8f1ac553a8367558a190521f19e0d1 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Mon, 16 Sep 2024 11:18:17 -0300 Subject: [PATCH 76/76] Update system contracts hashes --- core/lib/env_config/src/chain.rs | 6 +++--- etc/env/base/chain.toml | 4 ++-- etc/env/base/contracts.toml | 4 ++-- etc/env/file_based/genesis.yaml | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/lib/env_config/src/chain.rs b/core/lib/env_config/src/chain.rs index ca2c51803ba2..a9e954522b0a 100644 --- a/core/lib/env_config/src/chain.rs +++ b/core/lib/env_config/src/chain.rs @@ -100,10 +100,10 @@ mod tests { "0x010008bbde6fc402ea3a3d6cb15cb97e70245d3d4e48fb74362d4961b74c16b1", )), default_aa_hash: Some(hash( - "0x0100058d9eee51f4b9e9a9ecb7fd7e8301e90bef018c2bd913ed36e583fec8c2", + "0x0100058da8bd884adbce2b6acd828821257f183a76f9727c360a599a86270b0e", )), evm_simulator_hash: Some(hash( - "0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91", + "0x01000cdf5bb7dd8a97faf231a5e1e20f2fe308d6f200c3295c6e3629547cc4a4", )), l1_batch_commit_data_generator_mode, max_circuits_per_batch: 24100, @@ -139,7 +139,7 @@ mod tests { CHAIN_STATE_KEEPER_VALIDATION_COMPUTATIONAL_GAS_LIMIT="10000000" CHAIN_STATE_KEEPER_SAVE_CALL_TRACES="false" CHAIN_STATE_KEEPER_BOOTLOADER_HASH=0x010008bbde6fc402ea3a3d6cb15cb97e70245d3d4e48fb74362d4961b74c16b1 - CHAIN_STATE_KEEPER_DEFAULT_AA_HASH=0x0100058d9eee51f4b9e9a9ecb7fd7e8301e90bef018c2bd913ed36e583fec8c2 + CHAIN_STATE_KEEPER_DEFAULT_AA_HASH=0x0100058da8bd884adbce2b6acd828821257f183a76f9727c360a599a86270b0e CHAIN_STATE_KEEPER_PROTECTIVE_READS_PERSISTENCE_ENABLED=true CHAIN_STATE_KEEPER_L1_BATCH_COMMIT_DATA_GENERATOR_MODE="{l1_batch_commit_data_generator_mode}" "# diff --git a/etc/env/base/chain.toml b/etc/env/base/chain.toml index b5a4e4b2e75c..ce08957ca5aa 100644 --- a/etc/env/base/chain.toml +++ b/etc/env/base/chain.toml @@ -91,8 +91,8 @@ validation_computational_gas_limit = 300000 save_call_traces = true bootloader_hash = "0x010008bbde6fc402ea3a3d6cb15cb97e70245d3d4e48fb74362d4961b74c16b1" -default_aa_hash = "0x0100058d9eee51f4b9e9a9ecb7fd7e8301e90bef018c2bd913ed36e583fec8c2" -evm_simulator_hash = "0x01000ccb740e2345754450eda583f59b31a346920a22f968dfcfc63feae303ee" +default_aa_hash = "0x0100058da8bd884adbce2b6acd828821257f183a76f9727c360a599a86270b0e" +evm_simulator_hash = "0x01000cdf5bb7dd8a97faf231a5e1e20f2fe308d6f200c3295c6e3629547cc4a4" protective_reads_persistence_enabled = false diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index fab072c07cec..579340b76cfa 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -26,8 +26,8 @@ RECURSION_NODE_LEVEL_VK_HASH = "0x1186ec268d49f1905f8d9c1e9d39fc33e98c74f91d91a2 RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc8966504064f1f6ba3f1ba863210" RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" -GENESIS_ROOT = "0xbfa72908d61bf6e208a1140eb8b66a8e9fc0cc3ecd76f73d994fa75c49778530" -GENESIS_BATCH_COMMITMENT = "0xeac224ce2445688015b7b88a168332657fb1de5ccb3c55407d6107fbd483459e" +GENESIS_ROOT = "0x607f9b4f9de04a40d0aa73771f4d527a870a516307e7528c6c3f0a082286ceee" +GENESIS_BATCH_COMMITMENT = "0x6e98bc9297f2aba301b9a1422d9a114bedb9d9b80fc9780bf303508659d24ee9" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "56" diff --git a/etc/env/file_based/genesis.yaml b/etc/env/file_based/genesis.yaml index 7f0dca74ef79..1402e45acfdb 100644 --- a/etc/env/file_based/genesis.yaml +++ b/etc/env/file_based/genesis.yaml @@ -4,8 +4,9 @@ genesis_batch_commitment: 0x2d00e5f8d77afcebf58a6b82ae56ba967566fe7dfbcb6760319f genesis_protocol_semantic_version: '0.24.2' # deprecated genesis_protocol_version: 24 -default_aa_hash: 0x0100058d9eee51f4b9e9a9ecb7fd7e8301e90bef018c2bd913ed36e583fec8c2 +default_aa_hash: 0x0100058da8bd884adbce2b6acd828821257f183a76f9727c360a599a86270b0e bootloader_hash: 0x010008bbde6fc402ea3a3d6cb15cb97e70245d3d4e48fb74362d4961b74c16b1 +evm_simulator_hash: 0x01000cdf5bb7dd8a97faf231a5e1e20f2fe308d6f200c3295c6e3629547cc4a4 l1_chain_id: 9 l2_chain_id: 270 fee_account: '0x0000000000000000000000000000000000000001' @@ -13,4 +14,3 @@ prover: recursion_scheduler_level_vk_hash: 0x14f97b81e54b35fe673d8708cc1a19e1ea5b5e348e12d31e39824ed4f42bbca2 dummy_verifier: true l1_batch_commit_data_generator_mode: Rollup -evm_simulator_hash: 0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91