From bbd7db9bf064c6e683e7ed57a42f5899cf3748a4 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 11 Sep 2024 12:48:56 -0300 Subject: [PATCH 01/45] Make address optional in transaction data --- .../system-constants-generator/src/utils.rs | 4 +- core/lib/dal/src/consensus/mod.rs | 16 +++- core/lib/dal/src/models/tests.rs | 2 +- core/lib/dal/src/tests/mod.rs | 6 +- core/lib/dal/src/transactions_dal.rs | 74 +++++++++++++++---- 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/block_tip.rs | 2 +- .../src/versions/vm_fast/tests/circuits.rs | 2 +- .../src/versions/vm_fast/tests/code_oracle.rs | 8 +- .../vm_fast/tests/get_used_contracts.rs | 6 +- .../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/precompiles.rs | 6 +- .../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 | 4 +- .../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 +- .../types/internals/transaction_data.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/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 ++- .../api_server/src/execution_sandbox/tests.rs | 2 +- core/node/consensus/src/registry/testonly.rs | 2 +- core/node/consensus/src/vm.rs | 2 +- core/node/eth_watch/src/tests.rs | 4 +- .../state_keeper/src/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 +- .../src/sdk/operations/deploy_contract.rs | 2 +- .../src/sdk/operations/execute_contract.rs | 2 +- .../loadnext/src/sdk/operations/transfer.rs | 4 +- core/tests/loadnext/src/sdk/signer.rs | 6 +- core/tests/test_account/src/lib.rs | 8 +- core/tests/vm-benchmark/src/transaction.rs | 8 +- prover/crates/lib/keystore/src/utils.rs | 1 + 72 files changed, 219 insertions(+), 163 deletions(-) diff --git a/core/bin/system-constants-generator/src/utils.rs b/core/bin/system-constants-generator/src/utils.rs index 3775b3c0e243..664ae0ebdb16 100644 --- a/core/bin/system-constants-generator/src/utils.rs +++ b/core/bin/system-constants-generator/src/utils.rs @@ -89,7 +89,7 @@ pub(super) fn get_l2_tx( pubdata_price: u32, ) -> L2Tx { L2Tx::new_signed( - contract_address, + Some(contract_address), vec![], Nonce(0), Fee { @@ -134,7 +134,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 f0ef336bc543..88620575c88a 100644 --- a/core/lib/dal/src/consensus/mod.rs +++ b/core/lib/dal/src/consensus/mod.rs @@ -401,9 +401,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)) @@ -487,7 +489,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/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 c17e8c5d1fe3..dc672fa1f807 100644 --- a/core/lib/dal/src/tests/mod.rs +++ b/core/lib/dal/src/tests/mod.rs @@ -74,7 +74,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(), + Some(Address::random()), vec![], zksync_types::Nonce(0), fee, @@ -110,7 +110,7 @@ pub(crate) fn mock_l1_execute() -> L1Tx { }; let execute = Execute { - contract_address: H160::random(), + contract_address: Some(H160::random()), value: Default::default(), calldata: vec![], factory_deps: vec![], @@ -138,7 +138,7 @@ pub(crate) fn mock_protocol_upgrade_transaction() -> ProtocolUpgradeTx { }; let execute = Execute { - contract_address: H160::random(), + contract_address: Some(H160::random()), 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 49791f776e08..bc44083ea319 100644 --- a/core/lib/dal/src/transactions_dal.rs +++ b/core/lib/dal/src/transactions_dal.rs @@ -58,7 +58,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) @@ -143,7 +149,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(), @@ -161,7 +167,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())); @@ -238,7 +250,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(), @@ -284,7 +296,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); @@ -413,7 +431,7 @@ impl TransactionsDal<'_, '_> { input_data, &json_data, tx_format, - contract_address, + contract_address_b, value, &paymaster, &paymaster_input, @@ -697,8 +715,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()); @@ -818,7 +843,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]], @@ -901,8 +926,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()); @@ -1013,7 +1045,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, @@ -1083,6 +1115,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()); @@ -1096,7 +1135,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); @@ -1203,7 +1242,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, @@ -1373,6 +1412,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; upgrade_hashes.push(tx_res.hash.as_bytes()); upgrade_initiator_address.push(common_data.sender.as_bytes()); @@ -1385,7 +1431,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); @@ -1484,7 +1530,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/mempool/src/tests.rs b/core/lib/mempool/src/tests.rs index 6ea1be3b514b..96ef600984f9 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(), + Some(Address::default()), 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: Some(Address::repeat_byte(0x11)), 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 a29e1101d520..34c70e0f9c45 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..0285320daa30 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: Some(Address::random()), 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..f7384da76d0d 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: Some(Address::random()), 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..38280aa80513 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: Some(Address::random()), 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..8bf575effe06 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: Some(Address::random()), 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/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/code_oracle.rs b/core/lib/multivm/src/versions/vm_fast/tests/code_oracle.rs index 836603d77d87..f29684260051 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 @@ -58,7 +58,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()), @@ -82,7 +82,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()), @@ -152,7 +152,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()), @@ -220,7 +220,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 3fcef71add07..746e9be923f2 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 @@ -65,7 +65,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]], @@ -150,7 +150,7 @@ fn execute_proxy_counter(gas: u32) -> (VmTester, ProxyCounterData, VmExecutionRe 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(), @@ -197,7 +197,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/l1_tx_execution.rs b/core/lib/multivm/src/versions/vm_fast/tests/l1_tx_execution.rs index f1399a1b4e68..ea3613b0fe79 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 a374f63608bc..a43bb7c0309e 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 @@ -37,7 +37,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 122b38601175..2ae43869d7f6 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/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/lib/multivm/src/versions/vm_fast/tests/refunds.rs b/core/lib/multivm/src/versions/vm_fast/tests/refunds.rs index 5ad6e3fa4f3d..1d276533898e 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 fe94189ed7cf..89b8788f52fe 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 @@ -68,7 +68,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![], @@ -125,7 +125,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 a61a0a2bd91c..55ca372c4a9f 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/sekp256r1.rs +++ b/core/lib/multivm/src/versions/vm_fast/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_fast/tests/storage.rs b/core/lib/multivm/src/versions/vm_fast/tests/storage.rs index 7fe15ca7bcd2..8258e21366ce 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/storage.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/storage.rs @@ -30,7 +30,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![], @@ -40,7 +40,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 3327012801ce..3370f8bce354 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 f972b29cda8a..f0ed2fb30c87 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..2ec86eb3ceaf 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: Some(Address::random()), 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 bed348afd2d9..02c73344a543 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 0708d67e27a3..b15ef7fde2bf 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 a42037a7f5be..ef19717a627c 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 @@ -82,7 +82,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]], @@ -208,7 +208,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(), 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 dcb1bff06d09..0fc12848227e 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 661286ca9697..91d78c69a931 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 eb3104fd637a..8bf5e9919889 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 ca058d672d2e..cc0085f20252 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 779e9b5c629d..cdd71354c8de 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 43e7baae3b2d..52e4d24bc0b4 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 6cc731a1387c..93be9506a3b0 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 0fe0b0220fae..126d174a6468 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/storage.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/storage.rs @@ -50,7 +50,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 31f6c3291ef6..2c380623636a 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 7c3ebff4a77d..d85a504de40f 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/upgrade.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/upgrade.rs @@ -276,7 +276,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(), @@ -326,7 +326,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/types/internals/transaction_data.rs b/core/lib/multivm/src/versions/vm_latest/types/internals/transaction_data.rs index 502be0dc22cc..2ec86eb3ceaf 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, @@ -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: Some(Address::random()), 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_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..b64e3f770185 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: Some(Address::random()), 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..a8f80ea3255e 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: Some(Address::random()), 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..22ab09296c91 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: Some(Address::random()), 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..c96004163a65 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: Some(Address::random()), gas_limit: U256::from(1u32), pubdata_price_limit: U256::from(1u32), max_fee_per_gas: U256::from(1u32), 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 402e16afd435..54e1b40b5b33 100644 --- a/core/lib/types/src/lib.rs +++ b/core/lib/types/src/lib.rs @@ -105,7 +105,7 @@ impl Eq for Transaction {} impl Transaction { /// Returns recipient account of the transaction. pub fn recipient_account(&self) -> Address { - self.execute.contract_address + self.execute.contract_address.unwrap_or_default() } pub fn nonce(&self) -> Option { @@ -253,7 +253,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, @@ -284,7 +284,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, @@ -377,7 +377,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 c71e6e4206c5..057c905d1c66 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/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![], diff --git a/core/node/consensus/src/vm.rs b/core/node/consensus/src/vm.rs index 11b6b5c67e3b..c93cafc09f9c 100644 --- a/core/node/consensus/src/vm.rs +++ b/core/node/consensus/src/vm.rs @@ -56,7 +56,7 @@ impl VM { call: abi::Call, ) -> ctx::Result { let tx = L2Tx::new( - *address, + Some(*address), call.calldata().context("call.calldata()")?, Nonce(0), Fee { diff --git a/core/node/eth_watch/src/tests.rs b/core/node/eth_watch/src/tests.rs index 7ae3b5494e98..e6e343f50bca 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(), diff --git a/core/node/state_keeper/src/executor/tests/tester.rs b/core/node/state_keeper/src/executor/tests/tester.rs index 8256435f2f5b..d524d1a20dd7 100644 --- a/core/node/state_keeper/src/executor/tests/tester.rs +++ b/core/node/state_keeper/src/executor/tests/tester.rs @@ -396,7 +396,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, @@ -432,7 +432,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 23aec8af49fb..edcf3ccc4f5c 100644 --- a/core/node/state_keeper/src/testonly/mod.rs +++ b/core/node/state_keeper/src/testonly/mod.rs @@ -131,7 +131,7 @@ pub 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![], @@ -143,7 +143,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 acb65bf1634d..b9984b782111 100644 --- a/core/node/test_utils/src/lib.rs +++ b/core/node/test_utils/src/lib.rs @@ -138,7 +138,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 530016408140..928da3b93157 100644 --- a/core/node/vm_runner/src/tests/mod.rs +++ b/core/node/vm_runner/src/tests/mod.rs @@ -202,7 +202,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/tests/loadnext/src/sdk/operations/deploy_contract.rs b/core/tests/loadnext/src/sdk/operations/deploy_contract.rs index 161d156a53e9..67e877ae8efb 100644 --- a/core/tests/loadnext/src/sdk/operations/deploy_contract.rs +++ b/core/tests/loadnext/src/sdk/operations/deploy_contract.rs @@ -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..627e889ed012 100644 --- a/core/tests/loadnext/src/sdk/operations/execute_contract.rs +++ b/core/tests/loadnext/src/sdk/operations/execute_contract.rs @@ -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..6f98f674ed95 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, @@ -122,7 +122,7 @@ impl Signer { paymaster_params: PaymasterParams, ) -> Result { let mut execute_contract = L2Tx::new( - contract, + Some(contract), calldata, nonce, fee, diff --git a/core/tests/test_account/src/lib.rs b/core/tests/test_account/src/lib.rs index 28e3d609e63d..d0c97abab729 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/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), diff --git a/prover/crates/lib/keystore/src/utils.rs b/prover/crates/lib/keystore/src/utils.rs index d9bb3b47dbb0..10504292d64f 100644 --- a/prover/crates/lib/keystore/src/utils.rs +++ b/prover/crates/lib/keystore/src/utils.rs @@ -115,6 +115,7 @@ pub fn calculate_snark_vk_hash(keystore: &Keystore) -> anyhow::Result { #[cfg(test)] mod tests { use std::str::FromStr; + use zksync_utils::env::Workspace; use super::*; From 4e6bed2507f600223b4fdf3d47f82d93723bf43f Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 11 Sep 2024 16:47:42 -0300 Subject: [PATCH 02/45] Add migrations and update queries with evm simulator --- ...af26470206d43fedf44c1a348b13865dbc0f.json} | 12 +++++-- ...0bf5f89e96ab4e6c199fccd17d38eaec77a7.json} | 28 ++++++++++------- ...4a0fe2f0c3bf5f11aec8400c0b6e5b58c62a.json} | 12 +++++-- ...927c5f5b88725987e82cf3ec5d499c5addbb.json} | 16 +++++++--- ...e9afe0ead3d435d166a3116551502a730731.json} | 26 ++++++++++------ ...6d3bc76cabe8b0c616ed13dd139327c4cc34.json} | 26 ++++++++++------ ...3a6f0a2de9a615e50a94d98d18e47621c709.json} | 18 +++++++---- ...87dde392c0efa13ecd42becfd0e5db79f059.json} | 14 ++++++--- ...884ca664431997692e4af804ecf5ff8b819a.json} | 5 +-- ...dfa954eaf93e6ab5b64bdaa8ef9984ccdf6b.json} | 26 ++++++++++------ ...08525bf32965ca06e847082c0fc3c54a1dde.json} | 10 ++++-- ...b7ce70b4aaa5c810c79d5bf854fe30c28fd4.json} | 26 ++++++++++------ ...bbb0aa11d1c974d6ae7c99d83560bb37357e.json} | 18 +++++++---- ...0ff9894b1de204599f4a4fd39cfde1020a3e.json} | 26 ++++++++++------ ...00ff851252dd9da2df5ab7da51324f9258400.json | 31 +++++++++++++++++++ ...686d545c780b37430bdcf70fc55e80588b6b.json} | 30 +++++++++++------- ...ba3af74e8e7b5944cb2943b5badb906167046.json | 30 ------------------ ...a68e5e5cf16897de4b6e3211d5e1c07e9294.json} | 10 ++++-- ...412e502df24849331486c604fb0d36d99554.json} | 12 +++++-- ...1bc51d4f949f0941156021a4844ed8c959ca.json} | 26 ++++++++++------ ...85d2efa5902269f3b5ad17b0259c3526877f.json} | 5 +-- .../20240911161714_evm-simulator.down.sql | 3 ++ .../20240911161714_evm-simulator.up.sql | 3 ++ core/lib/dal/src/blocks_dal.rs | 20 ++++++++++++ core/lib/dal/src/blocks_web3_dal.rs | 4 ++- core/lib/dal/src/factory_deps_dal.rs | 14 +++++++++ core/lib/dal/src/models/storage_block.rs | 19 ++++++++++++ .../src/models/storage_protocol_version.rs | 12 +++++++ core/lib/dal/src/models/storage_sync.rs | 3 ++ .../lib/dal/src/models/storage_transaction.rs | 16 ++++++---- core/lib/dal/src/protocol_versions_dal.rs | 12 +++++-- .../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 + 34 files changed, 356 insertions(+), 160 deletions(-) rename core/lib/dal/.sqlx/{query-85576fdbb4bd6e3a6e43511c065a2e3eaf72dfe0fa96b335b76c9506cb1ebdcc.json => query-0631be0bcabdb1697510ecbe6019af26470206d43fedf44c1a348b13865dbc0f.json} (62%) 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-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-39a105cba1be0ec8f2b2b88d2f10c6286fcc824e84bb40a6e9f289c34b85fded.json => query-3a7b285d40bf7aaa8f6251f69a4e3a6f0a2de9a615e50a94d98d18e47621c709.json} (81%) 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-45e52d05a4483def84c141e3529bab30553732953e589cd237595227044f438d.json => query-922dde793d7846594feaf13d475bbbb0aa11d1c974d6ae7c99d83560bb37357e.json} (83%) rename core/lib/dal/.sqlx/{query-de255be5d2e5ef215428e9a886e7c9dc036873c60b8b916ce8c446e310447b66.json => query-92d3a7d8c32c4575d6a225f0440b0ff9894b1de204599f4a4fd39cfde1020a3e.json} (80%) create mode 100644 core/lib/dal/.sqlx/query-9ca8d7418721beb1e9ee4f801a600ff851252dd9da2df5ab7da51324f9258400.json rename core/lib/dal/.sqlx/{query-52bb6de515e1edf4dcf34a31600edb31cfd855014dfca5041833b9d5d9f7a55e.json => query-acf497b952de2d8f83cf2b96f2eb686d545c780b37430bdcf70fc55e80588b6b.json} (80%) delete mode 100644 core/lib/dal/.sqlx/query-c4835d40921af47bfb4f60102bbba3af74e8e7b5944cb2943b5badb906167046.json 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-25fb31277591dd7d5d783bd8777f1a855e76b37b6ed36ae612b551f9a6a55633.json => query-ff68458acd9c98120bf4a6814c1985d2efa5902269f3b5ad17b0259c3526877f.json} (52%) create mode 100644 core/lib/dal/migrations/20240911161714_evm-simulator.down.sql create mode 100644 core/lib/dal/migrations/20240911161714_evm-simulator.up.sql diff --git a/core/lib/dal/.sqlx/query-85576fdbb4bd6e3a6e43511c065a2e3eaf72dfe0fa96b335b76c9506cb1ebdcc.json b/core/lib/dal/.sqlx/query-0631be0bcabdb1697510ecbe6019af26470206d43fedf44c1a348b13865dbc0f.json similarity index 62% rename from core/lib/dal/.sqlx/query-85576fdbb4bd6e3a6e43511c065a2e3eaf72dfe0fa96b335b76c9506cb1ebdcc.json rename to core/lib/dal/.sqlx/query-0631be0bcabdb1697510ecbe6019af26470206d43fedf44c1a348b13865dbc0f.json index 3297d411d8a7..ec5b6c771ff0 100644 --- a/core/lib/dal/.sqlx/query-85576fdbb4bd6e3a6e43511c065a2e3eaf72dfe0fa96b335b76c9506cb1ebdcc.json +++ b/core/lib/dal/.sqlx/query-0631be0bcabdb1697510ecbe6019af26470206d43fedf44c1a348b13865dbc0f.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.snark_wrapper_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.snark_wrapper_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": "snark_wrapper_vk_hash", "type_info": "Bytea" } @@ -44,9 +49,10 @@ false, false, false, + true, false, false ] }, - "hash": "85576fdbb4bd6e3a6e43511c065a2e3eaf72dfe0fa96b335b76c9506cb1ebdcc" + "hash": "0631be0bcabdb1697510ecbe6019af26470206d43fedf44c1a348b13865dbc0f" } 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-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-39a105cba1be0ec8f2b2b88d2f10c6286fcc824e84bb40a6e9f289c34b85fded.json b/core/lib/dal/.sqlx/query-3a7b285d40bf7aaa8f6251f69a4e3a6f0a2de9a615e50a94d98d18e47621c709.json similarity index 81% rename from core/lib/dal/.sqlx/query-39a105cba1be0ec8f2b2b88d2f10c6286fcc824e84bb40a6e9f289c34b85fded.json rename to core/lib/dal/.sqlx/query-3a7b285d40bf7aaa8f6251f69a4e3a6f0a2de9a615e50a94d98d18e47621c709.json index 26a3458bff9b..16f258cf3047 100644 --- a/core/lib/dal/.sqlx/query-39a105cba1be0ec8f2b2b88d2f10c6286fcc824e84bb40a6e9f289c34b85fded.json +++ b/core/lib/dal/.sqlx/query-3a7b285d40bf7aaa8f6251f69a4e3a6f0a2de9a615e50a94d98d18e47621c709.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 logs_bloom\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 logs_bloom\n FROM\n miniblocks\n ORDER BY\n number DESC\n LIMIT\n 1\n ", "describe": { "columns": [ { @@ -65,26 +65,31 @@ }, { "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" }, { - "ordinal": 16, + "ordinal": 17, "name": "logs_bloom", "type_info": "Bytea" } @@ -106,11 +111,12 @@ true, true, true, + true, false, true, true, true ] }, - "hash": "39a105cba1be0ec8f2b2b88d2f10c6286fcc824e84bb40a6e9f289c34b85fded" + "hash": "3a7b285d40bf7aaa8f6251f69a4e3a6f0a2de9a615e50a94d98d18e47621c709" } 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-45e52d05a4483def84c141e3529bab30553732953e589cd237595227044f438d.json b/core/lib/dal/.sqlx/query-922dde793d7846594feaf13d475bbbb0aa11d1c974d6ae7c99d83560bb37357e.json similarity index 83% rename from core/lib/dal/.sqlx/query-45e52d05a4483def84c141e3529bab30553732953e589cd237595227044f438d.json rename to core/lib/dal/.sqlx/query-922dde793d7846594feaf13d475bbbb0aa11d1c974d6ae7c99d83560bb37357e.json index 74a6187e6444..287c69687e53 100644 --- a/core/lib/dal/.sqlx/query-45e52d05a4483def84c141e3529bab30553732953e589cd237595227044f438d.json +++ b/core/lib/dal/.sqlx/query-922dde793d7846594feaf13d475bbbb0aa11d1c974d6ae7c99d83560bb37357e.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 logs_bloom\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 logs_bloom\n FROM\n miniblocks\n WHERE\n number = $1\n ", "describe": { "columns": [ { @@ -65,26 +65,31 @@ }, { "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" }, { - "ordinal": 16, + "ordinal": 17, "name": "logs_bloom", "type_info": "Bytea" } @@ -108,11 +113,12 @@ true, true, true, + true, false, true, true, true ] }, - "hash": "45e52d05a4483def84c141e3529bab30553732953e589cd237595227044f438d" + "hash": "922dde793d7846594feaf13d475bbbb0aa11d1c974d6ae7c99d83560bb37357e" } 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-9ca8d7418721beb1e9ee4f801a600ff851252dd9da2df5ab7da51324f9258400.json b/core/lib/dal/.sqlx/query-9ca8d7418721beb1e9ee4f801a600ff851252dd9da2df5ab7da51324f9258400.json new file mode 100644 index 000000000000..52ef95716470 --- /dev/null +++ b/core/lib/dal/.sqlx/query-9ca8d7418721beb1e9ee4f801a600ff851252dd9da2df5ab7da51324f9258400.json @@ -0,0 +1,31 @@ +{ + "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 logs_bloom,\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 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", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "9ca8d7418721beb1e9ee4f801a600ff851252dd9da2df5ab7da51324f9258400" +} 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-c4835d40921af47bfb4f60102bbba3af74e8e7b5944cb2943b5badb906167046.json b/core/lib/dal/.sqlx/query-c4835d40921af47bfb4f60102bbba3af74e8e7b5944cb2943b5badb906167046.json deleted file mode 100644 index 9ae9d2e50cde..000000000000 --- a/core/lib/dal/.sqlx/query-c4835d40921af47bfb4f60102bbba3af74e8e7b5944cb2943b5badb906167046.json +++ /dev/null @@ -1,30 +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 logs_bloom,\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", - "Int4", - "Int8", - "Int8", - "Int8", - "Bytea" - ] - }, - "nullable": [] - }, - "hash": "c4835d40921af47bfb4f60102bbba3af74e8e7b5944cb2943b5badb906167046" -} 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-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/migrations/20240911161714_evm-simulator.down.sql b/core/lib/dal/migrations/20240911161714_evm-simulator.down.sql new file mode 100644 index 000000000000..999728809a5e --- /dev/null +++ b/core/lib/dal/migrations/20240911161714_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/20240911161714_evm-simulator.up.sql b/core/lib/dal/migrations/20240911161714_evm-simulator.up.sql new file mode 100644 index 000000000000..ea8e0a83d20c --- /dev/null +++ b/core/lib/dal/migrations/20240911161714_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 1f4cc3b0b98c..5d82dc18d48c 100644 --- a/core/lib/dal/src/blocks_dal.rs +++ b/core/lib/dal/src/blocks_dal.rs @@ -325,6 +325,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, @@ -366,6 +367,7 @@ impl BlocksDal<'_, '_> { used_contract_hashes, bootloader_code_hash, default_aa_code_hash, + evm_simulator_code_hash, protocol_version, system_logs, pubdata_input @@ -610,6 +612,7 @@ impl BlocksDal<'_, '_> { used_contract_hashes, bootloader_code_hash, default_aa_code_hash, + evm_simulator_code_hash, protocol_version, system_logs, storage_refunds, @@ -641,6 +644,7 @@ impl BlocksDal<'_, '_> { $18, $19, $20, + $21, NOW(), NOW() ) @@ -659,6 +663,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, @@ -703,6 +708,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, @@ -730,6 +736,7 @@ impl BlocksDal<'_, '_> { $15, $16, $17, + $18, NOW(), NOW() ) @@ -752,6 +759,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, @@ -780,6 +791,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, @@ -820,6 +832,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, @@ -1031,6 +1044,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, @@ -1211,6 +1225,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, @@ -1291,6 +1306,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, @@ -1364,6 +1380,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, @@ -1489,6 +1506,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, @@ -1553,6 +1571,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, @@ -1631,6 +1650,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 36a4acc0a6db..78c01dc1f6b0 100644 --- a/core/lib/dal/src/blocks_web3_dal.rs +++ b/core/lib/dal/src/blocks_web3_dal.rs @@ -663,6 +663,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 @@ -730,7 +731,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..6731b05166dc 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,22 @@ 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 34e14387ca61..a98049e8ac6d 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. @@ -82,6 +83,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 +105,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 +114,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 +140,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>, @@ -177,6 +184,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 @@ -240,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()), @@ -275,6 +288,7 @@ 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, } @@ -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,6 +367,7 @@ 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 { @@ -395,6 +411,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 +435,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, @@ -471,6 +489,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 e53bf7b9d0a4..a1a61bd0670f 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 snark_wrapper_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( @@ -34,6 +35,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, } @@ -45,6 +51,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>, } @@ -60,6 +67,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/models/storage_transaction.rs b/core/lib/dal/src/models/storage_transaction.rs index 9f67e9025e0c..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| { - serde_json::from_value::
(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. - .or_else(|| Some(Address::default())), + }), cumulative_gas_used: Default::default(), // TODO: Should be actually calculated (SMA-1183). gas_used: { let refunded_gas: U256 = storage_receipt.refunded_gas.into(); @@ -508,6 +506,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()) + }; + // For legacy and EIP-2930 transactions it is gas price willing to be paid by the sender in wei. // For other transactions it should be the effective gas price if transaction is included in block, // otherwise this value should be set equal to the max fee per gas. @@ -528,7 +532,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(gas_price)), gas: bigdecimal_to_u256(self.gas_limit.unwrap_or_else(BigDecimal::zero)), diff --git a/core/lib/dal/src/protocol_versions_dal.rs b/core/lib/dal/src/protocol_versions_dal.rs index 8cb5094fd49e..d01ae3a52ac8 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") @@ -193,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 @@ -212,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) @@ -232,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.snark_wrapper_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 ec6ee0f92812..22c72fc4d152 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 dc672fa1f807..dd725aeda3ee 100644 --- a/core/lib/dal/src/tests/mod.rs +++ b/core/lib/dal/src/tests/mod.rs @@ -61,6 +61,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(), ) From 723c5e3ab18cd294b3d92606bf410642f436685e Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 11 Sep 2024 16:49:44 -0300 Subject: [PATCH 03/45] Add evm simulator as base system contract and update callers --- core/bin/genesis_generator/src/main.rs | 1 + .../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/constants/src/contracts.rs | 5 + core/lib/contracts/Cargo.toml | 2 + core/lib/contracts/src/lib.rs | 18 ++ core/lib/env_config/src/chain.rs | 11 +- core/lib/env_config/src/genesis.rs | 1 + core/lib/multivm/Cargo.toml | 2 + .../src/glue/types/vm/vm_block_result.rs | 6 + .../types/vm/vm_partial_execution_result.rs | 3 + .../glue/types/vm/vm_tx_execution_result.rs | 5 + .../vm_1_4_1/implementation/execution.rs | 1 + .../vm_1_4_1/tests/get_used_contracts.rs | 14 +- .../vm_1_4_2/implementation/execution.rs | 1 + .../src/versions/vm_1_4_2/tests/circuits.rs | 2 +- .../vm_1_4_2/tests/get_used_contracts.rs | 18 +- .../implementation/execution.rs | 1 + .../tests/get_used_contracts.rs | 18 +- .../vm_fast/tests/get_used_contracts.rs | 17 +- .../versions/vm_fast/tests/l1_tx_execution.rs | 7 +- .../versions/vm_fast/tests/nonce_holder.rs | 11 +- .../src/versions/vm_fast/tests/rollbacks.rs | 46 ++- .../tests/tester/transaction_test_info.rs | 71 ++--- core/lib/multivm/src/versions/vm_fast/vm.rs | 24 +- .../vm_latest/implementation/execution.rs | 8 + .../vm_latest/old_vm/oracles/decommitter.rs | 76 +++-- .../src/versions/vm_latest/tests/circuits.rs | 2 +- .../vm_latest/tests/get_used_contracts.rs | 17 +- .../vm_latest/tests/l1_tx_execution.rs | 7 +- .../src/versions/vm_latest/tests/migration.rs | 51 ---- .../src/versions/vm_latest/tests/mod.rs | 1 - .../versions/vm_latest/tests/nonce_holder.rs | 11 +- .../src/versions/vm_latest/tests/rollbacks.rs | 47 +++- .../tests/tester/transaction_test_info.rs | 73 +++-- .../vm_latest/tracers/default_tracers.rs | 13 +- .../vm_latest/tracers/evm_deploy_tracer.rs | 106 +++++++ .../src/versions/vm_latest/tracers/mod.rs | 2 + .../types/internals/transaction_data.rs | 8 +- .../vm_latest/types/internals/vm_state.rs | 16 +- .../src/versions/vm_latest/utils/mod.rs | 52 ++++ core/lib/multivm/src/versions/vm_latest/vm.rs | 20 +- .../implementation/execution.rs | 1 + .../tests/get_used_contracts.rs | 16 +- .../implementation/execution.rs | 1 + .../tests/get_used_contracts.rs | 18 +- core/lib/protobuf_config/src/chain.rs | 1 + core/lib/protobuf_config/src/genesis.rs | 6 + .../src/proto/config/genesis.proto | 1 + core/lib/prover_interface/src/inputs.rs | 1 + core/lib/tee_verifier/src/lib.rs | 4 + core/lib/types/src/abi.rs | 9 +- core/lib/types/src/api/mod.rs | 16 +- core/lib/types/src/commitment/mod.rs | 13 +- .../tests/post_boojum_1_4_1_test.json | 6 +- .../tests/post_boojum_1_4_2_test.json | 6 +- .../tests/post_boojum_1_5_0_test.json | 6 +- .../src/commitment/tests/pre_boojum_test.json | 6 +- core/lib/types/src/protocol_upgrade.rs | 8 + core/lib/types/src/storage/mod.rs | 11 +- core/lib/types/src/system_contracts.rs | 26 +- core/lib/vm_executor/src/oneshot/mock.rs | 1 + core/lib/vm_executor/src/storage.rs | 6 +- core/lib/vm_interface/Cargo.toml | 1 + .../lib/vm_interface/src/storage/in_memory.rs | 12 +- .../src/types/outputs/execution_result.rs | 1 + .../src/types/outputs/finished_l1batch.rs | 1 + .../node/api_server/src/web3/namespaces/en.rs | 6 + core/node/api_server/src/web3/tests/vm.rs | 1 + core/node/commitment_generator/src/lib.rs | 1 + core/node/eth_sender/src/eth_tx_aggregator.rs | 27 +- core/node/eth_sender/src/tests.rs | 6 +- core/node/eth_sender/src/zksync_functions.rs | 4 + core/node/eth_watch/src/tests.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/node_sync/src/tests.rs | 8 + core/node/proof_data_handler/src/tests.rs | 4 + core/node/state_keeper/src/executor/mod.rs | 2 +- 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 | 9 +- .../state_keeper/src/seal_criteria/mod.rs | 1 + core/node/state_keeper/src/testonly/mod.rs | 1 + .../src/testonly/test_batch_executor.rs | 2 + core/node/state_keeper/src/tests/mod.rs | 1 + .../src/updates/l1_batch_updates.rs | 1 + .../src/updates/l2_block_updates.rs | 40 +-- core/node/state_keeper/src/updates/mod.rs | 6 +- core/node/test_utils/src/lib.rs | 14 +- core/node/vm_runner/src/impls/bwip.rs | 17 ++ core/node/vm_runner/src/tests/mod.rs | 4 + .../vm_runner/src/tests/output_handler.rs | 4 + etc/env/base/chain.toml | 5 +- etc/env/base/contracts.toml | 6 +- etc/env/file_based/genesis.yaml | 5 +- .../src/l2upgrade/deployer.ts | 4 + prover/Cargo.lock | 266 ++++++++++++++++++ .../witness_generator/src/basic_circuits.rs | 3 +- .../forge_interface/deploy_ecosystem/input.rs | 2 + 104 files changed, 1149 insertions(+), 343 deletions(-) delete mode 100644 core/lib/multivm/src/versions/vm_latest/tests/migration.rs create mode 100644 core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs 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/bin/system-constants-generator/src/utils.rs b/core/bin/system-constants-generator/src/utils.rs index 664ae0ebdb16..989b235de61c 100644 --- a/core/bin/system-constants-generator/src/utils.rs +++ b/core/bin/system-constants-generator/src/utils.rs @@ -71,12 +71,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, + }, } }); @@ -219,9 +226,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 7e33f6964bb7..e24865fabbbd 100644 --- a/core/lib/config/src/configs/chain.rs +++ b/core/lib/config/src/configs/chain.rs @@ -138,6 +138,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, @@ -178,6 +180,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 6c4bacc3a6e2..3a962b18410d 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, @@ -49,6 +50,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 bc3b6025b15a..f6e6fcafdb5e 100644 --- a/core/lib/config/src/testonly.rs +++ b/core/lib/config/src/testonly.rs @@ -185,6 +185,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(), } } @@ -724,6 +725,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/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/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 f57649c9d695..5ab977a5dfd5 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -193,6 +193,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") } @@ -303,18 +307,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 } } @@ -335,9 +342,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. @@ -474,6 +491,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/env_config/src/chain.rs b/core/lib/env_config/src/chain.rs index a25c593bd881..ca2c51803ba2 100644 --- a/core/lib/env_config/src/chain.rs +++ b/core/lib/env_config/src/chain.rs @@ -97,10 +97,13 @@ mod tests { validation_computational_gas_limit: 10_000_000, save_call_traces: false, bootloader_hash: Some(hash( - "0x010007ede999d096c84553fb514d3d6ca76fbf39789dda76bfeda9f3ae06236e", + "0x010008bbde6fc402ea3a3d6cb15cb97e70245d3d4e48fb74362d4961b74c16b1", )), default_aa_hash: Some(hash( - "0x0100055b041eb28aff6e3a6e0f37c31fd053fc9ef142683b05e5f0aee6934066", + "0x0100058d9eee51f4b9e9a9ecb7fd7e8301e90bef018c2bd913ed36e583fec8c2", + )), + evm_simulator_hash: Some(hash( + "0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91", )), l1_batch_commit_data_generator_mode, max_circuits_per_batch: 24100, @@ -135,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=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/core/lib/env_config/src/genesis.rs b/core/lib/env_config/src/genesis.rs index bf30fd4cc339..6d1927828641 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/multivm/Cargo.toml b/core/lib/multivm/Cargo.toml index 4711eefa0d6c..28495da33021 100644 --- a/core/lib/multivm/Cargo.toml +++ b/core/lib/multivm/Cargo.toml @@ -29,6 +29,7 @@ zksync_contracts.workspace = true zksync_utils.workspace = true zksync_system_constants.workspace = true zksync_vm_interface.workspace = true +zksync_state.workspace = true anyhow.workspace = true hex.workspace = true @@ -38,6 +39,7 @@ pretty_assertions.workspace = true thiserror.workspace = true tracing.workspace = true vise.workspace = true +ethabi.workspace = true [dev-dependencies] assert_matches.workspace = true diff --git a/core/lib/multivm/src/glue/types/vm/vm_block_result.rs b/core/lib/multivm/src/glue/types/vm/vm_block_result.rs index ce928e652d76..6ef9b2947746 100644 --- a/core/lib/multivm/src/glue/types/vm/vm_block_result.rs +++ b/core/lib/multivm/src/glue/types/vm/vm_block_result.rs @@ -47,6 +47,7 @@ impl GlueFrom for crate::interface::Fi circuit_statistic: Default::default(), }, refunds: Refunds::default(), + new_known_factory_deps: Default::default(), }, final_execution_state: CurrentExecutionState { events: value.full_result.events, @@ -103,6 +104,7 @@ impl GlueFrom for crate::interface::Fi circuit_statistic: Default::default(), }, refunds: Refunds::default(), + new_known_factory_deps: Default::default(), }, final_execution_state: CurrentExecutionState { events: value.full_result.events, @@ -158,6 +160,7 @@ impl GlueFrom for crate::interface: circuit_statistic: Default::default(), }, refunds: Refunds::default(), + new_known_factory_deps: Default::default(), }, final_execution_state: CurrentExecutionState { events: value.full_result.events, @@ -227,6 +230,7 @@ impl GlueFrom circuit_statistic: Default::default(), }, refunds: Refunds::default(), + new_known_factory_deps: Default::default(), } } } @@ -259,6 +263,7 @@ impl GlueFrom circuit_statistic: Default::default(), }, refunds: Refunds::default(), + new_known_factory_deps: Default::default(), } } } @@ -307,6 +312,7 @@ impl GlueFrom circuit_statistic: Default::default(), }, refunds: Refunds::default(), + new_known_factory_deps: Default::default(), } } } diff --git a/core/lib/multivm/src/glue/types/vm/vm_partial_execution_result.rs b/core/lib/multivm/src/glue/types/vm/vm_partial_execution_result.rs index 3cb61b461a42..1891330b6d29 100644 --- a/core/lib/multivm/src/glue/types/vm/vm_partial_execution_result.rs +++ b/core/lib/multivm/src/glue/types/vm/vm_partial_execution_result.rs @@ -22,6 +22,7 @@ impl GlueFrom gas_refunded: 0, operator_suggested_refund: 0, }, + new_known_factory_deps: Default::default(), } } } @@ -48,6 +49,7 @@ impl GlueFrom gas_refunded: 0, operator_suggested_refund: 0, }, + new_known_factory_deps: Default::default(), } } } @@ -74,6 +76,7 @@ impl GlueFrom gas_refunded: 0, operator_suggested_refund: 0, }, + new_known_factory_deps: Default::default(), } } } diff --git a/core/lib/multivm/src/glue/types/vm/vm_tx_execution_result.rs b/core/lib/multivm/src/glue/types/vm/vm_tx_execution_result.rs index 2dc680ba77d9..2ea1e3984c47 100644 --- a/core/lib/multivm/src/glue/types/vm/vm_tx_execution_result.rs +++ b/core/lib/multivm/src/glue/types/vm/vm_tx_execution_result.rs @@ -66,12 +66,14 @@ impl GlueFrom VmExecutionResultAndLogs { result: ExecutionResult::Halt { reason: halt }, logs: Default::default(), statistics: Default::default(), refunds: Default::default(), + new_known_factory_deps: Default::default(), }, } } @@ -100,12 +102,14 @@ impl logs: Default::default(), statistics: Default::default(), refunds: Default::default(), + new_known_factory_deps: Default::default(), }, TxRevertReason::Halt(halt) => VmExecutionResultAndLogs { result: ExecutionResult::Halt { reason: halt }, logs: Default::default(), statistics: Default::default(), refunds: Default::default(), + new_known_factory_deps: Default::default(), }, } } @@ -129,6 +133,7 @@ impl GlueFrom { unreachable!("Halt is the only revert reason for VM 5") diff --git a/core/lib/multivm/src/versions/vm_1_4_1/implementation/execution.rs b/core/lib/multivm/src/versions/vm_1_4_1/implementation/execution.rs index db5aaa783df5..61b99cb676ed 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/implementation/execution.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/implementation/execution.rs @@ -96,6 +96,7 @@ impl Vm { logs, statistics, refunds, + new_known_factory_deps: Default::default(), }; (stop_reason, result) 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..b6b22c866a3f 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,26 @@ 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 } diff --git a/core/lib/multivm/src/versions/vm_1_4_2/implementation/execution.rs b/core/lib/multivm/src/versions/vm_1_4_2/implementation/execution.rs index d42d18809331..f49eb10e26bc 100644 --- a/core/lib/multivm/src/versions/vm_1_4_2/implementation/execution.rs +++ b/core/lib/multivm/src/versions/vm_1_4_2/implementation/execution.rs @@ -96,6 +96,7 @@ impl Vm { logs, statistics, refunds, + new_known_factory_deps: Default::default(), }; (stop_reason, result) 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_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..2054bf6a0fc6 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/implementation/execution.rs b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/execution.rs index a7c790a4bc30..73f122c701dc 100644 --- a/core/lib/multivm/src/versions/vm_boojum_integration/implementation/execution.rs +++ b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/execution.rs @@ -90,6 +90,7 @@ impl Vm { logs, statistics, refunds, + new_known_factory_deps: Default::default(), }; (stop_reason, result) 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 746e9be923f2..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 @@ -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_fast/tests/l1_tx_execution.rs b/core/lib/multivm/src/versions/vm_fast/tests/l1_tx_execution.rs index ea3613b0fe79..2079629fadc9 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 2ae43869d7f6..3db779601383 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..446de84b19cb 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,22 @@ 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(), + ), ), 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 105bc5f2fd43..359ba38d07a5 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 @@ -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_fast/vm.rs b/core/lib/multivm/src/versions/vm_fast/vm.rs index d8816cfaf2a6..0cc6f1baa688 100644 --- a/core/lib/multivm/src/versions/vm_fast/vm.rs +++ b/core/lib/multivm/src/versions/vm_fast/vm.rs @@ -393,10 +393,22 @@ impl Vm { .hash .into(); - let program_cache = HashMap::from([World::convert_system_contract_code( - &system_env.base_system_smart_contracts.default_aa, - false, - )]); + let evm_simulator_code_hash = system_env + .base_system_smart_contracts + .evm_simulator + .hash + .into(); + + let program_cache = HashMap::from([ + World::convert_system_contract_code( + &system_env.base_system_smart_contracts.default_aa, + false, + ), + World::convert_system_contract_code( + &system_env.base_system_smart_contracts.evm_simulator, + false, + ), + ]); let (_, bootloader) = World::convert_system_contract_code( &system_env.base_system_smart_contracts.bootloader, @@ -412,8 +424,7 @@ impl Vm { system_env.bootloader_gas_limit, 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, }, ); @@ -577,6 +588,7 @@ impl VmInterface for Vm { circuit_statistic, }, refunds, + new_known_factory_deps: Default::default(), } } diff --git a/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs b/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs index 66fc1a8bfd71..8242041b98fb 100644 --- a/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs +++ b/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs @@ -12,6 +12,7 @@ use crate::{ circuits_capacity::circuit_statistic_from_cycles, dispatcher::TracerDispatcher, DefaultExecutionTracer, PubdataTracer, RefundsTracer, }, + utils::extract_bytecodes_marked_as_known, vm::Vm, }, HistoryMode, @@ -93,12 +94,19 @@ impl Vm { circuit_statistic_from_cycles(tx_tracer.circuits_tracer.statistics), ); let result = tx_tracer.result_tracer.into_result(); + let factory_deps_marked_as_known = extract_bytecodes_marked_as_known(&logs.events); + let preimages = self.ask_decommitter(factory_deps_marked_as_known.clone()); + let new_known_factory_deps = factory_deps_marked_as_known + .into_iter() + .zip(preimages) + .collect(); let result = VmExecutionResultAndLogs { result, logs, statistics, refunds, + new_known_factory_deps: Some(new_known_factory_deps), }; (stop_reason, result) 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 0315aa38327d..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 @@ -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}; @@ -166,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 @@ -178,10 +176,10 @@ 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() @@ -190,7 +188,9 @@ impl DecommittmentProcess { 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; Ok(partial_query) } @@ -204,11 +204,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; @@ -251,28 +250,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]; + hash[0..4].copy_from_slice(&header.0); + 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/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 = [ 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 ef19717a627c..10f4bff22635 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 @@ -41,7 +41,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 @@ -63,7 +63,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::>() @@ -99,7 +99,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)); @@ -147,19 +147,22 @@ 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_latest/tests/l1_tx_execution.rs b/core/lib/multivm/src/versions/vm_latest/tests/l1_tx_execution.rs index 0fc12848227e..b424567aab02 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/migration.rs b/core/lib/multivm/src/versions/vm_latest/tests/migration.rs deleted file mode 100644 index 5b8da2551808..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, VmInterfaceExt}, - 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; 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 91d78c69a931..86d03970f5c3 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 52e4d24bc0b4..6b665fa555e0 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 08667ccc625f..f07d1602d300 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::{ @@ -14,8 +14,8 @@ pub(crate) enum TxModifier { WrongSignatureLength, WrongSignature, WrongMagicValue, - WrongNonce, - NonceReused, + WrongNonce(Nonce, Nonce), + NonceReused(H160, Nonce), } #[derive(Debug, Clone)] @@ -40,14 +40,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 ], }) } @@ -58,38 +55,34 @@ 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, }) } }; @@ -115,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 } } 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 6a908c2a73ed..f7def2a66106 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::PubdataTracer; +use super::{EvmDeployTracer, PubdataTracer}; use crate::{ glue::GlueInto, interface::{ @@ -38,7 +38,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, @@ -63,6 +63,8 @@ pub(crate) 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, + // This tracer is responsible for handling EVM deployments and providing the data to the code decommitter. + pub(crate) evm_deploy_tracer: EvmDeployTracer, subversion: MultiVMSubversion, storage: StoragePtr, _phantom: PhantomData, @@ -92,6 +94,7 @@ impl DefaultExecutionTracer { pubdata_tracer, ret_from_the_bootloader: None, circuits_tracer: CircuitsTracer::new(), + evm_deploy_tracer: EvmDeployTracer::new(), storage, _phantom: PhantomData, } @@ -172,6 +175,7 @@ macro_rules! dispatch_tracers { tracer.$function($( $params ),*); } $self.circuits_tracer.$function($( $params ),*); + $self.evm_deploy_tracer.$function($( $params ),*); }; } @@ -289,6 +293,11 @@ impl DefaultExecutionTracer { .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_deploy_tracer.rs b/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs new file mode 100644 index 000000000000..7cd32cea96fa --- /dev/null +++ b/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs @@ -0,0 +1,106 @@ +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_codes_contract; +use zksync_state::interface::WriteStorage; +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}; +use crate::{ + 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 +/// 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_codes_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..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,11 +1,13 @@ pub(crate) use circuits_tracer::CircuitsTracer; pub(crate) use default_tracers::DefaultExecutionTracer; +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) mod circuits_tracer; pub(crate) mod default_tracers; +pub(crate) mod evm_deploy_tracer; pub(crate) mod pubdata_tracer; pub(crate) mod refunds; pub(crate) mod result_tracer; 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 2ec86eb3ceaf..0a5ebb37360e 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 @@ -62,6 +62,12 @@ impl From for TransactionData { U256::zero() }; + let should_deploy_contract = if execute_tx.execute.contract_address.is_none() { + 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 +91,7 @@ impl From for TransactionData { value: execute_tx.execute.value, reserved: [ should_check_chain_id, - U256::zero(), + should_deploy_contract, U256::zero(), U256::zero(), ], 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 6f9522572ad8..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 @@ -98,6 +98,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, @@ -128,10 +140,8 @@ 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.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..742434b68970 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,58 @@ /// Utility functions for the VM. +use ethabi; +use once_cell::sync::Lazy; +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, KNOWN_CODES_STORAGE_ADDRESS}; +use zksync_vm_interface::VmEvent; + pub mod fee; pub mod l2_blocks; 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) +} + +/// Extracts all bytecodes marked as known on the system contracts. +pub fn extract_bytecodes_marked_as_known(all_generated_events: &[VmEvent]) -> Vec { + static PUBLISHED_BYTECODE_SIGNATURE: Lazy = Lazy::new(|| { + ethabi::long_signature( + "MarkedAsKnown", + &[ethabi::ParamType::FixedBytes(32), ethabi::ParamType::Bool], + ) + }); + + all_generated_events + .iter() + .filter(|event| { + // Filter events from the deployer contract that match the expected signature. + event.address == KNOWN_CODES_STORAGE_ADDRESS + && event.indexed_topics.len() == 3 + && event.indexed_topics[0] == *PUBLISHED_BYTECODE_SIGNATURE + }) + .map(|event| event.indexed_topics[1]) + .collect() +} diff --git a/core/lib/multivm/src/versions/vm_latest/vm.rs b/core/lib/multivm/src/versions/vm_latest/vm.rs index a445a1d51402..d3e8964bcd32 100644 --- a/core/lib/multivm/src/versions/vm_latest/vm.rs +++ b/core/lib/multivm/src/versions/vm_latest/vm.rs @@ -2,8 +2,9 @@ use circuit_sequencer_api_1_5_0::sort_storage_access::sort_storage_access_querie use zksync_types::{ l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log}, vm::VmVersion, - Transaction, + Transaction, H256, }; +use zksync_utils::{be_words_to_bytes, h256_to_u256}; use crate::{ glue::GlueInto, @@ -78,6 +79,23 @@ impl Vm { self.state.local_state.callstack.current.ergs_remaining } + pub(crate) fn ask_decommitter(&self, hashes: Vec) -> Vec> { + let mut result = vec![]; + for hash in hashes { + let bytecode = self + .state + .decommittment_processor + .known_bytecodes + .inner() + .get(&h256_to_u256(hash)) + .expect("Bytecode not found") + .clone(); + result.push(be_words_to_bytes(&bytecode)); + } + + result + } + // visible for testing pub(super) fn get_current_execution_state(&self) -> CurrentExecutionState { let (raw_events, l1_messages) = self.state.event_sink.flatten(); diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/execution.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/execution.rs index cadd183735e6..bb43dc3ffb61 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/execution.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/execution.rs @@ -87,6 +87,7 @@ impl Vm { logs, statistics, refunds, + new_known_factory_deps: Default::default(), }; (stop_reason, result) 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..8f8678167667 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,26 @@ 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 - .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)) .unwrap(); - known_bytecodes_without_aa_code + known_bytecodes_without_base_system_contracts } diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/execution.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/execution.rs index 42709c345ea6..8ad917353863 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/execution.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/execution.rs @@ -86,6 +86,7 @@ impl Vm { .refund_tracer .map(|r| r.get_refunds()) .unwrap_or_default(), + new_known_factory_deps: Default::default(), }; tx_tracer.dispatcher.save_results(&mut result); 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 } diff --git a/core/lib/protobuf_config/src/chain.rs b/core/lib/protobuf_config/src/chain.rs index f91bf07e43f8..169d09a2caa3 100644 --- a/core/lib/protobuf_config/src/chain.rs +++ b/core/lib/protobuf_config/src/chain.rs @@ -86,6 +86,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 59896aa244d8..42215cda9533 100644 --- a/core/lib/protobuf_config/src/genesis.rs +++ b/core/lib/protobuf_config/src/genesis.rs @@ -75,6 +75,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")?, @@ -105,6 +110,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 08cbb954fcbc..5e955bf4f00d 100644 --- a/core/lib/protobuf_config/src/proto/config/genesis.proto +++ b/core/lib/protobuf_config/src/proto/config/genesis.proto @@ -28,5 +28,6 @@ message Genesis { optional Prover prover = 10; optional L1BatchCommitDataGeneratorMode l1_batch_commit_data_generator_mode = 29; // optional, default to rollup optional string genesis_protocol_semantic_version = 12; // optional; + optional string evm_simulator_hash = 13; // required; h256 reserved 11; reserved "shared_bridge"; } 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/lib/tee_verifier/src/lib.rs b/core/lib/tee_verifier/src/lib.rs index 8728a4e52749..7da20637a6c1 100644 --- a/core/lib/tee_verifier/src/lib.rs +++ b/core/lib/tee_verifier/src/lib.rs @@ -305,6 +305,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/abi.rs b/core/lib/types/src/abi.rs index 84f8aba64869..c1c0efa66e4c 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, @@ -257,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 @@ -278,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()), @@ -291,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 { @@ -314,6 +317,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 916fae6a35bc..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 @@ -647,6 +647,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, @@ -662,6 +665,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 { @@ -672,9 +676,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, } @@ -690,6 +696,13 @@ impl ProtocolVersion { .or_else(|| self.base_system_contracts.map(|hashes| hashes.default_aa)) } + pub fn 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) } @@ -847,6 +860,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/commitment/mod.rs b/core/lib/types/src/commitment/mod.rs index 63d1bad486f3..944c0705f4f8 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, } @@ -478,14 +479,7 @@ impl L1BatchMetaParameters { result.extend(self.bootloader_code_hash.as_bytes()); 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.default_aa_code_hash.as_bytes()); - } - + result.extend(self.evm_simulator_code_hash.as_bytes()); result } @@ -551,6 +545,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 +648,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 +689,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/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/lib/types/src/protocol_upgrade.rs b/core/lib/types/src/protocol_upgrade.rs index 1afb108a0536..3766bda51ef3 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/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 a28c45b8feae..57ca0150f7f4 100644 --- a/core/lib/types/src/system_contracts.rs +++ b/core/lib/types/src/system_contracts.rs @@ -1,12 +1,14 @@ use std::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, P256VERIFY_PRECOMPILE_ADDRESS, PUBDATA_CHUNK_PUBLISHER_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, @@ -25,7 +27,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 +149,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), @@ -170,6 +178,18 @@ static SYSTEM_CONTRACT_LIST: [(&str, &str, Address, ContractLanguage); 25] = [ ), ]; +static EVM_SIMULATOR_HASH: Lazy = Lazy::new(|| { + hash_bytecode(&read_sys_contract_bytecode( + "", + "EvmInterpreter", + ContractLanguage::Yul, + )) +}); + +pub fn get_evm_simulator_hash() -> H256 { + *EVM_SIMULATOR_HASH +} + static SYSTEM_CONTRACTS: Lazy> = Lazy::new(|| { SYSTEM_CONTRACT_LIST .iter() diff --git a/core/lib/vm_executor/src/oneshot/mock.rs b/core/lib/vm_executor/src/oneshot/mock.rs index 8f3a12603c1a..8408206ede4c 100644 --- a/core/lib/vm_executor/src/oneshot/mock.rs +++ b/core/lib/vm_executor/src/oneshot/mock.rs @@ -68,6 +68,7 @@ impl MockOneshotExecutor { logs: Default::default(), statistics: Default::default(), refunds: Default::default(), + new_known_factory_deps: Default::default(), } }, ) diff --git a/core/lib/vm_executor/src/storage.rs b/core/lib/vm_executor/src/storage.rs index e39748786a30..e9b425c67cde 100644 --- a/core/lib/vm_executor/src/storage.rs +++ b/core/lib/vm_executor/src/storage.rs @@ -301,7 +301,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/lib/vm_interface/Cargo.toml b/core/lib/vm_interface/Cargo.toml index 694576dca3b0..a605a8a055dc 100644 --- a/core/lib/vm_interface/Cargo.toml +++ b/core/lib/vm_interface/Cargo.toml @@ -14,6 +14,7 @@ categories.workspace = true zksync_contracts.workspace = true zksync_system_constants.workspace = true zksync_types.workspace = true +zksync_utils.workspace = true anyhow.workspace = true async-trait.workspace = true diff --git a/core/lib/vm_interface/src/storage/in_memory.rs b/core/lib/vm_interface/src/storage/in_memory.rs index 6a8b56433455..27dd9c239444 100644 --- a/core/lib/vm_interface/src/storage/in_memory.rs +++ b/core/lib/vm_interface/src/storage/in_memory.rs @@ -1,10 +1,12 @@ 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, + 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, }; +use zksync_utils::u256_to_h256; use super::ReadStorage; @@ -62,6 +64,10 @@ impl InMemoryStorage { ] }) .chain(system_context_init_log) + .chain(vec![StorageLog::new_write_log( + get_deployer_key(u256_to_h256(1.into())), + get_evm_simulator_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/vm_interface/src/types/outputs/execution_result.rs b/core/lib/vm_interface/src/types/outputs/execution_result.rs index 6f9c02f0b587..3ca91c161525 100644 --- a/core/lib/vm_interface/src/types/outputs/execution_result.rs +++ b/core/lib/vm_interface/src/types/outputs/execution_result.rs @@ -118,6 +118,7 @@ pub struct VmExecutionResultAndLogs { pub logs: VmExecutionLogs, pub statistics: VmExecutionStatistics, pub refunds: Refunds, + pub new_known_factory_deps: Option)>>, } #[derive(Debug, Clone, PartialEq)] diff --git a/core/lib/vm_interface/src/types/outputs/finished_l1batch.rs b/core/lib/vm_interface/src/types/outputs/finished_l1batch.rs index 27241c2c0fae..a71c9f8f7a5e 100644 --- a/core/lib/vm_interface/src/types/outputs/finished_l1batch.rs +++ b/core/lib/vm_interface/src/types/outputs/finished_l1batch.rs @@ -26,6 +26,7 @@ impl FinishedL1Batch { logs: VmExecutionLogs::default(), statistics: VmExecutionStatistics::default(), refunds: Refunds::default(), + new_known_factory_deps: Default::default(), }, final_execution_state: CurrentExecutionState { events: vec![], diff --git a/core/node/api_server/src/web3/namespaces/en.rs b/core/node/api_server/src/web3/namespaces/en.rs index 26f4aa2b0b5f..c32ba3685f21 100644 --- a/core/node/api_server/src/web3/namespaces/en.rs +++ b/core/node/api_server/src/web3/namespaces/en.rs @@ -171,6 +171,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/api_server/src/web3/tests/vm.rs b/core/node/api_server/src/web3/tests/vm.rs index d8d1a2c7768e..e6dee2c43104 100644 --- a/core/node/api_server/src/web3/tests/vm.rs +++ b/core/node/api_server/src/web3/tests/vm.rs @@ -337,6 +337,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/commitment_generator/src/lib.rs b/core/node/commitment_generator/src/lib.rs index 6cb14cfda531..f9235531b813 100644 --- a/core/node/commitment_generator/src/lib.rs +++ b/core/node/commitment_generator/src/lib.rs @@ -176,6 +176,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 6e9e71d74ea4..f07cecb0dfa4 100644 --- a/core/node/eth_sender/src/eth_tx_aggregator.rs +++ b/core/node/eth_sender/src/eth_tx_aggregator.rs @@ -183,6 +183,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 @@ -219,6 +230,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(), @@ -239,7 +251,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(); @@ -268,9 +280,22 @@ 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_sender/src/tests.rs b/core/node/eth_sender/src/tests.rs index e03532458f18..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( @@ -74,6 +75,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..577c18277da0 100644 --- a/core/node/eth_sender/src/zksync_functions.rs +++ b/core/node/eth_sender/src/zksync_functions.rs @@ -12,6 +12,7 @@ pub(super) struct ZkSyncFunctions { pub(super) get_l2_bootloader_bytecode_hash: Function, pub(super) get_l2_default_account_bytecode_hash: Function, pub(super) get_verifier: Function, + pub(super) get_evm_simulator_bytecode_hash: 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/eth_watch/src/tests.rs b/core/node/eth_watch/src/tests.rs index e6e343f50bca..899690d6dabe 100644 --- a/core/node/eth_watch/src/tests.rs +++ b/core/node/eth_watch/src/tests.rs @@ -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/genesis/src/lib.rs b/core/node/genesis/src/lib.rs index 1f30d314bb06..65c795843bfb 100644 --- a/core/node/genesis/src/lib.rs +++ b/core/node/genesis/src/lib.rs @@ -104,6 +104,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(), @@ -235,6 +239,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 b7b8930c4957..c9875744e240 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 + .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/node_sync/src/tests.rs b/core/node/node_sync/src/tests.rs index d9a98c2bce36..a9eb2172e63e 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()); @@ -345,6 +346,13 @@ async fn external_io_works_without_local_protocol_version(snapshot_recovery: boo 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() .get_l2_block_header(snapshot.l2_block_number + 1) diff --git a/core/node/proof_data_handler/src/tests.rs b/core/node/proof_data_handler/src/tests.rs index 6ab7e4dec436..19c1b92f86bc 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/executor/mod.rs b/core/node/state_keeper/src/executor/mod.rs index 2fa5c3b9c128..903dae2f1cad 100644 --- a/core/node/state_keeper/src/executor/mod.rs +++ b/core/node/state_keeper/src/executor/mod.rs @@ -40,7 +40,7 @@ impl TxExecutionResult { _ => Self::Success { tx_metrics: Box::new(ExecutionMetricsForCriteria::new(Some(tx), &res.tx_result)), gas_remaining: res.tx_result.statistics.gas_remaining, - tx_result: res.tx_result, + tx_result: res.tx_result.clone(), compressed_bytecodes: res.compressed_bytecodes, call_tracer_result: res.call_traces, }, diff --git a/core/node/state_keeper/src/io/persistence.rs b/core/node/state_keeper/src/io/persistence.rs index 24b1ffca631c..d520fc8c88b6 100644 --- a/core/node/state_keeper/src/io/persistence.rs +++ b/core/node/state_keeper/src/io/persistence.rs @@ -462,6 +462,7 @@ mod tests { tx, tx_result, vec![], + vec![], BlockGasCount::default(), VmExecutionMetrics::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 7ea01e6af1e8..ef37f3cda75a 100644 --- a/core/node/state_keeper/src/io/tests/mod.rs +++ b/core/node/state_keeper/src/io/tests/mod.rs @@ -250,6 +250,7 @@ async fn processing_storage_logs_when_sealing_l2_block() { VmExecutionMetrics::default(), vec![], vec![], + vec![], ); let tx = create_transaction(10, 100); @@ -268,6 +269,7 @@ async fn processing_storage_logs_when_sealing_l2_block() { VmExecutionMetrics::default(), vec![], vec![], + vec![], ); let l1_batch_number = L1BatchNumber(2); @@ -357,6 +359,7 @@ async fn processing_events_when_sealing_l2_block() { VmExecutionMetrics::default(), vec![], vec![], + vec![], ); } @@ -457,6 +460,7 @@ async fn l2_block_processing_after_snapshot_recovery(commitment_mode: L1BatchCom tx.into(), create_execution_result([]), vec![], + vec![], BlockGasCount::default(), VmExecutionMetrics::default(), vec![], diff --git a/core/node/state_keeper/src/keeper.rs b/core/node/state_keeper/src/keeper.rs index d36ceec7d70c..22f24573070b 100644 --- a/core/node/state_keeper/src/keeper.rs +++ b/core/node/state_keeper/src/keeper.rs @@ -498,8 +498,9 @@ impl ZkSyncStateKeeper { updates_manager.extend_from_executed_transaction( tx, - *tx_result, + *tx_result.clone(), compressed_bytecodes, + tx_result.new_known_factory_deps.unwrap_or_default(), tx_l1_gas_this_tx, tx_execution_metrics, call_tracer_result, @@ -624,8 +625,9 @@ impl ZkSyncStateKeeper { } = *tx_metrics; updates_manager.extend_from_executed_transaction( tx, - *tx_result, + *tx_result.clone(), compressed_bytecodes, + tx_result.new_known_factory_deps.unwrap_or_default(), tx_l1_gas_this_tx, tx_execution_metrics, call_tracer_result, @@ -704,8 +706,9 @@ impl ZkSyncStateKeeper { } = *tx_metrics; updates_manager.extend_from_executed_transaction( tx, - *tx_result, + *tx_result.clone(), compressed_bytecodes, + tx_result.new_known_factory_deps.unwrap_or_default(), 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 e3fe849e8025..4919684a70d5 100644 --- a/core/node/state_keeper/src/seal_criteria/mod.rs +++ b/core/node/state_keeper/src/seal_criteria/mod.rs @@ -287,6 +287,7 @@ mod tests { tx, create_execution_result([]), vec![], + vec![], BlockGasCount::default(), VmExecutionMetrics::default(), vec![], diff --git a/core/node/state_keeper/src/testonly/mod.rs b/core/node/state_keeper/src/testonly/mod.rs index edcf3ccc4f5c..34a9a88bcb32 100644 --- a/core/node/state_keeper/src/testonly/mod.rs +++ b/core/node/state_keeper/src/testonly/mod.rs @@ -33,6 +33,7 @@ pub(crate) fn successful_exec() -> BatchTransactionExecutionResult { logs: Default::default(), statistics: Default::default(), refunds: Default::default(), + new_known_factory_deps: Default::default(), }), compressed_bytecodes: vec![], call_traces: 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 ffca8dff8643..2a883bb011b3 100644 --- a/core/node/state_keeper/src/testonly/test_batch_executor.rs +++ b/core/node/state_keeper/src/testonly/test_batch_executor.rs @@ -264,6 +264,7 @@ pub(crate) fn successful_exec_with_log() -> BatchTransactionExecutionResult { }, statistics: Default::default(), refunds: Default::default(), + new_known_factory_deps: Default::default(), }), compressed_bytecodes: vec![], call_traces: vec![], @@ -278,6 +279,7 @@ pub(crate) fn rejected_exec(reason: Halt) -> BatchTransactionExecutionResult { logs: Default::default(), statistics: Default::default(), refunds: Default::default(), + new_known_factory_deps: Default::default(), }), compressed_bytecodes: vec![], call_traces: vec![], 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(), } } 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 aa2e22cac483..8a714ed2e815 100644 --- a/core/node/state_keeper/src/updates/l1_batch_updates.rs +++ b/core/node/state_keeper/src/updates/l1_batch_updates.rs @@ -77,6 +77,7 @@ mod tests { VmExecutionMetrics::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 d8673088dc32..3d0d35096c2f 100644 --- a/core/node/state_keeper/src/updates/l2_block_updates.rs +++ b/core/node/state_keeper/src/updates/l2_block_updates.rs @@ -1,17 +1,14 @@ use std::collections::HashMap; -use once_cell::sync::Lazy; use zksync_multivm::{ interface::{ Call, CompressedBytecodeInfo, ExecutionResult, L2BlockEnv, TransactionExecutionResult, TxExecutionStatus, VmEvent, VmExecutionMetrics, VmExecutionResultAndLogs, }, - vm_latest::TransactionVmExt, + vm_latest::{utils::extract_bytecodes_marked_as_known, TransactionVmExt}, }; -use zksync_system_constants::KNOWN_CODES_STORAGE_ADDRESS; use zksync_types::{ block::{BlockGasCount, L2BlockHasher}, - ethabi, l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log}, L2BlockNumber, ProtocolVersionId, StorageLogWithPreviousValue, Transaction, H256, }; @@ -19,27 +16,6 @@ use zksync_utils::bytecode::hash_bytecode; use crate::metrics::KEEPER_METRICS; -/// Extracts all bytecodes marked as known on the system contracts. -fn extract_bytecodes_marked_as_known(all_generated_events: &[VmEvent]) -> Vec { - static PUBLISHED_BYTECODE_SIGNATURE: Lazy = Lazy::new(|| { - ethabi::long_signature( - "MarkedAsKnown", - &[ethabi::ParamType::FixedBytes(32), ethabi::ParamType::Bool], - ) - }); - - all_generated_events - .iter() - .filter(|event| { - // Filter events from the deployer contract that match the expected signature. - event.address == KNOWN_CODES_STORAGE_ADDRESS - && event.indexed_topics.len() == 3 - && event.indexed_topics[0] == *PUBLISHED_BYTECODE_SIGNATURE - }) - .map(|event| event.indexed_topics[1]) - .collect() -} - #[derive(Debug, Clone, PartialEq)] pub struct L2BlockUpdates { pub executed_transactions: Vec, @@ -104,6 +80,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, @@ -111,10 +88,12 @@ impl L2BlockUpdates { tx_l1_gas_this_tx: BlockGasCount, execution_metrics: VmExecutionMetrics, 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.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); @@ -145,11 +124,17 @@ impl L2BlockUpdates { // Get transaction factory deps let factory_deps = &tx.execute.factory_deps; - let tx_factory_deps: HashMap<_, _> = factory_deps + let mut tx_factory_deps: HashMap<_, _> = factory_deps .iter() - .map(|bytecode| (hash_bytecode(bytecode), bytecode)) + .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(|| { @@ -231,6 +216,7 @@ mod tests { VmExecutionMetrics::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 2fad56a99299..0761e36a97c9 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_multivm::{ }; use zksync_types::{ block::BlockGasCount, fee_model::BatchFeeInput, Address, L1BatchNumber, L2BlockNumber, - ProtocolVersionId, Transaction, + ProtocolVersionId, Transaction, H256, }; pub(crate) use self::{l1_batch_updates::L1BatchUpdates, l2_block_updates::L2BlockUpdates}; @@ -104,11 +104,13 @@ impl UpdatesManager { self.protocol_version } + #[allow(clippy::too_many_arguments)] pub fn extend_from_executed_transaction( &mut self, tx: Transaction, tx_execution_result: VmExecutionResultAndLogs, compressed_bytecodes: Vec, + new_known_factory_deps: Vec<(H256, Vec)>, tx_l1_gas_this_tx: BlockGasCount, execution_metrics: VmExecutionMetrics, call_traces: Vec, @@ -124,6 +126,7 @@ impl UpdatesManager { tx_l1_gas_this_tx, execution_metrics, compressed_bytecodes, + new_known_factory_deps, call_traces, ); latency.observe(); @@ -236,6 +239,7 @@ mod tests { new_block_gas_count(), VmExecutionMetrics::default(), vec![], + vec![], ); // Check that only pending state is updated. diff --git a/core/node/test_utils/src/lib.rs b/core/node/test_utils/src/lib.rs index b9984b782111..92b8b02462be 100644 --- a/core/node/test_utils/src/lib.rs +++ b/core/node/test_utils/src/lib.rs @@ -56,6 +56,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(), ); @@ -88,6 +89,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(), @@ -215,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, } } diff --git a/core/node/vm_runner/src/impls/bwip.rs b/core/node/vm_runner/src/impls/bwip.rs index f23f63533ff5..30473b6b3997 100644 --- a/core/node/vm_runner/src/impls/bwip.rs +++ b/core/node/vm_runner/src/impls/bwip.rs @@ -209,6 +209,10 @@ async fn get_updates_manager_witness_input_data( ) -> anyhow::Result { let initial_heap_content = output.batch.final_bootloader_memory.clone().unwrap(); // might be just empty let default_aa = system_env.base_system_smart_contracts.hashes().default_aa; + let evm_simulator = system_env + .base_system_smart_contracts + .hashes() + .evm_simulator; let bootloader = system_env.base_system_smart_contracts.hashes().bootloader; let bootloader_code_bytes = connection .factory_deps_dal() @@ -225,6 +229,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 used_contract_hashes = &output.batch.final_execution_state.used_contract_hashes; let hashes: HashSet = used_contract_hashes .iter() @@ -240,6 +252,10 @@ async fn get_updates_manager_witness_input_data( used_bytecodes.insert(account_code_hash, account_bytecode); } + if used_contract_hashes.contains(&evm_simulator_code_hash) { + used_bytecodes.insert(evm_simulator_code_hash, evm_simulator_bytecode); + } + let storage_refunds = output.batch.final_execution_state.storage_refunds.clone(); let pubdata_costs = output.batch.final_execution_state.pubdata_costs.clone(); let witness_block_state = WitnessStorageState { @@ -254,6 +270,7 @@ async fn get_updates_manager_witness_input_data( protocol_version: system_env.version, bootloader_code, default_account_code_hash: account_code_hash, + evm_simulator_code_hash, storage_refunds, pubdata_costs, witness_block_state, diff --git a/core/node/vm_runner/src/tests/mod.rs b/core/node/vm_runner/src/tests/mod.rs index 928da3b93157..ef1d37ef00e7 100644 --- a/core/node/vm_runner/src/tests/mod.rs +++ b/core/node/vm_runner/src/tests/mod.rs @@ -322,6 +322,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(); diff --git a/core/node/vm_runner/src/tests/output_handler.rs b/core/node/vm_runner/src/tests/output_handler.rs index 1bf30effdbe5..9376beab1aa7 100644 --- a/core/node/vm_runner/src/tests/output_handler.rs +++ b/core/node/vm_runner/src/tests/output_handler.rs @@ -66,6 +66,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/etc/env/base/chain.toml b/etc/env/base/chain.toml index 6cfacb3c72ce..b5a4e4b2e75c 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 = "0x010008bbde6fc402ea3a3d6cb15cb97e70245d3d4e48fb74362d4961b74c16b1" +default_aa_hash = "0x0100058d9eee51f4b9e9a9ecb7fd7e8301e90bef018c2bd913ed36e583fec8c2" +evm_simulator_hash = "0x01000ccb740e2345754450eda583f59b31a346920a22f968dfcfc63feae303ee" protective_reads_persistence_enabled = false diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index daa317a8bc90..fab072c07cec 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 = "0xabdb766b18a479a5c783a4b80e12686bc8ea3cc2d8a3050491b701d72370ebb5" -GENESIS_BATCH_COMMITMENT = "0x2d00e5f8d77afcebf58a6b82ae56ba967566fe7dfbcb6760319fb0d215d18ffd" +GENESIS_ROOT = "0xbfa72908d61bf6e208a1140eb8b66a8e9fc0cc3ecd76f73d994fa75c49778530" +GENESIS_BATCH_COMMITMENT = "0xeac224ce2445688015b7b88a168332657fb1de5ccb3c55407d6107fbd483459e" 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" diff --git a/etc/env/file_based/genesis.yaml b/etc/env/file_based/genesis.yaml index 220a75944e02..7f0dca74ef79 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.2' # 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/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'; } diff --git a/prover/Cargo.lock b/prover/Cargo.lock index 21e2ea8b21de..a838c8cbc0ef 100644 --- a/prover/Cargo.lock +++ b/prover/Cargo.lock @@ -347,6 +347,18 @@ dependencies = [ "tower-service", ] +[[package]] +name = "backon" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d67782c3f868daa71d3533538e98a8e13713231969def7536e8039606fc46bf0" +dependencies = [ + "fastrand", + "futures-core", + "pin-project", + "tokio", +] + [[package]] name = "backtrace" version = "0.3.72" @@ -500,6 +512,27 @@ dependencies = [ "which", ] +[[package]] +name = "bindgen" +version = "0.65.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "prettyplease", + "proc-macro2 1.0.85", + "quote 1.0.36", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.66", +] + [[package]] name = "bindgen" version = "0.69.4" @@ -793,6 +826,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "bytecount" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" + [[package]] name = "byteorder" version = "1.5.0" @@ -805,6 +844,48 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + [[package]] name = "cc" version = "1.1.14" @@ -1500,6 +1581,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if 1.0.0", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "debugid" version = "0.8.0" @@ -1866,6 +1960,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "version_check", +] + [[package]] name = "etcetera" version = "0.8.0" @@ -3228,6 +3331,22 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "librocksdb-sys" +version = "0.11.0+8.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3386f101bcb4bd252d8e9d2fb41ec3b0862a15a62b478c355b2982efa469e3e" +dependencies = [ + "bindgen 0.65.1", + "bzip2-sys", + "cc", + "glob", + "libc", + "libz-sys", + "lz4-sys", + "zstd-sys", +] + [[package]] name = "libsqlite3-sys" version = "0.30.1" @@ -3239,6 +3358,17 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "libz-sys" +version = "1.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -3305,6 +3435,16 @@ dependencies = [ "logos-codegen", ] +[[package]] +name = "lz4-sys" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109de74d5d2353660401699a4174a4ff23fcc649caf553df71933c7fb45ad868" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "match_cfg" version = "0.1.0" @@ -3402,6 +3542,21 @@ dependencies = [ "unicase", ] +[[package]] +name = "mini-moka" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c325dfab65f261f386debee8b0969da215b3fa0037e74c8a1234db7ba986d803" +dependencies = [ + "crossbeam-channel 0.5.13", + "crossbeam-utils 0.8.20", + "dashmap", + "skeptic", + "smallvec", + "tagptr", + "triomphe", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -4474,6 +4629,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "pulldown-cmark" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" +dependencies = [ + "bitflags 2.6.0", + "memchr", + "unicase", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -4882,6 +5048,16 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "rocksdb" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6f170a4041d50a0ce04b0d2e14916d6ca863ea2e422689a5b694395d299ffe" +dependencies = [ + "libc", + "librocksdb-sys", +] + [[package]] name = "rsa" version = "0.9.6" @@ -5189,6 +5365,9 @@ name = "semver" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] [[package]] name = "send_wrapper" @@ -5567,6 +5746,21 @@ dependencies = [ "time", ] +[[package]] +name = "skeptic" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" +dependencies = [ + "bytecount", + "cargo_metadata", + "error-chain", + "glob", + "pulldown-cmark", + "tempfile", + "walkdir", +] + [[package]] name = "slab" version = "0.4.9" @@ -6046,6 +6240,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "tap" version = "1.0.1" @@ -6495,6 +6695,12 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "triomphe" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6631e42e10b40c0690bf92f404ebcfe6e1fdb480391d15f17cc8e96eeed5369" + [[package]] name = "try-lock" version = "0.2.5" @@ -7657,6 +7863,8 @@ dependencies = [ "once_cell", "serde", "serde_json", + "zksync_config", + "zksync_env_config", "zksync_utils", ] @@ -7813,6 +8021,7 @@ dependencies = [ "circuit_sequencer_api 0.141.1", "circuit_sequencer_api 0.142.0", "circuit_sequencer_api 0.150.4", + "ethabi", "hex", "itertools 0.10.5", "once_cell", @@ -7827,6 +8036,7 @@ dependencies = [ "zk_evm 0.141.0", "zk_evm 0.150.4", "zksync_contracts", + "zksync_state", "zksync_system_constants", "zksync_types", "zksync_utils", @@ -8110,6 +8320,51 @@ dependencies = [ "zksync_utils", ] +[[package]] +name = "zksync_shared_metrics" +version = "0.1.0" +dependencies = [ + "rustc_version", + "tracing", + "vise", + "zksync_dal", + "zksync_types", +] + +[[package]] +name = "zksync_state" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "backon", + "chrono", + "itertools 0.10.5", + "mini-moka", + "once_cell", + "tokio", + "tracing", + "vise", + "zksync_dal", + "zksync_shared_metrics", + "zksync_storage", + "zksync_types", + "zksync_utils", + "zksync_vm_interface", +] + +[[package]] +name = "zksync_storage" +version = "0.1.0" +dependencies = [ + "num_cpus", + "once_cell", + "rocksdb", + "thread_local", + "tracing", + "vise", +] + [[package]] name = "zksync_system_constants" version = "0.1.0" @@ -8231,6 +8486,7 @@ dependencies = [ "zksync_contracts", "zksync_system_constants", "zksync_types", + "zksync_utils", ] [[package]] @@ -8317,3 +8573,13 @@ dependencies = [ "zksync_utils", "zksync_vlog", ] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] 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, 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 3a3a3003ac488295166a83af4e2def61ce44cc8e Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 11 Sep 2024 16:50:39 -0300 Subject: [PATCH 04/45] Add ts tests and contracts for evm simulator --- .../contracts/create/TestEVMCreate.sol | 30 + .../ts-integration/contracts/token/ERC20.sol | 76 ++ .../contracts/uniswap-v2/UniswapV2Factory.sol | 683 +++++++++++++++ .../evm-contracts/ConstructorRevert.sol | 11 + .../evm-contracts/CounterFallback.sol | 14 + .../evm-contracts/CounterWithParam.sol | 39 + .../ts-integration/evm-contracts/Creator.sol | 19 + .../evm-contracts/CreatorFallback.sol | 20 + .../ts-integration/evm-contracts/ERC20.sol | 78 ++ .../evm-contracts/GasCaller.sol | 16 + .../evm-contracts/OpcodeTest.sol | 123 +++ .../evm-contracts/OpcodeTestFallback.sol | 139 +++ .../evm-contracts/ProxyCaller.sol | 25 + .../evm-contracts/SelfDestruct.sol | 13 + .../evm-contracts/UniswapFallback.sol | 125 +++ core/tests/ts-integration/package.json | 6 +- core/tests/ts-integration/src/helpers.ts | 47 + .../tests/evm-contracts.test.ts | 828 ++++++++++++++++++ 18 files changed, 2291 insertions(+), 1 deletion(-) 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 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/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..514e2358624f --- /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; + } + +} 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..91e74bb2b11a --- /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; + } +} 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..868e57edca79 --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/ConstructorRevert.sol @@ -0,0 +1,11 @@ +// 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..c67dfec9459e --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/CounterFallback.sol @@ -0,0 +1,14 @@ +// 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..714b4d665ae3 --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/CounterWithParam.sol @@ -0,0 +1,39 @@ +// 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) public payable 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"; + } +} 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..63a6f7e3b1d7 --- /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..30ebabd7cc7a --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/CreatorFallback.sol @@ -0,0 +1,20 @@ +// 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..1b65e6541804 --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/ERC20.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity >=0.7.0; + +contract ERC20 { + string public symbol; + string public name; + uint8 public decimals; + uint256 public totalSupply; + + 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); + + 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 (uint256 balance) { + return balances[tokenOwner]; + } + + 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, 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, + 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); + emit Transfer(from, to, tokens); + return true; + } + + function allowance(address tokenOwner, address spender) public view returns (uint256 remaining) { + return allowed[tokenOwner][spender]; + } + + function safeAdd(uint256 a, uint256 b) internal pure returns (uint256 c) { + c = a + b; + require(c >= a); + } + + function safeSub(uint256 a, uint256 b) internal pure returns (uint256 c) { + require(b <= a); + c = a - b; + } + + function safeMul(uint256 a, uint256 b) internal pure returns (uint256 c) { + c = a * b; + require(a == 0 || c / a == b); + } + + 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 new file mode 100644 index 000000000000..25b56aa744d6 --- /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..721339bd7ae8 --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/OpcodeTest.sol @@ -0,0 +1,123 @@ +// 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..47f427a27333 --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/OpcodeTestFallback.sol @@ -0,0 +1,139 @@ +// 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..379d7c7addcd --- /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(); + } +} 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..12fec9555908 --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/SelfDestruct.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity >=0.7.0; + +contract SelfDestruct { + constructor() payable {} + + 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 new file mode 100644 index 000000000000..0237b4be1ba5 --- /dev/null +++ b/core/tests/ts-integration/evm-contracts/UniswapFallback.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.0; + +interface IUniswapV2ERC20 { + 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); + + function symbol() external pure returns (string memory); + + function decimals() external pure returns (uint8); + + function totalSupply() external returns (uint256); + + function balanceOf(address owner) external returns (uint256); + + function allowance(address owner, address spender) external returns (uint256); + + function approve(address spender, uint256 value) external returns (bool); + + function transfer(address to, uint256 value) external returns (bool); + + function transferFrom( + address from, + address to, + uint256 value + ) external returns (bool); + + function DOMAIN_SEPARATOR() external returns (bytes32); + + function PERMIT_TYPEHASH() external pure returns (bytes32); + + function nonces(address owner) external returns (uint256); + + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; +} + +interface IUniswapV2Pair { + 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, + uint256 amount0In, + uint256 amount1In, + uint256 amount0Out, + uint256 amount1Out, + address indexed to + ); + event Sync(uint112 reserve0, uint112 reserve1); + + function MINIMUM_LIQUIDITY() external pure returns (uint256); + + 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 (uint256); + + function price1CumulativeLast() external returns (uint256); + + function kLast() external returns (uint256); + + function mint(address to) external returns (uint256 liquidity); + + function burn(address to) external returns (uint256 amount0, uint256 amount1); + + function swap( + uint256 amount0Out, + uint256 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"); + uint256 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 0e9b863d8e16..b2494ed3878b 100644 --- a/core/tests/ts-integration/package.json +++ b/core/tests/ts-integration/package.json @@ -32,6 +32,10 @@ "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", + "solc": "0.8.20" } } 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..90eb0975f021 --- /dev/null +++ b/core/tests/ts-integration/tests/evm-contracts.test.ts @@ -0,0 +1,828 @@ +/** + * 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'; + +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.getFunction('callAndGetGas').staticCall(counterContract.getAddress()) + ).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.getFunction('callAndGetGas').staticCall(creatorContract.getAddress()) + ).toString(); + + const expected_gas = '70598'; // Gas cost when run with solidity interpreter - 3 (We have some changes that are needed) + 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.deploymentTransaction()?.wait(); + 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 + ); + + 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.randomBytes(32); + + const expectedAddress = ethers.getCreate2Address( + await evmCreateTester.getAddress(), + salt, + ethers.keccak256(initBytecode) + ); + + await (await evmCreateTester.create2(salt, initBytecode)).wait(); + + await assertCreatedCorrectly(deployer, expectedAddress, runtimeBytecode); + + 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.deploymentTransaction()?.wait(); + } catch (e: any) { + failReason = e.reason; + } + + expect(failReason).toBe(null); + }); + + test('Should NOT create evm contract from EOA when `to` is address(0x0)', async () => { + const args = 1; + + const factory = getEVMContractFactory(alice, artifacts.counter); + const { data, ...rest } = await factory.getDeployTransaction(args); + const dep_transaction = { + ...rest, + to: '0x0000000000000000000000000000000000000000', + chainId: alice.provider._network.chainId, + data + }; + await (await alice.sendTransaction(dep_transaction)).wait(); + const expectedAddressCreate = ethers.getCreateAddress({ + from: alice.address, + nonce: await alice.getNonce() + }); + + await assertContractNotCreated(deployer, expectedAddressCreate); + }); + }); + }); + + 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.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.deploymentTransaction()?.wait(); + await alice.provider.getTransactionReceipt( + proxyCallerContract.deploymentTransaction()?.hash ?? + (() => { + throw new Error('Deployment transaction has failed'); + })() + ); + + expect( + (await proxyCallerContract.getFunction('proxyGet')(await counterContract.getAddress())).toString() + ).toEqual('1'); + + await ( + await proxyCallerContract.getFunction('executeIncrememt')(await counterContract.getAddress(), 1) + ).wait(); + + expect( + (await proxyCallerContract.getFunction('proxyGet')(await counterContract.getAddress())).toString() + ).toEqual('2'); + + expect( + ( + await proxyCallerContract + .getFunction('proxyGetBytes') + .staticCall(await counterContract.getAddress()) + ).toString() + ).toEqual('0x54657374696e67'); + }); + + test('Create opcode works correctly', async () => { + const creatorFactory = getEVMContractFactory(alice, artifacts.creator); + const creatorContract = await creatorFactory.deploy(); + await creatorContract.deploymentTransaction()?.wait(); + + const nonce = 1; + + const runtimeBytecode = await creatorContract.getFunction('getCreationRuntimeCode')(); + + const expectedAddress = ethers.getCreateAddress({ + from: await creatorContract.getAddress(), + nonce + }); + + await (await creatorContract.getFunction('create')()).wait(); + + await assertCreatedCorrectly(deployer, expectedAddress, runtimeBytecode); + }); + + test('Should revert correctly', async () => { + const args = 1; + + const counterFactory = getEVMContractFactory(alice, artifacts.counter); + const counterContract = await counterFactory.deploy(args); + await counterContract.deploymentTransaction()?.wait(); + + let errorString; + + try { + await counterContract.getFunction('incrementWithRevert').staticCall(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.BaseContract; + 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.deploymentTransaction()?.wait(); + nativeToken = await deployContract(alice, contracts.erc20, []); + + 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); + deployLogged = true; + } + await ( + await alice.sendTransaction({ + to: userAccount.address, + value: BigInt('0xffffffffffffff') + }) + ).wait(); + }); + + test('view functions should work', async () => { + 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'); + }); + + 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(); + 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()); + } + + 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(); + const nativeApproveTx = await ( + await nativeToken.connect(alice).getFunction('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()); + } + + const evmTransferFromTx = await ( + 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 + ) + ).wait(); + if (logGasCosts) { + console.log('ERC20 native transferFrom gas: ' + nativeTransferFromTx.gasUsed.toString()); + console.log('ERC20 evm transferFrom gas: ' + evmTransferFromTx.gasUsed.toString()); + } + + 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.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'; + + beforeEach(async () => { + const erc20Factory = getEVMContractFactory(alice, artifacts.erc20); + evmToken1 = await erc20Factory.deploy({ gasLimit }); + await evmToken1.deploymentTransaction()?.wait(); + evmToken2 = await erc20Factory.deploy(); + await evmToken2.deploymentTransaction()?.wait(); + + const evmUniswapFactoryFactory = getEVMContractFactory(alice, artifacts.uniswapV2Factory); + evmUniswapFactory = await evmUniswapFactoryFactory.deploy('0x0000000000000000000000000000000000000000'); + await evmUniswapFactory.deploymentTransaction()?.wait(); + + nativeUniswapFactory = await deployContract( + alice, + contracts.uniswapV2Factory, + ['0x0000000000000000000000000000000000000000'], + undefined, + { + customData: { + factoryDeps: [contracts.uniswapV2Pair.bytecode] + } + } + ); + + const evmPairReceipt = await ( + await evmUniswapFactory.getFunction('createPair')(evmToken1.getAddress(), evmToken2.getAddress()) + ).wait(); + + const nativePairReceipt = await ( + await nativeUniswapFactory.getFunction('createPair')(evmToken1.getAddress(), evmToken2.getAddress()) + ).wait(); + + const evmUniswapPairFactory = getEVMContractFactory(alice, artifacts.uniswapV2Pair); + const nativeUniswapPairFactory = new zksync.ContractFactory( + contracts.uniswapV2Pair.abi, + contracts.uniswapV2Pair.bytecode, + alice + ); + evmUniswapPair = evmUniswapPairFactory.attach( + ethers.AbiCoder.defaultAbiCoder().decode( + ['address', 'uint256'], + evmPairReceipt.logs.find((log: any) => log.topics[0] === NEW_PAIR_TOPIC).data + )[0] + ); + nativeUniswapPair = nativeUniswapPairFactory.attach( + ethers.AbiCoder.defaultAbiCoder().decode( + ['address', 'uint256'], + nativePairReceipt.logs.find((log: any) => log.topics[0] === NEW_PAIR_TOPIC).data + )[0] + ); + 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(); + + // 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); + 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.getFunction('mint')(alice.address)).wait(); + const nativeMintReceipt = await (await nativeUniswapPair.getFunction('mint')(alice.address)).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(); + + await ( + await evmUniswapPair.getFunction('transfer')( + evmUniswapPair.getAddress(), + (await evmUniswapPair.getFunction('balanceOf')(alice.address)).toString() + ) + ).wait(); + await ( + await nativeUniswapPair.getFunction('transfer')( + nativeUniswapPair.getAddress(), + (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 + ); + + 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); + } + }); + + test("Should compare gas against uniswap fallback contract's call", async () => { + 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'); + })() + ); + + 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 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(); + + 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() + // }); + // }); + + afterAll(async () => { + await testMaster.deinitialize(); + if (logGasCosts) { + printCostData(); + } + }); +}); + +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'; + 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) + ); + + expect(storedCodeHash).toEqual(expectedStoredHash); +} + +async function assertCreatedCorrectly( + deployer: zksync.Contract, + deployedAddress: string, + expectedEVMBytecode: string +): Promise { + const expectedStoredHash = getSha256BlobHash(expectedEVMBytecode); + await assertStoredBytecodeHash(deployer, deployedAddress, expectedStoredHash); +} + +function getPaddedBytecode(bytes: ethers.BytesLike) { + const length = ethers.getBytes(bytes).length; + + const encodedLength = ethers.AbiCoder.defaultAbiCoder().encode(['uint256'], [length]); + + 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 + 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.getBytes(ethers.sha256(paddedBytes)); + hash[0] = 2; + hash[1] = 0; + + // Length of the bytecode + const lengthInBytes = ethers.getBytes(paddedBytes).length; + hash[2] = Math.floor(lengthInBytes / 256); + hash[3] = lengthInBytes % 256; + + return ethers.toBeHex(ethers.toBigInt(hash)); +} + +async function assertContractNotCreated(deployer: zksync.Contract, deployedAddress: string): Promise { + assertStoredBytecodeHash(deployer, deployedAddress, ethers.ZeroHash); +} + +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()] = []; +}); From 81321326ad4865972ef211c87f3210e2de130edb Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 11 Sep 2024 16:51:07 -0300 Subject: [PATCH 05/45] Update multivm bootloaders bin files for vm1_5_0 --- .../fee_estimate.yul/fee_estimate.yul.zbin | Bin 76320 -> 74912 bytes .../gas_test.yul/gas_test.yul.zbin | Bin 72416 -> 71008 bytes .../playground_batch.yul.zbin | Bin 76512 -> 75104 bytes .../proved_batch.yul/proved_batch.yul.zbin | Bin 72928 -> 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 75ee6377bdb645532c55f06f0e883cc078b5bd2b..ad45ddb49571509167df6fd155d50130db9b6afb 100644 GIT binary patch literal 74912 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 literal 72416 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 PUBCIJ&;7~A_uTs5GOKah 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..a7ba16384cc223b5a0018b18a61622aab864bfca 100644 GIT binary patch literal 71520 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 gzj^U9AG=}E?OV2O{*T}OlCEyaXQCedvZs=er6 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 Date: Wed, 11 Sep 2024 16:51:29 -0300 Subject: [PATCH 06/45] Update lock file --- Cargo.lock | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index b98d343564b8..8634bff8a594 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8478,6 +8478,8 @@ dependencies = [ "once_cell", "serde", "serde_json", + "zksync_config", + "zksync_env_config", "zksync_utils", ] @@ -8980,6 +8982,7 @@ dependencies = [ "zk_evm 0.150.4", "zksync_contracts", "zksync_eth_signer", + "zksync_state", "zksync_system_constants", "zksync_test_account", "zksync_types", @@ -9800,6 +9803,7 @@ dependencies = [ "zksync_contracts", "zksync_system_constants", "zksync_types", + "zksync_utils", ] [[package]] From dfef5ea76a97822394db196f98917580cb73874e Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 11 Sep 2024 17:23:23 -0300 Subject: [PATCH 07/45] Update contracts submodule --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index d3687694f71d..361d19af8346 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit d3687694f71d83fa286b9c186b4c3ea173028f83 +Subproject commit 361d19af8346efde0b53243e29612b15f232459e From ddc35ded3e7ec0f858b642b63aee323cc54b8464 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 12 Sep 2024 13:44:19 -0300 Subject: [PATCH 08/45] Improve get contract address for sql queries --- core/lib/dal/src/transactions_dal.rs | 76 ++++++++++------------------ 1 file changed, 28 insertions(+), 48 deletions(-) diff --git a/core/lib/dal/src/transactions_dal.rs b/core/lib/dal/src/transactions_dal.rs index bc44083ea319..a204a1a1979c 100644 --- a/core/lib/dal/src/transactions_dal.rs +++ b/core/lib/dal/src/transactions_dal.rs @@ -59,12 +59,9 @@ impl TransactionsDal<'_, '_> { l1_block_number: L1BlockNumber, ) -> DalResult<()> { 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 contract_address_as_bytes = contract_address + .and_then(|addr| Some(addr.as_bytes().to_vec())) + .unwrap_or_default(); let tx_hash = tx.hash(); let tx_hash_bytes = tx_hash.as_bytes(); let json_data = serde_json::to_value(&tx.execute) @@ -149,7 +146,7 @@ impl TransactionsDal<'_, '_> { serial_id, full_fee, layer_2_tip_fee, - contract_address_b, + contract_address_as_bytes, l1_block_number.0 as i32, value, empty_address.as_bytes(), @@ -168,12 +165,9 @@ impl TransactionsDal<'_, '_> { pub async fn insert_system_transaction(&mut self, tx: &ProtocolUpgradeTx) -> DalResult<()> { 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 contract_address_as_bytes = contract_address + .and_then(|addr| Some(addr.as_bytes().to_vec())) + .unwrap_or_default(); 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())); @@ -250,7 +244,7 @@ impl TransactionsDal<'_, '_> { gas_per_pubdata_limit, json_data, upgrade_id, - contract_address_b, + contract_address_as_bytes, l1_block_number, value, &Address::default().0.to_vec(), @@ -298,11 +292,9 @@ impl TransactionsDal<'_, '_> { let initiator_address = tx.initiator_account(); 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 contract_address_as_bytes = contract_address + .and_then(|addr| Some(addr.as_bytes().to_vec())) + .unwrap_or_default(); 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); @@ -431,7 +423,7 @@ impl TransactionsDal<'_, '_> { input_data, &json_data, tx_format, - contract_address_b, + contract_address_as_bytes, value, &paymaster, &paymaster_input, @@ -716,14 +708,11 @@ impl TransactionsDal<'_, '_> { })?; 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 contract_address_as_bytes = contract_address + .and_then(|addr| Some(addr.as_bytes().to_vec())) + .unwrap_or_default(); l2_values.push(u256_to_big_decimal(transaction.execute.value)); - l2_contract_addresses.push(contract_address_b); + l2_contract_addresses.push(contract_address_as_bytes); 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()); @@ -927,14 +916,11 @@ impl TransactionsDal<'_, '_> { })?; 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 contract_address_as_bytes = contract_address + .and_then(|addr| Some(addr.as_bytes().to_vec())) + .unwrap_or_default(); l2_values.push(u256_to_big_decimal(transaction.execute.value)); - l2_contract_addresses.push(contract_address_b); + l2_contract_addresses.push(contract_address_as_bytes); 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()); @@ -1116,12 +1102,9 @@ impl TransactionsDal<'_, '_> { })?; 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 contract_address_as_bytes = contract_address + .and_then(|addr| Some(addr.as_bytes().to_vec())) + .unwrap_or_default(); let tx = &tx_res.transaction; l1_hashes.push(tx_res.hash.as_bytes()); l1_initiator_address.push(common_data.sender.as_bytes()); @@ -1135,7 +1118,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(contract_address_b); + l1_contract_address.push(contract_address_as_bytes); 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); @@ -1413,12 +1396,9 @@ impl TransactionsDal<'_, '_> { })?; 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 contract_address_as_bytes = contract_address + .and_then(|addr| Some(addr.as_bytes().to_vec())) + .unwrap_or_default(); let tx = &tx_res.transaction; upgrade_hashes.push(tx_res.hash.as_bytes()); upgrade_initiator_address.push(common_data.sender.as_bytes()); @@ -1431,7 +1411,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(contract_address_b); + upgrade_contract_address.push(contract_address_as_bytes); 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); From a5c22ea2f21a34fb54f6dab1ee2132330c9ecc04 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 12 Sep 2024 15:11:40 -0300 Subject: [PATCH 09/45] Make recipient address optional for L2Tx --- core/lib/types/src/l2/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/lib/types/src/l2/mod.rs b/core/lib/types/src/l2/mod.rs index abd60491af38..036d2a7a036d 100644 --- a/core/lib/types/src/l2/mod.rs +++ b/core/lib/types/src/l2/mod.rs @@ -232,8 +232,8 @@ impl L2Tx { } /// Returns recipient account of the transaction. - pub fn recipient_account(&self) -> Address { - self.execute.contract_address.unwrap_or_default() + pub fn recipient_account(&self) -> Option

{ + self.execute.contract_address } /// Returns the account nonce associated with transaction. @@ -324,7 +324,7 @@ impl From for TransactionRequest { let mut base_tx_req = TransactionRequest { nonce: U256::from(tx.common_data.nonce.0), from: Some(tx.common_data.initiator_address), - to: Some(tx.recipient_account()), + to: tx.recipient_account(), value: tx.execute.value, gas_price: tx.common_data.fee.max_fee_per_gas, max_priority_fee_per_gas: None, @@ -400,7 +400,7 @@ impl From for api::Transaction { chain_id: U256::from(tx.common_data.extract_chain_id().unwrap_or_default()), nonce: U256::from(tx.common_data.nonce.0), from: Some(tx.common_data.initiator_address), - to: Some(tx.recipient_account()), + to: tx.recipient_account(), value: tx.execute.value, gas_price: Some(tx.common_data.fee.max_fee_per_gas), max_priority_fee_per_gas: Some(tx.common_data.fee.max_priority_fee_per_gas), From c075fb4bd9f88fd25ce62cd2ef709f57b21b616c Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 12 Sep 2024 16:02:15 -0300 Subject: [PATCH 10/45] Fix error lints --- core/lib/dal/src/transactions_dal.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/core/lib/dal/src/transactions_dal.rs b/core/lib/dal/src/transactions_dal.rs index a204a1a1979c..f9ff6b64957e 100644 --- a/core/lib/dal/src/transactions_dal.rs +++ b/core/lib/dal/src/transactions_dal.rs @@ -60,7 +60,7 @@ impl TransactionsDal<'_, '_> { ) -> DalResult<()> { let contract_address = tx.execute.contract_address; let contract_address_as_bytes = contract_address - .and_then(|addr| Some(addr.as_bytes().to_vec())) + .map(|addr| addr.as_bytes().to_vec()) .unwrap_or_default(); let tx_hash = tx.hash(); let tx_hash_bytes = tx_hash.as_bytes(); @@ -166,7 +166,7 @@ impl TransactionsDal<'_, '_> { pub async fn insert_system_transaction(&mut self, tx: &ProtocolUpgradeTx) -> DalResult<()> { let contract_address = tx.execute.contract_address; let contract_address_as_bytes = contract_address - .and_then(|addr| Some(addr.as_bytes().to_vec())) + .map(|addr| addr.as_bytes().to_vec()) .unwrap_or_default(); let tx_hash = tx.common_data.hash().0.to_vec(); let json_data = serde_json::to_value(&tx.execute) @@ -291,9 +291,8 @@ impl TransactionsDal<'_, '_> { let initiator_address = tx.initiator_account(); let contract_address = tx.execute.contract_address; - let unwrapped_contract_address = contract_address.unwrap_or_default(); let contract_address_as_bytes = contract_address - .and_then(|addr| Some(addr.as_bytes().to_vec())) + .map(|addr| addr.as_bytes().to_vec()) .unwrap_or_default(); let json_data = serde_json::to_value(&tx.execute) .unwrap_or_else(|_| panic!("cannot serialize tx {:?} to json", tx.hash())); @@ -709,7 +708,7 @@ impl TransactionsDal<'_, '_> { let contract_address = transaction.execute.contract_address; let contract_address_as_bytes = contract_address - .and_then(|addr| Some(addr.as_bytes().to_vec())) + .map(|addr| addr.as_bytes().to_vec()) .unwrap_or_default(); l2_values.push(u256_to_big_decimal(transaction.execute.value)); l2_contract_addresses.push(contract_address_as_bytes); @@ -917,7 +916,7 @@ impl TransactionsDal<'_, '_> { let contract_address = transaction.execute.contract_address; let contract_address_as_bytes = contract_address - .and_then(|addr| Some(addr.as_bytes().to_vec())) + .map(|addr| addr.as_bytes().to_vec()) .unwrap_or_default(); l2_values.push(u256_to_big_decimal(transaction.execute.value)); l2_contract_addresses.push(contract_address_as_bytes); @@ -1103,7 +1102,7 @@ impl TransactionsDal<'_, '_> { let contract_address = transaction.execute.contract_address; let contract_address_as_bytes = contract_address - .and_then(|addr| Some(addr.as_bytes().to_vec())) + .map(|addr| addr.as_bytes().to_vec()) .unwrap_or_default(); let tx = &tx_res.transaction; l1_hashes.push(tx_res.hash.as_bytes()); @@ -1397,7 +1396,7 @@ impl TransactionsDal<'_, '_> { let contract_address = transaction.execute.contract_address; let contract_address_as_bytes = contract_address - .and_then(|addr| Some(addr.as_bytes().to_vec())) + .map(|addr| addr.as_bytes().to_vec()) .unwrap_or_default(); let tx = &tx_res.transaction; upgrade_hashes.push(tx_res.hash.as_bytes()); From 6c94de922942c5c1dc258a0bb64bfd2c7b8d9b31 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 17 Sep 2024 11:25:52 -0300 Subject: [PATCH 11/45] Insert null in sql for contract address instead of empty bytes --- core/lib/dal/src/transactions_dal.rs | 36 +++++++++------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/core/lib/dal/src/transactions_dal.rs b/core/lib/dal/src/transactions_dal.rs index f9ff6b64957e..0a72289b48a4 100644 --- a/core/lib/dal/src/transactions_dal.rs +++ b/core/lib/dal/src/transactions_dal.rs @@ -59,9 +59,7 @@ impl TransactionsDal<'_, '_> { l1_block_number: L1BlockNumber, ) -> DalResult<()> { let contract_address = tx.execute.contract_address; - let contract_address_as_bytes = contract_address - .map(|addr| addr.as_bytes().to_vec()) - .unwrap_or_default(); + let contract_address_as_bytes = contract_address.map(|addr| addr.as_bytes().to_vec()); let tx_hash = tx.hash(); let tx_hash_bytes = tx_hash.as_bytes(); let json_data = serde_json::to_value(&tx.execute) @@ -165,9 +163,7 @@ impl TransactionsDal<'_, '_> { pub async fn insert_system_transaction(&mut self, tx: &ProtocolUpgradeTx) -> DalResult<()> { let contract_address = tx.execute.contract_address; - let contract_address_as_bytes = contract_address - .map(|addr| addr.as_bytes().to_vec()) - .unwrap_or_default(); + let contract_address_as_bytes = contract_address.map(|addr| addr.as_bytes().to_vec()); 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())); @@ -291,9 +287,7 @@ impl TransactionsDal<'_, '_> { let initiator_address = tx.initiator_account(); let contract_address = tx.execute.contract_address; - let contract_address_as_bytes = contract_address - .map(|addr| addr.as_bytes().to_vec()) - .unwrap_or_default(); + let contract_address_as_bytes = contract_address.map(|addr| addr.as_bytes().to_vec()); 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); @@ -707,9 +701,7 @@ impl TransactionsDal<'_, '_> { })?; let contract_address = transaction.execute.contract_address; - let contract_address_as_bytes = contract_address - .map(|addr| addr.as_bytes().to_vec()) - .unwrap_or_default(); + let contract_address_as_bytes = contract_address.map(|addr| addr.as_bytes().to_vec()); l2_values.push(u256_to_big_decimal(transaction.execute.value)); l2_contract_addresses.push(contract_address_as_bytes); l2_paymaster_input.push(&common_data.paymaster_params.paymaster_input[..]); @@ -831,7 +823,7 @@ impl TransactionsDal<'_, '_> { &l2_inputs as &[&[u8]], &l2_datas, &l2_tx_formats, - &l2_contract_addresses, + &l2_contract_addresses as &[Option>], &l2_values, &l2_paymaster as &[&[u8]], &l2_paymaster_input as &[&[u8]], @@ -915,9 +907,7 @@ impl TransactionsDal<'_, '_> { })?; let contract_address = transaction.execute.contract_address; - let contract_address_as_bytes = contract_address - .map(|addr| addr.as_bytes().to_vec()) - .unwrap_or_default(); + let contract_address_as_bytes = contract_address.map(|addr| addr.as_bytes().to_vec()); l2_values.push(u256_to_big_decimal(transaction.execute.value)); l2_contract_addresses.push(contract_address_as_bytes); l2_paymaster_input.push(&common_data.paymaster_params.paymaster_input[..]); @@ -1030,7 +1020,7 @@ impl TransactionsDal<'_, '_> { &l2_datas, &l2_refunded_gas, &l2_values, - &l2_contract_addresses, + &l2_contract_addresses as &[Option>], &l2_paymaster as &[&[u8]], &l2_paymaster_input as &[&[u8]], l2_block_number.0 as i32, @@ -1101,9 +1091,7 @@ impl TransactionsDal<'_, '_> { })?; let contract_address = transaction.execute.contract_address; - let contract_address_as_bytes = contract_address - .map(|addr| addr.as_bytes().to_vec()) - .unwrap_or_default(); + let contract_address_as_bytes = contract_address.map(|addr| addr.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()); @@ -1224,7 +1212,7 @@ impl TransactionsDal<'_, '_> { &l1_priority_op_id, &l1_full_fee, &l1_layer_2_tip_fee, - &l1_contract_address, + &l1_contract_address as &[Option>], &l1_l1_block_number, &l1_value, &l1_tx_format, @@ -1395,9 +1383,7 @@ impl TransactionsDal<'_, '_> { })?; let contract_address = transaction.execute.contract_address; - let contract_address_as_bytes = contract_address - .map(|addr| addr.as_bytes().to_vec()) - .unwrap_or_default(); + let contract_address_as_bytes = contract_address.map(|addr| addr.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()); @@ -1509,7 +1495,7 @@ impl TransactionsDal<'_, '_> { &upgrade_gas_per_pubdata_limit, &upgrade_data, &upgrade_upgrade_id, - &upgrade_contract_address, + &upgrade_contract_address as &[Option>], &upgrade_l1_block_number, &upgrade_value, &upgrade_tx_format, From b280eb3dff51cc9377438a4525f496b2460f0e29 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 17 Sep 2024 12:19:07 -0300 Subject: [PATCH 12/45] Remove require and support None value for protobuff Transaction --- core/lib/dal/src/consensus/mod.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/core/lib/dal/src/consensus/mod.rs b/core/lib/dal/src/consensus/mod.rs index 88620575c88a..f54938e8ec1a 100644 --- a/core/lib/dal/src/consensus/mod.rs +++ b/core/lib/dal/src/consensus/mod.rs @@ -401,11 +401,10 @@ impl ProtoRepr for proto::Transaction { } }, execute: Execute { - contract_address: Some( - required(&execute.contract_address) - .and_then(|x| parse_h160(x)) - .context("execute.contract_address")?, - ), + contract_address: execute + .contract_address + .as_ref() + .and_then(|x| parse_h160(x).ok()), calldata: required(&execute.calldata).context("calldata")?.clone(), value: required(&execute.value) .and_then(|x| parse_h256(x)) @@ -489,13 +488,7 @@ impl ProtoRepr for proto::Transaction { } }; let execute = proto::Execute { - contract_address: Some( - this.execute - .contract_address - .unwrap_or_default() - .as_bytes() - .into(), - ), + contract_address: this.execute.contract_address.map(|x| x.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(), From d49f3f84814fdbe8dd35c84855cec29284adf024 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 17 Sep 2024 12:22:23 -0300 Subject: [PATCH 13/45] Make address optional for Transaction recipient account --- core/lib/types/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/lib/types/src/lib.rs b/core/lib/types/src/lib.rs index 54e1b40b5b33..86b2e3f03d51 100644 --- a/core/lib/types/src/lib.rs +++ b/core/lib/types/src/lib.rs @@ -104,8 +104,8 @@ impl Eq for Transaction {} impl Transaction { /// Returns recipient account of the transaction. - pub fn recipient_account(&self) -> Address { - self.execute.contract_address.unwrap_or_default() + pub fn recipient_account(&self) -> Option
{ + self.execute.contract_address } pub fn nonce(&self) -> Option { From 5e9179d4558ec84e559dd58311e31561709a8864 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 17 Sep 2024 16:24:30 -0300 Subject: [PATCH 14/45] Optionally add contract address to transaction signature --- core/lib/types/src/tx/execute.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/lib/types/src/tx/execute.rs b/core/lib/types/src/tx/execute.rs index c5d31c0f8a03..c133261bc232 100644 --- a/core/lib/types/src/tx/execute.rs +++ b/core/lib/types/src/tx/execute.rs @@ -72,10 +72,9 @@ 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_or_default().as_bytes()), - ); + if let Some(contract_address) = self.contract_address { + builder.add_member("to", &contract_address); + } 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 From 0034e3e86a9be2c5448dc78939384beec6e3c6bd Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 17 Sep 2024 16:41:45 -0300 Subject: [PATCH 15/45] Check address is not null and reject transaction --- core/lib/types/src/transaction_request.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/lib/types/src/transaction_request.rs b/core/lib/types/src/transaction_request.rs index 057c905d1c66..5f26b1d6a6a5 100644 --- a/core/lib/types/src/transaction_request.rs +++ b/core/lib/types/src/transaction_request.rs @@ -817,6 +817,11 @@ impl L2Tx { let meta = value.eip712_meta.take().unwrap_or_default(); validate_factory_deps(&meta.factory_deps)?; + // TODO: Remove this check when evm equivalence gets enabled + if value.to.is_none() { + return Err(SerializationTransactionError::ToAddressIsNull); + } + let mut tx = L2Tx::new( value.to, value.input.0.clone(), From 9c3dad17cf08589cbe11c7f137af4c89dc4211b2 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 17 Sep 2024 17:42:30 -0300 Subject: [PATCH 16/45] Make test only Execute to always have a valid address instead of null --- core/lib/dal/src/consensus/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/dal/src/consensus/tests.rs b/core/lib/dal/src/consensus/tests.rs index f21d09290a2f..7059f1a74ea0 100644 --- a/core/lib/dal/src/consensus/tests.rs +++ b/core/lib/dal/src/consensus/tests.rs @@ -17,7 +17,7 @@ use crate::tests::mock_protocol_upgrade_transaction; fn execute(rng: &mut impl Rng) -> Execute { Execute { - contract_address: rng.gen(), + contract_address: Some(rng.gen()), value: rng.gen::().into(), calldata: (0..10 * 32).map(|_| rng.gen()).collect(), // TODO: find a way to generate valid random bytecode. From 96523684d3bf6a599f12b7cc1839eced6738c5bd Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 17 Sep 2024 20:05:49 -0300 Subject: [PATCH 17/45] Update execute use for tests in multivm crate to have a valid contract address --- core/lib/multivm/src/versions/vm_1_4_1/tests/gas_limit.rs | 6 ++---- core/lib/multivm/src/versions/vm_1_4_2/tests/gas_limit.rs | 6 ++---- .../src/versions/vm_boojum_integration/tests/gas_limit.rs | 6 ++---- core/lib/multivm/src/versions/vm_fast/tests/gas_limit.rs | 5 ++++- core/lib/multivm/src/versions/vm_latest/tests/gas_limit.rs | 5 ++++- .../src/versions/vm_refunds_enhancement/tests/gas_limit.rs | 6 ++---- .../src/versions/vm_virtual_blocks/tests/gas_limit.rs | 6 ++---- 7 files changed, 18 insertions(+), 22 deletions(-) diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/gas_limit.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/gas_limit.rs index 0ec921450daf..9dfda9e1a68c 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/tests/gas_limit.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/gas_limit.rs @@ -21,10 +21,8 @@ fn test_tx_gas_limit_offset() { let gas_limit = 9999.into(); let tx = vm.rich_accounts[0].get_l2_tx_for_execute( Execute { - contract_address: Default::default(), - calldata: vec![], - value: Default::default(), - factory_deps: None, + contract_address: Some(Default::default()), + ..Default::default() }, Some(Fee { gas_limit, diff --git a/core/lib/multivm/src/versions/vm_1_4_2/tests/gas_limit.rs b/core/lib/multivm/src/versions/vm_1_4_2/tests/gas_limit.rs index 6a57fd07ae71..b84e9d32126c 100644 --- a/core/lib/multivm/src/versions/vm_1_4_2/tests/gas_limit.rs +++ b/core/lib/multivm/src/versions/vm_1_4_2/tests/gas_limit.rs @@ -20,10 +20,8 @@ fn test_tx_gas_limit_offset() { let gas_limit = 9999.into(); let tx = vm.rich_accounts[0].get_l2_tx_for_execute( Execute { - contract_address: Default::default(), - calldata: vec![], - value: Default::default(), - factory_deps: None, + contract_address: Some(Default::default()), + ..Default::default() }, Some(Fee { gas_limit, diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/gas_limit.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/gas_limit.rs index 30a65097111d..637fd94c1c89 100644 --- a/core/lib/multivm/src/versions/vm_boojum_integration/tests/gas_limit.rs +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/gas_limit.rs @@ -21,10 +21,8 @@ fn test_tx_gas_limit_offset() { let gas_limit = 9999.into(); let tx = vm.rich_accounts[0].get_l2_tx_for_execute( Execute { - contract_address: Default::default(), - calldata: vec![], - value: Default::default(), - factory_deps: None, + contract_address: Some(Default::default()), + ..Default::default() }, Some(Fee { gas_limit, diff --git a/core/lib/multivm/src/versions/vm_fast/tests/gas_limit.rs b/core/lib/multivm/src/versions/vm_fast/tests/gas_limit.rs index b7a2154bdc71..3f0a47b980e2 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/gas_limit.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/gas_limit.rs @@ -18,7 +18,10 @@ fn test_tx_gas_limit_offset() { let gas_limit = 9999.into(); let tx = vm.rich_accounts[0].get_l2_tx_for_execute( - Execute::default(), + Execute { + contract_address: Some(Default::default()), + ..Default::default() + }, Some(Fee { gas_limit, ..Account::default_fee() diff --git a/core/lib/multivm/src/versions/vm_latest/tests/gas_limit.rs b/core/lib/multivm/src/versions/vm_latest/tests/gas_limit.rs index 34e1e2d25f31..cc9aac5bb91b 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/gas_limit.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/gas_limit.rs @@ -21,7 +21,10 @@ fn test_tx_gas_limit_offset() { let gas_limit = 9999.into(); let tx = vm.rich_accounts[0].get_l2_tx_for_execute( - Execute::default(), + Execute { + contract_address: Some(Default::default()), + ..Default::default() + }, Some(Fee { gas_limit, ..Account::default_fee() diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/tests/gas_limit.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/tests/gas_limit.rs index 0ea1669cf217..1ff6ce12557f 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/tests/gas_limit.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/tests/gas_limit.rs @@ -21,10 +21,8 @@ fn test_tx_gas_limit_offset() { let gas_limit = 9999.into(); let tx = vm.rich_accounts[0].get_l2_tx_for_execute( Execute { - contract_address: Default::default(), - calldata: vec![], - value: Default::default(), - factory_deps: None, + contract_address: Some(Default::default()), + ..Default::default() }, Some(Fee { gas_limit, diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/tests/gas_limit.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/tests/gas_limit.rs index 01ebe4c0d225..e51b8cab570e 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/tests/gas_limit.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/tests/gas_limit.rs @@ -21,10 +21,8 @@ fn test_tx_gas_limit_offset() { let gas_limit = 9999.into(); let tx = vm.rich_accounts[0].get_l2_tx_for_execute( Execute { - contract_address: Default::default(), - calldata: vec![], - value: Default::default(), - factory_deps: None, + contract_address: Some(Default::default()), + ..Default::default() }, Some(Fee { gas_limit, From 189e591222736930a6e18eb6665f23844f34043e Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 18 Sep 2024 10:52:43 -0300 Subject: [PATCH 18/45] Update comment for optional field in execute proto message --- core/lib/dal/src/consensus/proto/mod.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/dal/src/consensus/proto/mod.proto b/core/lib/dal/src/consensus/proto/mod.proto index da9151f10f4d..3ea49e9c0cd6 100644 --- a/core/lib/dal/src/consensus/proto/mod.proto +++ b/core/lib/dal/src/consensus/proto/mod.proto @@ -102,7 +102,7 @@ message ProtocolUpgradeTxCommonData { } message Execute { - optional bytes contract_address = 1; // required; H160 + optional bytes contract_address = 1; // optional; H160 optional bytes calldata = 2; // required optional bytes value = 3; // required; U256 repeated bytes factory_deps = 4; From 2ac399e174d4f53c3c94f02e5c128fbb7e6bcea6 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 18 Sep 2024 11:55:47 -0300 Subject: [PATCH 19/45] Unwrap contract address for l1 tx since it should always be present --- core/lib/types/src/l1/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/lib/types/src/l1/mod.rs b/core/lib/types/src/l1/mod.rs index 215836cb52f5..e8144c75db2e 100644 --- a/core/lib/types/src/l1/mod.rs +++ b/core/lib/types/src/l1/mod.rs @@ -274,7 +274,9 @@ 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.unwrap_or_default()), + // Unwrap used here because the contract address should always be present for L1 transactions. + // TODO: Consider restricting the contract address to not be optional in L1Tx. + to: address_to_u256(&t.execute.contract_address.unwrap()), 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, From be7793810acb7e5a517389d44ae08815fb400607 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 19 Sep 2024 12:59:02 -0300 Subject: [PATCH 20/45] Remove tests for the evm simulator --- .../evm-contracts/ConstructorRevert.sol | 11 - .../evm-contracts/CounterFallback.sol | 14 - .../evm-contracts/CounterWithParam.sol | 39 - .../ts-integration/evm-contracts/Creator.sol | 19 - .../evm-contracts/CreatorFallback.sol | 20 - .../ts-integration/evm-contracts/ERC20.sol | 78 -- .../evm-contracts/GasCaller.sol | 16 - .../evm-contracts/OpcodeTest.sol | 123 --- .../evm-contracts/OpcodeTestFallback.sol | 139 --- .../evm-contracts/ProxyCaller.sol | 25 - .../evm-contracts/SelfDestruct.sol | 13 - .../evm-contracts/UniswapFallback.sol | 125 --- .../tests/evm-contracts.test.ts | 828 ------------------ 13 files changed, 1450 deletions(-) delete mode 100644 core/tests/ts-integration/evm-contracts/ConstructorRevert.sol delete mode 100644 core/tests/ts-integration/evm-contracts/CounterFallback.sol delete mode 100644 core/tests/ts-integration/evm-contracts/CounterWithParam.sol delete mode 100644 core/tests/ts-integration/evm-contracts/Creator.sol delete mode 100644 core/tests/ts-integration/evm-contracts/CreatorFallback.sol delete mode 100644 core/tests/ts-integration/evm-contracts/ERC20.sol delete mode 100644 core/tests/ts-integration/evm-contracts/GasCaller.sol delete mode 100644 core/tests/ts-integration/evm-contracts/OpcodeTest.sol delete mode 100644 core/tests/ts-integration/evm-contracts/OpcodeTestFallback.sol delete mode 100644 core/tests/ts-integration/evm-contracts/ProxyCaller.sol delete mode 100644 core/tests/ts-integration/evm-contracts/SelfDestruct.sol delete mode 100644 core/tests/ts-integration/evm-contracts/UniswapFallback.sol delete mode 100644 core/tests/ts-integration/tests/evm-contracts.test.ts diff --git a/core/tests/ts-integration/evm-contracts/ConstructorRevert.sol b/core/tests/ts-integration/evm-contracts/ConstructorRevert.sol deleted file mode 100644 index 868e57edca79..000000000000 --- a/core/tests/ts-integration/evm-contracts/ConstructorRevert.sol +++ /dev/null @@ -1,11 +0,0 @@ -// 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 deleted file mode 100644 index c67dfec9459e..000000000000 --- a/core/tests/ts-integration/evm-contracts/CounterFallback.sol +++ /dev/null @@ -1,14 +0,0 @@ -// 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 deleted file mode 100644 index 714b4d665ae3..000000000000 --- a/core/tests/ts-integration/evm-contracts/CounterWithParam.sol +++ /dev/null @@ -1,39 +0,0 @@ -// 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) public payable 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"; - } -} diff --git a/core/tests/ts-integration/evm-contracts/Creator.sol b/core/tests/ts-integration/evm-contracts/Creator.sol deleted file mode 100644 index 63a6f7e3b1d7..000000000000 --- a/core/tests/ts-integration/evm-contracts/Creator.sol +++ /dev/null @@ -1,19 +0,0 @@ -// 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 deleted file mode 100644 index 30ebabd7cc7a..000000000000 --- a/core/tests/ts-integration/evm-contracts/CreatorFallback.sol +++ /dev/null @@ -1,20 +0,0 @@ -// 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 deleted file mode 100644 index 1b65e6541804..000000000000 --- a/core/tests/ts-integration/evm-contracts/ERC20.sol +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity >=0.7.0; - -contract ERC20 { - string public symbol; - string public name; - uint8 public decimals; - uint256 public totalSupply; - - 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); - - 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 (uint256 balance) { - return balances[tokenOwner]; - } - - 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, 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, - 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); - emit Transfer(from, to, tokens); - return true; - } - - function allowance(address tokenOwner, address spender) public view returns (uint256 remaining) { - return allowed[tokenOwner][spender]; - } - - function safeAdd(uint256 a, uint256 b) internal pure returns (uint256 c) { - c = a + b; - require(c >= a); - } - - function safeSub(uint256 a, uint256 b) internal pure returns (uint256 c) { - require(b <= a); - c = a - b; - } - - function safeMul(uint256 a, uint256 b) internal pure returns (uint256 c) { - c = a * b; - require(a == 0 || c / a == b); - } - - 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 deleted file mode 100644 index 25b56aa744d6..000000000000 --- a/core/tests/ts-integration/evm-contracts/GasCaller.sol +++ /dev/null @@ -1,16 +0,0 @@ -// 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 deleted file mode 100644 index 721339bd7ae8..000000000000 --- a/core/tests/ts-integration/evm-contracts/OpcodeTest.sol +++ /dev/null @@ -1,123 +0,0 @@ -// 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 deleted file mode 100644 index 47f427a27333..000000000000 --- a/core/tests/ts-integration/evm-contracts/OpcodeTestFallback.sol +++ /dev/null @@ -1,139 +0,0 @@ -// 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 deleted file mode 100644 index 379d7c7addcd..000000000000 --- a/core/tests/ts-integration/evm-contracts/ProxyCaller.sol +++ /dev/null @@ -1,25 +0,0 @@ -// 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(); - } -} diff --git a/core/tests/ts-integration/evm-contracts/SelfDestruct.sol b/core/tests/ts-integration/evm-contracts/SelfDestruct.sol deleted file mode 100644 index 12fec9555908..000000000000 --- a/core/tests/ts-integration/evm-contracts/SelfDestruct.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity >=0.7.0; - -contract SelfDestruct { - constructor() payable {} - - 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 deleted file mode 100644 index 0237b4be1ba5..000000000000 --- a/core/tests/ts-integration/evm-contracts/UniswapFallback.sol +++ /dev/null @@ -1,125 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity ^0.8.0; - -interface IUniswapV2ERC20 { - 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); - - function symbol() external pure returns (string memory); - - function decimals() external pure returns (uint8); - - function totalSupply() external returns (uint256); - - function balanceOf(address owner) external returns (uint256); - - function allowance(address owner, address spender) external returns (uint256); - - function approve(address spender, uint256 value) external returns (bool); - - function transfer(address to, uint256 value) external returns (bool); - - function transferFrom( - address from, - address to, - uint256 value - ) external returns (bool); - - function DOMAIN_SEPARATOR() external returns (bytes32); - - function PERMIT_TYPEHASH() external pure returns (bytes32); - - function nonces(address owner) external returns (uint256); - - function permit( - address owner, - address spender, - uint256 value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) external; -} - -interface IUniswapV2Pair { - 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, - uint256 amount0In, - uint256 amount1In, - uint256 amount0Out, - uint256 amount1Out, - address indexed to - ); - event Sync(uint112 reserve0, uint112 reserve1); - - function MINIMUM_LIQUIDITY() external pure returns (uint256); - - 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 (uint256); - - function price1CumulativeLast() external returns (uint256); - - function kLast() external returns (uint256); - - function mint(address to) external returns (uint256 liquidity); - - function burn(address to) external returns (uint256 amount0, uint256 amount1); - - function swap( - uint256 amount0Out, - uint256 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"); - uint256 balance = uniswapPair2.balanceOf(alice_address); - //uniswapPair2.transfer(address(uniswapPair),balance); - //uniswapPair.burn(alice_address); - } -} diff --git a/core/tests/ts-integration/tests/evm-contracts.test.ts b/core/tests/ts-integration/tests/evm-contracts.test.ts deleted file mode 100644 index 90eb0975f021..000000000000 --- a/core/tests/ts-integration/tests/evm-contracts.test.ts +++ /dev/null @@ -1,828 +0,0 @@ -/** - * 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'; - -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.getFunction('callAndGetGas').staticCall(counterContract.getAddress()) - ).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.getFunction('callAndGetGas').staticCall(creatorContract.getAddress()) - ).toString(); - - const expected_gas = '70598'; // Gas cost when run with solidity interpreter - 3 (We have some changes that are needed) - 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.deploymentTransaction()?.wait(); - 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 - ); - - 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.randomBytes(32); - - const expectedAddress = ethers.getCreate2Address( - await evmCreateTester.getAddress(), - salt, - ethers.keccak256(initBytecode) - ); - - await (await evmCreateTester.create2(salt, initBytecode)).wait(); - - await assertCreatedCorrectly(deployer, expectedAddress, runtimeBytecode); - - 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.deploymentTransaction()?.wait(); - } catch (e: any) { - failReason = e.reason; - } - - expect(failReason).toBe(null); - }); - - test('Should NOT create evm contract from EOA when `to` is address(0x0)', async () => { - const args = 1; - - const factory = getEVMContractFactory(alice, artifacts.counter); - const { data, ...rest } = await factory.getDeployTransaction(args); - const dep_transaction = { - ...rest, - to: '0x0000000000000000000000000000000000000000', - chainId: alice.provider._network.chainId, - data - }; - await (await alice.sendTransaction(dep_transaction)).wait(); - const expectedAddressCreate = ethers.getCreateAddress({ - from: alice.address, - nonce: await alice.getNonce() - }); - - await assertContractNotCreated(deployer, expectedAddressCreate); - }); - }); - }); - - 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.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.deploymentTransaction()?.wait(); - await alice.provider.getTransactionReceipt( - proxyCallerContract.deploymentTransaction()?.hash ?? - (() => { - throw new Error('Deployment transaction has failed'); - })() - ); - - expect( - (await proxyCallerContract.getFunction('proxyGet')(await counterContract.getAddress())).toString() - ).toEqual('1'); - - await ( - await proxyCallerContract.getFunction('executeIncrememt')(await counterContract.getAddress(), 1) - ).wait(); - - expect( - (await proxyCallerContract.getFunction('proxyGet')(await counterContract.getAddress())).toString() - ).toEqual('2'); - - expect( - ( - await proxyCallerContract - .getFunction('proxyGetBytes') - .staticCall(await counterContract.getAddress()) - ).toString() - ).toEqual('0x54657374696e67'); - }); - - test('Create opcode works correctly', async () => { - const creatorFactory = getEVMContractFactory(alice, artifacts.creator); - const creatorContract = await creatorFactory.deploy(); - await creatorContract.deploymentTransaction()?.wait(); - - const nonce = 1; - - const runtimeBytecode = await creatorContract.getFunction('getCreationRuntimeCode')(); - - const expectedAddress = ethers.getCreateAddress({ - from: await creatorContract.getAddress(), - nonce - }); - - await (await creatorContract.getFunction('create')()).wait(); - - await assertCreatedCorrectly(deployer, expectedAddress, runtimeBytecode); - }); - - test('Should revert correctly', async () => { - const args = 1; - - const counterFactory = getEVMContractFactory(alice, artifacts.counter); - const counterContract = await counterFactory.deploy(args); - await counterContract.deploymentTransaction()?.wait(); - - let errorString; - - try { - await counterContract.getFunction('incrementWithRevert').staticCall(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.BaseContract; - 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.deploymentTransaction()?.wait(); - nativeToken = await deployContract(alice, contracts.erc20, []); - - 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); - deployLogged = true; - } - await ( - await alice.sendTransaction({ - to: userAccount.address, - value: BigInt('0xffffffffffffff') - }) - ).wait(); - }); - - test('view functions should work', async () => { - 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'); - }); - - 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(); - 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()); - } - - 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(); - const nativeApproveTx = await ( - await nativeToken.connect(alice).getFunction('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()); - } - - const evmTransferFromTx = await ( - 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 - ) - ).wait(); - if (logGasCosts) { - console.log('ERC20 native transferFrom gas: ' + nativeTransferFromTx.gasUsed.toString()); - console.log('ERC20 evm transferFrom gas: ' + evmTransferFromTx.gasUsed.toString()); - } - - 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.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'; - - beforeEach(async () => { - const erc20Factory = getEVMContractFactory(alice, artifacts.erc20); - evmToken1 = await erc20Factory.deploy({ gasLimit }); - await evmToken1.deploymentTransaction()?.wait(); - evmToken2 = await erc20Factory.deploy(); - await evmToken2.deploymentTransaction()?.wait(); - - const evmUniswapFactoryFactory = getEVMContractFactory(alice, artifacts.uniswapV2Factory); - evmUniswapFactory = await evmUniswapFactoryFactory.deploy('0x0000000000000000000000000000000000000000'); - await evmUniswapFactory.deploymentTransaction()?.wait(); - - nativeUniswapFactory = await deployContract( - alice, - contracts.uniswapV2Factory, - ['0x0000000000000000000000000000000000000000'], - undefined, - { - customData: { - factoryDeps: [contracts.uniswapV2Pair.bytecode] - } - } - ); - - const evmPairReceipt = await ( - await evmUniswapFactory.getFunction('createPair')(evmToken1.getAddress(), evmToken2.getAddress()) - ).wait(); - - const nativePairReceipt = await ( - await nativeUniswapFactory.getFunction('createPair')(evmToken1.getAddress(), evmToken2.getAddress()) - ).wait(); - - const evmUniswapPairFactory = getEVMContractFactory(alice, artifacts.uniswapV2Pair); - const nativeUniswapPairFactory = new zksync.ContractFactory( - contracts.uniswapV2Pair.abi, - contracts.uniswapV2Pair.bytecode, - alice - ); - evmUniswapPair = evmUniswapPairFactory.attach( - ethers.AbiCoder.defaultAbiCoder().decode( - ['address', 'uint256'], - evmPairReceipt.logs.find((log: any) => log.topics[0] === NEW_PAIR_TOPIC).data - )[0] - ); - nativeUniswapPair = nativeUniswapPairFactory.attach( - ethers.AbiCoder.defaultAbiCoder().decode( - ['address', 'uint256'], - nativePairReceipt.logs.find((log: any) => log.topics[0] === NEW_PAIR_TOPIC).data - )[0] - ); - 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(); - - // 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); - 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.getFunction('mint')(alice.address)).wait(); - const nativeMintReceipt = await (await nativeUniswapPair.getFunction('mint')(alice.address)).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(); - - await ( - await evmUniswapPair.getFunction('transfer')( - evmUniswapPair.getAddress(), - (await evmUniswapPair.getFunction('balanceOf')(alice.address)).toString() - ) - ).wait(); - await ( - await nativeUniswapPair.getFunction('transfer')( - nativeUniswapPair.getAddress(), - (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 - ); - - 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); - } - }); - - test("Should compare gas against uniswap fallback contract's call", async () => { - 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'); - })() - ); - - 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 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(); - - 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() - // }); - // }); - - afterAll(async () => { - await testMaster.deinitialize(); - if (logGasCosts) { - printCostData(); - } - }); -}); - -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'; - 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) - ); - - expect(storedCodeHash).toEqual(expectedStoredHash); -} - -async function assertCreatedCorrectly( - deployer: zksync.Contract, - deployedAddress: string, - expectedEVMBytecode: string -): Promise { - const expectedStoredHash = getSha256BlobHash(expectedEVMBytecode); - await assertStoredBytecodeHash(deployer, deployedAddress, expectedStoredHash); -} - -function getPaddedBytecode(bytes: ethers.BytesLike) { - const length = ethers.getBytes(bytes).length; - - const encodedLength = ethers.AbiCoder.defaultAbiCoder().encode(['uint256'], [length]); - - 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 - 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.getBytes(ethers.sha256(paddedBytes)); - hash[0] = 2; - hash[1] = 0; - - // Length of the bytecode - const lengthInBytes = ethers.getBytes(paddedBytes).length; - hash[2] = Math.floor(lengthInBytes / 256); - hash[3] = lengthInBytes % 256; - - return ethers.toBeHex(ethers.toBigInt(hash)); -} - -async function assertContractNotCreated(deployer: zksync.Contract, deployedAddress: string): Promise { - assertStoredBytecodeHash(deployer, deployedAddress, ethers.ZeroHash); -} - -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()] = []; -}); From 7608ace8f1eb2c7d4d377e990c831eb4a728b312 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 19 Sep 2024 13:23:28 -0300 Subject: [PATCH 21/45] Delete contracts and aux functions used for evm tests --- .../contracts/create/TestEVMCreate.sol | 30 - .../ts-integration/contracts/token/ERC20.sol | 76 -- .../contracts/uniswap-v2/UniswapV2Factory.sol | 683 ------------------ core/tests/ts-integration/package.json | 6 +- core/tests/ts-integration/src/helpers.ts | 47 -- 5 files changed, 1 insertion(+), 841 deletions(-) delete mode 100644 core/tests/ts-integration/contracts/create/TestEVMCreate.sol delete mode 100644 core/tests/ts-integration/contracts/token/ERC20.sol delete 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 deleted file mode 100644 index 176790d14023..000000000000 --- a/core/tests/ts-integration/contracts/create/TestEVMCreate.sol +++ /dev/null @@ -1,30 +0,0 @@ -// 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 deleted file mode 100644 index 514e2358624f..000000000000 --- a/core/tests/ts-integration/contracts/token/ERC20.sol +++ /dev/null @@ -1,76 +0,0 @@ -// 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; - } - -} diff --git a/core/tests/ts-integration/contracts/uniswap-v2/UniswapV2Factory.sol b/core/tests/ts-integration/contracts/uniswap-v2/UniswapV2Factory.sol deleted file mode 100644 index 91e74bb2b11a..000000000000 --- a/core/tests/ts-integration/contracts/uniswap-v2/UniswapV2Factory.sol +++ /dev/null @@ -1,683 +0,0 @@ -// 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; - } -} diff --git a/core/tests/ts-integration/package.json b/core/tests/ts-integration/package.json index 6196355e95a0..8e5c0cf7470e 100644 --- a/core/tests/ts-integration/package.json +++ b/core/tests/ts-integration/package.json @@ -33,10 +33,6 @@ "typescript": "^4.3.5", "zksync-ethers": "^6.9.0", "elliptic": "^6.5.5", - "yaml": "^2.4.2", - "zksync-web3": "^0.15.5", - "csv-parser": "^3.0.0", - "csv-writer": "^1.6.0", - "solc": "0.8.20" + "yaml": "^2.4.2" } } diff --git a/core/tests/ts-integration/src/helpers.ts b/core/tests/ts-integration/src/helpers.ts index 327a4912a6c0..8e31c1a691ff 100644 --- a/core/tests/ts-integration/src/helpers.ts +++ b/core/tests/ts-integration/src/helpers.ts @@ -4,8 +4,6 @@ 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'; /** @@ -143,48 +141,3 @@ 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); -} From ed97d2415558c1f27c07d5ab494cfafa2cf8427f Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 19 Sep 2024 13:24:38 -0300 Subject: [PATCH 22/45] Fix fmt --- docs/guides/external-node/00_quick_start.md | 4 ++-- prover/crates/lib/prover_dal/src/fri_prover_dal.rs | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/guides/external-node/00_quick_start.md b/docs/guides/external-node/00_quick_start.md index 776e8a56e497..5eb601e3d590 100644 --- a/docs/guides/external-node/00_quick_start.md +++ b/docs/guides/external-node/00_quick_start.md @@ -65,8 +65,8 @@ The HTTP JSON-RPC API can be accessed on port `3060` and WebSocket API can be ac > [!NOTE] > -> To stop historical DB growth, you can enable DB pruning by uncommenting `EN_PRUNING_ENABLED: true` in docker compose file, -> you can read more about pruning in +> To stop historical DB growth, you can enable DB pruning by uncommenting `EN_PRUNING_ENABLED: true` in docker compose +> file, you can read more about pruning in > [08_pruning.md](https://github.com/matter-labs/zksync-era/blob/main/docs/guides/external-node/08_pruning.md) - 32 GB of RAM and a relatively modern CPU diff --git a/prover/crates/lib/prover_dal/src/fri_prover_dal.rs b/prover/crates/lib/prover_dal/src/fri_prover_dal.rs index 1b6c43f4c177..0c6ced8d169a 100644 --- a/prover/crates/lib/prover_dal/src/fri_prover_dal.rs +++ b/prover/crates/lib/prover_dal/src/fri_prover_dal.rs @@ -456,8 +456,14 @@ impl FriProverDal<'_, '_> { SELECT protocol_version AS "protocol_version!", protocol_version_patch AS "protocol_version_patch!", - COUNT(*) FILTER (WHERE status = 'queued') as queued, - COUNT(*) FILTER (WHERE status = 'in_progress') as in_progress + COUNT(*) FILTER ( + WHERE + status = 'queued' + ) AS queued, + COUNT(*) FILTER ( + WHERE + status = 'in_progress' + ) AS in_progress FROM prover_jobs_fri WHERE From f92206890e760f8841de2431feb8e036959988d5 Mon Sep 17 00:00:00 2001 From: Nacho Avecilla Date: Thu, 19 Sep 2024 13:29:24 -0300 Subject: [PATCH 23/45] feat: EVM simulator as optional for the server (#276) * Add evm simulator as optional for the server * Changes to make it work against era-contracts `main` * fmt * Calculate bytecode of evm gas manager only if evm simulator flag is on * Add multicall for get evm simulator bytecode hash * Use bytecode of default account for the evm simulator if not present * Remove unnecessary comments * Use bytecode of default account for evm simulator in gas test sc * Remove tests for the evm simulator --------- Co-authored-by: Javier Chatruc --- Cargo.lock | 6 + contracts | 2 +- .../bin/system-constants-generator/Cargo.toml | 2 + .../system-constants-generator/src/utils.rs | 27 +- core/lib/config/src/configs/mod.rs | 1 + .../config/src/configs/use_evm_simulator.rs | 7 + core/lib/contracts/src/lib.rs | 22 +- core/lib/env_config/src/lib.rs | 1 + core/lib/env_config/src/use_evm_simulator.rs | 9 + core/lib/multivm/Cargo.toml | 2 + .../vm_latest/tracers/default_tracers.rs | 26 +- core/lib/types/Cargo.toml | 1 + core/lib/types/src/system_contracts.rs | 54 +++- core/node/eth_sender/Cargo.toml | 1 + core/node/eth_sender/src/eth_tx_aggregator.rs | 72 +++-- core/node/eth_sender/src/zksync_functions.rs | 4 +- etc/env/base/chain.toml | 6 +- etc/env/base/contracts.toml | 6 +- etc/env/base/use_evm_simulator.toml | 2 + prover/Cargo.lock | 269 ++++++++++++++++++ 20 files changed, 460 insertions(+), 60 deletions(-) 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 68e8b2770607..a6c3689c8a4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7494,7 +7494,9 @@ dependencies = [ "once_cell", "serde", "serde_json", + "zksync_config", "zksync_contracts", + "zksync_env_config", "zksync_multivm", "zksync_types", "zksync_utils", @@ -9813,6 +9815,7 @@ dependencies = [ "zksync_config", "zksync_contracts", "zksync_dal", + "zksync_env_config", "zksync_eth_client", "zksync_l1_contract_interface", "zksync_node_fee_model", @@ -10159,7 +10162,9 @@ dependencies = [ "zk_evm 0.140.0", "zk_evm 0.141.0", "zk_evm 0.150.5", + "zksync_config", "zksync_contracts", + "zksync_env_config", "zksync_eth_signer", "zksync_state", "zksync_system_constants", @@ -10910,6 +10915,7 @@ dependencies = [ "zksync_config", "zksync_contracts", "zksync_crypto_primitives", + "zksync_env_config", "zksync_mini_merkle_tree", "zksync_protobuf", "zksync_protobuf_build", diff --git a/contracts b/contracts index 2edbd6912c6a..bce4b2d0f34b 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 2edbd6912c6a73b120377f5e53fe1cc5343407fc +Subproject commit bce4b2d0f34bd87f1aaadd291772935afb1c3bd6 diff --git a/core/bin/system-constants-generator/Cargo.toml b/core/bin/system-constants-generator/Cargo.toml index 7177d29ca743..39f4b458817d 100644 --- a/core/bin/system-constants-generator/Cargo.toml +++ b/core/bin/system-constants-generator/Cargo.toml @@ -15,6 +15,8 @@ zksync_types.workspace = true zksync_utils.workspace = true zksync_contracts.workspace = true zksync_multivm.workspace = true +zksync_config.workspace = true +zksync_env_config.workspace = true codegen.workspace = true serde.workspace = true diff --git a/core/bin/system-constants-generator/src/utils.rs b/core/bin/system-constants-generator/src/utils.rs index 32b4d04506d1..ac4d66185e33 100644 --- a/core/bin/system-constants-generator/src/utils.rs +++ b/core/bin/system-constants-generator/src/utils.rs @@ -1,10 +1,12 @@ -use std::{cell::RefCell, rc::Rc}; +use std::{cell::RefCell, rc::Rc, str::FromStr}; use once_cell::sync::Lazy; +use zksync_config::configs::use_evm_simulator; use zksync_contracts::{ load_sys_contract, read_bootloader_code, read_bytecode_from_path, read_sys_contract_bytecode, BaseSystemContracts, ContractLanguage, SystemContractCode, }; +use zksync_env_config::FromEnv; use zksync_multivm::{ interface::{ storage::{InMemoryStorage, StorageView, WriteStorage}, @@ -24,8 +26,9 @@ use zksync_types::{ block::L2BlockHasher, ethabi::Token, fee::Fee, fee_model::BatchFeeInput, l1::L1Tx, l2::L2Tx, utils::storage_key_for_eth_balance, AccountTreeId, Address, Execute, K256PrivateKey, L1BatchNumber, L1TxCommonData, L2BlockNumber, L2ChainId, Nonce, ProtocolVersionId, StorageKey, - Transaction, BOOTLOADER_ADDRESS, SYSTEM_CONTEXT_ADDRESS, SYSTEM_CONTEXT_GAS_PRICE_POSITION, - SYSTEM_CONTEXT_TX_ORIGIN_POSITION, U256, ZKPORTER_IS_AVAILABLE, + Transaction, BOOTLOADER_ADDRESS, H256, SYSTEM_CONTEXT_ADDRESS, + SYSTEM_CONTEXT_GAS_PRICE_POSITION, SYSTEM_CONTEXT_TX_ORIGIN_POSITION, U256, + ZKPORTER_IS_AVAILABLE, }; use zksync_utils::{bytecode::hash_bytecode, bytes_to_be_words, u256_to_h256}; @@ -71,9 +74,21 @@ 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); + + let mut evm_simulator_bytecode = bytecode.clone(); + let mut evm_simulator_hash = + H256::from_str("0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32") + .unwrap(); + + if use_evm_simulator::UseEvmSimulator::from_env() + .unwrap() + .use_evm_simulator + { + evm_simulator_bytecode = + read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); + evm_simulator_hash = hash_bytecode(&evm_simulator_bytecode.clone()); + } + BaseSystemContracts { default_aa: SystemContractCode { code: bytes_to_be_words(bytecode), diff --git a/core/lib/config/src/configs/mod.rs b/core/lib/config/src/configs/mod.rs index 1ad503e0687f..456749e05a5e 100644 --- a/core/lib/config/src/configs/mod.rs +++ b/core/lib/config/src/configs/mod.rs @@ -65,6 +65,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/src/lib.rs b/core/lib/contracts/src/lib.rs index 0d3a2a853f0d..5f86f546c767 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -8,6 +8,7 @@ use std::{ fs::{self, File}, io::BufReader, path::{Path, PathBuf}, + str::FromStr, }; use ethabi::{ @@ -16,6 +17,8 @@ use ethabi::{ }; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; +use zksync_config::configs::use_evm_simulator::{self}; +use zksync_env_config::FromEnv; use zksync_utils::{bytecode::hash_bytecode, bytes_to_be_words, env::Workspace}; pub mod test_contracts; @@ -338,13 +341,24 @@ impl BaseSystemContracts { let hash = hash_bytecode(&bytecode); let default_aa = SystemContractCode { - code: bytes_to_be_words(bytecode), + code: bytes_to_be_words(bytecode.clone()), hash, }; - let evm_simulator_bytecode = - read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); - let evm_simulator_hash = hash_bytecode(&evm_simulator_bytecode); + // If evm simulator is not enabled, use the default account bytecode and hash. + let mut evm_simulator_bytecode = bytecode; + let mut evm_simulator_hash = + H256::from_str("0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32") + .unwrap(); + + if use_evm_simulator::UseEvmSimulator::from_env() + .unwrap() + .use_evm_simulator + { + evm_simulator_bytecode = + read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); + evm_simulator_hash = hash_bytecode(&evm_simulator_bytecode); + } let evm_simulator = SystemContractCode { code: bytes_to_be_words(evm_simulator_bytecode), diff --git a/core/lib/env_config/src/lib.rs b/core/lib/env_config/src/lib.rs index b72c2c5d5b94..701817522d37 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/core/lib/multivm/Cargo.toml b/core/lib/multivm/Cargo.toml index 6156c1138890..86e19637b2b6 100644 --- a/core/lib/multivm/Cargo.toml +++ b/core/lib/multivm/Cargo.toml @@ -25,6 +25,8 @@ circuit_sequencer_api_1_4_2.workspace = true circuit_sequencer_api_1_5_0.workspace = true zksync_types.workspace = true +zksync_config.workspace = true +zksync_env_config.workspace = true zksync_contracts.workspace = true zksync_utils.workspace = true zksync_system_constants.workspace = true 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 f7def2a66106..5b61b5174e19 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 @@ -12,6 +12,8 @@ use zk_evm_1_5_0::{ witness_trace::DummyTracer, zkevm_opcode_defs::{decoding::EncodingModeProduction, Opcode, RetOpcode}, }; +use zksync_config::configs::use_evm_simulator::{self}; +use zksync_env_config::FromEnv; use super::{EvmDeployTracer, PubdataTracer}; use crate::{ @@ -64,7 +66,7 @@ pub struct DefaultExecutionTracer { // take into account e.g circuits produced by the initial bootloader memory commitment. pub(crate) circuits_tracer: CircuitsTracer, // This tracer is responsible for handling EVM deployments and providing the data to the code decommitter. - pub(crate) evm_deploy_tracer: EvmDeployTracer, + pub(crate) evm_deploy_tracer: Option>, subversion: MultiVMSubversion, storage: StoragePtr, _phantom: PhantomData, @@ -80,6 +82,9 @@ impl DefaultExecutionTracer { pubdata_tracer: Option>, subversion: MultiVMSubversion, ) -> Self { + let active_evm = use_evm_simulator::UseEvmSimulator::from_env() + .unwrap() + .use_evm_simulator; Self { tx_has_been_processed: false, execution_mode, @@ -94,7 +99,11 @@ impl DefaultExecutionTracer { pubdata_tracer, ret_from_the_bootloader: None, circuits_tracer: CircuitsTracer::new(), - evm_deploy_tracer: EvmDeployTracer::new(), + evm_deploy_tracer: if active_evm { + Some(EvmDeployTracer::new()) + } else { + None + }, storage, _phantom: PhantomData, } @@ -175,7 +184,9 @@ macro_rules! dispatch_tracers { tracer.$function($( $params ),*); } $self.circuits_tracer.$function($( $params ),*); - $self.evm_deploy_tracer.$function($( $params ),*); + if let Some(tracer) = &mut $self.evm_deploy_tracer { + tracer.$function($( $params ),*); + } }; } @@ -293,10 +304,11 @@ impl DefaultExecutionTracer { .finish_cycle(state, bootloader_state) .stricter(&result); - result = self - .evm_deploy_tracer - .finish_cycle(state, bootloader_state) - .stricter(&result); + if let Some(evm_deploy_tracer) = &mut self.evm_deploy_tracer { + result = evm_deploy_tracer + .finish_cycle(state, bootloader_state) + .stricter(&result); + } result.stricter(&self.should_stop_execution()) } diff --git a/core/lib/types/Cargo.toml b/core/lib/types/Cargo.toml index 54c38384a7ad..f976c26b71c1 100644 --- a/core/lib/types/Cargo.toml +++ b/core/lib/types/Cargo.toml @@ -17,6 +17,7 @@ zksync_basic_types.workspace = true zksync_contracts.workspace = true zksync_mini_merkle_tree.workspace = true zksync_config.workspace = true +zksync_env_config.workspace = true zksync_protobuf.workspace = true zksync_crypto_primitives.workspace = true diff --git a/core/lib/types/src/system_contracts.rs b/core/lib/types/src/system_contracts.rs index 57ca0150f7f4..f88e24e21ca7 100644 --- a/core/lib/types/src/system_contracts.rs +++ b/core/lib/types/src/system_contracts.rs @@ -1,8 +1,10 @@ -use std::path::PathBuf; +use std::{path::PathBuf, str::FromStr}; use once_cell::sync::Lazy; use zksync_basic_types::{AccountTreeId, Address, H256, U256}; +use zksync_config::configs::use_evm_simulator; use zksync_contracts::{read_sys_contract_bytecode, ContractLanguage, SystemContractsRepo}; +use zksync_env_config::FromEnv; 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, @@ -179,11 +181,19 @@ static SYSTEM_CONTRACT_LIST: [(&str, &str, Address, ContractLanguage); 26] = [ ]; static EVM_SIMULATOR_HASH: Lazy = Lazy::new(|| { - hash_bytecode(&read_sys_contract_bytecode( - "", - "EvmInterpreter", - ContractLanguage::Yul, - )) + if use_evm_simulator::UseEvmSimulator::from_env() + .unwrap() + .use_evm_simulator + { + hash_bytecode(&read_sys_contract_bytecode( + "", + "EvmInterpreter", + ContractLanguage::Yul, + )) + } else { + H256::from_str("0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32") + .unwrap() + } }); pub fn get_evm_simulator_hash() -> H256 { @@ -191,11 +201,21 @@ pub fn get_evm_simulator_hash() -> H256 { } static SYSTEM_CONTRACTS: Lazy> = Lazy::new(|| { + let evm_simulator_is_used = use_evm_simulator::UseEvmSimulator::from_env() + .unwrap() + .use_evm_simulator; SYSTEM_CONTRACT_LIST .iter() - .map(|(path, name, address, contract_lang)| DeployedContract { - account_id: AccountTreeId::new(*address), - bytecode: read_sys_contract_bytecode(path, name, contract_lang.clone()), + .filter_map(|(path, name, address, contract_lang)| { + let result = if *name == "EvmGasManager" && !evm_simulator_is_used { + None + } else { + Some(DeployedContract { + account_id: AccountTreeId::new(*address), + bytecode: read_sys_contract_bytecode(path, name, contract_lang.clone()), + }) + }; + result }) .collect::>() }); @@ -207,12 +227,22 @@ pub fn get_system_smart_contracts() -> Vec { /// Loads system contracts from a given directory. pub fn get_system_smart_contracts_from_dir(path: PathBuf) -> Vec { + let evm_simulator_is_used = use_evm_simulator::UseEvmSimulator::from_env() + .unwrap() + .use_evm_simulator; let repo = SystemContractsRepo { root: path }; SYSTEM_CONTRACT_LIST .iter() - .map(|(path, name, address, contract_lang)| DeployedContract { - account_id: AccountTreeId::new(*address), - bytecode: repo.read_sys_contract_bytecode(path, name, contract_lang.clone()), + .filter_map(|(path, name, address, contract_lang)| { + let result = if *name == "EvmGasManager" && !evm_simulator_is_used { + None + } else { + Some(DeployedContract { + account_id: AccountTreeId::new(*address), + bytecode: repo.read_sys_contract_bytecode(path, name, contract_lang.clone()), + }) + }; + result }) .collect::>() } diff --git a/core/node/eth_sender/Cargo.toml b/core/node/eth_sender/Cargo.toml index a7aa88c3550e..d58c7488262d 100644 --- a/core/node/eth_sender/Cargo.toml +++ b/core/node/eth_sender/Cargo.toml @@ -15,6 +15,7 @@ vise.workspace = true zksync_types.workspace = true zksync_dal.workspace = true zksync_config.workspace = true +zksync_env_config.workspace = true zksync_contracts.workspace = true zksync_eth_client.workspace = true zksync_utils.workspace = true diff --git a/core/node/eth_sender/src/eth_tx_aggregator.rs b/core/node/eth_sender/src/eth_tx_aggregator.rs index f07cecb0dfa4..49a108231b2a 100644 --- a/core/node/eth_sender/src/eth_tx_aggregator.rs +++ b/core/node/eth_sender/src/eth_tx_aggregator.rs @@ -1,7 +1,13 @@ +use std::str::FromStr; + use tokio::sync::watch; -use zksync_config::configs::eth_sender::SenderConfig; +use zksync_config::configs::{ + eth_sender::SenderConfig, + use_evm_simulator::{self}, +}; use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; +use zksync_env_config::FromEnv; use zksync_eth_client::{BoundEthInterface, CallFunctionArgs}; use zksync_l1_contract_interface::{ i_executor::{ @@ -186,12 +192,17 @@ impl EthTxAggregator { 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, + .as_ref() + .and_then(|f| f.encode_input(&[]).ok()); + + let get_evm_simulator_hash_call = if let Some(input) = get_l2_evm_simulator_hash_input { + Some(Multicall3Call { + target: self.state_transition_chain_contract, + allow_failure: ALLOW_FAILURE, + calldata: input, + }) + } else { + None }; // Third zksync contract call @@ -226,15 +237,19 @@ impl EthTxAggregator { calldata: get_protocol_version_input, }; - // Convert structs into tokens and return vector with them - vec![ + let mut token_vec = 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(), - ] + ]; + + if let Some(call) = get_evm_simulator_hash_call { + token_vec.push(call.into_token()); + } + + token_vec } // The role of the method below is to de-tokenize multicall call's result, which is actually a token. @@ -250,8 +265,12 @@ impl EthTxAggregator { }; if let Token::Array(call_results) = token { + let use_evm_simulator = use_evm_simulator::UseEvmSimulator::from_env() + .unwrap() + .use_evm_simulator; + let number_of_calls = if use_evm_simulator { 6 } else { 5 }; // 5 calls are aggregated in multicall - if call_results.len() != 6 { + if call_results.len() != number_of_calls { return parse_error(&call_results); } let mut call_results_iterator = call_results.into_iter(); @@ -280,17 +299,26 @@ 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 mut evm_simulator = H256::from_str( + "0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32", + ) + .unwrap(); + + if use_evm_simulator { + 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 + ), + ))); + } + evm_simulator = H256::from_slice(&multicall3_evm_simulator); } - let evm_simulator = H256::from_slice(&multicall3_evm_simulator); let base_system_contracts_hashes = BaseSystemContractsHashes { bootloader, diff --git a/core/node/eth_sender/src/zksync_functions.rs b/core/node/eth_sender/src/zksync_functions.rs index 577c18277da0..6779ac24836c 100644 --- a/core/node/eth_sender/src/zksync_functions.rs +++ b/core/node/eth_sender/src/zksync_functions.rs @@ -12,7 +12,7 @@ pub(super) struct ZkSyncFunctions { pub(super) get_l2_bootloader_bytecode_hash: Function, pub(super) get_l2_default_account_bytecode_hash: Function, pub(super) get_verifier: Function, - pub(super) get_evm_simulator_bytecode_hash: Function, + pub(super) get_evm_simulator_bytecode_hash: Option, pub(super) get_verifier_params: Function, pub(super) get_protocol_version: Function, @@ -61,7 +61,7 @@ impl Default for ZkSyncFunctions { let get_l2_default_account_bytecode_hash = get_function(&zksync_contract, "getL2DefaultAccountBytecodeHash"); let get_evm_simulator_bytecode_hash = - get_function(&zksync_contract, "getL2EvmSimulatorBytecodeHash"); + get_optional_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"); diff --git a/etc/env/base/chain.toml b/etc/env/base/chain.toml index 5bdb08e3f952..15b14c9f2cc1 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 = "0x010008bbde6fc402ea3a3d6cb15cb97e70245d3d4e48fb74362d4961b74c16b1" -default_aa_hash = "0x0100058de8a8fda78449f14bece247271bdbba5dc73fc96135c35a17ee4dd090" -evm_simulator_hash = "0x01000cdf5bb7dd8a97faf231a5e1e20f2fe308d6f200c3295c6e3629547cc4a4" +bootloader_hash = "0x010008e742608b21bf7eb23c1a9d0602047e3618b464c9b59c0fba3b3d7ab66e" +default_aa_hash = "0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32" +evm_simulator_hash = "0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32" protective_reads_persistence_enabled = false diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index 69bcbf6dabec..daa317a8bc90 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 = "0x79679719d4932b95d89e1ad1faeccb4982bed5ca79f738d3d72d3cfcea6f3722" -GENESIS_BATCH_COMMITMENT = "0xb793269d781342f2980720a9da3009d91cfebb5187977b69807fea8444c5cb2f" +GENESIS_ROOT = "0xabdb766b18a479a5c783a4b80e12686bc8ea3cc2d8a3050491b701d72370ebb5" +GENESIS_BATCH_COMMITMENT = "0x2d00e5f8d77afcebf58a6b82ae56ba967566fe7dfbcb6760319fb0d215d18ffd" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 -GENESIS_ROLLUP_LEAF_INDEX = "56" +GENESIS_ROLLUP_LEAF_INDEX = "54" GENESIS_PROTOCOL_VERSION = "24" GENESIS_PROTOCOL_SEMANTIC_VERSION = "0.24.2" L1_WETH_BRIDGE_IMPL_ADDR = "0x5E6D086F5eC079ADFF4FB3774CDf3e8D6a34F7E9" diff --git a/etc/env/base/use_evm_simulator.toml b/etc/env/base/use_evm_simulator.toml new file mode 100644 index 000000000000..0db670361f16 --- /dev/null +++ b/etc/env/base/use_evm_simulator.toml @@ -0,0 +1,2 @@ +[use_evm_simulator] +use_evm_simulator = false diff --git a/prover/Cargo.lock b/prover/Cargo.lock index 5624403d7853..57d160560b0d 100644 --- a/prover/Cargo.lock +++ b/prover/Cargo.lock @@ -355,6 +355,18 @@ dependencies = [ "tracing", ] +[[package]] +name = "backon" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d67782c3f868daa71d3533538e98a8e13713231969def7536e8039606fc46bf0" +dependencies = [ + "fastrand", + "futures-core", + "pin-project", + "tokio", +] + [[package]] name = "backtrace" version = "0.3.72" @@ -460,6 +472,27 @@ dependencies = [ "which", ] +[[package]] +name = "bindgen" +version = "0.65.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "prettyplease", + "proc-macro2 1.0.85", + "quote 1.0.36", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.66", +] + [[package]] name = "bindgen" version = "0.69.4" @@ -731,6 +764,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "bytecount" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" + [[package]] name = "byteorder" version = "1.5.0" @@ -743,6 +782,48 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + [[package]] name = "cc" version = "1.1.14" @@ -1360,6 +1441,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "debugid" version = "0.8.0" @@ -1718,6 +1812,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "version_check", +] + [[package]] name = "etcetera" version = "0.8.0" @@ -3064,6 +3167,22 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "librocksdb-sys" +version = "0.11.0+8.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3386f101bcb4bd252d8e9d2fb41ec3b0862a15a62b478c355b2982efa469e3e" +dependencies = [ + "bindgen 0.65.1", + "bzip2-sys", + "cc", + "glob", + "libc", + "libz-sys", + "lz4-sys", + "zstd-sys", +] + [[package]] name = "libsqlite3-sys" version = "0.30.1" @@ -3075,6 +3194,17 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "libz-sys" +version = "1.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -3141,6 +3271,16 @@ dependencies = [ "logos-codegen", ] +[[package]] +name = "lz4-sys" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb44a01837a858d47e5a630d2ccf304c8efcc4b83b8f9f75b7a9ee4fcc6e57d" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "match_cfg" version = "0.1.0" @@ -3223,6 +3363,21 @@ dependencies = [ "unicase", ] +[[package]] +name = "mini-moka" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c325dfab65f261f386debee8b0969da215b3fa0037e74c8a1234db7ba986d803" +dependencies = [ + "crossbeam-channel", + "crossbeam-utils", + "dashmap", + "skeptic", + "smallvec", + "tagptr", + "triomphe", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -4282,6 +4437,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "pulldown-cmark" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" +dependencies = [ + "bitflags 2.6.0", + "memchr", + "unicase", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -4690,6 +4856,16 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "rocksdb" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6f170a4041d50a0ce04b0d2e14916d6ca863ea2e422689a5b694395d299ffe" +dependencies = [ + "libc", + "librocksdb-sys", +] + [[package]] name = "rsa" version = "0.9.6" @@ -4997,6 +5173,9 @@ name = "semver" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] [[package]] name = "send_wrapper" @@ -5385,6 +5564,21 @@ dependencies = [ "time", ] +[[package]] +name = "skeptic" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" +dependencies = [ + "bytecount", + "cargo_metadata", + "error-chain", + "glob", + "pulldown-cmark", + "tempfile", + "walkdir", +] + [[package]] name = "slab" version = "0.4.9" @@ -5864,6 +6058,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "tap" version = "1.0.1" @@ -6313,6 +6513,12 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "triomphe" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6631e42e10b40c0690bf92f404ebcfe6e1fdb480391d15f17cc8e96eeed5369" + [[package]] name = "try-lock" version = "0.2.5" @@ -7485,6 +7691,8 @@ dependencies = [ "once_cell", "serde", "serde_json", + "zksync_config", + "zksync_env_config", "zksync_utils", ] @@ -7681,6 +7889,7 @@ dependencies = [ "circuit_sequencer_api 0.141.2", "circuit_sequencer_api 0.142.2", "circuit_sequencer_api 0.150.5", + "ethabi", "hex", "itertools 0.10.5", "once_cell", @@ -7693,7 +7902,10 @@ dependencies = [ "zk_evm 0.140.0", "zk_evm 0.141.0", "zk_evm 0.150.5", + "zksync_config", "zksync_contracts", + "zksync_env_config", + "zksync_state", "zksync_system_constants", "zksync_types", "zksync_utils", @@ -7995,6 +8207,51 @@ dependencies = [ "zksync_utils", ] +[[package]] +name = "zksync_shared_metrics" +version = "0.1.0" +dependencies = [ + "rustc_version", + "tracing", + "vise", + "zksync_dal", + "zksync_types", +] + +[[package]] +name = "zksync_state" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "backon", + "chrono", + "itertools 0.10.5", + "mini-moka", + "once_cell", + "tokio", + "tracing", + "vise", + "zksync_dal", + "zksync_shared_metrics", + "zksync_storage", + "zksync_types", + "zksync_utils", + "zksync_vm_interface", +] + +[[package]] +name = "zksync_storage" +version = "0.1.0" +dependencies = [ + "num_cpus", + "once_cell", + "rocksdb", + "thread_local", + "tracing", + "vise", +] + [[package]] name = "zksync_system_constants" version = "0.1.0" @@ -8031,6 +8288,7 @@ dependencies = [ "zksync_config", "zksync_contracts", "zksync_crypto_primitives", + "zksync_env_config", "zksync_mini_merkle_tree", "zksync_protobuf", "zksync_protobuf_build", @@ -8137,6 +8395,7 @@ dependencies = [ "zksync_contracts", "zksync_system_constants", "zksync_types", + "zksync_utils", ] [[package]] @@ -8223,3 +8482,13 @@ dependencies = [ "zksync_utils", "zksync_vlog", ] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] From 2388ae823225f524051d10eacd0dab6e716de1b6 Mon Sep 17 00:00:00 2001 From: Javier Chatruc Date: Thu, 19 Sep 2024 13:31:26 -0300 Subject: [PATCH 24/45] Revert multivm bootloader change --- .../fee_estimate.yul/fee_estimate.yul.zbin | Bin 74912 -> 76320 bytes .../gas_test.yul/gas_test.yul.zbin | Bin 71008 -> 72416 bytes .../playground_batch.yul.zbin | Bin 75104 -> 76512 bytes .../proved_batch.yul/proved_batch.yul.zbin | Bin 71520 -> 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 ad45ddb49571509167df6fd155d50130db9b6afb..75ee6377bdb645532c55f06f0e883cc078b5bd2b 100644 GIT binary patch literal 76320 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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 aa92225a4782a7a937208a46dbee5dbac7da7dcb..b1a5e063d84b66ebea9a6e021ef42d29b1346760 100644 GIT binary patch literal 76512 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 PUBCIJ&;7~A_uTs5GOKah literal 75104 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 gzj^U9AG=}E?OV2O{*T Date: Thu, 19 Sep 2024 14:52:55 -0300 Subject: [PATCH 25/45] Check for evm simulator to avoid failing for transactions with null contract address --- core/lib/types/src/transaction_request.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/lib/types/src/transaction_request.rs b/core/lib/types/src/transaction_request.rs index 5f26b1d6a6a5..e99e228086fb 100644 --- a/core/lib/types/src/transaction_request.rs +++ b/core/lib/types/src/transaction_request.rs @@ -4,6 +4,8 @@ use rlp::{DecoderError, Rlp, RlpStream}; use serde::{Deserialize, Serialize}; use thiserror::Error; use zksync_basic_types::H256; +use zksync_config::configs::use_evm_simulator; +use zksync_env_config::FromEnv; use zksync_system_constants::{DEFAULT_L2_TX_GAS_PER_PUBDATA_BYTE, MAX_ENCODED_TX_SIZE}; use zksync_utils::{ bytecode::{hash_bytecode, validate_bytecode, InvalidBytecodeError}, @@ -817,8 +819,11 @@ impl L2Tx { let meta = value.eip712_meta.take().unwrap_or_default(); validate_factory_deps(&meta.factory_deps)?; + let use_evm_simulator = use_evm_simulator::UseEvmSimulator::from_env() + .unwrap() + .use_evm_simulator; // TODO: Remove this check when evm equivalence gets enabled - if value.to.is_none() { + if value.to.is_none() && !use_evm_simulator { return Err(SerializationTransactionError::ToAddressIsNull); } From c14b5aa95f8354265d8886f48fa0b2675fbe12f7 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 19 Sep 2024 14:53:34 -0300 Subject: [PATCH 26/45] Fix multicall with evm simulator on --- core/node/eth_sender/src/eth_tx_aggregator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/node/eth_sender/src/eth_tx_aggregator.rs b/core/node/eth_sender/src/eth_tx_aggregator.rs index 49a108231b2a..2ce923fa1213 100644 --- a/core/node/eth_sender/src/eth_tx_aggregator.rs +++ b/core/node/eth_sender/src/eth_tx_aggregator.rs @@ -246,7 +246,7 @@ impl EthTxAggregator { ]; if let Some(call) = get_evm_simulator_hash_call { - token_vec.push(call.into_token()); + token_vec.insert(2, call.into_token()); } token_vec From c8d189603a8d162ceb65167ae2e800cfe09b73df Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Thu, 19 Sep 2024 15:47:31 -0300 Subject: [PATCH 27/45] Fix multicall when evm simulator is absent --- core/node/eth_sender/src/eth_tx_aggregator.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/core/node/eth_sender/src/eth_tx_aggregator.rs b/core/node/eth_sender/src/eth_tx_aggregator.rs index 2ce923fa1213..0b3656024927 100644 --- a/core/node/eth_sender/src/eth_tx_aggregator.rs +++ b/core/node/eth_sender/src/eth_tx_aggregator.rs @@ -189,20 +189,23 @@ impl EthTxAggregator { calldata: get_l2_default_aa_hash_input, }; - let get_l2_evm_simulator_hash_input = self + let mut get_l2_evm_simulator_hash_input = self .functions .get_evm_simulator_bytecode_hash .as_ref() .and_then(|f| f.encode_input(&[]).ok()); - let get_evm_simulator_hash_call = if let Some(input) = get_l2_evm_simulator_hash_input { - Some(Multicall3Call { + let use_evm_simulator = use_evm_simulator::UseEvmSimulator::from_env() + .unwrap() + .use_evm_simulator; + + let get_evm_simulator_hash_call = match get_l2_evm_simulator_hash_input { + Some(input) if use_evm_simulator => Some(Multicall3Call { target: self.state_transition_chain_contract, allow_failure: ALLOW_FAILURE, calldata: input, - }) - } else { - None + }), + _ => None, }; // Third zksync contract call From 072222df4ebcafaccded990d3ea0b892bb19c7a1 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 20 Sep 2024 13:16:30 -0300 Subject: [PATCH 28/45] Remove hardcoded hash for evm simulator when its not enabled --- .../system-constants-generator/src/utils.rs | 19 ++++++------------- core/lib/contracts/src/lib.rs | 19 ++++++------------- core/lib/types/src/system_contracts.rs | 8 ++++++-- core/lib/types/src/transaction_request.rs | 1 + core/node/eth_sender/src/eth_tx_aggregator.rs | 13 +++++-------- 5 files changed, 24 insertions(+), 36 deletions(-) diff --git a/core/bin/system-constants-generator/src/utils.rs b/core/bin/system-constants-generator/src/utils.rs index ac4d66185e33..b5f5717b5c23 100644 --- a/core/bin/system-constants-generator/src/utils.rs +++ b/core/bin/system-constants-generator/src/utils.rs @@ -75,19 +75,12 @@ pub static GAS_TEST_SYSTEM_CONTRACTS: Lazy = Lazy::new(|| { let bytecode = read_sys_contract_bytecode("", "DefaultAccount", ContractLanguage::Sol); let hash = hash_bytecode(&bytecode); - let mut evm_simulator_bytecode = bytecode.clone(); - let mut evm_simulator_hash = - H256::from_str("0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32") - .unwrap(); - - if use_evm_simulator::UseEvmSimulator::from_env() - .unwrap() - .use_evm_simulator - { - evm_simulator_bytecode = - read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); - evm_simulator_hash = hash_bytecode(&evm_simulator_bytecode.clone()); - } + let (evm_simulator_bytecode, evm_simulator_hash) = if use_evm_simulator::UseEvmSimulator::from_env().unwrap().use_evm_simulator { + let evm_simulator_bytecode = read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); + (evm_simulator_bytecode.clone(), hash_bytecode(&evm_simulator_bytecode)) + } else { + (bytecode.clone(), hash) + }; BaseSystemContracts { default_aa: SystemContractCode { diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index 5f86f546c767..2f29098f73dc 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -346,19 +346,12 @@ impl BaseSystemContracts { }; // If evm simulator is not enabled, use the default account bytecode and hash. - let mut evm_simulator_bytecode = bytecode; - let mut evm_simulator_hash = - H256::from_str("0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32") - .unwrap(); - - if use_evm_simulator::UseEvmSimulator::from_env() - .unwrap() - .use_evm_simulator - { - evm_simulator_bytecode = - read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); - evm_simulator_hash = hash_bytecode(&evm_simulator_bytecode); - } + let (evm_simulator_bytecode, evm_simulator_hash) = if use_evm_simulator::UseEvmSimulator::from_env().unwrap().use_evm_simulator { + let evm_simulator_bytecode = read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); + (evm_simulator_bytecode.clone(), hash_bytecode(&evm_simulator_bytecode)) + } else { + (bytecode.clone(), hash) + }; let evm_simulator = SystemContractCode { code: bytes_to_be_words(evm_simulator_bytecode), diff --git a/core/lib/types/src/system_contracts.rs b/core/lib/types/src/system_contracts.rs index f88e24e21ca7..628da94af573 100644 --- a/core/lib/types/src/system_contracts.rs +++ b/core/lib/types/src/system_contracts.rs @@ -191,8 +191,12 @@ static EVM_SIMULATOR_HASH: Lazy = Lazy::new(|| { ContractLanguage::Yul, )) } else { - H256::from_str("0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32") - .unwrap() + let default_account_code = read_sys_contract_bytecode( + "", + "DefaultAccount", + ContractLanguage::Sol, + ); + hash_bytecode(&default_account_code) } }); diff --git a/core/lib/types/src/transaction_request.rs b/core/lib/types/src/transaction_request.rs index e99e228086fb..5de1ef003442 100644 --- a/core/lib/types/src/transaction_request.rs +++ b/core/lib/types/src/transaction_request.rs @@ -822,6 +822,7 @@ impl L2Tx { let use_evm_simulator = use_evm_simulator::UseEvmSimulator::from_env() .unwrap() .use_evm_simulator; + // TODO: Remove this check when evm equivalence gets enabled if value.to.is_none() && !use_evm_simulator { return Err(SerializationTransactionError::ToAddressIsNull); diff --git a/core/node/eth_sender/src/eth_tx_aggregator.rs b/core/node/eth_sender/src/eth_tx_aggregator.rs index 0b3656024927..54c6c698e270 100644 --- a/core/node/eth_sender/src/eth_tx_aggregator.rs +++ b/core/node/eth_sender/src/eth_tx_aggregator.rs @@ -303,12 +303,7 @@ impl EthTxAggregator { } let default_aa = H256::from_slice(&multicall3_default_aa); - let mut evm_simulator = H256::from_str( - "0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32", - ) - .unwrap(); - - if use_evm_simulator { + let evm_simulator = if use_evm_simulator { let multicall3_evm_simulator = Multicall3Result::from_token(call_results_iterator.next().unwrap())? .return_data; @@ -320,8 +315,10 @@ impl EthTxAggregator { ), ))); } - evm_simulator = H256::from_slice(&multicall3_evm_simulator); - } + H256::from_slice(&multicall3_evm_simulator) + } else { + default_aa + }; let base_system_contracts_hashes = BaseSystemContractsHashes { bootloader, From a08ea6c2e3e5205915e7139195c173e74f11b4bf Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 20 Sep 2024 13:36:29 -0300 Subject: [PATCH 29/45] Fix format --- .../system-constants-generator/src/utils.rs | 20 +++++++++++++------ core/lib/contracts/src/lib.rs | 20 +++++++++++++------ core/lib/types/src/system_contracts.rs | 7 ++----- core/lib/types/src/transaction_request.rs | 2 +- 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/core/bin/system-constants-generator/src/utils.rs b/core/bin/system-constants-generator/src/utils.rs index b5f5717b5c23..1ad9d28ab1ac 100644 --- a/core/bin/system-constants-generator/src/utils.rs +++ b/core/bin/system-constants-generator/src/utils.rs @@ -75,12 +75,20 @@ 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, evm_simulator_hash) = if use_evm_simulator::UseEvmSimulator::from_env().unwrap().use_evm_simulator { - let evm_simulator_bytecode = read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); - (evm_simulator_bytecode.clone(), hash_bytecode(&evm_simulator_bytecode)) - } else { - (bytecode.clone(), hash) - }; + let (evm_simulator_bytecode, evm_simulator_hash) = + if use_evm_simulator::UseEvmSimulator::from_env() + .unwrap() + .use_evm_simulator + { + let evm_simulator_bytecode = + read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); + ( + evm_simulator_bytecode.clone(), + hash_bytecode(&evm_simulator_bytecode), + ) + } else { + (bytecode.clone(), hash) + }; BaseSystemContracts { default_aa: SystemContractCode { diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index 2f29098f73dc..2fd8bf44c24c 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -346,12 +346,20 @@ impl BaseSystemContracts { }; // If evm simulator is not enabled, use the default account bytecode and hash. - let (evm_simulator_bytecode, evm_simulator_hash) = if use_evm_simulator::UseEvmSimulator::from_env().unwrap().use_evm_simulator { - let evm_simulator_bytecode = read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); - (evm_simulator_bytecode.clone(), hash_bytecode(&evm_simulator_bytecode)) - } else { - (bytecode.clone(), hash) - }; + let (evm_simulator_bytecode, evm_simulator_hash) = + if use_evm_simulator::UseEvmSimulator::from_env() + .unwrap() + .use_evm_simulator + { + let evm_simulator_bytecode = + read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); + ( + evm_simulator_bytecode.clone(), + hash_bytecode(&evm_simulator_bytecode), + ) + } else { + (bytecode.clone(), hash) + }; let evm_simulator = SystemContractCode { code: bytes_to_be_words(evm_simulator_bytecode), diff --git a/core/lib/types/src/system_contracts.rs b/core/lib/types/src/system_contracts.rs index 628da94af573..f92ff7c0c518 100644 --- a/core/lib/types/src/system_contracts.rs +++ b/core/lib/types/src/system_contracts.rs @@ -191,11 +191,8 @@ static EVM_SIMULATOR_HASH: Lazy = Lazy::new(|| { ContractLanguage::Yul, )) } else { - let default_account_code = read_sys_contract_bytecode( - "", - "DefaultAccount", - ContractLanguage::Sol, - ); + let default_account_code = + read_sys_contract_bytecode("", "DefaultAccount", ContractLanguage::Sol); hash_bytecode(&default_account_code) } }); diff --git a/core/lib/types/src/transaction_request.rs b/core/lib/types/src/transaction_request.rs index 5de1ef003442..cfcc659008b9 100644 --- a/core/lib/types/src/transaction_request.rs +++ b/core/lib/types/src/transaction_request.rs @@ -822,7 +822,7 @@ impl L2Tx { let use_evm_simulator = use_evm_simulator::UseEvmSimulator::from_env() .unwrap() .use_evm_simulator; - + // TODO: Remove this check when evm equivalence gets enabled if value.to.is_none() && !use_evm_simulator { return Err(SerializationTransactionError::ToAddressIsNull); From 5bdabe3c8e48987a2d4114b19b3a79fdab47ca31 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 20 Sep 2024 16:28:19 -0300 Subject: [PATCH 30/45] Check for evm simulator in execute_internal_transfer_test function --- .../system-constants-generator/src/utils.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/core/bin/system-constants-generator/src/utils.rs b/core/bin/system-constants-generator/src/utils.rs index 1ad9d28ab1ac..220962475fd8 100644 --- a/core/bin/system-constants-generator/src/utils.rs +++ b/core/bin/system-constants-generator/src/utils.rs @@ -237,13 +237,24 @@ pub(super) fn execute_internal_transfer_test() -> u32 { let bytecode = read_sys_contract_bytecode("", "DefaultAccount", ContractLanguage::Sol); let hash = hash_bytecode(&bytecode); let default_aa = SystemContractCode { - code: bytes_to_be_words(bytecode), + code: bytes_to_be_words(bytecode.clone()), hash, }; - let evm_simulator_bytecode = - read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); - let evm_simulator_hash = hash_bytecode(&evm_simulator_bytecode); + let (evm_simulator_bytecode, evm_simulator_hash) = + if use_evm_simulator::UseEvmSimulator::from_env() + .unwrap() + .use_evm_simulator + { + let evm_simulator_bytecode = + read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); + ( + evm_simulator_bytecode.clone(), + hash_bytecode(&evm_simulator_bytecode), + ) + } else { + (bytecode.clone(), hash) + }; let evm_simulator = SystemContractCode { code: bytes_to_be_words(evm_simulator_bytecode), hash: evm_simulator_hash, From 72e22184788d080ea53441007f176be4475982aa Mon Sep 17 00:00:00 2001 From: perekopskiy <53865202+perekopskiy@users.noreply.github.com> Date: Tue, 24 Sep 2024 15:12:13 +0300 Subject: [PATCH 31/45] feat(contract-verifier): add new compilers (#2947) --- docker/contract-verifier/Dockerfile | 2 +- docker/contract-verifier/install-all-solc.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/contract-verifier/Dockerfile b/docker/contract-verifier/Dockerfile index 7fcc695bf70b..7943dae835af 100644 --- a/docker/contract-verifier/Dockerfile +++ b/docker/contract-verifier/Dockerfile @@ -47,7 +47,7 @@ RUN mkdir -p /etc/zksolc-bin/vm-1.5.0-a167aa3 && \ chmod +x /etc/zksolc-bin/vm-1.5.0-a167aa3/zksolc # install zksolc 1.5.x -RUN for VERSION in $(seq -f "v1.5.%g" 0 3); do \ +RUN for VERSION in $(seq -f "v1.5.%g" 0 4); do \ mkdir -p /etc/zksolc-bin/$VERSION && \ wget https://github.com/matter-labs/zksolc-bin/raw/main/linux-amd64/zksolc-linux-amd64-musl-$VERSION -O /etc/zksolc-bin/$VERSION/zksolc && \ chmod +x /etc/zksolc-bin/$VERSION/zksolc; \ diff --git a/docker/contract-verifier/install-all-solc.sh b/docker/contract-verifier/install-all-solc.sh index bc7cec143ccd..4fe992f83578 100755 --- a/docker/contract-verifier/install-all-solc.sh +++ b/docker/contract-verifier/install-all-solc.sh @@ -26,7 +26,7 @@ done # Download zkVM solc list=( "0.8.25-1.0.0" "0.8.24-1.0.0" "0.8.23-1.0.0" "0.8.22-1.0.0" "0.8.21-1.0.0" "0.8.20-1.0.0" "0.8.19-1.0.0" "0.8.18-1.0.0" "0.8.17-1.0.0" "0.8.16-1.0.0" "0.8.15-1.0.0" "0.8.14-1.0.0" "0.8.13-1.0.0" "0.8.12-1.0.0" "0.8.11-1.0.0" "0.8.10-1.0.0" "0.8.9-1.0.0" "0.8.8-1.0.0" "0.8.7-1.0.0" "0.8.6-1.0.0" "0.8.5-1.0.0" "0.8.4-1.0.0" "0.8.3-1.0.0" "0.8.2-1.0.0" "0.8.1-1.0.0" "0.8.0-1.0.0" "0.7.6-1.0.0" "0.7.5-1.0.0" "0.7.4-1.0.0" "0.7.3-1.0.0" "0.7.2-1.0.0" "0.7.1-1.0.0" "0.7.0-1.0.0" "0.6.12-1.0.0" "0.6.11-1.0.0" "0.6.10-1.0.0" "0.6.9-1.0.0" "0.6.8-1.0.0" "0.6.7-1.0.0" "0.6.6-1.0.0" "0.6.5-1.0.0" "0.6.4-1.0.0" "0.6.3-1.0.0" "0.6.2-1.0.0" "0.6.1-1.0.0" "0.6.0-1.0.0" "0.5.17-1.0.0" "0.5.16-1.0.0" "0.5.15-1.0.0" "0.5.14-1.0.0" "0.5.13-1.0.0" "0.5.12-1.0.0" "0.5.11-1.0.0" "0.5.10-1.0.0" "0.5.9-1.0.0" "0.5.8-1.0.0" "0.5.7-1.0.0" "0.5.6-1.0.0" "0.5.5-1.0.0" "0.5.4-1.0.0" "0.5.3-1.0.0" "0.5.2-1.0.0" "0.5.1-1.0.0" "0.5.0-1.0.0" "0.4.26-1.0.0" "0.4.25-1.0.0" "0.4.24-1.0.0" "0.4.23-1.0.0" "0.4.22-1.0.0" "0.4.21-1.0.0" "0.4.20-1.0.0" "0.4.19-1.0.0" "0.4.18-1.0.0" "0.4.17-1.0.0" "0.4.16-1.0.0" "0.4.15-1.0.0" "0.4.14-1.0.0" "0.4.13-1.0.0" "0.4.12-1.0.0" - "0.8.26-1.0.1" "0.8.25-1.0.1" "0.8.24-1.0.1" "0.8.23-1.0.1" "0.8.22-1.0.1" "0.8.21-1.0.1" "0.8.20-1.0.1" "0.8.19-1.0.1" "0.8.18-1.0.1" "0.8.17-1.0.1" "0.8.16-1.0.1" "0.8.15-1.0.1" "0.8.14-1.0.1" "0.8.13-1.0.1" "0.8.12-1.0.1" "0.8.11-1.0.1" "0.8.10-1.0.1" "0.8.9-1.0.1" "0.8.8-1.0.1" "0.8.7-1.0.1" "0.8.6-1.0.1" "0.8.5-1.0.1" "0.8.4-1.0.1" "0.8.3-1.0.1" "0.8.2-1.0.1" "0.8.1-1.0.1" "0.8.0-1.0.1" "0.7.6-1.0.1" "0.7.5-1.0.1" "0.7.4-1.0.1" "0.7.3-1.0.1" "0.7.2-1.0.1" "0.7.1-1.0.1" "0.7.0-1.0.1" "0.6.12-1.0.1" "0.6.11-1.0.1" "0.6.10-1.0.1" "0.6.9-1.0.1" "0.6.8-1.0.1" "0.6.7-1.0.1" "0.6.6-1.0.1" "0.6.5-1.0.1" "0.6.4-1.0.1" "0.6.3-1.0.1" "0.6.2-1.0.1" "0.6.1-1.0.1" "0.6.0-1.0.1" "0.5.17-1.0.1" "0.5.16-1.0.1" "0.5.15-1.0.1" "0.5.14-1.0.1" "0.5.13-1.0.1" "0.5.12-1.0.1" "0.5.11-1.0.1" "0.5.10-1.0.1" "0.5.9-1.0.1" "0.5.8-1.0.1" "0.5.7-1.0.1" "0.5.6-1.0.1" "0.5.5-1.0.1" "0.5.4-1.0.1" "0.5.3-1.0.1" "0.5.2-1.0.1" "0.5.1-1.0.1" "0.5.0-1.0.1" "0.4.26-1.0.1" "0.4.25-1.0.1" "0.4.24-1.0.1" "0.4.23-1.0.1" "0.4.22-1.0.1" "0.4.21-1.0.1" "0.4.20-1.0.1" "0.4.19-1.0.1" "0.4.18-1.0.1" "0.4.17-1.0.1" "0.4.16-1.0.1" "0.4.15-1.0.1" "0.4.14-1.0.1" "0.4.13-1.0.1" "0.4.12-1.0.1" + "0.8.27-1.0.1" "0.8.26-1.0.1" "0.8.25-1.0.1" "0.8.24-1.0.1" "0.8.23-1.0.1" "0.8.22-1.0.1" "0.8.21-1.0.1" "0.8.20-1.0.1" "0.8.19-1.0.1" "0.8.18-1.0.1" "0.8.17-1.0.1" "0.8.16-1.0.1" "0.8.15-1.0.1" "0.8.14-1.0.1" "0.8.13-1.0.1" "0.8.12-1.0.1" "0.8.11-1.0.1" "0.8.10-1.0.1" "0.8.9-1.0.1" "0.8.8-1.0.1" "0.8.7-1.0.1" "0.8.6-1.0.1" "0.8.5-1.0.1" "0.8.4-1.0.1" "0.8.3-1.0.1" "0.8.2-1.0.1" "0.8.1-1.0.1" "0.8.0-1.0.1" "0.7.6-1.0.1" "0.7.5-1.0.1" "0.7.4-1.0.1" "0.7.3-1.0.1" "0.7.2-1.0.1" "0.7.1-1.0.1" "0.7.0-1.0.1" "0.6.12-1.0.1" "0.6.11-1.0.1" "0.6.10-1.0.1" "0.6.9-1.0.1" "0.6.8-1.0.1" "0.6.7-1.0.1" "0.6.6-1.0.1" "0.6.5-1.0.1" "0.6.4-1.0.1" "0.6.3-1.0.1" "0.6.2-1.0.1" "0.6.1-1.0.1" "0.6.0-1.0.1" "0.5.17-1.0.1" "0.5.16-1.0.1" "0.5.15-1.0.1" "0.5.14-1.0.1" "0.5.13-1.0.1" "0.5.12-1.0.1" "0.5.11-1.0.1" "0.5.10-1.0.1" "0.5.9-1.0.1" "0.5.8-1.0.1" "0.5.7-1.0.1" "0.5.6-1.0.1" "0.5.5-1.0.1" "0.5.4-1.0.1" "0.5.3-1.0.1" "0.5.2-1.0.1" "0.5.1-1.0.1" "0.5.0-1.0.1" "0.4.26-1.0.1" "0.4.25-1.0.1" "0.4.24-1.0.1" "0.4.23-1.0.1" "0.4.22-1.0.1" "0.4.21-1.0.1" "0.4.20-1.0.1" "0.4.19-1.0.1" "0.4.18-1.0.1" "0.4.17-1.0.1" "0.4.16-1.0.1" "0.4.15-1.0.1" "0.4.14-1.0.1" "0.4.13-1.0.1" "0.4.12-1.0.1" ) for version in ${list[@]}; do From 934048091023f7f2b1dbbdedb0c0b793e6fe32cf Mon Sep 17 00:00:00 2001 From: Yury Akudovich Date: Tue, 24 Sep 2024 18:07:00 +0200 Subject: [PATCH 32/45] ci: Copy setup_keys to docker/circuit-prover-gpu-gar (#2951) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Copy setup keys to be available for docker/circuit-prover-gpu-gar. ## Why ❔ To build circuit-prover-gpu image with keys. ## Checklist - [x] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [x] Code has been formatted via `zk fmt` and `zk lint`. --- .../build-prover-fri-gpu-gar-and-circuit-prover-gpu-gar.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-prover-fri-gpu-gar-and-circuit-prover-gpu-gar.yml b/.github/workflows/build-prover-fri-gpu-gar-and-circuit-prover-gpu-gar.yml index 031677cf9b64..b92fb8e81110 100644 --- a/.github/workflows/build-prover-fri-gpu-gar-and-circuit-prover-gpu-gar.yml +++ b/.github/workflows/build-prover-fri-gpu-gar-and-circuit-prover-gpu-gar.yml @@ -28,6 +28,7 @@ jobs: - name: Download Setup data run: | gsutil -m rsync -r gs://matterlabs-setup-data-us/${{ inputs.setup_keys_id }} docker/prover-gpu-fri-gar + cp -v docker/prover-gpu-fri-gar/*.bin docker/circuit-prover-gpu-gar/ - name: Login to us-central1 GAR run: | From 9010c5692c6f361fe1219855fb9de656c2cb31ae Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 24 Sep 2024 13:59:16 -0300 Subject: [PATCH 33/45] Fix doc comment for UseEvmSimulator config --- core/lib/config/src/configs/use_evm_simulator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/config/src/configs/use_evm_simulator.rs b/core/lib/config/src/configs/use_evm_simulator.rs index 76113613a17d..7309c92a3445 100644 --- a/core/lib/config/src/configs/use_evm_simulator.rs +++ b/core/lib/config/src/configs/use_evm_simulator.rs @@ -1,6 +1,6 @@ use serde::Deserialize; -/// Configuration for the use evm simulator +/// Configure whether to enable the EVM simulator on the stack. #[derive(Debug, Deserialize, Clone, PartialEq)] pub struct UseEvmSimulator { pub use_evm_simulator: bool, From 774b8481048644bc38c3fd0f900f3c9e43ca0292 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 24 Sep 2024 14:18:21 -0300 Subject: [PATCH 34/45] Remove evm simulator code hash from miniblocks table --- ...1089c4f64c785f758b3684771073f9967923.json} | 4 +- ...00ff851252dd9da2df5ab7da51324f9258400.json | 31 -------- ...ba3af74e8e7b5944cb2943b5badb906167046.json | 30 +++++++ ...2ffa59f55223e99383ada49b633428a72718.json} | 4 +- ...bb57ffb1411826a6406d9d86958650183bbb.json} | 4 +- ...ce25e8b15a8f8c15a3523ef2a04528be2741.json} | 4 +- .../20240911161714_evm-simulator.up.sql | 1 - core/lib/dal/src/blocks_dal.rs | 78 +++++++++---------- core/lib/dal/src/blocks_web3_dal.rs | 2 +- core/lib/dal/src/sync_dal.rs | 3 +- ...0cd5c6b1122c35d7ffdbbba30327ca3fb5a8.json} | 4 +- 11 files changed, 80 insertions(+), 85 deletions(-) rename core/lib/dal/.sqlx/{query-2060d7de5c06f2fd24b43de6eeca927c5f5b88725987e82cf3ec5d499c5addbb.json => query-0c9f40c61a37959109319118b9191089c4f64c785f758b3684771073f9967923.json} (90%) delete mode 100644 core/lib/dal/.sqlx/query-9ca8d7418721beb1e9ee4f801a600ff851252dd9da2df5ab7da51324f9258400.json create mode 100644 core/lib/dal/.sqlx/query-c4835d40921af47bfb4f60102bbba3af74e8e7b5944cb2943b5badb906167046.json rename core/lib/dal/.sqlx/{query-922dde793d7846594feaf13d475bbbb0aa11d1c974d6ae7c99d83560bb37357e.json => query-c774df1fd626c38c28abf9fc0fa12ffa59f55223e99383ada49b633428a72718.json} (66%) rename core/lib/dal/.sqlx/{query-1ab1ee0657abc6586204dae61cb54a0fe2f0c3bf5f11aec8400c0b6e5b58c62a.json => query-e4d2e039442c204cdcb6ee24fde9bb57ffb1411826a6406d9d86958650183bbb.json} (96%) rename core/lib/dal/.sqlx/{query-3a7b285d40bf7aaa8f6251f69a4e3a6f0a2de9a615e50a94d98d18e47621c709.json => query-f9f2560aacc9cf94c560f3692d0dce25e8b15a8f8c15a3523ef2a04528be2741.json} (65%) rename prover/crates/lib/prover_dal/.sqlx/{query-97adb49780c9edde6a3cfda09dadbd694e1781e013247d090a280a1f894de464.json => query-29f7a564a8373f7e44840e8e9e7d0cd5c6b1122c35d7ffdbbba30327ca3fb5a8.json} (53%) diff --git a/core/lib/dal/.sqlx/query-2060d7de5c06f2fd24b43de6eeca927c5f5b88725987e82cf3ec5d499c5addbb.json b/core/lib/dal/.sqlx/query-0c9f40c61a37959109319118b9191089c4f64c785f758b3684771073f9967923.json similarity index 90% rename from core/lib/dal/.sqlx/query-2060d7de5c06f2fd24b43de6eeca927c5f5b88725987e82cf3ec5d499c5addbb.json rename to core/lib/dal/.sqlx/query-0c9f40c61a37959109319118b9191089c4f64c785f758b3684771073f9967923.json index 7b4fa2793dba..b624e45f2bb1 100644 --- a/core/lib/dal/.sqlx/query-2060d7de5c06f2fd24b43de6eeca927c5f5b88725987e82cf3ec5d499c5addbb.json +++ b/core/lib/dal/.sqlx/query-0c9f40c61a37959109319118b9191089c4f64c785f758b3684771073f9967923.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.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 ", + "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 l1_batches.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 INNER JOIN l1_batches ON l1_batches.number = miniblocks.l1_batch_number\n WHERE\n miniblocks.number BETWEEN $1 AND $2\n ", "describe": { "columns": [ { @@ -97,5 +97,5 @@ false ] }, - "hash": "2060d7de5c06f2fd24b43de6eeca927c5f5b88725987e82cf3ec5d499c5addbb" + "hash": "0c9f40c61a37959109319118b9191089c4f64c785f758b3684771073f9967923" } diff --git a/core/lib/dal/.sqlx/query-9ca8d7418721beb1e9ee4f801a600ff851252dd9da2df5ab7da51324f9258400.json b/core/lib/dal/.sqlx/query-9ca8d7418721beb1e9ee4f801a600ff851252dd9da2df5ab7da51324f9258400.json deleted file mode 100644 index 52ef95716470..000000000000 --- a/core/lib/dal/.sqlx/query-9ca8d7418721beb1e9ee4f801a600ff851252dd9da2df5ab7da51324f9258400.json +++ /dev/null @@ -1,31 +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 evm_simulator_code_hash,\n protocol_version,\n virtual_blocks,\n fair_pubdata_price,\n gas_limit,\n logs_bloom,\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 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", - "Bytea" - ] - }, - "nullable": [] - }, - "hash": "9ca8d7418721beb1e9ee4f801a600ff851252dd9da2df5ab7da51324f9258400" -} diff --git a/core/lib/dal/.sqlx/query-c4835d40921af47bfb4f60102bbba3af74e8e7b5944cb2943b5badb906167046.json b/core/lib/dal/.sqlx/query-c4835d40921af47bfb4f60102bbba3af74e8e7b5944cb2943b5badb906167046.json new file mode 100644 index 000000000000..9ae9d2e50cde --- /dev/null +++ b/core/lib/dal/.sqlx/query-c4835d40921af47bfb4f60102bbba3af74e8e7b5944cb2943b5badb906167046.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 protocol_version,\n virtual_blocks,\n fair_pubdata_price,\n gas_limit,\n logs_bloom,\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", + "Int4", + "Int8", + "Int8", + "Int8", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "c4835d40921af47bfb4f60102bbba3af74e8e7b5944cb2943b5badb906167046" +} diff --git a/core/lib/dal/.sqlx/query-922dde793d7846594feaf13d475bbbb0aa11d1c974d6ae7c99d83560bb37357e.json b/core/lib/dal/.sqlx/query-c774df1fd626c38c28abf9fc0fa12ffa59f55223e99383ada49b633428a72718.json similarity index 66% rename from core/lib/dal/.sqlx/query-922dde793d7846594feaf13d475bbbb0aa11d1c974d6ae7c99d83560bb37357e.json rename to core/lib/dal/.sqlx/query-c774df1fd626c38c28abf9fc0fa12ffa59f55223e99383ada49b633428a72718.json index 287c69687e53..c1205a219525 100644 --- a/core/lib/dal/.sqlx/query-922dde793d7846594feaf13d475bbbb0aa11d1c974d6ae7c99d83560bb37357e.json +++ b/core/lib/dal/.sqlx/query-c774df1fd626c38c28abf9fc0fa12ffa59f55223e99383ada49b633428a72718.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 evm_simulator_code_hash,\n protocol_version,\n virtual_blocks,\n fair_pubdata_price,\n gas_limit,\n logs_bloom\n FROM\n miniblocks\n WHERE\n number = $1\n ", + "query": "\n SELECT\n miniblocks.number,\n miniblocks.timestamp,\n miniblocks.hash,\n miniblocks.l1_tx_count,\n miniblocks.l2_tx_count,\n fee_account_address AS \"fee_account_address!\",\n miniblocks.base_fee_per_gas,\n miniblocks.l1_gas_price,\n miniblocks.l2_fair_gas_price,\n miniblocks.gas_per_pubdata_limit,\n miniblocks.bootloader_code_hash,\n miniblocks.default_aa_code_hash,\n l1_batches.evm_simulator_code_hash,\n miniblocks.protocol_version,\n miniblocks.virtual_blocks,\n miniblocks.fair_pubdata_price,\n miniblocks.gas_limit,\n miniblocks.logs_bloom\n FROM\n miniblocks\n INNER JOIN l1_batches ON miniblocks.l1_batch_number = l1_batches.number\n WHERE\n miniblocks.number = $1\n ", "describe": { "columns": [ { @@ -120,5 +120,5 @@ true ] }, - "hash": "922dde793d7846594feaf13d475bbbb0aa11d1c974d6ae7c99d83560bb37357e" + "hash": "c774df1fd626c38c28abf9fc0fa12ffa59f55223e99383ada49b633428a72718" } diff --git a/core/lib/dal/.sqlx/query-1ab1ee0657abc6586204dae61cb54a0fe2f0c3bf5f11aec8400c0b6e5b58c62a.json b/core/lib/dal/.sqlx/query-e4d2e039442c204cdcb6ee24fde9bb57ffb1411826a6406d9d86958650183bbb.json similarity index 96% rename from core/lib/dal/.sqlx/query-1ab1ee0657abc6586204dae61cb54a0fe2f0c3bf5f11aec8400c0b6e5b58c62a.json rename to core/lib/dal/.sqlx/query-e4d2e039442c204cdcb6ee24fde9bb57ffb1411826a6406d9d86958650183bbb.json index 12ddbfbc4211..444870f46031 100644 --- a/core/lib/dal/.sqlx/query-1ab1ee0657abc6586204dae61cb54a0fe2f0c3bf5f11aec8400c0b6e5b58c62a.json +++ b/core/lib/dal/.sqlx/query-e4d2e039442c204cdcb6ee24fde9bb57ffb1411826a6406d9d86958650183bbb.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.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 ", + "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 l1_batches.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": [ { @@ -132,5 +132,5 @@ false ] }, - "hash": "1ab1ee0657abc6586204dae61cb54a0fe2f0c3bf5f11aec8400c0b6e5b58c62a" + "hash": "e4d2e039442c204cdcb6ee24fde9bb57ffb1411826a6406d9d86958650183bbb" } diff --git a/core/lib/dal/.sqlx/query-3a7b285d40bf7aaa8f6251f69a4e3a6f0a2de9a615e50a94d98d18e47621c709.json b/core/lib/dal/.sqlx/query-f9f2560aacc9cf94c560f3692d0dce25e8b15a8f8c15a3523ef2a04528be2741.json similarity index 65% rename from core/lib/dal/.sqlx/query-3a7b285d40bf7aaa8f6251f69a4e3a6f0a2de9a615e50a94d98d18e47621c709.json rename to core/lib/dal/.sqlx/query-f9f2560aacc9cf94c560f3692d0dce25e8b15a8f8c15a3523ef2a04528be2741.json index 16f258cf3047..8b323291548b 100644 --- a/core/lib/dal/.sqlx/query-3a7b285d40bf7aaa8f6251f69a4e3a6f0a2de9a615e50a94d98d18e47621c709.json +++ b/core/lib/dal/.sqlx/query-f9f2560aacc9cf94c560f3692d0dce25e8b15a8f8c15a3523ef2a04528be2741.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 evm_simulator_code_hash,\n protocol_version,\n virtual_blocks,\n fair_pubdata_price,\n gas_limit,\n logs_bloom\n FROM\n miniblocks\n ORDER BY\n number DESC\n LIMIT\n 1\n ", + "query": "\n SELECT\n miniblocks.number,\n miniblocks.timestamp,\n miniblocks.hash,\n miniblocks.l1_tx_count,\n miniblocks.l2_tx_count,\n fee_account_address AS \"fee_account_address!\",\n miniblocks.base_fee_per_gas,\n miniblocks.l1_gas_price,\n miniblocks.l2_fair_gas_price,\n miniblocks.gas_per_pubdata_limit,\n miniblocks.bootloader_code_hash,\n miniblocks.default_aa_code_hash,\n l1_batches.evm_simulator_code_hash,\n miniblocks.protocol_version,\n miniblocks.virtual_blocks,\n miniblocks.fair_pubdata_price,\n miniblocks.gas_limit,\n miniblocks.logs_bloom\n FROM\n miniblocks\n INNER JOIN l1_batches ON miniblocks.l1_batch_number = l1_batches.number\n ORDER BY\n number DESC\n LIMIT\n 1\n ", "describe": { "columns": [ { @@ -118,5 +118,5 @@ true ] }, - "hash": "3a7b285d40bf7aaa8f6251f69a4e3a6f0a2de9a615e50a94d98d18e47621c709" + "hash": "f9f2560aacc9cf94c560f3692d0dce25e8b15a8f8c15a3523ef2a04528be2741" } diff --git a/core/lib/dal/migrations/20240911161714_evm-simulator.up.sql b/core/lib/dal/migrations/20240911161714_evm-simulator.up.sql index ea8e0a83d20c..4bc764b77d7c 100644 --- a/core/lib/dal/migrations/20240911161714_evm-simulator.up.sql +++ b/core/lib/dal/migrations/20240911161714_evm-simulator.up.sql @@ -1,3 +1,2 @@ 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 5d82dc18d48c..2ede5005b9f6 100644 --- a/core/lib/dal/src/blocks_dal.rs +++ b/core/lib/dal/src/blocks_dal.rs @@ -708,7 +708,6 @@ impl BlocksDal<'_, '_> { gas_per_pubdata_limit, bootloader_code_hash, default_aa_code_hash, - evm_simulator_code_hash, protocol_version, virtual_blocks, fair_pubdata_price, @@ -736,7 +735,6 @@ impl BlocksDal<'_, '_> { $15, $16, $17, - $18, NOW(), NOW() ) @@ -759,10 +757,6 @@ 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, @@ -779,26 +773,27 @@ impl BlocksDal<'_, '_> { StorageL2BlockHeader, r#" SELECT - number, - timestamp, - hash, - l1_tx_count, - l2_tx_count, + miniblocks.number, + miniblocks.timestamp, + miniblocks.hash, + miniblocks.l1_tx_count, + miniblocks.l2_tx_count, fee_account_address AS "fee_account_address!", - base_fee_per_gas, - l1_gas_price, - l2_fair_gas_price, - gas_per_pubdata_limit, - bootloader_code_hash, - default_aa_code_hash, - evm_simulator_code_hash, - protocol_version, - virtual_blocks, - fair_pubdata_price, - gas_limit, - logs_bloom + miniblocks.base_fee_per_gas, + miniblocks.l1_gas_price, + miniblocks.l2_fair_gas_price, + miniblocks.gas_per_pubdata_limit, + miniblocks.bootloader_code_hash, + miniblocks.default_aa_code_hash, + l1_batches.evm_simulator_code_hash, + miniblocks.protocol_version, + miniblocks.virtual_blocks, + miniblocks.fair_pubdata_price, + miniblocks.gas_limit, + miniblocks.logs_bloom FROM miniblocks + INNER JOIN l1_batches ON miniblocks.l1_batch_number = l1_batches.number ORDER BY number DESC LIMIT @@ -820,28 +815,29 @@ impl BlocksDal<'_, '_> { StorageL2BlockHeader, r#" SELECT - number, - timestamp, - hash, - l1_tx_count, - l2_tx_count, + miniblocks.number, + miniblocks.timestamp, + miniblocks.hash, + miniblocks.l1_tx_count, + miniblocks.l2_tx_count, fee_account_address AS "fee_account_address!", - base_fee_per_gas, - l1_gas_price, - l2_fair_gas_price, - gas_per_pubdata_limit, - bootloader_code_hash, - default_aa_code_hash, - evm_simulator_code_hash, - protocol_version, - virtual_blocks, - fair_pubdata_price, - gas_limit, - logs_bloom + miniblocks.base_fee_per_gas, + miniblocks.l1_gas_price, + miniblocks.l2_fair_gas_price, + miniblocks.gas_per_pubdata_limit, + miniblocks.bootloader_code_hash, + miniblocks.default_aa_code_hash, + l1_batches.evm_simulator_code_hash, + miniblocks.protocol_version, + miniblocks.virtual_blocks, + miniblocks.fair_pubdata_price, + miniblocks.gas_limit, + miniblocks.logs_bloom FROM miniblocks + INNER JOIN l1_batches ON miniblocks.l1_batch_number = l1_batches.number WHERE - number = $1 + miniblocks.number = $1 "#, i64::from(l2_block_number.0), ) diff --git a/core/lib/dal/src/blocks_web3_dal.rs b/core/lib/dal/src/blocks_web3_dal.rs index 78c01dc1f6b0..332d4cd6c113 100644 --- a/core/lib/dal/src/blocks_web3_dal.rs +++ b/core/lib/dal/src/blocks_web3_dal.rs @@ -663,7 +663,7 @@ impl BlocksWeb3Dal<'_, '_> { miniblocks.fair_pubdata_price, miniblocks.bootloader_code_hash, miniblocks.default_aa_code_hash, - miniblocks.evm_simulator_code_hash, + l1_batches.evm_simulator_code_hash, miniblocks.protocol_version, miniblocks.fee_account_address FROM diff --git a/core/lib/dal/src/sync_dal.rs b/core/lib/dal/src/sync_dal.rs index 22c72fc4d152..c3120d240c49 100644 --- a/core/lib/dal/src/sync_dal.rs +++ b/core/lib/dal/src/sync_dal.rs @@ -50,13 +50,14 @@ impl SyncDal<'_, '_> { miniblocks.fair_pubdata_price, miniblocks.bootloader_code_hash, miniblocks.default_aa_code_hash, - miniblocks.evm_simulator_code_hash, + l1_batches.evm_simulator_code_hash, miniblocks.virtual_blocks, miniblocks.hash, miniblocks.protocol_version AS "protocol_version!", miniblocks.fee_account_address AS "fee_account_address!" FROM miniblocks + INNER JOIN l1_batches ON l1_batches.number = miniblocks.l1_batch_number WHERE miniblocks.number BETWEEN $1 AND $2 "#, diff --git a/prover/crates/lib/prover_dal/.sqlx/query-97adb49780c9edde6a3cfda09dadbd694e1781e013247d090a280a1f894de464.json b/prover/crates/lib/prover_dal/.sqlx/query-29f7a564a8373f7e44840e8e9e7d0cd5c6b1122c35d7ffdbbba30327ca3fb5a8.json similarity index 53% rename from prover/crates/lib/prover_dal/.sqlx/query-97adb49780c9edde6a3cfda09dadbd694e1781e013247d090a280a1f894de464.json rename to prover/crates/lib/prover_dal/.sqlx/query-29f7a564a8373f7e44840e8e9e7d0cd5c6b1122c35d7ffdbbba30327ca3fb5a8.json index ce9e492a7d4a..05163dcfa2e6 100644 --- a/prover/crates/lib/prover_dal/.sqlx/query-97adb49780c9edde6a3cfda09dadbd694e1781e013247d090a280a1f894de464.json +++ b/prover/crates/lib/prover_dal/.sqlx/query-29f7a564a8373f7e44840e8e9e7d0cd5c6b1122c35d7ffdbbba30327ca3fb5a8.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n protocol_version AS \"protocol_version!\",\n protocol_version_patch AS \"protocol_version_patch!\",\n COUNT(*) FILTER (WHERE status = 'queued') as queued,\n COUNT(*) FILTER (WHERE status = 'in_progress') as in_progress\n FROM\n prover_jobs_fri\n WHERE\n status IN ('queued', 'in_progress')\n AND protocol_version IS NOT NULL\n GROUP BY\n protocol_version,\n protocol_version_patch\n ", + "query": "\n SELECT\n protocol_version AS \"protocol_version!\",\n protocol_version_patch AS \"protocol_version_patch!\",\n COUNT(*) FILTER (\n WHERE\n status = 'queued'\n ) AS queued,\n COUNT(*) FILTER (\n WHERE\n status = 'in_progress'\n ) AS in_progress\n FROM\n prover_jobs_fri\n WHERE\n status IN ('queued', 'in_progress')\n AND protocol_version IS NOT NULL\n GROUP BY\n protocol_version,\n protocol_version_patch\n ", "describe": { "columns": [ { @@ -34,5 +34,5 @@ null ] }, - "hash": "97adb49780c9edde6a3cfda09dadbd694e1781e013247d090a280a1f894de464" + "hash": "29f7a564a8373f7e44840e8e9e7d0cd5c6b1122c35d7ffdbbba30327ca3fb5a8" } From e85228b2e49b266945f10a550d80db67e0c2fc40 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 24 Sep 2024 18:03:39 -0300 Subject: [PATCH 35/45] Fix review comments --- core/lib/dal/src/models/storage_transaction.rs | 3 ++- .../lib/multivm/src/glue/types/vm/vm_block_result.rs | 12 ++++++------ .../src/glue/types/vm/vm_partial_execution_result.rs | 6 +++--- .../src/glue/types/vm/vm_tx_execution_result.rs | 10 +++++----- .../versions/vm_1_4_1/implementation/execution.rs | 2 +- .../versions/vm_1_4_2/implementation/execution.rs | 2 +- .../implementation/execution.rs | 2 +- core/lib/multivm/src/versions/vm_fast/vm.rs | 2 +- .../implementation/execution.rs | 2 +- .../vm_virtual_blocks/implementation/execution.rs | 2 +- core/lib/types/src/l2/mod.rs | 5 ++++- core/lib/types/src/lib.rs | 5 ++++- core/lib/types/src/transaction_request.rs | 8 +++----- core/lib/vm_executor/src/oneshot/mock.rs | 2 +- .../src/types/outputs/finished_l1batch.rs | 2 +- core/node/api_server/src/web3/tests/vm.rs | 2 +- core/node/state_keeper/src/testonly/mod.rs | 2 +- .../state_keeper/src/testonly/test_batch_executor.rs | 4 ++-- core/node/state_keeper/src/tests/mod.rs | 2 +- .../state_keeper/src/updates/l2_block_updates.rs | 7 +------ 20 files changed, 41 insertions(+), 41 deletions(-) diff --git a/core/lib/dal/src/models/storage_transaction.rs b/core/lib/dal/src/models/storage_transaction.rs index 746026af73e5..6dc9c5c7a924 100644 --- a/core/lib/dal/src/models/storage_transaction.rs +++ b/core/lib/dal/src/models/storage_transaction.rs @@ -367,7 +367,8 @@ impl From for TransactionReceipt { .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. + }).or_else(|| Some(Address::zero())), 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/glue/types/vm/vm_block_result.rs b/core/lib/multivm/src/glue/types/vm/vm_block_result.rs index 6ef9b2947746..50bb19938fe7 100644 --- a/core/lib/multivm/src/glue/types/vm/vm_block_result.rs +++ b/core/lib/multivm/src/glue/types/vm/vm_block_result.rs @@ -47,7 +47,7 @@ impl GlueFrom for crate::interface::Fi circuit_statistic: Default::default(), }, refunds: Refunds::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, }, final_execution_state: CurrentExecutionState { events: value.full_result.events, @@ -104,7 +104,7 @@ impl GlueFrom for crate::interface::Fi circuit_statistic: Default::default(), }, refunds: Refunds::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, }, final_execution_state: CurrentExecutionState { events: value.full_result.events, @@ -160,7 +160,7 @@ impl GlueFrom for crate::interface: circuit_statistic: Default::default(), }, refunds: Refunds::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, }, final_execution_state: CurrentExecutionState { events: value.full_result.events, @@ -230,7 +230,7 @@ impl GlueFrom circuit_statistic: Default::default(), }, refunds: Refunds::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, } } } @@ -263,7 +263,7 @@ impl GlueFrom circuit_statistic: Default::default(), }, refunds: Refunds::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, } } } @@ -312,7 +312,7 @@ impl GlueFrom circuit_statistic: Default::default(), }, refunds: Refunds::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, } } } diff --git a/core/lib/multivm/src/glue/types/vm/vm_partial_execution_result.rs b/core/lib/multivm/src/glue/types/vm/vm_partial_execution_result.rs index 1891330b6d29..4c4cffcc6876 100644 --- a/core/lib/multivm/src/glue/types/vm/vm_partial_execution_result.rs +++ b/core/lib/multivm/src/glue/types/vm/vm_partial_execution_result.rs @@ -22,7 +22,7 @@ impl GlueFrom gas_refunded: 0, operator_suggested_refund: 0, }, - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, } } } @@ -49,7 +49,7 @@ impl GlueFrom gas_refunded: 0, operator_suggested_refund: 0, }, - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, } } } @@ -76,7 +76,7 @@ impl GlueFrom gas_refunded: 0, operator_suggested_refund: 0, }, - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, } } } diff --git a/core/lib/multivm/src/glue/types/vm/vm_tx_execution_result.rs b/core/lib/multivm/src/glue/types/vm/vm_tx_execution_result.rs index 2ea1e3984c47..8978d4348edd 100644 --- a/core/lib/multivm/src/glue/types/vm/vm_tx_execution_result.rs +++ b/core/lib/multivm/src/glue/types/vm/vm_tx_execution_result.rs @@ -66,14 +66,14 @@ impl GlueFrom VmExecutionResultAndLogs { result: ExecutionResult::Halt { reason: halt }, logs: Default::default(), statistics: Default::default(), refunds: Default::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, }, } } @@ -102,14 +102,14 @@ impl logs: Default::default(), statistics: Default::default(), refunds: Default::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, }, TxRevertReason::Halt(halt) => VmExecutionResultAndLogs { result: ExecutionResult::Halt { reason: halt }, logs: Default::default(), statistics: Default::default(), refunds: Default::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, }, } } @@ -133,7 +133,7 @@ impl GlueFrom { unreachable!("Halt is the only revert reason for VM 5") diff --git a/core/lib/multivm/src/versions/vm_1_4_1/implementation/execution.rs b/core/lib/multivm/src/versions/vm_1_4_1/implementation/execution.rs index 4767b5dcfa92..cc199fef9416 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/implementation/execution.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/implementation/execution.rs @@ -99,7 +99,7 @@ impl Vm { logs, statistics, refunds, - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, }; (stop_reason, result) diff --git a/core/lib/multivm/src/versions/vm_1_4_2/implementation/execution.rs b/core/lib/multivm/src/versions/vm_1_4_2/implementation/execution.rs index f49eb10e26bc..f6e49cd8b149 100644 --- a/core/lib/multivm/src/versions/vm_1_4_2/implementation/execution.rs +++ b/core/lib/multivm/src/versions/vm_1_4_2/implementation/execution.rs @@ -96,7 +96,7 @@ impl Vm { logs, statistics, refunds, - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, }; (stop_reason, result) diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/implementation/execution.rs b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/execution.rs index d21db3992040..b8b939f86731 100644 --- a/core/lib/multivm/src/versions/vm_boojum_integration/implementation/execution.rs +++ b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/execution.rs @@ -93,7 +93,7 @@ impl Vm { logs, statistics, refunds, - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, }; (stop_reason, result) diff --git a/core/lib/multivm/src/versions/vm_fast/vm.rs b/core/lib/multivm/src/versions/vm_fast/vm.rs index a94c51de6a7f..1757d952bfe8 100644 --- a/core/lib/multivm/src/versions/vm_fast/vm.rs +++ b/core/lib/multivm/src/versions/vm_fast/vm.rs @@ -601,7 +601,7 @@ impl VmInterface for Vm { circuit_statistic: full_tracer.1.circuit_statistic(), }, refunds, - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, } } diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/execution.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/execution.rs index 696f2993f511..9462a89be2ab 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/execution.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/execution.rs @@ -90,7 +90,7 @@ impl Vm { logs, statistics, refunds, - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, }; (stop_reason, result) diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/execution.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/execution.rs index 33946f20ecbd..b1ad4d257b77 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/execution.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/execution.rs @@ -88,7 +88,7 @@ impl Vm { .refund_tracer .map(|r| r.get_refunds()) .unwrap_or_default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, }; tx_tracer.dispatcher.save_results(&mut result); diff --git a/core/lib/types/src/l2/mod.rs b/core/lib/types/src/l2/mod.rs index 036d2a7a036d..110a90c44242 100644 --- a/core/lib/types/src/l2/mod.rs +++ b/core/lib/types/src/l2/mod.rs @@ -4,7 +4,9 @@ use anyhow::Context as _; use num_enum::TryFromPrimitive; use rlp::Rlp; use serde::{Deserialize, Serialize}; +use zksync_config::configs::use_evm_simulator; use zksync_crypto_primitives::K256PrivateKey; +use zksync_env_config::FromEnv; use self::error::SignError; use crate::{ @@ -216,7 +218,8 @@ impl L2Tx { let raw = req.get_signed_bytes(&sig).context("get_signed_bytes")?; let (req, hash) = TransactionRequest::from_bytes_unverified(&raw).context("from_bytes_unverified()")?; - let mut tx = L2Tx::from_request_unverified(req).context("from_request_unverified()")?; + let use_evm_simulator = use_evm_simulator::UseEvmSimulator::from_env().unwrap().use_evm_simulator; + let mut tx = L2Tx::from_request_unverified(req, use_evm_simulator).context("from_request_unverified()")?; tx.set_input(raw, hash); Ok(tx) } diff --git a/core/lib/types/src/lib.rs b/core/lib/types/src/lib.rs index 86b2e3f03d51..1e38b63dcdda 100644 --- a/core/lib/types/src/lib.rs +++ b/core/lib/types/src/lib.rs @@ -16,7 +16,9 @@ use serde::{Deserialize, Serialize}; pub use storage::*; pub use tx::Execute; pub use zksync_basic_types::{protocol_version::ProtocolVersionId, vm, *}; +use zksync_config::configs::use_evm_simulator; pub use zksync_crypto_primitives::*; +use zksync_env_config::FromEnv; use zksync_utils::{ address_to_u256, bytecode::hash_bytecode, h256_to_u256, u256_to_account_address, }; @@ -389,7 +391,8 @@ impl TryFrom for Transaction { abi::Transaction::L2(raw) => { let (req, hash) = transaction_request::TransactionRequest::from_bytes_unverified(&raw)?; - let mut tx = L2Tx::from_request_unverified(req)?; + let use_evm_simulator = use_evm_simulator::UseEvmSimulator::from_env().unwrap().use_evm_simulator; + let mut tx = L2Tx::from_request_unverified(req, use_evm_simulator)?; tx.set_input(raw, hash); tx.into() } diff --git a/core/lib/types/src/transaction_request.rs b/core/lib/types/src/transaction_request.rs index cfcc659008b9..d51378452dda 100644 --- a/core/lib/types/src/transaction_request.rs +++ b/core/lib/types/src/transaction_request.rs @@ -811,6 +811,7 @@ impl TransactionRequest { impl L2Tx { pub(crate) fn from_request_unverified( mut value: TransactionRequest, + use_evm_simulator: bool, ) -> Result { let fee = value.get_fee_data_checked()?; let nonce = value.get_nonce_checked()?; @@ -819,10 +820,6 @@ impl L2Tx { let meta = value.eip712_meta.take().unwrap_or_default(); validate_factory_deps(&meta.factory_deps)?; - let use_evm_simulator = use_evm_simulator::UseEvmSimulator::from_env() - .unwrap() - .use_evm_simulator; - // TODO: Remove this check when evm equivalence gets enabled if value.to.is_none() && !use_evm_simulator { return Err(SerializationTransactionError::ToAddressIsNull); @@ -858,7 +855,8 @@ impl L2Tx { value: TransactionRequest, max_tx_size: usize, ) -> Result { - let tx = Self::from_request_unverified(value)?; + let use_evm_simulator = use_evm_simulator::UseEvmSimulator::from_env().unwrap().use_evm_simulator; + let tx = Self::from_request_unverified(value, use_evm_simulator)?; tx.check_encoded_size(max_tx_size)?; Ok(tx) } diff --git a/core/lib/vm_executor/src/oneshot/mock.rs b/core/lib/vm_executor/src/oneshot/mock.rs index 8408206ede4c..a7363c633c6c 100644 --- a/core/lib/vm_executor/src/oneshot/mock.rs +++ b/core/lib/vm_executor/src/oneshot/mock.rs @@ -68,7 +68,7 @@ impl MockOneshotExecutor { logs: Default::default(), statistics: Default::default(), refunds: Default::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, } }, ) diff --git a/core/lib/vm_interface/src/types/outputs/finished_l1batch.rs b/core/lib/vm_interface/src/types/outputs/finished_l1batch.rs index a71c9f8f7a5e..8f7c1d4fb0d6 100644 --- a/core/lib/vm_interface/src/types/outputs/finished_l1batch.rs +++ b/core/lib/vm_interface/src/types/outputs/finished_l1batch.rs @@ -26,7 +26,7 @@ impl FinishedL1Batch { logs: VmExecutionLogs::default(), statistics: VmExecutionStatistics::default(), refunds: Refunds::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, }, final_execution_state: CurrentExecutionState { events: vec![], diff --git a/core/node/api_server/src/web3/tests/vm.rs b/core/node/api_server/src/web3/tests/vm.rs index 0093712767dc..b6ec32b1afc6 100644 --- a/core/node/api_server/src/web3/tests/vm.rs +++ b/core/node/api_server/src/web3/tests/vm.rs @@ -393,7 +393,7 @@ impl HttpTest for SendTransactionWithDetailedOutputTest { logs: vm_execution_logs.clone(), statistics: Default::default(), refunds: Default::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, } }); tx_executor diff --git a/core/node/state_keeper/src/testonly/mod.rs b/core/node/state_keeper/src/testonly/mod.rs index 34a9a88bcb32..d1e82c44bd6f 100644 --- a/core/node/state_keeper/src/testonly/mod.rs +++ b/core/node/state_keeper/src/testonly/mod.rs @@ -33,7 +33,7 @@ pub(crate) fn successful_exec() -> BatchTransactionExecutionResult { logs: Default::default(), statistics: Default::default(), refunds: Default::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, }), compressed_bytecodes: vec![], call_traces: 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 2a883bb011b3..cb282f3b7d6d 100644 --- a/core/node/state_keeper/src/testonly/test_batch_executor.rs +++ b/core/node/state_keeper/src/testonly/test_batch_executor.rs @@ -264,7 +264,7 @@ pub(crate) fn successful_exec_with_log() -> BatchTransactionExecutionResult { }, statistics: Default::default(), refunds: Default::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, }), compressed_bytecodes: vec![], call_traces: vec![], @@ -279,7 +279,7 @@ pub(crate) fn rejected_exec(reason: Halt) -> BatchTransactionExecutionResult { logs: Default::default(), statistics: Default::default(), refunds: Default::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, }), compressed_bytecodes: vec![], call_traces: vec![], diff --git a/core/node/state_keeper/src/tests/mod.rs b/core/node/state_keeper/src/tests/mod.rs index 10c42c7857bd..9e971541b204 100644 --- a/core/node/state_keeper/src/tests/mod.rs +++ b/core/node/state_keeper/src/tests/mod.rs @@ -138,7 +138,7 @@ pub(super) fn create_execution_result( circuit_statistic: Default::default(), }, refunds: Refunds::default(), - new_known_factory_deps: Default::default(), + new_known_factory_deps: None, } } 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 3d0d35096c2f..2301016c314a 100644 --- a/core/node/state_keeper/src/updates/l2_block_updates.rs +++ b/core/node/state_keeper/src/updates/l2_block_updates.rs @@ -129,12 +129,7 @@ impl L2BlockUpdates { .map(|bytecode| (hash_bytecode(bytecode), bytecode.clone())) .collect(); - new_known_factory_deps - .into_iter() - .for_each(|(hash, bytecode)| { - tx_factory_deps.insert(hash, bytecode); - }); - + tx_factory_deps.extend(new_known_factory_deps.clone()); // 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(|| { From 6313c7de05e09a9f997356613a72d6b52c24154a Mon Sep 17 00:00:00 2001 From: mtzsky Date: Wed, 25 Sep 2024 08:39:13 +0200 Subject: [PATCH 36/45] docs: fix invalid links to "namespaces/eth.rs" and "execution_sandbox.rs" (#2945) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ This PR fixes 2 invalid links in the documents which was caused by refactor (refactor: Split the rest of the zksync_core (https://github.com/matter-labs/zksync-era/pull/1940)) ## Why ❔ Unclarity in documentation ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [x] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. --- docs/guides/advanced/05_how_call_works.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/advanced/05_how_call_works.md b/docs/guides/advanced/05_how_call_works.md index 7f283cf8e0cf..5b9458ddce8e 100644 --- a/docs/guides/advanced/05_how_call_works.md +++ b/docs/guides/advanced/05_how_call_works.md @@ -110,10 +110,10 @@ In this article, we covered the 'life of a call' from the RPC to the inner worki https://github.com/matter-labs/zksync-era/blob/edd48fc37bdd58f9f9d85e27d684c01ef2cac8ae/core/bin/zksync_core/src/api_server/web3/backend_jsonrpc/namespaces/eth.rs 'namespaces RPC api' [namespaces_rpc_impl]: - https://github.com/matter-labs/zksync-era/blob/main/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs#L94 + https://github.com/matter-labs/zksync-era/blob/main/core/node/api_server/src/web3/namespaces/eth.rs 'namespaces RPC implementation' [execution_sandbox]: - https://github.com/matter-labs/zksync-era/blob/main/core/lib/zksync_core/src/api_server/execution_sandbox/execute.rs + https://github.com/matter-labs/zksync-era/blob/main/core/node/api_server/src/execution_sandbox/execute.rs 'execution sandbox' [vm_code]: https://github.com/matter-labs/zksync-era/blob/ccd13ce88ff52c3135d794c6f92bec3b16f2210f/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs#L108 From 2edd8a2c1f4ea30b39e608fdb399bf1566c7a637 Mon Sep 17 00:00:00 2001 From: EmilLuta Date: Wed, 25 Sep 2024 11:56:11 +0200 Subject: [PATCH 37/45] chore(prover): Fixes broken non-GPU setup (#2953) Previously, this was done via a compile flag. This was deemed poor taste and we've moved a specific env-var - `ZKSYNC_USE_CUDA_STUBS`. This is wired deep within crypto dependencies. This PR updates the dependencies, adds documentation on how to work with the flag and updates all workflows (fixing the broken ones from RUSTFLAGS time). --------- Co-authored-by: Igor Aleksanov --- .github/workflows/build-docker-from-tag.yml | 2 +- .../build-witness-generator-template.yml | 1 + .github/workflows/ci-common-reusable.yml | 2 +- .github/workflows/ci-core-lint-reusable.yml | 2 +- .github/workflows/ci-prover-reusable.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/release-test-stage.yml | 2 +- docker/witness-generator/Dockerfile | 3 +- docker/witness-vector-generator/Dockerfile | 3 +- docs/guides/external-node/00_quick_start.md | 3 +- docs/guides/setup-dev.md | 23 ++++++++------- prover/Cargo.lock | 28 +++++++++---------- prover/Cargo.toml | 4 +-- 13 files changed, 40 insertions(+), 37 deletions(-) diff --git a/.github/workflows/build-docker-from-tag.yml b/.github/workflows/build-docker-from-tag.yml index 0141bd825655..206e15bd195f 100644 --- a/.github/workflows/build-docker-from-tag.yml +++ b/.github/workflows/build-docker-from-tag.yml @@ -103,7 +103,7 @@ jobs: image_tag_suffix: ${{ needs.setup.outputs.image_tag_suffix }}-avx512 ERA_BELLMAN_CUDA_RELEASE: ${{ vars.ERA_BELLMAN_CUDA_RELEASE }} CUDA_ARCH: "60;70;75;80;89" - WITNESS_GENERATOR_RUST_FLAGS: "-Ctarget_feature=+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl --cfg=no_cuda" + WITNESS_GENERATOR_RUST_FLAGS: "-Ctarget_feature=+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl" secrets: DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/build-witness-generator-template.yml b/.github/workflows/build-witness-generator-template.yml index 9c29297460d9..33d78b3cf2fc 100644 --- a/.github/workflows/build-witness-generator-template.yml +++ b/.github/workflows/build-witness-generator-template.yml @@ -51,6 +51,7 @@ jobs: ERA_BELLMAN_CUDA_RELEASE: ${{ inputs.ERA_BELLMAN_CUDA_RELEASE }} CUDA_ARCH: ${{ inputs.CUDA_ARCH }} WITNESS_GENERATOR_RUST_FLAGS: ${{ inputs.WITNESS_GENERATOR_RUST_FLAGS }} + ZKSYNC_USE_CUDA_STUBS: true runs-on: [ matterlabs-ci-runner-c3d ] strategy: matrix: diff --git a/.github/workflows/ci-common-reusable.yml b/.github/workflows/ci-common-reusable.yml index 3d28df592e98..2f51229aeaf9 100644 --- a/.github/workflows/ci-common-reusable.yml +++ b/.github/workflows/ci-common-reusable.yml @@ -22,7 +22,7 @@ jobs: echo "SCCACHE_GCS_SERVICE_ACCOUNT=gha-ci-runners@matterlabs-infra.iam.gserviceaccount.com" >> .env echo "SCCACHE_GCS_RW_MODE=READ_WRITE" >> .env echo "RUSTC_WRAPPER=sccache" >> .env - echo "RUSTFLAGS=--cfg=no_cuda" >> .env + echo "ZKSYNC_USE_CUDA_STUBS=true" >> .env - name: Start services run: | diff --git a/.github/workflows/ci-core-lint-reusable.yml b/.github/workflows/ci-core-lint-reusable.yml index 85e4be3ff5e3..6d0785fe46f1 100644 --- a/.github/workflows/ci-core-lint-reusable.yml +++ b/.github/workflows/ci-core-lint-reusable.yml @@ -19,7 +19,7 @@ jobs: echo "SCCACHE_GCS_SERVICE_ACCOUNT=gha-ci-runners@matterlabs-infra.iam.gserviceaccount.com" >> .env echo "SCCACHE_GCS_RW_MODE=READ_WRITE" >> .env echo "RUSTC_WRAPPER=sccache" >> .env - echo "RUSTFLAGS=--cfg=no_cuda" >> .env + echo "ZKSYNC_USE_CUDA_STUBS=true" >> .env echo "prover_url=postgres://postgres:notsecurepassword@localhost:5432/zksync_local_prover" >> $GITHUB_ENV echo "core_url=postgres://postgres:notsecurepassword@localhost:5432/zksync_local" >> $GITHUB_ENV diff --git a/.github/workflows/ci-prover-reusable.yml b/.github/workflows/ci-prover-reusable.yml index 6fa987b1cecf..3f842b23488e 100644 --- a/.github/workflows/ci-prover-reusable.yml +++ b/.github/workflows/ci-prover-reusable.yml @@ -57,7 +57,7 @@ jobs: echo "SCCACHE_GCS_SERVICE_ACCOUNT=gha-ci-runners@matterlabs-infra.iam.gserviceaccount.com" >> .env echo "SCCACHE_GCS_RW_MODE=READ_WRITE" >> .env echo "RUSTC_WRAPPER=sccache" >> .env - echo "RUSTFLAGS=--cfg=no_cuda" >> .env + echo "ZKSYNC_USE_CUDA_STUBS=true" >> .env - name: Start services run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8c228956012..0a27a719aeb6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -166,7 +166,7 @@ jobs: with: image_tag_suffix: ${{ needs.setup.outputs.image_tag_suffix }}-avx512 action: "build" - WITNESS_GENERATOR_RUST_FLAGS: "-Ctarget_feature=+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl --cfg=no_cuda" + WITNESS_GENERATOR_RUST_FLAGS: "-Ctarget_feature=+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl" secrets: DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/release-test-stage.yml b/.github/workflows/release-test-stage.yml index 988426d0cb6e..11a844fdd2ba 100644 --- a/.github/workflows/release-test-stage.yml +++ b/.github/workflows/release-test-stage.yml @@ -115,7 +115,7 @@ jobs: image_tag_suffix: ${{ needs.setup.outputs.image_tag_suffix }}-avx512 ERA_BELLMAN_CUDA_RELEASE: ${{ vars.ERA_BELLMAN_CUDA_RELEASE }} CUDA_ARCH: "60;70;75;80;89" - WITNESS_GENERATOR_RUST_FLAGS: "-Ctarget_feature=+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl --cfg=no_cuda" + WITNESS_GENERATOR_RUST_FLAGS: "-Ctarget_feature=+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl " secrets: DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/docker/witness-generator/Dockerfile b/docker/witness-generator/Dockerfile index 06d836c9fa58..29e226987711 100644 --- a/docker/witness-generator/Dockerfile +++ b/docker/witness-generator/Dockerfile @@ -1,8 +1,9 @@ FROM ghcr.io/matter-labs/zksync-build-base:latest AS builder ARG DEBIAN_FRONTEND=noninteractive -ARG RUST_FLAGS="--cfg=no_cuda" +ARG RUST_FLAGS="" ENV RUSTFLAGS=${RUST_FLAGS} +ENV ZKSYNC_USE_CUDA_STUBS=true # set of args for use of sccache ARG SCCACHE_GCS_BUCKET="" diff --git a/docker/witness-vector-generator/Dockerfile b/docker/witness-vector-generator/Dockerfile index eb46b459c695..b305f89b0011 100644 --- a/docker/witness-vector-generator/Dockerfile +++ b/docker/witness-vector-generator/Dockerfile @@ -1,8 +1,7 @@ FROM ghcr.io/matter-labs/zksync-build-base:latest AS builder ARG DEBIAN_FRONTEND=noninteractive -ARG RUST_FLAGS="--cfg=no_cuda" -ENV RUSTFLAGS=${RUST_FLAGS} +ENV ZKSYNC_USE_CUDA_STUBS=true # set of args for use of sccache ARG SCCACHE_GCS_BUCKET="" diff --git a/docs/guides/external-node/00_quick_start.md b/docs/guides/external-node/00_quick_start.md index 75d8ba891512..287a4d2d47c0 100644 --- a/docs/guides/external-node/00_quick_start.md +++ b/docs/guides/external-node/00_quick_start.md @@ -34,8 +34,7 @@ cd docker-compose-examples docker compose --file testnet-external-node-docker-compose.yml down --volumes ``` -You can see the status of the node (after recovery) in -[local grafana dashboard](http://localhost:3000/dashboards). +You can see the status of the node (after recovery) in [local grafana dashboard](http://localhost:3000/dashboards). Those commands start ZKsync node locally inside docker. diff --git a/docs/guides/setup-dev.md b/docs/guides/setup-dev.md index 7781e65e5bfb..4eef211cd3d1 100644 --- a/docs/guides/setup-dev.md +++ b/docs/guides/setup-dev.md @@ -49,9 +49,9 @@ cargo install sqlx-cli --version 0.8.1 curl -L https://foundry.paradigm.xyz | bash foundryup --branch master -# Non GPU setup, can be skipped if the machine has a GPU configured for provers -echo "export RUSTFLAGS='--cfg=no_cuda'" >> ~/.bashrc - +# Non CUDA (GPU) setup, can be skipped if the machine has a CUDA installed for provers +# Don't do that if you intend to run provers on your machine. Check the prover docs for a setup instead. +echo "export ZKSYNC_USE_CUDA_STUBS=true" >> ~/.bashrc # You will need to reload your `*rc` file here # Clone the repo to the desired location @@ -243,20 +243,23 @@ commands related to deployment, you can pass flags for Foundry integration. ## Non-GPU setup -Circuit Prover requires a GPU (& CUDA bindings) to run. If you still want to be able to build everything locally on -non-GPU setup, you'll need to change your rustflags. +Circuit Prover requires a CUDA bindings to run. If you still want to be able to build everything locally on non-CUDA +setup, you'll need use CUDA stubs. For a single run, it's enough to export it on the shell: ``` -export RUSTFLAGS='--cfg=no_cuda' +export ZKSYNC_USE_CUDA_STUBS=true ``` -For persistent runs, you can either echo it in your ~/.rc file (discouraged), or configure it for your taste in -`config.toml`. +For persistent runs, you can echo it in your ~/.rc file + +``` +echo "export ZKSYNC_USE_CUDA_STUBS=true" >> ~/.rc +``` -For project level configuration, edit `/path/to/zksync/.cargo/config.toml`. For global cargo setup, -`~/.cargo/config.toml`. Add the following: +Note that the same can be achieved with RUSTFLAGS (discouraged). The flag is `--cfg=no_cuda`. You can either set +RUSTFLAGS as env var, or pass it in `config.toml` (either project level or global). The config would need the following: ```toml [build] diff --git a/prover/Cargo.lock b/prover/Cargo.lock index 88c0d1114fc4..1abec8d0c1a8 100644 --- a/prover/Cargo.lock +++ b/prover/Cargo.lock @@ -650,9 +650,9 @@ dependencies = [ [[package]] name = "boojum-cuda" -version = "0.150.7" +version = "0.150.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac7735446f2263e8d12435fc4d5a02c7727838eaffc7c518a961b3e839fb59e7" +checksum = "04f9a6d958dd58a0899737e5a1fc6597aefcf7980bf8be5be5329e701cbd45ca" dependencies = [ "boojum", "cmake", @@ -1690,9 +1690,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "era_cudart" -version = "0.150.7" +version = "0.150.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f76aa50bd291b43ad56fb7da3e63c4c3cecb3c7e19db76c8097856371bc0d84a" +checksum = "51f0d6e329b2c11d134c3140951209be968ef316ed64ddde75640eaed7f10264" dependencies = [ "bitflags 2.6.0", "era_cudart_sys", @@ -1701,9 +1701,9 @@ dependencies = [ [[package]] name = "era_cudart_sys" -version = "0.150.7" +version = "0.150.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d2db304df6b72141d45b140ec6df68ecd2300a7ab27de18b3e0e3af38c9776" +checksum = "060e8186234c7a281021fb95614e06e94e1fc7ab78938360a5c27af0f8fc6105" dependencies = [ "serde_json", ] @@ -5313,9 +5313,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "shivini" -version = "0.150.7" +version = "0.150.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f11e6942c89861aecb72261f8220800a1b69b8a5463c07c24df75b81fd809b0" +checksum = "ebb6d928451f0779f14da02ee9d51d4bde560328edc6471f0d5c5c11954345c4" dependencies = [ "bincode", "blake2 0.10.6", @@ -7279,9 +7279,9 @@ dependencies = [ [[package]] name = "zksync-gpu-ffi" -version = "0.150.7" +version = "0.150.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aecd7f624185b785e9d8457986ac34685d478e2baa78417d51b102b7d0fa27fd" +checksum = "86511b3957adfe415ecdbd1ee01c51aa3ca131a607e61ca024976312f613b0f9" dependencies = [ "bindgen 0.59.2", "cmake", @@ -7295,9 +7295,9 @@ dependencies = [ [[package]] name = "zksync-gpu-prover" -version = "0.150.7" +version = "0.150.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a089b11fcdbd37065acaf427545cb50b87e6712951a10f3761b3d370e4b8f9bc" +checksum = "9e4c00f2db603d1b696bc2e9d822bb4c087050de5b65559067fc2232786cbc93" dependencies = [ "bit-vec", "cfg-if", @@ -7312,9 +7312,9 @@ dependencies = [ [[package]] name = "zksync-wrapper-prover" -version = "0.150.7" +version = "0.150.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc764c21d4ae15c5bc2c07c14c814c5e3ba8d194ddcca543b8cec95456031832" +checksum = "d58df1ec10e0d5eb58563bb01abda5ed185c9b9621502e361848ca40eb7868ac" dependencies = [ "circuit_definitions", "zkevm_test_harness", diff --git a/prover/Cargo.toml b/prover/Cargo.toml index b21ad800afac..e95bae3d4c16 100644 --- a/prover/Cargo.toml +++ b/prover/Cargo.toml @@ -63,8 +63,8 @@ circuit_sequencer_api = "=0.150.5" zkevm_test_harness = "=0.150.5" # GPU proving dependencies -wrapper_prover = { package = "zksync-wrapper-prover", version = "=0.150.7" } -shivini = "=0.150.7" +wrapper_prover = { package = "zksync-wrapper-prover", version = "=0.150.9" } +shivini = "=0.150.9" # Core workspace dependencies zksync_multivm = { path = "../core/lib/multivm", version = "0.1.0" } From 1fdbb304a8cdc739bcdc0087dfd4e34560d5dff2 Mon Sep 17 00:00:00 2001 From: EmilLuta Date: Wed, 25 Sep 2024 13:04:40 +0200 Subject: [PATCH 38/45] chore(prover-gateway): Speed up polling (#2957) 16 minutes is just ridiculous. This should've been done a long time ago, but has been avoided due to other priorities and always put on the back-burner/forgotten. Today we change it. --- etc/env/base/fri_prover_gateway.toml | 2 +- etc/env/file_based/general.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/env/base/fri_prover_gateway.toml b/etc/env/base/fri_prover_gateway.toml index 8974298a57c3..f77b5d592580 100644 --- a/etc/env/base/fri_prover_gateway.toml +++ b/etc/env/base/fri_prover_gateway.toml @@ -1,6 +1,6 @@ [fri_prover_gateway] api_url="http://127.0.0.1:3320" -api_poll_duration_secs=1000 +api_poll_duration_secs=15 prometheus_listener_port=3314 prometheus_pushgateway_url="http://127.0.0.1:9091" prometheus_push_interval_ms=100 diff --git a/etc/env/file_based/general.yaml b/etc/env/file_based/general.yaml index 6a36f65c97c3..cdf02175458b 100644 --- a/etc/env/file_based/general.yaml +++ b/etc/env/file_based/general.yaml @@ -172,7 +172,7 @@ data_handler: tee_support: true prover_gateway: api_url: http://127.0.0.1:3320 - api_poll_duration_secs: 1000 + api_poll_duration_secs: 15 prometheus_listener_port: 3310 prometheus_pushgateway_url: http://127.0.0.1:9091 prometheus_push_interval_ms: 100 From 218646aa1c56200f4ffee99b7f83366e2689354f Mon Sep 17 00:00:00 2001 From: Danil Date: Wed, 25 Sep 2024 13:44:48 +0200 Subject: [PATCH 39/45] fix(api): Return correct flat call tracer (#2917) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ It was an inconsistency between call tracer results ## Why ❔ ## Checklist - [x] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [x] Code has been formatted via `zk fmt` and `zk lint`. --------- Signed-off-by: Danil --- ...46bd1b7b9269375f11f050099cb6d3c1427aa.json | 34 +++ ...c783b3710ee47f88edce1b17c2b8fa21dadd3.json | 22 -- ...355e6aec05ba4af297a03169e3122a67ae53e.json | 28 +++ ...0fb28594859564a0f888eae748ad1f9fcede5.json | 22 -- core/lib/dal/src/blocks_web3_dal.rs | 13 +- .../lib/dal/src/models/storage_transaction.rs | 42 ++-- core/lib/dal/src/transactions_dal.rs | 24 +- core/lib/types/src/api/mod.rs | 80 +++++- core/lib/types/src/debug_flat_call.rs | 235 +----------------- core/lib/web3_decl/src/namespaces/debug.rs | 18 +- .../backend_jsonrpsee/namespaces/debug.rs | 21 +- .../api_server/src/web3/namespaces/debug.rs | 172 ++++++++++--- core/node/api_server/src/web3/tests/debug.rs | 44 +++- core/node/api_server/src/web3/tests/vm.rs | 22 +- .../ts-integration/tests/api/debug.test.ts | 6 +- prover/crates/bin/prover_fri/src/utils.rs | 2 +- ...f1cdac8b194f09926c133985479c533a651f2.json | 18 ++ ...0d001cdf5bc7ba988b742571ec90a938434e3.json | 17 -- ...0cd5c6b1122c35d7ffdbbba30327ca3fb5a8.json} | 4 +- ...cf8c93630d529ec96e67aac078f18196f61a5.json | 19 ++ ...adefab0bf3abf6853a6d36123c8adcaf813b.json} | 4 +- ...d48c95ca5b4520dde415a2b5ff32ece47c86.json} | 4 +- ...8d4cc59246dda91b19526e73f27a17c8e3da.json} | 4 +- ...a468057599be1e6c6c96a947c33df53a68224.json | 15 -- ...2e61157bf58aec70903623afc9da24d46a336.json | 16 -- ...1b931c0d8dbc6835dfac20107ea7412ce9fbb.json | 15 -- ...9a67936d572f8046d3a1c7a4f100ff209d81d.json | 18 -- ...41976a264759c4060c1a38e466ee2052fc17d.json | 15 ++ ...2a4a98ec63eb942c73ce4448d0957346047cd.json | 17 ++ ...08a01b63ae4aa03c983c3a52c802d585e5a80.json | 15 ++ ...700302981be0afef31a8864613484f8521f9e.json | 19 -- ...b5a4672ad50a9de92c84d939ac4c69842e355.json | 16 ++ ...d005d8760c4809b7aef902155196873da66e.json} | 4 +- ...8e1010d7389457b3c97e9b238a3a0291a54e.json} | 4 +- .../crates/lib/prover_dal/src/cli_test_dal.rs | 99 ++++---- .../lib/prover_dal/src/fri_prover_dal.rs | 10 +- .../src/fri_witness_generator_dal.rs | 15 +- yarn.lock | 2 +- 38 files changed, 576 insertions(+), 559 deletions(-) create mode 100644 core/lib/dal/.sqlx/query-6171f2d631f69dba52cd913742a46bd1b7b9269375f11f050099cb6d3c1427aa.json delete mode 100644 core/lib/dal/.sqlx/query-b98e3790de305017c8fa5fba4c0c783b3710ee47f88edce1b17c2b8fa21dadd3.json create mode 100644 core/lib/dal/.sqlx/query-bdfd7e9d4462ac9cf6f91fced84355e6aec05ba4af297a03169e3122a67ae53e.json delete mode 100644 core/lib/dal/.sqlx/query-c37432fabd092fa235fc70e11430fb28594859564a0f888eae748ad1f9fcede5.json create mode 100644 prover/crates/lib/prover_dal/.sqlx/query-1297f0977132185d6bd4501f490f1cdac8b194f09926c133985479c533a651f2.json delete mode 100644 prover/crates/lib/prover_dal/.sqlx/query-1926cf432237684de2383179a6d0d001cdf5bc7ba988b742571ec90a938434e3.json rename prover/crates/lib/prover_dal/.sqlx/{query-97adb49780c9edde6a3cfda09dadbd694e1781e013247d090a280a1f894de464.json => query-29f7a564a8373f7e44840e8e9e7d0cd5c6b1122c35d7ffdbbba30327ca3fb5a8.json} (53%) create mode 100644 prover/crates/lib/prover_dal/.sqlx/query-2d1461e068e43fd16714610b383cf8c93630d529ec96e67aac078f18196f61a5.json rename prover/crates/lib/prover_dal/.sqlx/{query-75c1affbca0901edd5d0e2f12ef4d935674a5aff2f34421d753b4d1a9dea5b12.json => query-35a76415cb746d03da31481edc65adefab0bf3abf6853a6d36123c8adcaf813b.json} (70%) rename prover/crates/lib/prover_dal/.sqlx/{query-548414f8148740c991c345e5fd46ea738d209eb07e7a6bcbdb33e25b3347a08c.json => query-3727d5614d2fe2a4d96f880eb72cd48c95ca5b4520dde415a2b5ff32ece47c86.json} (70%) rename prover/crates/lib/prover_dal/.sqlx/{query-c19fc4c8e4b3a3ef4f9c0f4c22ed68c598eada8e60938a8e4b5cd32b53f5a574.json => query-37ad15f54f4a6f4f79c71a857f3a8d4cc59246dda91b19526e73f27a17c8e3da.json} (69%) delete mode 100644 prover/crates/lib/prover_dal/.sqlx/query-39f60c638d445c5dbf23e01fd89a468057599be1e6c6c96a947c33df53a68224.json delete mode 100644 prover/crates/lib/prover_dal/.sqlx/query-3a9ffd4d88f2cfac22835aac2512e61157bf58aec70903623afc9da24d46a336.json delete mode 100644 prover/crates/lib/prover_dal/.sqlx/query-3bb8fbd9e83703887e0a3c196031b931c0d8dbc6835dfac20107ea7412ce9fbb.json delete mode 100644 prover/crates/lib/prover_dal/.sqlx/query-434f7cb51a7d22948cd26e962679a67936d572f8046d3a1c7a4f100ff209d81d.json create mode 100644 prover/crates/lib/prover_dal/.sqlx/query-73266a8526c6adc315900e2e95441976a264759c4060c1a38e466ee2052fc17d.json create mode 100644 prover/crates/lib/prover_dal/.sqlx/query-9730c8225ff2cf3111185e81f602a4a98ec63eb942c73ce4448d0957346047cd.json create mode 100644 prover/crates/lib/prover_dal/.sqlx/query-a817f0fec85388b3e2510ce259208a01b63ae4aa03c983c3a52c802d585e5a80.json delete mode 100644 prover/crates/lib/prover_dal/.sqlx/query-aabcfa9005b8e1d84cfa083a47a700302981be0afef31a8864613484f8521f9e.json create mode 100644 prover/crates/lib/prover_dal/.sqlx/query-c8daa62b3835c15fafb3f83deabb5a4672ad50a9de92c84d939ac4c69842e355.json rename prover/crates/lib/prover_dal/.sqlx/{query-63cf7038e6c48af8ed9afc7d6ea07edd87cb16a79c13e7d4291d99736e51d3b9.json => query-e875dcbbdaed6998dbea45d4eab5d005d8760c4809b7aef902155196873da66e.json} (82%) rename prover/crates/lib/prover_dal/.sqlx/{query-0eac6f7b2d799059328584029b437891598dc79b5ed11258b2c90c3f282929ad.json => query-eec29cbff034818f4fb5ec1e6ad38e1010d7389457b3c97e9b238a3a0291a54e.json} (78%) diff --git a/core/lib/dal/.sqlx/query-6171f2d631f69dba52cd913742a46bd1b7b9269375f11f050099cb6d3c1427aa.json b/core/lib/dal/.sqlx/query-6171f2d631f69dba52cd913742a46bd1b7b9269375f11f050099cb6d3c1427aa.json new file mode 100644 index 000000000000..84ff845b0d01 --- /dev/null +++ b/core/lib/dal/.sqlx/query-6171f2d631f69dba52cd913742a46bd1b7b9269375f11f050099cb6d3c1427aa.json @@ -0,0 +1,34 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n transactions.hash AS tx_hash,\n transactions.index_in_block AS tx_index_in_block,\n call_trace\n FROM\n call_traces\n INNER JOIN transactions ON tx_hash = transactions.hash\n WHERE\n transactions.miniblock_number = $1\n ORDER BY\n transactions.index_in_block\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "tx_hash", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "tx_index_in_block", + "type_info": "Int4" + }, + { + "ordinal": 2, + "name": "call_trace", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + true, + false + ] + }, + "hash": "6171f2d631f69dba52cd913742a46bd1b7b9269375f11f050099cb6d3c1427aa" +} diff --git a/core/lib/dal/.sqlx/query-b98e3790de305017c8fa5fba4c0c783b3710ee47f88edce1b17c2b8fa21dadd3.json b/core/lib/dal/.sqlx/query-b98e3790de305017c8fa5fba4c0c783b3710ee47f88edce1b17c2b8fa21dadd3.json deleted file mode 100644 index 81981683e895..000000000000 --- a/core/lib/dal/.sqlx/query-b98e3790de305017c8fa5fba4c0c783b3710ee47f88edce1b17c2b8fa21dadd3.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT\n protocol_version\n FROM\n transactions\n INNER JOIN miniblocks ON transactions.miniblock_number = miniblocks.number\n WHERE\n transactions.hash = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "protocol_version", - "type_info": "Int4" - } - ], - "parameters": { - "Left": [ - "Bytea" - ] - }, - "nullable": [ - true - ] - }, - "hash": "b98e3790de305017c8fa5fba4c0c783b3710ee47f88edce1b17c2b8fa21dadd3" -} diff --git a/core/lib/dal/.sqlx/query-bdfd7e9d4462ac9cf6f91fced84355e6aec05ba4af297a03169e3122a67ae53e.json b/core/lib/dal/.sqlx/query-bdfd7e9d4462ac9cf6f91fced84355e6aec05ba4af297a03169e3122a67ae53e.json new file mode 100644 index 000000000000..0b1f56ef9f33 --- /dev/null +++ b/core/lib/dal/.sqlx/query-bdfd7e9d4462ac9cf6f91fced84355e6aec05ba4af297a03169e3122a67ae53e.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n protocol_version,\n index_in_block\n FROM\n transactions\n INNER JOIN miniblocks ON transactions.miniblock_number = miniblocks.number\n WHERE\n transactions.hash = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "index_in_block", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + true, + true + ] + }, + "hash": "bdfd7e9d4462ac9cf6f91fced84355e6aec05ba4af297a03169e3122a67ae53e" +} diff --git a/core/lib/dal/.sqlx/query-c37432fabd092fa235fc70e11430fb28594859564a0f888eae748ad1f9fcede5.json b/core/lib/dal/.sqlx/query-c37432fabd092fa235fc70e11430fb28594859564a0f888eae748ad1f9fcede5.json deleted file mode 100644 index 906cd1081403..000000000000 --- a/core/lib/dal/.sqlx/query-c37432fabd092fa235fc70e11430fb28594859564a0f888eae748ad1f9fcede5.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT\n call_trace\n FROM\n call_traces\n INNER JOIN transactions ON tx_hash = transactions.hash\n WHERE\n transactions.miniblock_number = $1\n ORDER BY\n transactions.index_in_block\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "call_trace", - "type_info": "Bytea" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - false - ] - }, - "hash": "c37432fabd092fa235fc70e11430fb28594859564a0f888eae748ad1f9fcede5" -} diff --git a/core/lib/dal/src/blocks_web3_dal.rs b/core/lib/dal/src/blocks_web3_dal.rs index 36a4acc0a6db..3d17a919a073 100644 --- a/core/lib/dal/src/blocks_web3_dal.rs +++ b/core/lib/dal/src/blocks_web3_dal.rs @@ -527,7 +527,7 @@ impl BlocksWeb3Dal<'_, '_> { pub async fn get_traces_for_l2_block( &mut self, block_number: L2BlockNumber, - ) -> DalResult> { + ) -> DalResult> { let protocol_version = sqlx::query!( r#" SELECT @@ -554,6 +554,8 @@ impl BlocksWeb3Dal<'_, '_> { CallTrace, r#" SELECT + transactions.hash AS tx_hash, + transactions.index_in_block AS tx_index_in_block, call_trace FROM call_traces @@ -570,7 +572,11 @@ impl BlocksWeb3Dal<'_, '_> { .fetch_all(self.storage) .await? .into_iter() - .map(|call_trace| call_trace.into_call(protocol_version)) + .map(|call_trace| { + let hash = H256::from_slice(&call_trace.tx_hash); + let index = call_trace.tx_index_in_block.unwrap_or_default() as usize; + (call_trace.into_call(protocol_version), hash, index) + }) .collect()) } @@ -1084,8 +1090,9 @@ mod tests { .await .unwrap(); assert_eq!(traces.len(), 2); - for (trace, tx_result) in traces.iter().zip(&tx_results) { + for ((trace, hash, _index), tx_result) in traces.iter().zip(&tx_results) { let expected_trace = tx_result.call_trace().unwrap(); + assert_eq!(&tx_result.hash, hash); assert_eq!(*trace, expected_trace); } } diff --git a/core/lib/dal/src/models/storage_transaction.rs b/core/lib/dal/src/models/storage_transaction.rs index 9f67e9025e0c..bb219ee1d61b 100644 --- a/core/lib/dal/src/models/storage_transaction.rs +++ b/core/lib/dal/src/models/storage_transaction.rs @@ -561,32 +561,38 @@ impl StorageApiTransaction { #[derive(Debug, Clone, sqlx::FromRow)] pub(crate) struct CallTrace { pub call_trace: Vec, + pub tx_hash: Vec, + pub tx_index_in_block: Option, } impl CallTrace { pub(crate) fn into_call(self, protocol_version: ProtocolVersionId) -> Call { - if protocol_version.is_pre_1_5_0() { - if let Ok(legacy_call_trace) = bincode::deserialize::(&self.call_trace) { - legacy_call_trace.into() - } else { - let legacy_mixed_call_trace = - bincode::deserialize::(&self.call_trace) - .expect("Failed to deserialize call trace"); - legacy_mixed_call_trace.into() - } - } else { - bincode::deserialize(&self.call_trace).unwrap() - } + parse_call_trace(&self.call_trace, protocol_version) } +} - pub(crate) fn from_call(call: Call, protocol_version: ProtocolVersionId) -> Self { - let call_trace = if protocol_version.is_pre_1_5_0() { - bincode::serialize(&LegacyCall::try_from(call).unwrap()) +pub(crate) fn parse_call_trace(call_trace: &[u8], protocol_version: ProtocolVersionId) -> Call { + if protocol_version.is_pre_1_5_0() { + if let Ok(legacy_call_trace) = bincode::deserialize::(call_trace) { + legacy_call_trace.into() } else { - bincode::serialize(&call) + let legacy_mixed_call_trace = bincode::deserialize::(call_trace) + .expect("Failed to deserialize call trace"); + legacy_mixed_call_trace.into() } - .unwrap(); + } else { + bincode::deserialize(call_trace).unwrap() + } +} - Self { call_trace } +pub(crate) fn serialize_call_into_bytes( + call: Call, + protocol_version: ProtocolVersionId, +) -> Vec { + if protocol_version.is_pre_1_5_0() { + bincode::serialize(&LegacyCall::try_from(call).unwrap()) + } else { + bincode::serialize(&call) } + .unwrap() } diff --git a/core/lib/dal/src/transactions_dal.rs b/core/lib/dal/src/transactions_dal.rs index 0a72289b48a4..408837d699e6 100644 --- a/core/lib/dal/src/transactions_dal.rs +++ b/core/lib/dal/src/transactions_dal.rs @@ -20,7 +20,9 @@ use zksync_vm_interface::{ }; use crate::{ - models::storage_transaction::{CallTrace, StorageTransaction}, + models::storage_transaction::{ + parse_call_trace, serialize_call_into_bytes, StorageTransaction, + }, Core, CoreDal, }; @@ -521,8 +523,7 @@ impl TransactionsDal<'_, '_> { let mut bytea_call_traces = Vec::with_capacity(transactions.len()); for tx_res in transactions { if let Some(call_trace) = tx_res.call_trace() { - bytea_call_traces - .push(CallTrace::from_call(call_trace, protocol_version).call_trace); + bytea_call_traces.push(serialize_call_into_bytes(call_trace, protocol_version)); call_traces_tx_hashes.push(tx_res.hash.as_bytes()); } } @@ -2112,11 +2113,12 @@ impl TransactionsDal<'_, '_> { Ok(data) } - pub async fn get_call_trace(&mut self, tx_hash: H256) -> DalResult> { + pub async fn get_call_trace(&mut self, tx_hash: H256) -> DalResult> { let row = sqlx::query!( r#" SELECT - protocol_version + protocol_version, + index_in_block FROM transactions INNER JOIN miniblocks ON transactions.miniblock_number = miniblocks.number @@ -2139,8 +2141,7 @@ impl TransactionsDal<'_, '_> { .map(|v| (v as u16).try_into().unwrap()) .unwrap_or_else(ProtocolVersionId::last_potentially_undefined); - Ok(sqlx::query_as!( - CallTrace, + Ok(sqlx::query!( r#" SELECT call_trace @@ -2155,7 +2156,12 @@ impl TransactionsDal<'_, '_> { .with_arg("tx_hash", &tx_hash) .fetch_optional(self.storage) .await? - .map(|call_trace| call_trace.into_call(protocol_version))) + .map(|call_trace| { + ( + parse_call_trace(&call_trace.call_trace, protocol_version), + row.index_in_block.unwrap_or_default() as usize, + ) + })) } pub(crate) async fn get_tx_by_hash(&mut self, hash: H256) -> DalResult> { @@ -2227,7 +2233,7 @@ mod tests { .await .unwrap(); - let call_trace = conn + let (call_trace, _) = conn .transactions_dal() .get_call_trace(tx_hash) .await diff --git a/core/lib/types/src/api/mod.rs b/core/lib/types/src/api/mod.rs index f648204ca557..432b6c309c10 100644 --- a/core/lib/types/src/api/mod.rs +++ b/core/lib/types/src/api/mod.rs @@ -13,7 +13,10 @@ use zksync_contracts::BaseSystemContractsHashes; pub use crate::transaction_request::{ Eip712Meta, SerializationTransactionError, TransactionRequest, }; -use crate::{protocol_version::L1VerifierConfig, Address, L2BlockNumber, ProtocolVersionId}; +use crate::{ + debug_flat_call::DebugCallFlat, protocol_version::L1VerifierConfig, Address, L2BlockNumber, + ProtocolVersionId, +}; pub mod en; pub mod state_override; @@ -602,6 +605,7 @@ pub struct ResultDebugCall { } #[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)] +#[serde(rename_all = "camelCase")] pub enum DebugCallType { #[default] Call, @@ -701,19 +705,20 @@ impl ProtocolVersion { } } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, Copy)] #[serde(rename_all = "camelCase")] pub enum SupportedTracers { CallTracer, + FlatCallTracer, } -#[derive(Debug, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Serialize, Deserialize, Clone, Default, Copy)] #[serde(rename_all = "camelCase")] pub struct CallTracerConfig { pub only_top_call: bool, } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, Copy)] #[serde(rename_all = "camelCase")] pub struct TracerConfig { pub tracer: SupportedTracers, @@ -721,6 +726,17 @@ pub struct TracerConfig { pub tracer_config: CallTracerConfig, } +impl Default for TracerConfig { + fn default() -> Self { + TracerConfig { + tracer: SupportedTracers::CallTracer, + tracer_config: CallTracerConfig { + only_top_call: false, + }, + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum BlockStatus { @@ -728,6 +744,62 @@ pub enum BlockStatus { Verified, } +/// Result tracers need to have a nested result field for compatibility. So we have two different +/// structs 1 for blocks tracing and one for txs and call tracing +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(untagged)] +pub enum CallTracerBlockResult { + CallTrace(Vec), + FlatCallTrace(Vec), +} + +impl CallTracerBlockResult { + pub fn unwrap_flatten(self) -> Vec { + match self { + Self::CallTrace(_) => { + panic!("Result is a FlatCallTrace") + } + Self::FlatCallTrace(a) => a, + } + } + + pub fn unwrap_default(self) -> Vec { + match self { + Self::CallTrace(a) => a, + Self::FlatCallTrace(_) => { + panic!("Result is a CallTrace") + } + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(untagged)] +pub enum CallTracerResult { + CallTrace(DebugCall), + FlatCallTrace(Vec), +} + +impl CallTracerResult { + pub fn unwrap_flat(self) -> Vec { + match self { + Self::CallTrace(_) => { + panic!("Result is a FlatCallTrace") + } + Self::FlatCallTrace(a) => a, + } + } + + pub fn unwrap_default(self) -> DebugCall { + match self { + Self::CallTrace(a) => a, + Self::FlatCallTrace(_) => { + panic!("Result is a CallTrace") + } + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct BlockDetailsBase { diff --git a/core/lib/types/src/debug_flat_call.rs b/core/lib/types/src/debug_flat_call.rs index b5c0d79c8579..89a008b5fb5f 100644 --- a/core/lib/types/src/debug_flat_call.rs +++ b/core/lib/types/src/debug_flat_call.rs @@ -1,26 +1,24 @@ use serde::{Deserialize, Serialize}; use zksync_basic_types::{web3::Bytes, U256}; -use crate::{ - api::{DebugCall, DebugCallType, ResultDebugCall}, - Address, -}; +use crate::{api::DebugCallType, Address, H256}; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct DebugCallFlat { pub action: Action, - pub result: CallResult, + pub result: Option, pub subtraces: usize, - pub traceaddress: Vec, - pub error: Option, - pub revert_reason: Option, + pub trace_address: Vec, + pub transaction_position: usize, + pub transaction_hash: H256, + pub r#type: DebugCallType, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Action { - pub r#type: DebugCallType, + pub call_type: DebugCallType, pub from: Address, pub to: Address, pub gas: U256, @@ -34,222 +32,3 @@ pub struct CallResult { pub output: Bytes, pub gas_used: U256, } - -pub fn flatten_debug_calls(calls: Vec) -> Vec { - let mut flattened_calls = Vec::new(); - for (index, result_debug_call) in calls.into_iter().enumerate() { - let mut trace_address = vec![index]; // Initialize the trace addressees with the index of the top-level call - flatten_call_recursive( - &result_debug_call.result, - &mut flattened_calls, - &mut trace_address, - ); - } - flattened_calls -} - -fn flatten_call_recursive( - call: &DebugCall, - flattened_calls: &mut Vec, - trace_address: &mut Vec, -) { - let flat_call = DebugCallFlat { - action: Action { - r#type: call.r#type.clone(), - from: call.from, - to: call.to, - gas: call.gas, - value: call.value, - input: call.input.clone(), - }, - result: CallResult { - output: call.output.clone(), - gas_used: call.gas_used, - }, - subtraces: call.calls.len(), - traceaddress: trace_address.clone(), // Clone the current trace address - error: call.error.clone(), - revert_reason: call.revert_reason.clone(), - }; - flattened_calls.push(flat_call); - - // Process nested calls - for (index, nested_call) in call.calls.iter().enumerate() { - trace_address.push(index); // Update trace addressees for the nested call - flatten_call_recursive(nested_call, flattened_calls, trace_address); - trace_address.pop(); // Reset trace addressees after processing the nested call (prevent to keep filling the vector) - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::{ - api::{DebugCall, DebugCallType, ResultDebugCall}, - Address, BOOTLOADER_ADDRESS, - }; - - #[test] - fn test_flatten_debug_call() { - let result_debug_trace: Vec = [1, 1] - .map(|_| ResultDebugCall { - result: new_testing_debug_call(), - }) - .into(); - - let debug_call_flat = flatten_debug_calls(result_debug_trace); - let expected_debug_call_flat = expected_flat_trace(); - assert_eq!(debug_call_flat, expected_debug_call_flat); - } - - fn new_testing_debug_call() -> DebugCall { - DebugCall { - r#type: DebugCallType::Call, - from: Address::zero(), - to: BOOTLOADER_ADDRESS, - gas: 1000.into(), - gas_used: 1000.into(), - value: 0.into(), - output: vec![].into(), - input: vec![].into(), - error: None, - revert_reason: None, - calls: new_testing_trace(), - } - } - - fn new_testing_trace() -> Vec { - let first_call_trace = DebugCall { - from: Address::zero(), - to: Address::zero(), - gas: 100.into(), - gas_used: 42.into(), - ..DebugCall::default() - }; - let second_call_trace = DebugCall { - from: Address::zero(), - to: Address::zero(), - value: 123.into(), - gas: 58.into(), - gas_used: 10.into(), - input: Bytes(b"input".to_vec()), - output: Bytes(b"output".to_vec()), - ..DebugCall::default() - }; - [first_call_trace, second_call_trace].into() - } - - fn expected_flat_trace() -> Vec { - [ - DebugCallFlat { - action: Action { - r#type: DebugCallType::Call, - from: Address::zero(), - to: BOOTLOADER_ADDRESS, - gas: 1000.into(), - value: 0.into(), - input: vec![].into(), - }, - result: CallResult { - output: vec![].into(), - gas_used: 1000.into(), - }, - subtraces: 2, - traceaddress: [0].into(), - error: None, - revert_reason: None, - }, - DebugCallFlat { - action: Action { - r#type: DebugCallType::Call, - from: Address::zero(), - to: Address::zero(), - gas: 100.into(), - value: 0.into(), - input: vec![].into(), - }, - result: CallResult { - output: vec![].into(), - gas_used: 42.into(), - }, - subtraces: 0, - traceaddress: [0, 0].into(), - error: None, - revert_reason: None, - }, - DebugCallFlat { - action: Action { - r#type: DebugCallType::Call, - from: Address::zero(), - to: Address::zero(), - gas: 58.into(), - value: 123.into(), - input: b"input".to_vec().into(), - }, - result: CallResult { - output: b"output".to_vec().into(), - gas_used: 10.into(), - }, - subtraces: 0, - traceaddress: [0, 1].into(), - error: None, - revert_reason: None, - }, - DebugCallFlat { - action: Action { - r#type: DebugCallType::Call, - from: Address::zero(), - to: BOOTLOADER_ADDRESS, - gas: 1000.into(), - value: 0.into(), - input: vec![].into(), - }, - result: CallResult { - output: vec![].into(), - gas_used: 1000.into(), - }, - subtraces: 2, - traceaddress: [1].into(), - error: None, - revert_reason: None, - }, - DebugCallFlat { - action: Action { - r#type: DebugCallType::Call, - from: Address::zero(), - to: Address::zero(), - gas: 100.into(), - value: 0.into(), - input: vec![].into(), - }, - result: CallResult { - output: vec![].into(), - gas_used: 42.into(), - }, - subtraces: 0, - traceaddress: [1, 0].into(), - error: None, - revert_reason: None, - }, - DebugCallFlat { - action: Action { - r#type: DebugCallType::Call, - from: Address::zero(), - to: Address::zero(), - gas: 58.into(), - value: 123.into(), - input: b"input".to_vec().into(), - }, - result: CallResult { - output: b"output".to_vec().into(), - gas_used: 10.into(), - }, - subtraces: 0, - traceaddress: [1, 1].into(), - error: None, - revert_reason: None, - }, - ] - .into() - } -} diff --git a/core/lib/web3_decl/src/namespaces/debug.rs b/core/lib/web3_decl/src/namespaces/debug.rs index 1fbe3237104b..8ca5622e95d4 100644 --- a/core/lib/web3_decl/src/namespaces/debug.rs +++ b/core/lib/web3_decl/src/namespaces/debug.rs @@ -2,8 +2,7 @@ use jsonrpsee::core::RpcResult; use jsonrpsee::proc_macros::rpc; use zksync_types::{ - api::{BlockId, BlockNumber, DebugCall, ResultDebugCall, TracerConfig}, - debug_flat_call::DebugCallFlat, + api::{BlockId, BlockNumber, CallTracerBlockResult, CallTracerResult, TracerConfig}, transaction_request::CallRequest, }; @@ -26,21 +25,14 @@ pub trait DebugNamespace { &self, block: BlockNumber, options: Option, - ) -> RpcResult>; - - #[method(name = "traceBlockByNumber.callFlatTracer")] - async fn trace_block_by_number_flat( - &self, - block: BlockNumber, - options: Option, - ) -> RpcResult>; + ) -> RpcResult; #[method(name = "traceBlockByHash")] async fn trace_block_by_hash( &self, hash: H256, options: Option, - ) -> RpcResult>; + ) -> RpcResult; #[method(name = "traceCall")] async fn trace_call( @@ -48,12 +40,12 @@ pub trait DebugNamespace { request: CallRequest, block: Option, options: Option, - ) -> RpcResult; + ) -> RpcResult; #[method(name = "traceTransaction")] async fn trace_transaction( &self, tx_hash: H256, options: Option, - ) -> RpcResult>; + ) -> RpcResult>; } diff --git a/core/node/api_server/src/web3/backend_jsonrpsee/namespaces/debug.rs b/core/node/api_server/src/web3/backend_jsonrpsee/namespaces/debug.rs index 726beae2cc90..50981a2b284f 100644 --- a/core/node/api_server/src/web3/backend_jsonrpsee/namespaces/debug.rs +++ b/core/node/api_server/src/web3/backend_jsonrpsee/namespaces/debug.rs @@ -1,6 +1,5 @@ use zksync_types::{ - api::{BlockId, BlockNumber, DebugCall, ResultDebugCall, TracerConfig}, - debug_flat_call::DebugCallFlat, + api::{BlockId, BlockNumber, CallTracerBlockResult, CallTracerResult, TracerConfig}, transaction_request::CallRequest, H256, }; @@ -17,27 +16,17 @@ impl DebugNamespaceServer for DebugNamespace { &self, block: BlockNumber, options: Option, - ) -> RpcResult> { + ) -> RpcResult { self.debug_trace_block_impl(BlockId::Number(block), options) .await .map_err(|err| self.current_method().map_err(err)) } - async fn trace_block_by_number_flat( - &self, - block: BlockNumber, - options: Option, - ) -> RpcResult> { - self.debug_trace_block_flat_impl(BlockId::Number(block), options) - .await - .map_err(|err| self.current_method().map_err(err)) - } - async fn trace_block_by_hash( &self, hash: H256, options: Option, - ) -> RpcResult> { + ) -> RpcResult { self.debug_trace_block_impl(BlockId::Hash(hash), options) .await .map_err(|err| self.current_method().map_err(err)) @@ -48,7 +37,7 @@ impl DebugNamespaceServer for DebugNamespace { request: CallRequest, block: Option, options: Option, - ) -> RpcResult { + ) -> RpcResult { self.debug_trace_call_impl(request, block, options) .await .map_err(|err| self.current_method().map_err(err)) @@ -58,7 +47,7 @@ impl DebugNamespaceServer for DebugNamespace { &self, tx_hash: H256, options: Option, - ) -> RpcResult> { + ) -> RpcResult> { self.debug_trace_transaction_impl(tx_hash, options) .await .map_err(|err| self.current_method().map_err(err)) diff --git a/core/node/api_server/src/web3/namespaces/debug.rs b/core/node/api_server/src/web3/namespaces/debug.rs index 2c6c70f6faa1..68c7951cee45 100644 --- a/core/node/api_server/src/web3/namespaces/debug.rs +++ b/core/node/api_server/src/web3/namespaces/debug.rs @@ -3,8 +3,11 @@ use zksync_dal::{CoreDal, DalError}; use zksync_multivm::interface::{Call, CallType, ExecutionResult, OneshotTracingParams}; use zksync_system_constants::MAX_ENCODED_TX_SIZE; use zksync_types::{ - api::{BlockId, BlockNumber, DebugCall, DebugCallType, ResultDebugCall, TracerConfig}, - debug_flat_call::{flatten_debug_calls, DebugCallFlat}, + api::{ + BlockId, BlockNumber, CallTracerBlockResult, CallTracerResult, DebugCall, DebugCallType, + ResultDebugCall, SupportedTracers, TracerConfig, + }, + debug_flat_call::{Action, CallResult, DebugCallFlat}, fee_model::BatchFeeInput, l2::L2Tx, transaction_request::CallRequest, @@ -42,13 +45,39 @@ impl DebugNamespace { }) } - pub(crate) fn map_call(call: Call, only_top_call: bool) -> DebugCall { + pub(crate) fn map_call( + call: Call, + index: usize, + transaction_hash: H256, + tracer_option: TracerConfig, + ) -> CallTracerResult { + match tracer_option.tracer { + SupportedTracers::CallTracer => CallTracerResult::CallTrace(Self::map_default_call( + call, + tracer_option.tracer_config.only_top_call, + )), + SupportedTracers::FlatCallTracer => { + let mut calls = vec![]; + let mut traces = vec![index]; + Self::flatten_call( + call, + &mut calls, + &mut traces, + tracer_option.tracer_config.only_top_call, + index, + transaction_hash, + ); + CallTracerResult::FlatCallTrace(calls) + } + } + } + pub(crate) fn map_default_call(call: Call, only_top_call: bool) -> DebugCall { let calls = if only_top_call { vec![] } else { call.calls .into_iter() - .map(|call| Self::map_call(call, false)) + .map(|call| Self::map_default_call(call, false)) .collect() }; let debug_type = match call.r#type { @@ -71,6 +100,63 @@ impl DebugNamespace { } } + fn flatten_call( + call: Call, + calls: &mut Vec, + trace_address: &mut Vec, + only_top_call: bool, + transaction_position: usize, + transaction_hash: H256, + ) { + let subtraces = call.calls.len(); + let debug_type = match call.r#type { + CallType::Call(_) => DebugCallType::Call, + CallType::Create => DebugCallType::Create, + CallType::NearCall => unreachable!("We have to filter our near calls before"), + }; + + let result = if call.error.is_none() { + Some(CallResult { + output: web3::Bytes::from(call.output), + gas_used: U256::from(call.gas_used), + }) + } else { + None + }; + + calls.push(DebugCallFlat { + action: Action { + call_type: debug_type, + from: call.from, + to: call.to, + gas: U256::from(call.gas), + value: call.value, + input: web3::Bytes::from(call.input), + }, + result, + subtraces, + trace_address: trace_address.clone(), // Clone the current trace address + transaction_position, + transaction_hash, + r#type: DebugCallType::Call, + }); + + if !only_top_call { + for (number, call) in call.calls.into_iter().enumerate() { + trace_address.push(number); + Self::flatten_call( + call, + calls, + trace_address, + false, + transaction_position, + transaction_hash, + ); + trace_address.pop(); + } + } + } + pub(crate) fn current_method(&self) -> &MethodTracer { &self.state.current_method } @@ -79,16 +165,13 @@ impl DebugNamespace { &self, block_id: BlockId, options: Option, - ) -> Result, Web3Error> { + ) -> Result { self.current_method().set_block_id(block_id); if matches!(block_id, BlockId::Number(BlockNumber::Pending)) { // See `EthNamespace::get_block_impl()` for an explanation why this check is needed. - return Ok(vec![]); + return Ok(CallTracerBlockResult::CallTrace(vec![])); } - let only_top_call = options - .map(|options| options.tracer_config.only_top_call) - .unwrap_or(false); let mut connection = self.state.acquire_connection().await?; let block_number = self.state.resolve_block(&mut connection, block_id).await?; self.current_method() @@ -99,41 +182,55 @@ impl DebugNamespace { .get_traces_for_l2_block(block_number) .await .map_err(DalError::generalize)?; - let call_trace = call_traces - .into_iter() - .map(|call_trace| { - let result = Self::map_call(call_trace, only_top_call); - ResultDebugCall { result } - }) - .collect(); - Ok(call_trace) - } - pub async fn debug_trace_block_flat_impl( - &self, - block_id: BlockId, - options: Option, - ) -> Result, Web3Error> { - let call_trace = self.debug_trace_block_impl(block_id, options).await?; - let call_trace_flat = flatten_debug_calls(call_trace); - Ok(call_trace_flat) + let options = options.unwrap_or_default(); + let result = match options.tracer { + SupportedTracers::CallTracer => CallTracerBlockResult::CallTrace( + call_traces + .into_iter() + .map(|(call, _, _)| ResultDebugCall { + result: Self::map_default_call(call, options.tracer_config.only_top_call), + }) + .collect(), + ), + SupportedTracers::FlatCallTracer => { + let mut flat_calls = vec![]; + for (call, tx_hash, tx_index) in call_traces { + let mut traces = vec![tx_index]; + Self::flatten_call( + call, + &mut flat_calls, + &mut traces, + options.tracer_config.only_top_call, + tx_index, + tx_hash, + ); + } + CallTracerBlockResult::FlatCallTrace(flat_calls) + } + }; + Ok(result) } pub async fn debug_trace_transaction_impl( &self, tx_hash: H256, options: Option, - ) -> Result, Web3Error> { - let only_top_call = options - .map(|options| options.tracer_config.only_top_call) - .unwrap_or(false); + ) -> Result, Web3Error> { let mut connection = self.state.acquire_connection().await?; let call_trace = connection .transactions_dal() .get_call_trace(tx_hash) .await .map_err(DalError::generalize)?; - Ok(call_trace.map(|call_trace| Self::map_call(call_trace, only_top_call))) + Ok(call_trace.map(|(call_trace, index_in_block)| { + Self::map_call( + call_trace, + index_in_block, + tx_hash, + options.unwrap_or_default(), + ) + })) } pub async fn debug_trace_call_impl( @@ -141,13 +238,11 @@ impl DebugNamespace { mut request: CallRequest, block_id: Option, options: Option, - ) -> Result { + ) -> Result { let block_id = block_id.unwrap_or(BlockId::Number(BlockNumber::Pending)); self.current_method().set_block_id(block_id); - let only_top_call = options - .map(|options| options.tracer_config.only_top_call) - .unwrap_or(false); + let options = options.unwrap_or_default(); let mut connection = self.state.acquire_connection().await?; let block_args = self @@ -182,7 +277,7 @@ impl DebugNamespace { // We don't need properly trace if we only need top call let tracing_params = OneshotTracingParams { - trace_calls: !only_top_call, + trace_calls: !options.tracer_config.only_top_call, }; let connection = self.state.acquire_connection().await?; @@ -212,7 +307,8 @@ impl DebugNamespace { )) } }; - + // It's a call request, it's safe to keep it zero + let hash = H256::zero(); let call = Call::new_high_level( call.common_data.fee.gas_limit.as_u64(), result.vm.statistics.gas_used, @@ -222,6 +318,6 @@ impl DebugNamespace { revert_reason, result.call_traces, ); - Ok(Self::map_call(call, false)) + Ok(Self::map_call(call, 0, hash, options)) } } diff --git a/core/node/api_server/src/web3/tests/debug.rs b/core/node/api_server/src/web3/tests/debug.rs index 76496b42cadb..7711570c3c54 100644 --- a/core/node/api_server/src/web3/tests/debug.rs +++ b/core/node/api_server/src/web3/tests/debug.rs @@ -1,7 +1,10 @@ //! Tests for the `debug` Web3 namespace. use zksync_multivm::interface::{Call, TransactionExecutionResult}; -use zksync_types::BOOTLOADER_ADDRESS; +use zksync_types::{ + api::{CallTracerConfig, SupportedTracers, TracerConfig}, + BOOTLOADER_ADDRESS, +}; use zksync_web3_decl::{ client::{DynClient, L2}, namespaces::DebugNamespaceClient, @@ -58,18 +61,19 @@ impl HttpTest for TraceBlockTest { let block_traces = match block_id { api::BlockId::Number(number) => client.trace_block_by_number(number, None).await?, api::BlockId::Hash(hash) => client.trace_block_by_hash(hash, None).await?, - }; + } + .unwrap_default(); assert_eq!(block_traces.len(), tx_results.len()); // equals to the number of transactions in the block for (trace, tx_result) in block_traces.iter().zip(&tx_results) { - let api::ResultDebugCall { result } = trace; + let result = &trace.result; assert_eq!(result.from, Address::zero()); assert_eq!(result.to, BOOTLOADER_ADDRESS); assert_eq!(result.gas, tx_result.transaction.gas_limit()); let expected_calls: Vec<_> = tx_result .call_traces .iter() - .map(|call| DebugNamespace::map_call(call.clone(), false)) + .map(|call| DebugNamespace::map_default_call(call.clone(), false)) .collect(); assert_eq!(result.calls, expected_calls); } @@ -122,7 +126,18 @@ impl HttpTest for TraceBlockFlatTest { for block_id in block_ids { if let api::BlockId::Number(number) = block_id { - let block_traces = client.trace_block_by_number_flat(number, None).await?; + let block_traces = client + .trace_block_by_number( + number, + Some(TracerConfig { + tracer: SupportedTracers::FlatCallTracer, + tracer_config: CallTracerConfig { + only_top_call: false, + }, + }), + ) + .await? + .unwrap_flatten(); // A transaction with 2 nested calls will convert into 3 Flattened calls. // Also in this test, all tx have the same # of nested calls @@ -133,10 +148,10 @@ impl HttpTest for TraceBlockFlatTest { // First tx has 2 nested calls, thus 2 sub-traces assert_eq!(block_traces[0].subtraces, 2); - assert_eq!(block_traces[0].traceaddress, [0]); + assert_eq!(block_traces[0].trace_address, [0]); // Second flat-call (fist nested call) do not have nested calls assert_eq!(block_traces[1].subtraces, 0); - assert_eq!(block_traces[1].traceaddress, [0, 0]); + assert_eq!(block_traces[1].trace_address, [0, 0]); let top_level_call_indexes = [0, 3, 6]; let top_level_traces = top_level_call_indexes @@ -157,7 +172,15 @@ impl HttpTest for TraceBlockFlatTest { let missing_block_number = api::BlockNumber::from(*self.0 + 100); let error = client - .trace_block_by_number_flat(missing_block_number, None) + .trace_block_by_number( + missing_block_number, + Some(TracerConfig { + tracer: SupportedTracers::FlatCallTracer, + tracer_config: CallTracerConfig { + only_top_call: false, + }, + }), + ) .await .unwrap_err(); if let ClientError::Call(error) = error { @@ -198,13 +221,14 @@ impl HttpTest for TraceTransactionTest { let expected_calls: Vec<_> = tx_results[0] .call_traces .iter() - .map(|call| DebugNamespace::map_call(call.clone(), false)) + .map(|call| DebugNamespace::map_default_call(call.clone(), false)) .collect(); let result = client .trace_transaction(tx_results[0].hash, None) .await? - .context("no transaction traces")?; + .context("no transaction traces")? + .unwrap_default(); assert_eq!(result.from, Address::zero()); assert_eq!(result.to, BOOTLOADER_ADDRESS); assert_eq!(result.gas, tx_results[0].transaction.gas_limit()); diff --git a/core/node/api_server/src/web3/tests/vm.rs b/core/node/api_server/src/web3/tests/vm.rs index 9bdcf1159303..b8f74370303e 100644 --- a/core/node/api_server/src/web3/tests/vm.rs +++ b/core/node/api_server/src/web3/tests/vm.rs @@ -488,12 +488,16 @@ impl HttpTest for TraceCallTest { self.fee_input.expect_default(Self::FEE_SCALE); let call_request = CallTest::call_request(b"pending"); - let call_result = client.trace_call(call_request.clone(), None, None).await?; + let call_result = client + .trace_call(call_request.clone(), None, None) + .await? + .unwrap_default(); Self::assert_debug_call(&call_request, &call_result); let pending_block_number = api::BlockId::Number(api::BlockNumber::Pending); let call_result = client .trace_call(call_request.clone(), Some(pending_block_number), None) - .await?; + .await? + .unwrap_default(); Self::assert_debug_call(&call_request, &call_result); let latest_block_numbers = [api::BlockNumber::Latest, 1.into()]; @@ -506,7 +510,8 @@ impl HttpTest for TraceCallTest { Some(api::BlockId::Number(number)), None, ) - .await?; + .await? + .unwrap_default(); Self::assert_debug_call(&call_request, &call_result); } @@ -557,12 +562,16 @@ impl HttpTest for TraceCallTestAfterSnapshotRecovery { ) -> anyhow::Result<()> { self.fee_input.expect_default(TraceCallTest::FEE_SCALE); let call_request = CallTest::call_request(b"pending"); - let call_result = client.trace_call(call_request.clone(), None, None).await?; + let call_result = client + .trace_call(call_request.clone(), None, None) + .await? + .unwrap_default(); TraceCallTest::assert_debug_call(&call_request, &call_result); let pending_block_number = api::BlockId::Number(api::BlockNumber::Pending); let call_result = client .trace_call(call_request.clone(), Some(pending_block_number), None) - .await?; + .await? + .unwrap_default(); TraceCallTest::assert_debug_call(&call_request, &call_result); let first_local_l2_block = StorageInitialization::SNAPSHOT_RECOVERY_BLOCK + 1; @@ -584,7 +593,8 @@ impl HttpTest for TraceCallTestAfterSnapshotRecovery { let number = api::BlockId::Number(number); let call_result = client .trace_call(call_request.clone(), Some(number), None) - .await?; + .await? + .unwrap_default(); TraceCallTest::assert_debug_call(&call_request, &call_result); } Ok(()) diff --git a/core/tests/ts-integration/tests/api/debug.test.ts b/core/tests/ts-integration/tests/api/debug.test.ts index 054aa57cf64e..2af18c8438b8 100644 --- a/core/tests/ts-integration/tests/api/debug.test.ts +++ b/core/tests/ts-integration/tests/api/debug.test.ts @@ -50,7 +50,7 @@ describe('Debug methods', () => { output: '0x', revertReason: 'Error function_selector = 0x, data = 0x', to: BOOTLOADER_FORMAL_ADDRESS, - type: 'Call', + type: 'call', value: expect.any(String), calls: expect.any(Array) }; @@ -75,7 +75,7 @@ describe('Debug methods', () => { input: expect.any(String), output: '0x', to: BOOTLOADER_FORMAL_ADDRESS, - type: 'Call', + type: 'call', value: expect.any(String), calls: expect.any(Array) // We intentionally skip `error` and `revertReason` fields: the block may contain failing txs @@ -99,7 +99,7 @@ describe('Debug methods', () => { output: '0x', revertReason: null, to: BOOTLOADER_FORMAL_ADDRESS, - type: 'Call', + type: 'call', value: '0x0', calls: expect.any(Array) }; diff --git a/prover/crates/bin/prover_fri/src/utils.rs b/prover/crates/bin/prover_fri/src/utils.rs index 181dc857c364..86e6568f8e40 100644 --- a/prover/crates/bin/prover_fri/src/utils.rs +++ b/prover/crates/bin/prover_fri/src/utils.rs @@ -200,7 +200,7 @@ mod tests { round: AggregationRound::BasicCircuits, }; - let result = get_setup_data_key(key.clone()); + let result = get_setup_data_key(key); // Check if the key has remained same assert_eq!(key, result); diff --git a/prover/crates/lib/prover_dal/.sqlx/query-1297f0977132185d6bd4501f490f1cdac8b194f09926c133985479c533a651f2.json b/prover/crates/lib/prover_dal/.sqlx/query-1297f0977132185d6bd4501f490f1cdac8b194f09926c133985479c533a651f2.json new file mode 100644 index 000000000000..c99572bcc8e5 --- /dev/null +++ b/prover/crates/lib/prover_dal/.sqlx/query-1297f0977132185d6bd4501f490f1cdac8b194f09926c133985479c533a651f2.json @@ -0,0 +1,18 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE prover_jobs_fri\n SET\n status = $1\n WHERE\n l1_batch_number = $2\n AND sequence_number = $3\n AND aggregation_round = $4\n AND circuit_id = $5\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8", + "Int4", + "Int2", + "Int2" + ] + }, + "nullable": [] + }, + "hash": "1297f0977132185d6bd4501f490f1cdac8b194f09926c133985479c533a651f2" +} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-1926cf432237684de2383179a6d0d001cdf5bc7ba988b742571ec90a938434e3.json b/prover/crates/lib/prover_dal/.sqlx/query-1926cf432237684de2383179a6d0d001cdf5bc7ba988b742571ec90a938434e3.json deleted file mode 100644 index 4015a22ff3fd..000000000000 --- a/prover/crates/lib/prover_dal/.sqlx/query-1926cf432237684de2383179a6d0d001cdf5bc7ba988b742571ec90a938434e3.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE leaf_aggregation_witness_jobs_fri \n SET status = $1, attempts = $2\n WHERE l1_batch_number = $3\n AND circuit_id = $4", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Int2", - "Int8", - "Int2" - ] - }, - "nullable": [] - }, - "hash": "1926cf432237684de2383179a6d0d001cdf5bc7ba988b742571ec90a938434e3" -} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-97adb49780c9edde6a3cfda09dadbd694e1781e013247d090a280a1f894de464.json b/prover/crates/lib/prover_dal/.sqlx/query-29f7a564a8373f7e44840e8e9e7d0cd5c6b1122c35d7ffdbbba30327ca3fb5a8.json similarity index 53% rename from prover/crates/lib/prover_dal/.sqlx/query-97adb49780c9edde6a3cfda09dadbd694e1781e013247d090a280a1f894de464.json rename to prover/crates/lib/prover_dal/.sqlx/query-29f7a564a8373f7e44840e8e9e7d0cd5c6b1122c35d7ffdbbba30327ca3fb5a8.json index ce9e492a7d4a..05163dcfa2e6 100644 --- a/prover/crates/lib/prover_dal/.sqlx/query-97adb49780c9edde6a3cfda09dadbd694e1781e013247d090a280a1f894de464.json +++ b/prover/crates/lib/prover_dal/.sqlx/query-29f7a564a8373f7e44840e8e9e7d0cd5c6b1122c35d7ffdbbba30327ca3fb5a8.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n protocol_version AS \"protocol_version!\",\n protocol_version_patch AS \"protocol_version_patch!\",\n COUNT(*) FILTER (WHERE status = 'queued') as queued,\n COUNT(*) FILTER (WHERE status = 'in_progress') as in_progress\n FROM\n prover_jobs_fri\n WHERE\n status IN ('queued', 'in_progress')\n AND protocol_version IS NOT NULL\n GROUP BY\n protocol_version,\n protocol_version_patch\n ", + "query": "\n SELECT\n protocol_version AS \"protocol_version!\",\n protocol_version_patch AS \"protocol_version_patch!\",\n COUNT(*) FILTER (\n WHERE\n status = 'queued'\n ) AS queued,\n COUNT(*) FILTER (\n WHERE\n status = 'in_progress'\n ) AS in_progress\n FROM\n prover_jobs_fri\n WHERE\n status IN ('queued', 'in_progress')\n AND protocol_version IS NOT NULL\n GROUP BY\n protocol_version,\n protocol_version_patch\n ", "describe": { "columns": [ { @@ -34,5 +34,5 @@ null ] }, - "hash": "97adb49780c9edde6a3cfda09dadbd694e1781e013247d090a280a1f894de464" + "hash": "29f7a564a8373f7e44840e8e9e7d0cd5c6b1122c35d7ffdbbba30327ca3fb5a8" } diff --git a/prover/crates/lib/prover_dal/.sqlx/query-2d1461e068e43fd16714610b383cf8c93630d529ec96e67aac078f18196f61a5.json b/prover/crates/lib/prover_dal/.sqlx/query-2d1461e068e43fd16714610b383cf8c93630d529ec96e67aac078f18196f61a5.json new file mode 100644 index 000000000000..50d121213fb9 --- /dev/null +++ b/prover/crates/lib/prover_dal/.sqlx/query-2d1461e068e43fd16714610b383cf8c93630d529ec96e67aac078f18196f61a5.json @@ -0,0 +1,19 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE prover_jobs_fri\n SET\n status = $1,\n attempts = $2\n WHERE\n l1_batch_number = $3\n AND sequence_number = $4\n AND aggregation_round = $5\n AND circuit_id = $6\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int2", + "Int8", + "Int4", + "Int2", + "Int2" + ] + }, + "nullable": [] + }, + "hash": "2d1461e068e43fd16714610b383cf8c93630d529ec96e67aac078f18196f61a5" +} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-75c1affbca0901edd5d0e2f12ef4d935674a5aff2f34421d753b4d1a9dea5b12.json b/prover/crates/lib/prover_dal/.sqlx/query-35a76415cb746d03da31481edc65adefab0bf3abf6853a6d36123c8adcaf813b.json similarity index 70% rename from prover/crates/lib/prover_dal/.sqlx/query-75c1affbca0901edd5d0e2f12ef4d935674a5aff2f34421d753b4d1a9dea5b12.json rename to prover/crates/lib/prover_dal/.sqlx/query-35a76415cb746d03da31481edc65adefab0bf3abf6853a6d36123c8adcaf813b.json index 14463ecbe426..bf8db798e7d4 100644 --- a/prover/crates/lib/prover_dal/.sqlx/query-75c1affbca0901edd5d0e2f12ef4d935674a5aff2f34421d753b4d1a9dea5b12.json +++ b/prover/crates/lib/prover_dal/.sqlx/query-35a76415cb746d03da31481edc65adefab0bf3abf6853a6d36123c8adcaf813b.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE scheduler_witness_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n l1_batch_number = $1\n AND attempts >= $2\n AND (status = 'in_progress' OR status = 'failed')\n RETURNING\n l1_batch_number,\n status,\n attempts,\n error,\n picked_by\n ", + "query": "\n UPDATE scheduler_witness_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n l1_batch_number = $1\n AND attempts >= $2\n AND (\n status = 'in_progress'\n OR status = 'failed'\n )\n RETURNING\n l1_batch_number,\n status,\n attempts,\n error,\n picked_by\n ", "describe": { "columns": [ { @@ -43,5 +43,5 @@ true ] }, - "hash": "75c1affbca0901edd5d0e2f12ef4d935674a5aff2f34421d753b4d1a9dea5b12" + "hash": "35a76415cb746d03da31481edc65adefab0bf3abf6853a6d36123c8adcaf813b" } diff --git a/prover/crates/lib/prover_dal/.sqlx/query-548414f8148740c991c345e5fd46ea738d209eb07e7a6bcbdb33e25b3347a08c.json b/prover/crates/lib/prover_dal/.sqlx/query-3727d5614d2fe2a4d96f880eb72cd48c95ca5b4520dde415a2b5ff32ece47c86.json similarity index 70% rename from prover/crates/lib/prover_dal/.sqlx/query-548414f8148740c991c345e5fd46ea738d209eb07e7a6bcbdb33e25b3347a08c.json rename to prover/crates/lib/prover_dal/.sqlx/query-3727d5614d2fe2a4d96f880eb72cd48c95ca5b4520dde415a2b5ff32ece47c86.json index 8f5b046b974f..d7eb6a32b421 100644 --- a/prover/crates/lib/prover_dal/.sqlx/query-548414f8148740c991c345e5fd46ea738d209eb07e7a6bcbdb33e25b3347a08c.json +++ b/prover/crates/lib/prover_dal/.sqlx/query-3727d5614d2fe2a4d96f880eb72cd48c95ca5b4520dde415a2b5ff32ece47c86.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE witness_inputs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n l1_batch_number = $1\n AND attempts >= $2\n AND (status = 'in_progress' OR status = 'failed')\n RETURNING\n l1_batch_number,\n status,\n attempts,\n error,\n picked_by\n ", + "query": "\n UPDATE witness_inputs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n l1_batch_number = $1\n AND attempts >= $2\n AND (\n status = 'in_progress'\n OR status = 'failed'\n )\n RETURNING\n l1_batch_number,\n status,\n attempts,\n error,\n picked_by\n ", "describe": { "columns": [ { @@ -43,5 +43,5 @@ true ] }, - "hash": "548414f8148740c991c345e5fd46ea738d209eb07e7a6bcbdb33e25b3347a08c" + "hash": "3727d5614d2fe2a4d96f880eb72cd48c95ca5b4520dde415a2b5ff32ece47c86" } diff --git a/prover/crates/lib/prover_dal/.sqlx/query-c19fc4c8e4b3a3ef4f9c0f4c22ed68c598eada8e60938a8e4b5cd32b53f5a574.json b/prover/crates/lib/prover_dal/.sqlx/query-37ad15f54f4a6f4f79c71a857f3a8d4cc59246dda91b19526e73f27a17c8e3da.json similarity index 69% rename from prover/crates/lib/prover_dal/.sqlx/query-c19fc4c8e4b3a3ef4f9c0f4c22ed68c598eada8e60938a8e4b5cd32b53f5a574.json rename to prover/crates/lib/prover_dal/.sqlx/query-37ad15f54f4a6f4f79c71a857f3a8d4cc59246dda91b19526e73f27a17c8e3da.json index 3c4c8d7a29f3..c97fe7f4042b 100644 --- a/prover/crates/lib/prover_dal/.sqlx/query-c19fc4c8e4b3a3ef4f9c0f4c22ed68c598eada8e60938a8e4b5cd32b53f5a574.json +++ b/prover/crates/lib/prover_dal/.sqlx/query-37ad15f54f4a6f4f79c71a857f3a8d4cc59246dda91b19526e73f27a17c8e3da.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE recursion_tip_witness_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n l1_batch_number = $1\n AND attempts >= $2\n AND (status = 'in_progress' OR status = 'failed')\n RETURNING\n l1_batch_number,\n status,\n attempts,\n error,\n picked_by\n ", + "query": "\n UPDATE recursion_tip_witness_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n l1_batch_number = $1\n AND attempts >= $2\n AND (\n status = 'in_progress'\n OR status = 'failed'\n )\n RETURNING\n l1_batch_number,\n status,\n attempts,\n error,\n picked_by\n ", "describe": { "columns": [ { @@ -43,5 +43,5 @@ true ] }, - "hash": "c19fc4c8e4b3a3ef4f9c0f4c22ed68c598eada8e60938a8e4b5cd32b53f5a574" + "hash": "37ad15f54f4a6f4f79c71a857f3a8d4cc59246dda91b19526e73f27a17c8e3da" } diff --git a/prover/crates/lib/prover_dal/.sqlx/query-39f60c638d445c5dbf23e01fd89a468057599be1e6c6c96a947c33df53a68224.json b/prover/crates/lib/prover_dal/.sqlx/query-39f60c638d445c5dbf23e01fd89a468057599be1e6c6c96a947c33df53a68224.json deleted file mode 100644 index 5cec4d7d7d03..000000000000 --- a/prover/crates/lib/prover_dal/.sqlx/query-39f60c638d445c5dbf23e01fd89a468057599be1e6c6c96a947c33df53a68224.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n recursion_tip_witness_jobs_fri (\n l1_batch_number,\n status,\n number_of_final_node_jobs,\n created_at,\n updated_at\n )\n VALUES\n ($1, 'waiting_for_proofs',1, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET status = $2\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Text" - ] - }, - "nullable": [] - }, - "hash": "39f60c638d445c5dbf23e01fd89a468057599be1e6c6c96a947c33df53a68224" -} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-3a9ffd4d88f2cfac22835aac2512e61157bf58aec70903623afc9da24d46a336.json b/prover/crates/lib/prover_dal/.sqlx/query-3a9ffd4d88f2cfac22835aac2512e61157bf58aec70903623afc9da24d46a336.json deleted file mode 100644 index 063ae8fc90a3..000000000000 --- a/prover/crates/lib/prover_dal/.sqlx/query-3a9ffd4d88f2cfac22835aac2512e61157bf58aec70903623afc9da24d46a336.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n node_aggregation_witness_jobs_fri (\n l1_batch_number,\n circuit_id,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number, circuit_id, depth) DO\n UPDATE\n SET status = $3\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Int2", - "Text" - ] - }, - "nullable": [] - }, - "hash": "3a9ffd4d88f2cfac22835aac2512e61157bf58aec70903623afc9da24d46a336" -} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-3bb8fbd9e83703887e0a3c196031b931c0d8dbc6835dfac20107ea7412ce9fbb.json b/prover/crates/lib/prover_dal/.sqlx/query-3bb8fbd9e83703887e0a3c196031b931c0d8dbc6835dfac20107ea7412ce9fbb.json deleted file mode 100644 index 693905084151..000000000000 --- a/prover/crates/lib/prover_dal/.sqlx/query-3bb8fbd9e83703887e0a3c196031b931c0d8dbc6835dfac20107ea7412ce9fbb.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n proof_compression_jobs_fri (\n l1_batch_number,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET status = $2\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Text" - ] - }, - "nullable": [] - }, - "hash": "3bb8fbd9e83703887e0a3c196031b931c0d8dbc6835dfac20107ea7412ce9fbb" -} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-434f7cb51a7d22948cd26e962679a67936d572f8046d3a1c7a4f100ff209d81d.json b/prover/crates/lib/prover_dal/.sqlx/query-434f7cb51a7d22948cd26e962679a67936d572f8046d3a1c7a4f100ff209d81d.json deleted file mode 100644 index 7615523f92f1..000000000000 --- a/prover/crates/lib/prover_dal/.sqlx/query-434f7cb51a7d22948cd26e962679a67936d572f8046d3a1c7a4f100ff209d81d.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE prover_jobs_fri SET status = $1\n WHERE l1_batch_number = $2\n AND sequence_number = $3\n AND aggregation_round = $4\n AND circuit_id = $5", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Int8", - "Int4", - "Int2", - "Int2" - ] - }, - "nullable": [] - }, - "hash": "434f7cb51a7d22948cd26e962679a67936d572f8046d3a1c7a4f100ff209d81d" -} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-73266a8526c6adc315900e2e95441976a264759c4060c1a38e466ee2052fc17d.json b/prover/crates/lib/prover_dal/.sqlx/query-73266a8526c6adc315900e2e95441976a264759c4060c1a38e466ee2052fc17d.json new file mode 100644 index 000000000000..f8b141a8dac9 --- /dev/null +++ b/prover/crates/lib/prover_dal/.sqlx/query-73266a8526c6adc315900e2e95441976a264759c4060c1a38e466ee2052fc17d.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n recursion_tip_witness_jobs_fri (l1_batch_number, status, number_of_final_node_jobs, created_at, updated_at)\n VALUES\n ($1, 'waiting_for_proofs', 1, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET\n status = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Text" + ] + }, + "nullable": [] + }, + "hash": "73266a8526c6adc315900e2e95441976a264759c4060c1a38e466ee2052fc17d" +} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-9730c8225ff2cf3111185e81f602a4a98ec63eb942c73ce4448d0957346047cd.json b/prover/crates/lib/prover_dal/.sqlx/query-9730c8225ff2cf3111185e81f602a4a98ec63eb942c73ce4448d0957346047cd.json new file mode 100644 index 000000000000..d23ed8d9fc8a --- /dev/null +++ b/prover/crates/lib/prover_dal/.sqlx/query-9730c8225ff2cf3111185e81f602a4a98ec63eb942c73ce4448d0957346047cd.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE leaf_aggregation_witness_jobs_fri\n SET\n status = $1,\n attempts = $2\n WHERE\n l1_batch_number = $3\n AND circuit_id = $4\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int2", + "Int8", + "Int2" + ] + }, + "nullable": [] + }, + "hash": "9730c8225ff2cf3111185e81f602a4a98ec63eb942c73ce4448d0957346047cd" +} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-a817f0fec85388b3e2510ce259208a01b63ae4aa03c983c3a52c802d585e5a80.json b/prover/crates/lib/prover_dal/.sqlx/query-a817f0fec85388b3e2510ce259208a01b63ae4aa03c983c3a52c802d585e5a80.json new file mode 100644 index 000000000000..93532150f7f8 --- /dev/null +++ b/prover/crates/lib/prover_dal/.sqlx/query-a817f0fec85388b3e2510ce259208a01b63ae4aa03c983c3a52c802d585e5a80.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n proof_compression_jobs_fri (l1_batch_number, status, created_at, updated_at)\n VALUES\n ($1, $2, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET\n status = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Text" + ] + }, + "nullable": [] + }, + "hash": "a817f0fec85388b3e2510ce259208a01b63ae4aa03c983c3a52c802d585e5a80" +} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-aabcfa9005b8e1d84cfa083a47a700302981be0afef31a8864613484f8521f9e.json b/prover/crates/lib/prover_dal/.sqlx/query-aabcfa9005b8e1d84cfa083a47a700302981be0afef31a8864613484f8521f9e.json deleted file mode 100644 index 3d60050c92ed..000000000000 --- a/prover/crates/lib/prover_dal/.sqlx/query-aabcfa9005b8e1d84cfa083a47a700302981be0afef31a8864613484f8521f9e.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE prover_jobs_fri \n SET status = $1, attempts = $2\n WHERE l1_batch_number = $3\n AND sequence_number =$4\n AND aggregation_round = $5\n AND circuit_id = $6", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Int2", - "Int8", - "Int4", - "Int2", - "Int2" - ] - }, - "nullable": [] - }, - "hash": "aabcfa9005b8e1d84cfa083a47a700302981be0afef31a8864613484f8521f9e" -} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-c8daa62b3835c15fafb3f83deabb5a4672ad50a9de92c84d939ac4c69842e355.json b/prover/crates/lib/prover_dal/.sqlx/query-c8daa62b3835c15fafb3f83deabb5a4672ad50a9de92c84d939ac4c69842e355.json new file mode 100644 index 000000000000..cadc931fa1ca --- /dev/null +++ b/prover/crates/lib/prover_dal/.sqlx/query-c8daa62b3835c15fafb3f83deabb5a4672ad50a9de92c84d939ac4c69842e355.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n node_aggregation_witness_jobs_fri (l1_batch_number, circuit_id, status, created_at, updated_at)\n VALUES\n ($1, $2, 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number, circuit_id, depth) DO\n UPDATE\n SET\n status = $3\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int2", + "Text" + ] + }, + "nullable": [] + }, + "hash": "c8daa62b3835c15fafb3f83deabb5a4672ad50a9de92c84d939ac4c69842e355" +} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-63cf7038e6c48af8ed9afc7d6ea07edd87cb16a79c13e7d4291d99736e51d3b9.json b/prover/crates/lib/prover_dal/.sqlx/query-e875dcbbdaed6998dbea45d4eab5d005d8760c4809b7aef902155196873da66e.json similarity index 82% rename from prover/crates/lib/prover_dal/.sqlx/query-63cf7038e6c48af8ed9afc7d6ea07edd87cb16a79c13e7d4291d99736e51d3b9.json rename to prover/crates/lib/prover_dal/.sqlx/query-e875dcbbdaed6998dbea45d4eab5d005d8760c4809b7aef902155196873da66e.json index 208b23d939f8..4ee9278fe42a 100644 --- a/prover/crates/lib/prover_dal/.sqlx/query-63cf7038e6c48af8ed9afc7d6ea07edd87cb16a79c13e7d4291d99736e51d3b9.json +++ b/prover/crates/lib/prover_dal/.sqlx/query-e875dcbbdaed6998dbea45d4eab5d005d8760c4809b7aef902155196873da66e.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n scheduler_witness_jobs_fri (\n l1_batch_number,\n scheduler_partial_input_blob_url,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, '', 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET status = $2\n ", + "query": "\n INSERT INTO\n scheduler_witness_jobs_fri (\n l1_batch_number,\n scheduler_partial_input_blob_url,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, '', 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET\n status = $2\n ", "describe": { "columns": [], "parameters": { @@ -11,5 +11,5 @@ }, "nullable": [] }, - "hash": "63cf7038e6c48af8ed9afc7d6ea07edd87cb16a79c13e7d4291d99736e51d3b9" + "hash": "e875dcbbdaed6998dbea45d4eab5d005d8760c4809b7aef902155196873da66e" } diff --git a/prover/crates/lib/prover_dal/.sqlx/query-0eac6f7b2d799059328584029b437891598dc79b5ed11258b2c90c3f282929ad.json b/prover/crates/lib/prover_dal/.sqlx/query-eec29cbff034818f4fb5ec1e6ad38e1010d7389457b3c97e9b238a3a0291a54e.json similarity index 78% rename from prover/crates/lib/prover_dal/.sqlx/query-0eac6f7b2d799059328584029b437891598dc79b5ed11258b2c90c3f282929ad.json rename to prover/crates/lib/prover_dal/.sqlx/query-eec29cbff034818f4fb5ec1e6ad38e1010d7389457b3c97e9b238a3a0291a54e.json index 61518273b4d3..f8e92b1ad666 100644 --- a/prover/crates/lib/prover_dal/.sqlx/query-0eac6f7b2d799059328584029b437891598dc79b5ed11258b2c90c3f282929ad.json +++ b/prover/crates/lib/prover_dal/.sqlx/query-eec29cbff034818f4fb5ec1e6ad38e1010d7389457b3c97e9b238a3a0291a54e.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n leaf_aggregation_witness_jobs_fri (\n l1_batch_number,\n circuit_id,\n status,\n number_of_basic_circuits,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, 'waiting_for_proofs', 2, NOW(), NOW())\n ON CONFLICT (l1_batch_number, circuit_id) DO\n UPDATE\n SET status = $3\n ", + "query": "\n INSERT INTO\n leaf_aggregation_witness_jobs_fri (\n l1_batch_number,\n circuit_id,\n status,\n number_of_basic_circuits,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, 'waiting_for_proofs', 2, NOW(), NOW())\n ON CONFLICT (l1_batch_number, circuit_id) DO\n UPDATE\n SET\n status = $3\n ", "describe": { "columns": [], "parameters": { @@ -12,5 +12,5 @@ }, "nullable": [] }, - "hash": "0eac6f7b2d799059328584029b437891598dc79b5ed11258b2c90c3f282929ad" + "hash": "eec29cbff034818f4fb5ec1e6ad38e1010d7389457b3c97e9b238a3a0291a54e" } diff --git a/prover/crates/lib/prover_dal/src/cli_test_dal.rs b/prover/crates/lib/prover_dal/src/cli_test_dal.rs index 19fe0e4f57b0..d08418203378 100644 --- a/prover/crates/lib/prover_dal/src/cli_test_dal.rs +++ b/prover/crates/lib/prover_dal/src/cli_test_dal.rs @@ -21,11 +21,16 @@ impl CliTestDal<'_, '_> { sequence_number: usize, ) { sqlx::query!( - "UPDATE prover_jobs_fri SET status = $1 - WHERE l1_batch_number = $2 + r#" + UPDATE prover_jobs_fri + SET + status = $1 + WHERE + l1_batch_number = $2 AND sequence_number = $3 AND aggregation_round = $4 - AND circuit_id = $5", + AND circuit_id = $5 + "#, status.to_string(), batch_number.0 as i64, sequence_number as i64, @@ -44,7 +49,7 @@ impl CliTestDal<'_, '_> { circuit_id: u8, ) { sqlx::query!( - " + r#" INSERT INTO leaf_aggregation_witness_jobs_fri ( l1_batch_number, @@ -58,8 +63,9 @@ impl CliTestDal<'_, '_> { ($1, $2, 'waiting_for_proofs', 2, NOW(), NOW()) ON CONFLICT (l1_batch_number, circuit_id) DO UPDATE - SET status = $3 - ", + SET + status = $3 + "#, batch_number.0 as i64, circuit_id as i16, status.to_string() @@ -76,21 +82,16 @@ impl CliTestDal<'_, '_> { circuit_id: u8, ) { sqlx::query!( - " + r#" INSERT INTO - node_aggregation_witness_jobs_fri ( - l1_batch_number, - circuit_id, - status, - created_at, - updated_at - ) + node_aggregation_witness_jobs_fri (l1_batch_number, circuit_id, status, created_at, updated_at) VALUES ($1, $2, 'waiting_for_proofs', NOW(), NOW()) ON CONFLICT (l1_batch_number, circuit_id, depth) DO UPDATE - SET status = $3 - ", + SET + status = $3 + "#, batch_number.0 as i64, circuit_id as i16, status.to_string(), @@ -102,21 +103,16 @@ impl CliTestDal<'_, '_> { pub async fn insert_rt_job(&mut self, status: WitnessJobStatus, batch_number: L1BatchNumber) { sqlx::query!( - " + r#" INSERT INTO - recursion_tip_witness_jobs_fri ( - l1_batch_number, - status, - number_of_final_node_jobs, - created_at, - updated_at - ) + recursion_tip_witness_jobs_fri (l1_batch_number, status, number_of_final_node_jobs, created_at, updated_at) VALUES - ($1, 'waiting_for_proofs',1, NOW(), NOW()) + ($1, 'waiting_for_proofs', 1, NOW(), NOW()) ON CONFLICT (l1_batch_number) DO UPDATE - SET status = $2 - ", + SET + status = $2 + "#, batch_number.0 as i64, status.to_string(), ) @@ -131,7 +127,7 @@ impl CliTestDal<'_, '_> { batch_number: L1BatchNumber, ) { sqlx::query!( - " + r#" INSERT INTO scheduler_witness_jobs_fri ( l1_batch_number, @@ -144,8 +140,9 @@ impl CliTestDal<'_, '_> { ($1, '', 'waiting_for_proofs', NOW(), NOW()) ON CONFLICT (l1_batch_number) DO UPDATE - SET status = $2 - ", + SET + status = $2 + "#, batch_number.0 as i64, status.to_string(), ) @@ -160,20 +157,16 @@ impl CliTestDal<'_, '_> { batch_number: L1BatchNumber, ) { sqlx::query!( - " + r#" INSERT INTO - proof_compression_jobs_fri ( - l1_batch_number, - status, - created_at, - updated_at - ) + proof_compression_jobs_fri (l1_batch_number, status, created_at, updated_at) VALUES ($1, $2, NOW(), NOW()) ON CONFLICT (l1_batch_number) DO UPDATE - SET status = $2 - ", + SET + status = $2 + "#, batch_number.0 as i64, status.to_string(), ) @@ -192,12 +185,17 @@ impl CliTestDal<'_, '_> { sequence_number: usize, ) { sqlx::query!( - "UPDATE prover_jobs_fri - SET status = $1, attempts = $2 - WHERE l1_batch_number = $3 - AND sequence_number =$4 + r#" + UPDATE prover_jobs_fri + SET + status = $1, + attempts = $2 + WHERE + l1_batch_number = $3 + AND sequence_number = $4 AND aggregation_round = $5 - AND circuit_id = $6", + AND circuit_id = $6 + "#, status.to_string(), attempts as i64, batch_number.0 as i64, @@ -218,10 +216,15 @@ impl CliTestDal<'_, '_> { batch_number: L1BatchNumber, ) { sqlx::query!( - "UPDATE leaf_aggregation_witness_jobs_fri - SET status = $1, attempts = $2 - WHERE l1_batch_number = $3 - AND circuit_id = $4", + r#" + UPDATE leaf_aggregation_witness_jobs_fri + SET + status = $1, + attempts = $2 + WHERE + l1_batch_number = $3 + AND circuit_id = $4 + "#, status.to_string(), attempts as i64, batch_number.0 as i64, diff --git a/prover/crates/lib/prover_dal/src/fri_prover_dal.rs b/prover/crates/lib/prover_dal/src/fri_prover_dal.rs index 1a3b8de0ce4b..71d0c11728b1 100644 --- a/prover/crates/lib/prover_dal/src/fri_prover_dal.rs +++ b/prover/crates/lib/prover_dal/src/fri_prover_dal.rs @@ -528,8 +528,14 @@ impl FriProverDal<'_, '_> { SELECT protocol_version AS "protocol_version!", protocol_version_patch AS "protocol_version_patch!", - COUNT(*) FILTER (WHERE status = 'queued') as queued, - COUNT(*) FILTER (WHERE status = 'in_progress') as in_progress + COUNT(*) FILTER ( + WHERE + status = 'queued' + ) AS queued, + COUNT(*) FILTER ( + WHERE + status = 'in_progress' + ) AS in_progress FROM prover_jobs_fri WHERE diff --git a/prover/crates/lib/prover_dal/src/fri_witness_generator_dal.rs b/prover/crates/lib/prover_dal/src/fri_witness_generator_dal.rs index 66e34f7f8e75..c7ba0f60ef3f 100644 --- a/prover/crates/lib/prover_dal/src/fri_witness_generator_dal.rs +++ b/prover/crates/lib/prover_dal/src/fri_witness_generator_dal.rs @@ -1719,7 +1719,10 @@ impl FriWitnessGeneratorDal<'_, '_> { WHERE l1_batch_number = $1 AND attempts >= $2 - AND (status = 'in_progress' OR status = 'failed') + AND ( + status = 'in_progress' + OR status = 'failed' + ) RETURNING l1_batch_number, status, @@ -1786,7 +1789,10 @@ impl FriWitnessGeneratorDal<'_, '_> { WHERE l1_batch_number = $1 AND attempts >= $2 - AND (status = 'in_progress' OR status = 'failed') + AND ( + status = 'in_progress' + OR status = 'failed' + ) RETURNING l1_batch_number, status, @@ -1827,7 +1833,10 @@ impl FriWitnessGeneratorDal<'_, '_> { WHERE l1_batch_number = $1 AND attempts >= $2 - AND (status = 'in_progress' OR status = 'failed') + AND ( + status = 'in_progress' + OR status = 'failed' + ) RETURNING l1_batch_number, status, diff --git a/yarn.lock b/yarn.lock index b70e64f148a1..3c764c7c7b7f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6903,7 +6903,7 @@ jest-each@^29.7.0: jest-util "^29.7.0" pretty-format "^29.7.0" -jest-environment-node@^29.7.0: +jest-environment-node@^29.0.3, jest-environment-node@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== From e214dd094457f196712722e084010a7ef94ee475 Mon Sep 17 00:00:00 2001 From: zksync-era-bot <147085853+zksync-era-bot@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:56:17 +0400 Subject: [PATCH 40/45] chore(main): release core 24.27.0 (#2940) :robot: I have created a release *beep* *boop* --- ## [24.27.0](https://github.com/matter-labs/zksync-era/compare/core-v24.26.0...core-v24.27.0) (2024-09-25) ### Features * **vm:** Split old and new VM implementations ([#2915](https://github.com/matter-labs/zksync-era/issues/2915)) ([93bc66f](https://github.com/matter-labs/zksync-era/commit/93bc66f21f9f67a440f06f1c4402e0d687698741)) ### Bug Fixes * **api:** Return correct flat call tracer ([#2917](https://github.com/matter-labs/zksync-era/issues/2917)) ([218646a](https://github.com/matter-labs/zksync-era/commit/218646aa1c56200f4ffee99b7f83366e2689354f)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: zksync-era-bot --- .github/release-please/manifest.json | 2 +- Cargo.lock | 2 +- core/CHANGELOG.md | 12 ++++++++++++ core/bin/external_node/Cargo.toml | 2 +- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/release-please/manifest.json b/.github/release-please/manifest.json index 5b7501b65736..44e10fb13fdf 100644 --- a/.github/release-please/manifest.json +++ b/.github/release-please/manifest.json @@ -1,5 +1,5 @@ { - "core": "24.26.0", + "core": "24.27.0", "prover": "16.5.0", "zk_toolbox": "0.1.2" } diff --git a/Cargo.lock b/Cargo.lock index 50f0784d9fa2..0a26aab604c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9855,7 +9855,7 @@ dependencies = [ [[package]] name = "zksync_external_node" -version = "24.26.0" +version = "24.27.0" dependencies = [ "anyhow", "assert_matches", diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 9f4d65132ecc..6cf2ff4419a9 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [24.27.0](https://github.com/matter-labs/zksync-era/compare/core-v24.26.0...core-v24.27.0) (2024-09-25) + + +### Features + +* **vm:** Split old and new VM implementations ([#2915](https://github.com/matter-labs/zksync-era/issues/2915)) ([93bc66f](https://github.com/matter-labs/zksync-era/commit/93bc66f21f9f67a440f06f1c4402e0d687698741)) + + +### Bug Fixes + +* **api:** Return correct flat call tracer ([#2917](https://github.com/matter-labs/zksync-era/issues/2917)) ([218646a](https://github.com/matter-labs/zksync-era/commit/218646aa1c56200f4ffee99b7f83366e2689354f)) + ## [24.26.0](https://github.com/matter-labs/zksync-era/compare/core-v24.25.0...core-v24.26.0) (2024-09-23) diff --git a/core/bin/external_node/Cargo.toml b/core/bin/external_node/Cargo.toml index a0f12b24244a..d841ee5b42e6 100644 --- a/core/bin/external_node/Cargo.toml +++ b/core/bin/external_node/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "zksync_external_node" description = "Non-validator ZKsync node" -version = "24.26.0" # x-release-please-version +version = "24.27.0" # x-release-please-version edition.workspace = true authors.workspace = true homepage.workspace = true From 0f7c5da093d4791e809ac3fa67b6f80531cbee9a Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 25 Sep 2024 11:43:06 -0300 Subject: [PATCH 41/45] Update sqlx cached queries --- ...f1cdac8b194f09926c133985479c533a651f2.json | 18 ++++++++++++++++++ ...0d001cdf5bc7ba988b742571ec90a938434e3.json | 17 ----------------- ...cf8c93630d529ec96e67aac078f18196f61a5.json | 19 +++++++++++++++++++ ...adefab0bf3abf6853a6d36123c8adcaf813b.json} | 4 ++-- ...d48c95ca5b4520dde415a2b5ff32ece47c86.json} | 4 ++-- ...8d4cc59246dda91b19526e73f27a17c8e3da.json} | 4 ++-- ...a468057599be1e6c6c96a947c33df53a68224.json | 15 --------------- ...2e61157bf58aec70903623afc9da24d46a336.json | 16 ---------------- ...1b931c0d8dbc6835dfac20107ea7412ce9fbb.json | 15 --------------- ...9a67936d572f8046d3a1c7a4f100ff209d81d.json | 18 ------------------ ...41976a264759c4060c1a38e466ee2052fc17d.json | 15 +++++++++++++++ ...2a4a98ec63eb942c73ce4448d0957346047cd.json | 17 +++++++++++++++++ ...08a01b63ae4aa03c983c3a52c802d585e5a80.json | 15 +++++++++++++++ ...700302981be0afef31a8864613484f8521f9e.json | 19 ------------------- ...b5a4672ad50a9de92c84d939ac4c69842e355.json | 16 ++++++++++++++++ ...d005d8760c4809b7aef902155196873da66e.json} | 4 ++-- ...8e1010d7389457b3c97e9b238a3a0291a54e.json} | 4 ++-- 17 files changed, 110 insertions(+), 110 deletions(-) create mode 100644 prover/crates/lib/prover_dal/.sqlx/query-1297f0977132185d6bd4501f490f1cdac8b194f09926c133985479c533a651f2.json delete mode 100644 prover/crates/lib/prover_dal/.sqlx/query-1926cf432237684de2383179a6d0d001cdf5bc7ba988b742571ec90a938434e3.json create mode 100644 prover/crates/lib/prover_dal/.sqlx/query-2d1461e068e43fd16714610b383cf8c93630d529ec96e67aac078f18196f61a5.json rename prover/crates/lib/prover_dal/.sqlx/{query-75c1affbca0901edd5d0e2f12ef4d935674a5aff2f34421d753b4d1a9dea5b12.json => query-35a76415cb746d03da31481edc65adefab0bf3abf6853a6d36123c8adcaf813b.json} (70%) rename prover/crates/lib/prover_dal/.sqlx/{query-548414f8148740c991c345e5fd46ea738d209eb07e7a6bcbdb33e25b3347a08c.json => query-3727d5614d2fe2a4d96f880eb72cd48c95ca5b4520dde415a2b5ff32ece47c86.json} (70%) rename prover/crates/lib/prover_dal/.sqlx/{query-c19fc4c8e4b3a3ef4f9c0f4c22ed68c598eada8e60938a8e4b5cd32b53f5a574.json => query-37ad15f54f4a6f4f79c71a857f3a8d4cc59246dda91b19526e73f27a17c8e3da.json} (69%) delete mode 100644 prover/crates/lib/prover_dal/.sqlx/query-39f60c638d445c5dbf23e01fd89a468057599be1e6c6c96a947c33df53a68224.json delete mode 100644 prover/crates/lib/prover_dal/.sqlx/query-3a9ffd4d88f2cfac22835aac2512e61157bf58aec70903623afc9da24d46a336.json delete mode 100644 prover/crates/lib/prover_dal/.sqlx/query-3bb8fbd9e83703887e0a3c196031b931c0d8dbc6835dfac20107ea7412ce9fbb.json delete mode 100644 prover/crates/lib/prover_dal/.sqlx/query-434f7cb51a7d22948cd26e962679a67936d572f8046d3a1c7a4f100ff209d81d.json create mode 100644 prover/crates/lib/prover_dal/.sqlx/query-73266a8526c6adc315900e2e95441976a264759c4060c1a38e466ee2052fc17d.json create mode 100644 prover/crates/lib/prover_dal/.sqlx/query-9730c8225ff2cf3111185e81f602a4a98ec63eb942c73ce4448d0957346047cd.json create mode 100644 prover/crates/lib/prover_dal/.sqlx/query-a817f0fec85388b3e2510ce259208a01b63ae4aa03c983c3a52c802d585e5a80.json delete mode 100644 prover/crates/lib/prover_dal/.sqlx/query-aabcfa9005b8e1d84cfa083a47a700302981be0afef31a8864613484f8521f9e.json create mode 100644 prover/crates/lib/prover_dal/.sqlx/query-c8daa62b3835c15fafb3f83deabb5a4672ad50a9de92c84d939ac4c69842e355.json rename prover/crates/lib/prover_dal/.sqlx/{query-63cf7038e6c48af8ed9afc7d6ea07edd87cb16a79c13e7d4291d99736e51d3b9.json => query-e875dcbbdaed6998dbea45d4eab5d005d8760c4809b7aef902155196873da66e.json} (82%) rename prover/crates/lib/prover_dal/.sqlx/{query-0eac6f7b2d799059328584029b437891598dc79b5ed11258b2c90c3f282929ad.json => query-eec29cbff034818f4fb5ec1e6ad38e1010d7389457b3c97e9b238a3a0291a54e.json} (78%) diff --git a/prover/crates/lib/prover_dal/.sqlx/query-1297f0977132185d6bd4501f490f1cdac8b194f09926c133985479c533a651f2.json b/prover/crates/lib/prover_dal/.sqlx/query-1297f0977132185d6bd4501f490f1cdac8b194f09926c133985479c533a651f2.json new file mode 100644 index 000000000000..c99572bcc8e5 --- /dev/null +++ b/prover/crates/lib/prover_dal/.sqlx/query-1297f0977132185d6bd4501f490f1cdac8b194f09926c133985479c533a651f2.json @@ -0,0 +1,18 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE prover_jobs_fri\n SET\n status = $1\n WHERE\n l1_batch_number = $2\n AND sequence_number = $3\n AND aggregation_round = $4\n AND circuit_id = $5\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8", + "Int4", + "Int2", + "Int2" + ] + }, + "nullable": [] + }, + "hash": "1297f0977132185d6bd4501f490f1cdac8b194f09926c133985479c533a651f2" +} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-1926cf432237684de2383179a6d0d001cdf5bc7ba988b742571ec90a938434e3.json b/prover/crates/lib/prover_dal/.sqlx/query-1926cf432237684de2383179a6d0d001cdf5bc7ba988b742571ec90a938434e3.json deleted file mode 100644 index 4015a22ff3fd..000000000000 --- a/prover/crates/lib/prover_dal/.sqlx/query-1926cf432237684de2383179a6d0d001cdf5bc7ba988b742571ec90a938434e3.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE leaf_aggregation_witness_jobs_fri \n SET status = $1, attempts = $2\n WHERE l1_batch_number = $3\n AND circuit_id = $4", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Int2", - "Int8", - "Int2" - ] - }, - "nullable": [] - }, - "hash": "1926cf432237684de2383179a6d0d001cdf5bc7ba988b742571ec90a938434e3" -} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-2d1461e068e43fd16714610b383cf8c93630d529ec96e67aac078f18196f61a5.json b/prover/crates/lib/prover_dal/.sqlx/query-2d1461e068e43fd16714610b383cf8c93630d529ec96e67aac078f18196f61a5.json new file mode 100644 index 000000000000..50d121213fb9 --- /dev/null +++ b/prover/crates/lib/prover_dal/.sqlx/query-2d1461e068e43fd16714610b383cf8c93630d529ec96e67aac078f18196f61a5.json @@ -0,0 +1,19 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE prover_jobs_fri\n SET\n status = $1,\n attempts = $2\n WHERE\n l1_batch_number = $3\n AND sequence_number = $4\n AND aggregation_round = $5\n AND circuit_id = $6\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int2", + "Int8", + "Int4", + "Int2", + "Int2" + ] + }, + "nullable": [] + }, + "hash": "2d1461e068e43fd16714610b383cf8c93630d529ec96e67aac078f18196f61a5" +} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-75c1affbca0901edd5d0e2f12ef4d935674a5aff2f34421d753b4d1a9dea5b12.json b/prover/crates/lib/prover_dal/.sqlx/query-35a76415cb746d03da31481edc65adefab0bf3abf6853a6d36123c8adcaf813b.json similarity index 70% rename from prover/crates/lib/prover_dal/.sqlx/query-75c1affbca0901edd5d0e2f12ef4d935674a5aff2f34421d753b4d1a9dea5b12.json rename to prover/crates/lib/prover_dal/.sqlx/query-35a76415cb746d03da31481edc65adefab0bf3abf6853a6d36123c8adcaf813b.json index 14463ecbe426..bf8db798e7d4 100644 --- a/prover/crates/lib/prover_dal/.sqlx/query-75c1affbca0901edd5d0e2f12ef4d935674a5aff2f34421d753b4d1a9dea5b12.json +++ b/prover/crates/lib/prover_dal/.sqlx/query-35a76415cb746d03da31481edc65adefab0bf3abf6853a6d36123c8adcaf813b.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE scheduler_witness_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n l1_batch_number = $1\n AND attempts >= $2\n AND (status = 'in_progress' OR status = 'failed')\n RETURNING\n l1_batch_number,\n status,\n attempts,\n error,\n picked_by\n ", + "query": "\n UPDATE scheduler_witness_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n l1_batch_number = $1\n AND attempts >= $2\n AND (\n status = 'in_progress'\n OR status = 'failed'\n )\n RETURNING\n l1_batch_number,\n status,\n attempts,\n error,\n picked_by\n ", "describe": { "columns": [ { @@ -43,5 +43,5 @@ true ] }, - "hash": "75c1affbca0901edd5d0e2f12ef4d935674a5aff2f34421d753b4d1a9dea5b12" + "hash": "35a76415cb746d03da31481edc65adefab0bf3abf6853a6d36123c8adcaf813b" } diff --git a/prover/crates/lib/prover_dal/.sqlx/query-548414f8148740c991c345e5fd46ea738d209eb07e7a6bcbdb33e25b3347a08c.json b/prover/crates/lib/prover_dal/.sqlx/query-3727d5614d2fe2a4d96f880eb72cd48c95ca5b4520dde415a2b5ff32ece47c86.json similarity index 70% rename from prover/crates/lib/prover_dal/.sqlx/query-548414f8148740c991c345e5fd46ea738d209eb07e7a6bcbdb33e25b3347a08c.json rename to prover/crates/lib/prover_dal/.sqlx/query-3727d5614d2fe2a4d96f880eb72cd48c95ca5b4520dde415a2b5ff32ece47c86.json index 8f5b046b974f..d7eb6a32b421 100644 --- a/prover/crates/lib/prover_dal/.sqlx/query-548414f8148740c991c345e5fd46ea738d209eb07e7a6bcbdb33e25b3347a08c.json +++ b/prover/crates/lib/prover_dal/.sqlx/query-3727d5614d2fe2a4d96f880eb72cd48c95ca5b4520dde415a2b5ff32ece47c86.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE witness_inputs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n l1_batch_number = $1\n AND attempts >= $2\n AND (status = 'in_progress' OR status = 'failed')\n RETURNING\n l1_batch_number,\n status,\n attempts,\n error,\n picked_by\n ", + "query": "\n UPDATE witness_inputs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n l1_batch_number = $1\n AND attempts >= $2\n AND (\n status = 'in_progress'\n OR status = 'failed'\n )\n RETURNING\n l1_batch_number,\n status,\n attempts,\n error,\n picked_by\n ", "describe": { "columns": [ { @@ -43,5 +43,5 @@ true ] }, - "hash": "548414f8148740c991c345e5fd46ea738d209eb07e7a6bcbdb33e25b3347a08c" + "hash": "3727d5614d2fe2a4d96f880eb72cd48c95ca5b4520dde415a2b5ff32ece47c86" } diff --git a/prover/crates/lib/prover_dal/.sqlx/query-c19fc4c8e4b3a3ef4f9c0f4c22ed68c598eada8e60938a8e4b5cd32b53f5a574.json b/prover/crates/lib/prover_dal/.sqlx/query-37ad15f54f4a6f4f79c71a857f3a8d4cc59246dda91b19526e73f27a17c8e3da.json similarity index 69% rename from prover/crates/lib/prover_dal/.sqlx/query-c19fc4c8e4b3a3ef4f9c0f4c22ed68c598eada8e60938a8e4b5cd32b53f5a574.json rename to prover/crates/lib/prover_dal/.sqlx/query-37ad15f54f4a6f4f79c71a857f3a8d4cc59246dda91b19526e73f27a17c8e3da.json index 3c4c8d7a29f3..c97fe7f4042b 100644 --- a/prover/crates/lib/prover_dal/.sqlx/query-c19fc4c8e4b3a3ef4f9c0f4c22ed68c598eada8e60938a8e4b5cd32b53f5a574.json +++ b/prover/crates/lib/prover_dal/.sqlx/query-37ad15f54f4a6f4f79c71a857f3a8d4cc59246dda91b19526e73f27a17c8e3da.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE recursion_tip_witness_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n l1_batch_number = $1\n AND attempts >= $2\n AND (status = 'in_progress' OR status = 'failed')\n RETURNING\n l1_batch_number,\n status,\n attempts,\n error,\n picked_by\n ", + "query": "\n UPDATE recursion_tip_witness_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n l1_batch_number = $1\n AND attempts >= $2\n AND (\n status = 'in_progress'\n OR status = 'failed'\n )\n RETURNING\n l1_batch_number,\n status,\n attempts,\n error,\n picked_by\n ", "describe": { "columns": [ { @@ -43,5 +43,5 @@ true ] }, - "hash": "c19fc4c8e4b3a3ef4f9c0f4c22ed68c598eada8e60938a8e4b5cd32b53f5a574" + "hash": "37ad15f54f4a6f4f79c71a857f3a8d4cc59246dda91b19526e73f27a17c8e3da" } diff --git a/prover/crates/lib/prover_dal/.sqlx/query-39f60c638d445c5dbf23e01fd89a468057599be1e6c6c96a947c33df53a68224.json b/prover/crates/lib/prover_dal/.sqlx/query-39f60c638d445c5dbf23e01fd89a468057599be1e6c6c96a947c33df53a68224.json deleted file mode 100644 index 5cec4d7d7d03..000000000000 --- a/prover/crates/lib/prover_dal/.sqlx/query-39f60c638d445c5dbf23e01fd89a468057599be1e6c6c96a947c33df53a68224.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n recursion_tip_witness_jobs_fri (\n l1_batch_number,\n status,\n number_of_final_node_jobs,\n created_at,\n updated_at\n )\n VALUES\n ($1, 'waiting_for_proofs',1, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET status = $2\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Text" - ] - }, - "nullable": [] - }, - "hash": "39f60c638d445c5dbf23e01fd89a468057599be1e6c6c96a947c33df53a68224" -} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-3a9ffd4d88f2cfac22835aac2512e61157bf58aec70903623afc9da24d46a336.json b/prover/crates/lib/prover_dal/.sqlx/query-3a9ffd4d88f2cfac22835aac2512e61157bf58aec70903623afc9da24d46a336.json deleted file mode 100644 index 063ae8fc90a3..000000000000 --- a/prover/crates/lib/prover_dal/.sqlx/query-3a9ffd4d88f2cfac22835aac2512e61157bf58aec70903623afc9da24d46a336.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n node_aggregation_witness_jobs_fri (\n l1_batch_number,\n circuit_id,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number, circuit_id, depth) DO\n UPDATE\n SET status = $3\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Int2", - "Text" - ] - }, - "nullable": [] - }, - "hash": "3a9ffd4d88f2cfac22835aac2512e61157bf58aec70903623afc9da24d46a336" -} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-3bb8fbd9e83703887e0a3c196031b931c0d8dbc6835dfac20107ea7412ce9fbb.json b/prover/crates/lib/prover_dal/.sqlx/query-3bb8fbd9e83703887e0a3c196031b931c0d8dbc6835dfac20107ea7412ce9fbb.json deleted file mode 100644 index 693905084151..000000000000 --- a/prover/crates/lib/prover_dal/.sqlx/query-3bb8fbd9e83703887e0a3c196031b931c0d8dbc6835dfac20107ea7412ce9fbb.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n proof_compression_jobs_fri (\n l1_batch_number,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET status = $2\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Text" - ] - }, - "nullable": [] - }, - "hash": "3bb8fbd9e83703887e0a3c196031b931c0d8dbc6835dfac20107ea7412ce9fbb" -} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-434f7cb51a7d22948cd26e962679a67936d572f8046d3a1c7a4f100ff209d81d.json b/prover/crates/lib/prover_dal/.sqlx/query-434f7cb51a7d22948cd26e962679a67936d572f8046d3a1c7a4f100ff209d81d.json deleted file mode 100644 index 7615523f92f1..000000000000 --- a/prover/crates/lib/prover_dal/.sqlx/query-434f7cb51a7d22948cd26e962679a67936d572f8046d3a1c7a4f100ff209d81d.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE prover_jobs_fri SET status = $1\n WHERE l1_batch_number = $2\n AND sequence_number = $3\n AND aggregation_round = $4\n AND circuit_id = $5", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Int8", - "Int4", - "Int2", - "Int2" - ] - }, - "nullable": [] - }, - "hash": "434f7cb51a7d22948cd26e962679a67936d572f8046d3a1c7a4f100ff209d81d" -} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-73266a8526c6adc315900e2e95441976a264759c4060c1a38e466ee2052fc17d.json b/prover/crates/lib/prover_dal/.sqlx/query-73266a8526c6adc315900e2e95441976a264759c4060c1a38e466ee2052fc17d.json new file mode 100644 index 000000000000..f8b141a8dac9 --- /dev/null +++ b/prover/crates/lib/prover_dal/.sqlx/query-73266a8526c6adc315900e2e95441976a264759c4060c1a38e466ee2052fc17d.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n recursion_tip_witness_jobs_fri (l1_batch_number, status, number_of_final_node_jobs, created_at, updated_at)\n VALUES\n ($1, 'waiting_for_proofs', 1, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET\n status = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Text" + ] + }, + "nullable": [] + }, + "hash": "73266a8526c6adc315900e2e95441976a264759c4060c1a38e466ee2052fc17d" +} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-9730c8225ff2cf3111185e81f602a4a98ec63eb942c73ce4448d0957346047cd.json b/prover/crates/lib/prover_dal/.sqlx/query-9730c8225ff2cf3111185e81f602a4a98ec63eb942c73ce4448d0957346047cd.json new file mode 100644 index 000000000000..d23ed8d9fc8a --- /dev/null +++ b/prover/crates/lib/prover_dal/.sqlx/query-9730c8225ff2cf3111185e81f602a4a98ec63eb942c73ce4448d0957346047cd.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE leaf_aggregation_witness_jobs_fri\n SET\n status = $1,\n attempts = $2\n WHERE\n l1_batch_number = $3\n AND circuit_id = $4\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int2", + "Int8", + "Int2" + ] + }, + "nullable": [] + }, + "hash": "9730c8225ff2cf3111185e81f602a4a98ec63eb942c73ce4448d0957346047cd" +} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-a817f0fec85388b3e2510ce259208a01b63ae4aa03c983c3a52c802d585e5a80.json b/prover/crates/lib/prover_dal/.sqlx/query-a817f0fec85388b3e2510ce259208a01b63ae4aa03c983c3a52c802d585e5a80.json new file mode 100644 index 000000000000..93532150f7f8 --- /dev/null +++ b/prover/crates/lib/prover_dal/.sqlx/query-a817f0fec85388b3e2510ce259208a01b63ae4aa03c983c3a52c802d585e5a80.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n proof_compression_jobs_fri (l1_batch_number, status, created_at, updated_at)\n VALUES\n ($1, $2, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET\n status = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Text" + ] + }, + "nullable": [] + }, + "hash": "a817f0fec85388b3e2510ce259208a01b63ae4aa03c983c3a52c802d585e5a80" +} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-aabcfa9005b8e1d84cfa083a47a700302981be0afef31a8864613484f8521f9e.json b/prover/crates/lib/prover_dal/.sqlx/query-aabcfa9005b8e1d84cfa083a47a700302981be0afef31a8864613484f8521f9e.json deleted file mode 100644 index 3d60050c92ed..000000000000 --- a/prover/crates/lib/prover_dal/.sqlx/query-aabcfa9005b8e1d84cfa083a47a700302981be0afef31a8864613484f8521f9e.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE prover_jobs_fri \n SET status = $1, attempts = $2\n WHERE l1_batch_number = $3\n AND sequence_number =$4\n AND aggregation_round = $5\n AND circuit_id = $6", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Int2", - "Int8", - "Int4", - "Int2", - "Int2" - ] - }, - "nullable": [] - }, - "hash": "aabcfa9005b8e1d84cfa083a47a700302981be0afef31a8864613484f8521f9e" -} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-c8daa62b3835c15fafb3f83deabb5a4672ad50a9de92c84d939ac4c69842e355.json b/prover/crates/lib/prover_dal/.sqlx/query-c8daa62b3835c15fafb3f83deabb5a4672ad50a9de92c84d939ac4c69842e355.json new file mode 100644 index 000000000000..cadc931fa1ca --- /dev/null +++ b/prover/crates/lib/prover_dal/.sqlx/query-c8daa62b3835c15fafb3f83deabb5a4672ad50a9de92c84d939ac4c69842e355.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n node_aggregation_witness_jobs_fri (l1_batch_number, circuit_id, status, created_at, updated_at)\n VALUES\n ($1, $2, 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number, circuit_id, depth) DO\n UPDATE\n SET\n status = $3\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int2", + "Text" + ] + }, + "nullable": [] + }, + "hash": "c8daa62b3835c15fafb3f83deabb5a4672ad50a9de92c84d939ac4c69842e355" +} diff --git a/prover/crates/lib/prover_dal/.sqlx/query-63cf7038e6c48af8ed9afc7d6ea07edd87cb16a79c13e7d4291d99736e51d3b9.json b/prover/crates/lib/prover_dal/.sqlx/query-e875dcbbdaed6998dbea45d4eab5d005d8760c4809b7aef902155196873da66e.json similarity index 82% rename from prover/crates/lib/prover_dal/.sqlx/query-63cf7038e6c48af8ed9afc7d6ea07edd87cb16a79c13e7d4291d99736e51d3b9.json rename to prover/crates/lib/prover_dal/.sqlx/query-e875dcbbdaed6998dbea45d4eab5d005d8760c4809b7aef902155196873da66e.json index 208b23d939f8..4ee9278fe42a 100644 --- a/prover/crates/lib/prover_dal/.sqlx/query-63cf7038e6c48af8ed9afc7d6ea07edd87cb16a79c13e7d4291d99736e51d3b9.json +++ b/prover/crates/lib/prover_dal/.sqlx/query-e875dcbbdaed6998dbea45d4eab5d005d8760c4809b7aef902155196873da66e.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n scheduler_witness_jobs_fri (\n l1_batch_number,\n scheduler_partial_input_blob_url,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, '', 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET status = $2\n ", + "query": "\n INSERT INTO\n scheduler_witness_jobs_fri (\n l1_batch_number,\n scheduler_partial_input_blob_url,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, '', 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET\n status = $2\n ", "describe": { "columns": [], "parameters": { @@ -11,5 +11,5 @@ }, "nullable": [] }, - "hash": "63cf7038e6c48af8ed9afc7d6ea07edd87cb16a79c13e7d4291d99736e51d3b9" + "hash": "e875dcbbdaed6998dbea45d4eab5d005d8760c4809b7aef902155196873da66e" } diff --git a/prover/crates/lib/prover_dal/.sqlx/query-0eac6f7b2d799059328584029b437891598dc79b5ed11258b2c90c3f282929ad.json b/prover/crates/lib/prover_dal/.sqlx/query-eec29cbff034818f4fb5ec1e6ad38e1010d7389457b3c97e9b238a3a0291a54e.json similarity index 78% rename from prover/crates/lib/prover_dal/.sqlx/query-0eac6f7b2d799059328584029b437891598dc79b5ed11258b2c90c3f282929ad.json rename to prover/crates/lib/prover_dal/.sqlx/query-eec29cbff034818f4fb5ec1e6ad38e1010d7389457b3c97e9b238a3a0291a54e.json index 61518273b4d3..f8e92b1ad666 100644 --- a/prover/crates/lib/prover_dal/.sqlx/query-0eac6f7b2d799059328584029b437891598dc79b5ed11258b2c90c3f282929ad.json +++ b/prover/crates/lib/prover_dal/.sqlx/query-eec29cbff034818f4fb5ec1e6ad38e1010d7389457b3c97e9b238a3a0291a54e.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n leaf_aggregation_witness_jobs_fri (\n l1_batch_number,\n circuit_id,\n status,\n number_of_basic_circuits,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, 'waiting_for_proofs', 2, NOW(), NOW())\n ON CONFLICT (l1_batch_number, circuit_id) DO\n UPDATE\n SET status = $3\n ", + "query": "\n INSERT INTO\n leaf_aggregation_witness_jobs_fri (\n l1_batch_number,\n circuit_id,\n status,\n number_of_basic_circuits,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, 'waiting_for_proofs', 2, NOW(), NOW())\n ON CONFLICT (l1_batch_number, circuit_id) DO\n UPDATE\n SET\n status = $3\n ", "describe": { "columns": [], "parameters": { @@ -12,5 +12,5 @@ }, "nullable": [] }, - "hash": "0eac6f7b2d799059328584029b437891598dc79b5ed11258b2c90c3f282929ad" + "hash": "eec29cbff034818f4fb5ec1e6ad38e1010d7389457b3c97e9b238a3a0291a54e" } From b5c7544c3e48370b0fca6bc6ade93c44a798f766 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 25 Sep 2024 11:43:22 -0300 Subject: [PATCH 42/45] Fix lints and format --- .../system-constants-generator/src/utils.rs | 7 +- core/lib/contracts/src/lib.rs | 1 - .../lib/dal/src/models/storage_transaction.rs | 5 +- .../src/versions/vm_fast/tests/rollbacks.rs | 3 +- .../tests/tester/transaction_test_info.rs | 2 +- core/lib/multivm/src/versions/vm_latest/vm.rs | 3 +- core/lib/types/src/l2/mod.rs | 7 +- core/lib/types/src/lib.rs | 4 +- core/lib/types/src/system_contracts.rs | 12 +-- core/lib/types/src/transaction_request.rs | 4 +- core/node/eth_sender/src/eth_tx_aggregator.rs | 4 +- core/node/state_keeper/src/updates/mod.rs | 2 +- docs/guides/external-node/00_quick_start.md | 3 +- .../crates/lib/prover_dal/src/cli_test_dal.rs | 99 ++++++++++--------- .../src/fri_witness_generator_dal.rs | 15 ++- 15 files changed, 92 insertions(+), 79 deletions(-) diff --git a/core/bin/system-constants-generator/src/utils.rs b/core/bin/system-constants-generator/src/utils.rs index a11590729aec..002836b5d962 100644 --- a/core/bin/system-constants-generator/src/utils.rs +++ b/core/bin/system-constants-generator/src/utils.rs @@ -1,4 +1,4 @@ -use std::{cell::RefCell, rc::Rc, str::FromStr}; +use std::{cell::RefCell, rc::Rc}; use once_cell::sync::Lazy; use zksync_config::configs::use_evm_simulator; @@ -26,9 +26,8 @@ use zksync_types::{ block::L2BlockHasher, ethabi::Token, fee::Fee, fee_model::BatchFeeInput, l1::L1Tx, l2::L2Tx, utils::storage_key_for_eth_balance, AccountTreeId, Address, Execute, K256PrivateKey, L1BatchNumber, L1TxCommonData, L2BlockNumber, L2ChainId, Nonce, ProtocolVersionId, StorageKey, - Transaction, BOOTLOADER_ADDRESS, H256, SYSTEM_CONTEXT_ADDRESS, - SYSTEM_CONTEXT_GAS_PRICE_POSITION, SYSTEM_CONTEXT_TX_ORIGIN_POSITION, U256, - ZKPORTER_IS_AVAILABLE, + Transaction, BOOTLOADER_ADDRESS, SYSTEM_CONTEXT_ADDRESS, SYSTEM_CONTEXT_GAS_PRICE_POSITION, + SYSTEM_CONTEXT_TX_ORIGIN_POSITION, U256, ZKPORTER_IS_AVAILABLE, }; use zksync_utils::{bytecode::hash_bytecode, bytes_to_be_words, u256_to_h256}; diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index 2fd8bf44c24c..33c811277dfd 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -8,7 +8,6 @@ use std::{ fs::{self, File}, io::BufReader, path::{Path, PathBuf}, - str::FromStr, }; use ethabi::{ diff --git a/core/lib/dal/src/models/storage_transaction.rs b/core/lib/dal/src/models/storage_transaction.rs index 6dc9c5c7a924..7106b0dadf21 100644 --- a/core/lib/dal/src/models/storage_transaction.rs +++ b/core/lib/dal/src/models/storage_transaction.rs @@ -367,8 +367,9 @@ impl From for TransactionReceipt { .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. - }).or_else(|| Some(Address::zero())), + // For better compatibility with various clients, we never return null. + }) + .or_else(|| Some(Address::zero())), 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_fast/tests/rollbacks.rs b/core/lib/multivm/src/versions/vm_fast/tests/rollbacks.rs index 81d7303b74dc..548bf8daadfc 100644 --- a/core/lib/multivm/src/versions/vm_fast/tests/rollbacks.rs +++ b/core/lib/multivm/src/versions/vm_fast/tests/rollbacks.rs @@ -152,7 +152,8 @@ fn test_vm_loadnext_rollbacks() { 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), 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 5cc9ead8b548..46def9e52499 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,6 +1,6 @@ use std::fmt; -use zksync_types::{ExecuteTransactionCommon, Transaction, H160, U256}; +use zksync_types::{ExecuteTransactionCommon, Nonce, Transaction, H160, U256}; use zksync_vm2::interface::{Event, StateInterface}; use super::VmTester; diff --git a/core/lib/multivm/src/versions/vm_latest/vm.rs b/core/lib/multivm/src/versions/vm_latest/vm.rs index 48020a329ef5..e66ff00e885f 100644 --- a/core/lib/multivm/src/versions/vm_latest/vm.rs +++ b/core/lib/multivm/src/versions/vm_latest/vm.rs @@ -4,8 +4,7 @@ use zksync_types::{ vm::VmVersion, Transaction, H256, }; -use zksync_utils::{be_words_to_bytes, h256_to_u256}; -use zksync_utils::u256_to_h256; +use zksync_utils::{be_words_to_bytes, h256_to_u256, u256_to_h256}; use crate::{ glue::GlueInto, diff --git a/core/lib/types/src/l2/mod.rs b/core/lib/types/src/l2/mod.rs index 110a90c44242..106a0afd2c40 100644 --- a/core/lib/types/src/l2/mod.rs +++ b/core/lib/types/src/l2/mod.rs @@ -218,8 +218,11 @@ impl L2Tx { let raw = req.get_signed_bytes(&sig).context("get_signed_bytes")?; let (req, hash) = TransactionRequest::from_bytes_unverified(&raw).context("from_bytes_unverified()")?; - let use_evm_simulator = use_evm_simulator::UseEvmSimulator::from_env().unwrap().use_evm_simulator; - let mut tx = L2Tx::from_request_unverified(req, use_evm_simulator).context("from_request_unverified()")?; + let use_evm_simulator = use_evm_simulator::UseEvmSimulator::from_env() + .unwrap() + .use_evm_simulator; + let mut tx = L2Tx::from_request_unverified(req, use_evm_simulator) + .context("from_request_unverified()")?; tx.set_input(raw, hash); Ok(tx) } diff --git a/core/lib/types/src/lib.rs b/core/lib/types/src/lib.rs index 1e38b63dcdda..6b7d3b2e2ab0 100644 --- a/core/lib/types/src/lib.rs +++ b/core/lib/types/src/lib.rs @@ -391,7 +391,9 @@ impl TryFrom for Transaction { abi::Transaction::L2(raw) => { let (req, hash) = transaction_request::TransactionRequest::from_bytes_unverified(&raw)?; - let use_evm_simulator = use_evm_simulator::UseEvmSimulator::from_env().unwrap().use_evm_simulator; + let use_evm_simulator = use_evm_simulator::UseEvmSimulator::from_env() + .unwrap() + .use_evm_simulator; let mut tx = L2Tx::from_request_unverified(req, use_evm_simulator)?; tx.set_input(raw, hash); tx.into() diff --git a/core/lib/types/src/system_contracts.rs b/core/lib/types/src/system_contracts.rs index f92ff7c0c518..dd0355cd8435 100644 --- a/core/lib/types/src/system_contracts.rs +++ b/core/lib/types/src/system_contracts.rs @@ -1,4 +1,4 @@ -use std::{path::PathBuf, str::FromStr}; +use std::path::PathBuf; use once_cell::sync::Lazy; use zksync_basic_types::{AccountTreeId, Address, H256, U256}; @@ -208,15 +208,14 @@ static SYSTEM_CONTRACTS: Lazy> = Lazy::new(|| { SYSTEM_CONTRACT_LIST .iter() .filter_map(|(path, name, address, contract_lang)| { - let result = if *name == "EvmGasManager" && !evm_simulator_is_used { + if *name == "EvmGasManager" && !evm_simulator_is_used { None } else { Some(DeployedContract { account_id: AccountTreeId::new(*address), bytecode: read_sys_contract_bytecode(path, name, contract_lang.clone()), }) - }; - result + } }) .collect::>() }); @@ -235,15 +234,14 @@ pub fn get_system_smart_contracts_from_dir(path: PathBuf) -> Vec>() } diff --git a/core/lib/types/src/transaction_request.rs b/core/lib/types/src/transaction_request.rs index d51378452dda..0ec77d5016d9 100644 --- a/core/lib/types/src/transaction_request.rs +++ b/core/lib/types/src/transaction_request.rs @@ -855,7 +855,9 @@ impl L2Tx { value: TransactionRequest, max_tx_size: usize, ) -> Result { - let use_evm_simulator = use_evm_simulator::UseEvmSimulator::from_env().unwrap().use_evm_simulator; + let use_evm_simulator = use_evm_simulator::UseEvmSimulator::from_env() + .unwrap() + .use_evm_simulator; let tx = Self::from_request_unverified(value, use_evm_simulator)?; tx.check_encoded_size(max_tx_size)?; Ok(tx) diff --git a/core/node/eth_sender/src/eth_tx_aggregator.rs b/core/node/eth_sender/src/eth_tx_aggregator.rs index 54c6c698e270..be73188f8e89 100644 --- a/core/node/eth_sender/src/eth_tx_aggregator.rs +++ b/core/node/eth_sender/src/eth_tx_aggregator.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use tokio::sync::watch; use zksync_config::configs::{ eth_sender::SenderConfig, @@ -189,7 +187,7 @@ impl EthTxAggregator { calldata: get_l2_default_aa_hash_input, }; - let mut get_l2_evm_simulator_hash_input = self + let get_l2_evm_simulator_hash_input = self .functions .get_evm_simulator_bytecode_hash .as_ref() diff --git a/core/node/state_keeper/src/updates/mod.rs b/core/node/state_keeper/src/updates/mod.rs index 0761e36a97c9..59267b976dbe 100644 --- a/core/node/state_keeper/src/updates/mod.rs +++ b/core/node/state_keeper/src/updates/mod.rs @@ -236,10 +236,10 @@ mod tests { tx, create_execution_result([]), vec![], + vec![], new_block_gas_count(), VmExecutionMetrics::default(), vec![], - vec![], ); // Check that only pending state is updated. diff --git a/docs/guides/external-node/00_quick_start.md b/docs/guides/external-node/00_quick_start.md index 75d8ba891512..287a4d2d47c0 100644 --- a/docs/guides/external-node/00_quick_start.md +++ b/docs/guides/external-node/00_quick_start.md @@ -34,8 +34,7 @@ cd docker-compose-examples docker compose --file testnet-external-node-docker-compose.yml down --volumes ``` -You can see the status of the node (after recovery) in -[local grafana dashboard](http://localhost:3000/dashboards). +You can see the status of the node (after recovery) in [local grafana dashboard](http://localhost:3000/dashboards). Those commands start ZKsync node locally inside docker. diff --git a/prover/crates/lib/prover_dal/src/cli_test_dal.rs b/prover/crates/lib/prover_dal/src/cli_test_dal.rs index 19fe0e4f57b0..d08418203378 100644 --- a/prover/crates/lib/prover_dal/src/cli_test_dal.rs +++ b/prover/crates/lib/prover_dal/src/cli_test_dal.rs @@ -21,11 +21,16 @@ impl CliTestDal<'_, '_> { sequence_number: usize, ) { sqlx::query!( - "UPDATE prover_jobs_fri SET status = $1 - WHERE l1_batch_number = $2 + r#" + UPDATE prover_jobs_fri + SET + status = $1 + WHERE + l1_batch_number = $2 AND sequence_number = $3 AND aggregation_round = $4 - AND circuit_id = $5", + AND circuit_id = $5 + "#, status.to_string(), batch_number.0 as i64, sequence_number as i64, @@ -44,7 +49,7 @@ impl CliTestDal<'_, '_> { circuit_id: u8, ) { sqlx::query!( - " + r#" INSERT INTO leaf_aggregation_witness_jobs_fri ( l1_batch_number, @@ -58,8 +63,9 @@ impl CliTestDal<'_, '_> { ($1, $2, 'waiting_for_proofs', 2, NOW(), NOW()) ON CONFLICT (l1_batch_number, circuit_id) DO UPDATE - SET status = $3 - ", + SET + status = $3 + "#, batch_number.0 as i64, circuit_id as i16, status.to_string() @@ -76,21 +82,16 @@ impl CliTestDal<'_, '_> { circuit_id: u8, ) { sqlx::query!( - " + r#" INSERT INTO - node_aggregation_witness_jobs_fri ( - l1_batch_number, - circuit_id, - status, - created_at, - updated_at - ) + node_aggregation_witness_jobs_fri (l1_batch_number, circuit_id, status, created_at, updated_at) VALUES ($1, $2, 'waiting_for_proofs', NOW(), NOW()) ON CONFLICT (l1_batch_number, circuit_id, depth) DO UPDATE - SET status = $3 - ", + SET + status = $3 + "#, batch_number.0 as i64, circuit_id as i16, status.to_string(), @@ -102,21 +103,16 @@ impl CliTestDal<'_, '_> { pub async fn insert_rt_job(&mut self, status: WitnessJobStatus, batch_number: L1BatchNumber) { sqlx::query!( - " + r#" INSERT INTO - recursion_tip_witness_jobs_fri ( - l1_batch_number, - status, - number_of_final_node_jobs, - created_at, - updated_at - ) + recursion_tip_witness_jobs_fri (l1_batch_number, status, number_of_final_node_jobs, created_at, updated_at) VALUES - ($1, 'waiting_for_proofs',1, NOW(), NOW()) + ($1, 'waiting_for_proofs', 1, NOW(), NOW()) ON CONFLICT (l1_batch_number) DO UPDATE - SET status = $2 - ", + SET + status = $2 + "#, batch_number.0 as i64, status.to_string(), ) @@ -131,7 +127,7 @@ impl CliTestDal<'_, '_> { batch_number: L1BatchNumber, ) { sqlx::query!( - " + r#" INSERT INTO scheduler_witness_jobs_fri ( l1_batch_number, @@ -144,8 +140,9 @@ impl CliTestDal<'_, '_> { ($1, '', 'waiting_for_proofs', NOW(), NOW()) ON CONFLICT (l1_batch_number) DO UPDATE - SET status = $2 - ", + SET + status = $2 + "#, batch_number.0 as i64, status.to_string(), ) @@ -160,20 +157,16 @@ impl CliTestDal<'_, '_> { batch_number: L1BatchNumber, ) { sqlx::query!( - " + r#" INSERT INTO - proof_compression_jobs_fri ( - l1_batch_number, - status, - created_at, - updated_at - ) + proof_compression_jobs_fri (l1_batch_number, status, created_at, updated_at) VALUES ($1, $2, NOW(), NOW()) ON CONFLICT (l1_batch_number) DO UPDATE - SET status = $2 - ", + SET + status = $2 + "#, batch_number.0 as i64, status.to_string(), ) @@ -192,12 +185,17 @@ impl CliTestDal<'_, '_> { sequence_number: usize, ) { sqlx::query!( - "UPDATE prover_jobs_fri - SET status = $1, attempts = $2 - WHERE l1_batch_number = $3 - AND sequence_number =$4 + r#" + UPDATE prover_jobs_fri + SET + status = $1, + attempts = $2 + WHERE + l1_batch_number = $3 + AND sequence_number = $4 AND aggregation_round = $5 - AND circuit_id = $6", + AND circuit_id = $6 + "#, status.to_string(), attempts as i64, batch_number.0 as i64, @@ -218,10 +216,15 @@ impl CliTestDal<'_, '_> { batch_number: L1BatchNumber, ) { sqlx::query!( - "UPDATE leaf_aggregation_witness_jobs_fri - SET status = $1, attempts = $2 - WHERE l1_batch_number = $3 - AND circuit_id = $4", + r#" + UPDATE leaf_aggregation_witness_jobs_fri + SET + status = $1, + attempts = $2 + WHERE + l1_batch_number = $3 + AND circuit_id = $4 + "#, status.to_string(), attempts as i64, batch_number.0 as i64, diff --git a/prover/crates/lib/prover_dal/src/fri_witness_generator_dal.rs b/prover/crates/lib/prover_dal/src/fri_witness_generator_dal.rs index 66e34f7f8e75..c7ba0f60ef3f 100644 --- a/prover/crates/lib/prover_dal/src/fri_witness_generator_dal.rs +++ b/prover/crates/lib/prover_dal/src/fri_witness_generator_dal.rs @@ -1719,7 +1719,10 @@ impl FriWitnessGeneratorDal<'_, '_> { WHERE l1_batch_number = $1 AND attempts >= $2 - AND (status = 'in_progress' OR status = 'failed') + AND ( + status = 'in_progress' + OR status = 'failed' + ) RETURNING l1_batch_number, status, @@ -1786,7 +1789,10 @@ impl FriWitnessGeneratorDal<'_, '_> { WHERE l1_batch_number = $1 AND attempts >= $2 - AND (status = 'in_progress' OR status = 'failed') + AND ( + status = 'in_progress' + OR status = 'failed' + ) RETURNING l1_batch_number, status, @@ -1827,7 +1833,10 @@ impl FriWitnessGeneratorDal<'_, '_> { WHERE l1_batch_number = $1 AND attempts >= $2 - AND (status = 'in_progress' OR status = 'failed') + AND ( + status = 'in_progress' + OR status = 'failed' + ) RETURNING l1_batch_number, status, From 653b5433c797d6b910d7ded42165f84ce6476ee1 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 25 Sep 2024 12:08:15 -0300 Subject: [PATCH 43/45] Add evm simulator config to load config function --- core/bin/zksync_server/src/main.rs | 2 ++ core/lib/zksync_core_leftovers/src/temp_config_store/mod.rs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/core/bin/zksync_server/src/main.rs b/core/bin/zksync_server/src/main.rs index 84898d6da067..748a9437ed27 100644 --- a/core/bin/zksync_server/src/main.rs +++ b/core/bin/zksync_server/src/main.rs @@ -11,6 +11,7 @@ use zksync_config::{ }, fri_prover_group::FriProverGroupConfig, house_keeper::HouseKeeperConfig, + use_evm_simulator::UseEvmSimulator, BasicWitnessInputProducerConfig, ContractsConfig, DatabaseSecrets, ExperimentalVmConfig, ExternalPriceApiClientConfig, FriProofCompressorConfig, FriProverConfig, FriProverGatewayConfig, FriWitnessGeneratorConfig, FriWitnessVectorGeneratorConfig, @@ -205,6 +206,7 @@ fn load_env_config() -> anyhow::Result { basic_witness_input_producer_config: BasicWitnessInputProducerConfig::from_env().ok(), core_object_store: ObjectStoreConfig::from_env().ok(), base_token_adjuster_config: BaseTokenAdjusterConfig::from_env().ok(), + use_evm_simulator: UseEvmSimulator::from_env().ok(), commitment_generator: None, pruning: None, snapshot_recovery: None, diff --git a/core/lib/zksync_core_leftovers/src/temp_config_store/mod.rs b/core/lib/zksync_core_leftovers/src/temp_config_store/mod.rs index 2d6af705f482..90c3750e3261 100644 --- a/core/lib/zksync_core_leftovers/src/temp_config_store/mod.rs +++ b/core/lib/zksync_core_leftovers/src/temp_config_store/mod.rs @@ -10,6 +10,7 @@ use zksync_config::{ }, fri_prover_group::FriProverGroupConfig, house_keeper::HouseKeeperConfig, + use_evm_simulator::UseEvmSimulator, vm_runner::BasicWitnessInputProducerConfig, wallets::{AddressWallet, EthSender, StateKeeper, TokenMultiplierSetter, Wallet, Wallets}, CommitmentGeneratorConfig, DatabaseSecrets, ExperimentalVmConfig, @@ -75,6 +76,7 @@ pub struct TempConfigStore { pub core_object_store: Option, pub base_token_adjuster_config: Option, pub commitment_generator: Option, + pub use_evm_simulator: Option, pub pruning: Option, pub snapshot_recovery: Option, pub external_price_api_client_config: Option, @@ -196,6 +198,7 @@ fn load_env_config() -> anyhow::Result { basic_witness_input_producer_config: BasicWitnessInputProducerConfig::from_env().ok(), core_object_store: ObjectStoreConfig::from_env().ok(), base_token_adjuster_config: BaseTokenAdjusterConfig::from_env().ok(), + use_evm_simulator: UseEvmSimulator::from_env().ok(), commitment_generator: None, pruning: None, snapshot_recovery: None, From d2d61a4108f812d254702f130be61728a21be337 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 25 Sep 2024 13:07:57 -0300 Subject: [PATCH 44/45] Add evm simulator to general test config and protobuf message --- core/lib/config/src/configs/general.rs | 2 ++ core/lib/config/src/testonly.rs | 9 +++++++++ core/lib/protobuf_config/src/general.rs | 2 ++ core/lib/protobuf_config/src/lib.rs | 1 + .../src/proto/config/general.proto | 2 ++ .../src/proto/config/use_evm_simulator.proto | 7 +++++++ .../protobuf_config/src/use_evm_simulator.rs | 20 +++++++++++++++++++ .../src/temp_config_store/mod.rs | 1 + 8 files changed, 44 insertions(+) create mode 100644 core/lib/protobuf_config/src/proto/config/use_evm_simulator.proto create mode 100644 core/lib/protobuf_config/src/use_evm_simulator.rs diff --git a/core/lib/config/src/configs/general.rs b/core/lib/config/src/configs/general.rs index bb733510f77d..b7c78cbdb700 100644 --- a/core/lib/config/src/configs/general.rs +++ b/core/lib/config/src/configs/general.rs @@ -10,6 +10,7 @@ use crate::{ prover_job_monitor::ProverJobMonitorConfig, pruning::PruningConfig, snapshot_recovery::SnapshotRecoveryConfig, + use_evm_simulator::UseEvmSimulator, vm_runner::{BasicWitnessInputProducerConfig, ProtectiveReadsWriterConfig}, CommitmentGeneratorConfig, ExperimentalVmConfig, ExternalPriceApiClientConfig, FriProofCompressorConfig, FriProverConfig, FriProverGatewayConfig, @@ -51,6 +52,7 @@ pub struct GeneralConfig { pub pruning: Option, pub core_object_store: Option, pub base_token_adjuster: Option, + pub use_evm_simulator: Option, pub external_price_api_client_config: Option, pub consensus_config: Option, pub external_proof_integration_api_config: Option, diff --git a/core/lib/config/src/testonly.rs b/core/lib/config/src/testonly.rs index 1884b30b5f9a..e05459aa7858 100644 --- a/core/lib/config/src/testonly.rs +++ b/core/lib/config/src/testonly.rs @@ -40,6 +40,14 @@ impl Sample for Network { } } +impl Distribution for EncodeDist { + fn sample(&self, rng: &mut R) -> configs::use_evm_simulator::UseEvmSimulator { + configs::use_evm_simulator::UseEvmSimulator { + use_evm_simulator: rng.gen(), + } + } +} + impl Distribution for EncodeDist { fn sample(&self, rng: &mut R) -> configs::chain::FeeModelVersion { type T = configs::chain::FeeModelVersion; @@ -1154,6 +1162,7 @@ impl Distribution for EncodeDist { protective_reads_writer_config: self.sample(rng), basic_witness_input_producer_config: self.sample(rng), commitment_generator: self.sample(rng), + use_evm_simulator: self.sample(rng), snapshot_recovery: self.sample(rng), pruning: self.sample(rng), core_object_store: self.sample(rng), diff --git a/core/lib/protobuf_config/src/general.rs b/core/lib/protobuf_config/src/general.rs index b73539a0897f..736420e34268 100644 --- a/core/lib/protobuf_config/src/general.rs +++ b/core/lib/protobuf_config/src/general.rs @@ -46,6 +46,7 @@ impl ProtoRepr for proto::GeneralConfig { ), experimental_vm_config: read_optional_repr(&self.experimental_vm), prover_job_monitor_config: read_optional_repr(&self.prover_job_monitor), + use_evm_simulator: read_optional_repr(&self.use_evm_simulator), }) } @@ -102,6 +103,7 @@ impl ProtoRepr for proto::GeneralConfig { .as_ref() .map(ProtoRepr::build), experimental_vm: this.experimental_vm_config.as_ref().map(ProtoRepr::build), + use_evm_simulator: this.use_evm_simulator.as_ref().map(ProtoRepr::build), prover_job_monitor: this .prover_job_monitor_config .as_ref() diff --git a/core/lib/protobuf_config/src/lib.rs b/core/lib/protobuf_config/src/lib.rs index a4822edbe8e4..c1a65ee55b6d 100644 --- a/core/lib/protobuf_config/src/lib.rs +++ b/core/lib/protobuf_config/src/lib.rs @@ -28,6 +28,7 @@ mod prover; mod pruning; mod secrets; mod snapshots_creator; +mod use_evm_simulator; mod da_client; mod external_price_api_client; diff --git a/core/lib/protobuf_config/src/proto/config/general.proto b/core/lib/protobuf_config/src/proto/config/general.proto index ee70b61b18b3..c3f7c88cf850 100644 --- a/core/lib/protobuf_config/src/proto/config/general.proto +++ b/core/lib/protobuf_config/src/proto/config/general.proto @@ -26,6 +26,7 @@ import "zksync/config/external_proof_integration_api.proto"; import "zksync/core/consensus.proto"; import "zksync/config/prover_job_monitor.proto"; import "zksync/config/da_client.proto"; +import "zksync/config/use_evm_simulator.proto"; message GeneralConfig { optional database.Postgres postgres = 1; @@ -62,4 +63,5 @@ message GeneralConfig { optional experimental.Vm experimental_vm = 44; optional prover_job_monitor.ProverJobMonitor prover_job_monitor = 45; optional da_client.DataAvailabilityClient da_client = 46; + optional use_evm_simulator.UseEvmSimulator use_evm_simulator = 47; } diff --git a/core/lib/protobuf_config/src/proto/config/use_evm_simulator.proto b/core/lib/protobuf_config/src/proto/config/use_evm_simulator.proto new file mode 100644 index 000000000000..f0ca7329f903 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/config/use_evm_simulator.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; + +package zksync.config.use_evm_simulator; + +message UseEvmSimulator { + optional bool use_evm_simulator = 1; +} diff --git a/core/lib/protobuf_config/src/use_evm_simulator.rs b/core/lib/protobuf_config/src/use_evm_simulator.rs new file mode 100644 index 000000000000..703b8f8cc3ce --- /dev/null +++ b/core/lib/protobuf_config/src/use_evm_simulator.rs @@ -0,0 +1,20 @@ +use zksync_config::configs::{self}; +use zksync_protobuf::ProtoRepr; + +use crate::proto::use_evm_simulator as proto; + +impl ProtoRepr for proto::UseEvmSimulator { + type Type = configs::use_evm_simulator::UseEvmSimulator; + + fn read(&self) -> anyhow::Result { + Ok(configs::use_evm_simulator::UseEvmSimulator { + use_evm_simulator: self.use_evm_simulator.unwrap_or_default(), + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + use_evm_simulator: Some(this.use_evm_simulator), + } + } +} diff --git a/core/lib/zksync_core_leftovers/src/temp_config_store/mod.rs b/core/lib/zksync_core_leftovers/src/temp_config_store/mod.rs index 90c3750e3261..47f6e6a2241c 100644 --- a/core/lib/zksync_core_leftovers/src/temp_config_store/mod.rs +++ b/core/lib/zksync_core_leftovers/src/temp_config_store/mod.rs @@ -119,6 +119,7 @@ impl TempConfigStore { pruning: self.pruning.clone(), external_price_api_client_config: self.external_price_api_client_config.clone(), consensus_config: None, + use_evm_simulator: self.use_evm_simulator.clone(), external_proof_integration_api_config: self .external_proof_integration_api_config .clone(), From 44e714b9b27a58939c54e7377f330e4afd05acc7 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 25 Sep 2024 13:25:54 -0300 Subject: [PATCH 45/45] Add use evm simulator config to general config file --- etc/env/file_based/general.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/etc/env/file_based/general.yaml b/etc/env/file_based/general.yaml index cdf02175458b..23455ecc972d 100644 --- a/etc/env/file_based/general.yaml +++ b/etc/env/file_based/general.yaml @@ -305,6 +305,9 @@ external_price_api_client: house_keeper: l1_batch_metrics_reporting_interval_ms: 10000 +use_evm_simulator: + use_evm_simulator: false + prometheus: listener_port: 3314 pushgateway_url: http://127.0.0.1:9091