diff --git a/Cargo.lock b/Cargo.lock index 279d06bb9450..026096325aca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2375,6 +2375,7 @@ dependencies = [ "zksync_core", "zksync_dal", "zksync_env_config", + "zksync_node_genesis", "zksync_protobuf", "zksync_protobuf_config", "zksync_types", @@ -8460,6 +8461,7 @@ dependencies = [ "zksync_mempool", "zksync_merkle_tree", "zksync_mini_merkle_tree", + "zksync_node_genesis", "zksync_object_store", "zksync_proof_data_handler", "zksync_protobuf", @@ -8662,6 +8664,7 @@ dependencies = [ "zksync_eth_client", "zksync_health_check", "zksync_l1_contract_interface", + "zksync_node_genesis", "zksync_object_store", "zksync_protobuf_config", "zksync_shared_metrics", @@ -8809,6 +8812,27 @@ dependencies = [ "zksync_web3_decl", ] +[[package]] +name = "zksync_node_genesis" +version = "0.1.0" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "multivm", + "thiserror", + "tokio", + "tracing", + "vise", + "zksync_config", + "zksync_contracts", + "zksync_dal", + "zksync_eth_client", + "zksync_merkle_tree", + "zksync_system_constants", + "zksync_types", + "zksync_utils", +] + [[package]] name = "zksync_object_store" version = "0.1.0" @@ -8947,6 +8971,7 @@ dependencies = [ "zksync_core", "zksync_env_config", "zksync_eth_client", + "zksync_node_genesis", "zksync_protobuf_config", "zksync_storage", "zksync_types", diff --git a/Cargo.toml b/Cargo.toml index 728cfc9d197b..ae089b3cd25f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,8 @@ members = [ "core/node/block_reverter", "core/node/commitment_generator", "core/node/house_keeper", + "core/node/genesis", + "core/node/shared_metrics", # Libraries "core/lib/db_connection", "core/lib/zksync_core", @@ -228,3 +230,4 @@ zksync_proof_data_handler = { path = "core/node/proof_data_handler" } zksync_block_reverter = { path = "core/node/block_reverter" } zksync_commitment_generator = { path = "core/node/commitment_generator" } zksync_house_keeper = { path = "core/node/house_keeper" } +zksync_node_genesis = { path = "core/node/genesis" } diff --git a/core/bin/external_node/Cargo.toml b/core/bin/external_node/Cargo.toml index e754b2e6f2cc..1dd64e8c051f 100644 --- a/core/bin/external_node/Cargo.toml +++ b/core/bin/external_node/Cargo.toml @@ -32,6 +32,7 @@ zksync_web3_decl.workspace = true zksync_types.workspace = true zksync_block_reverter.workspace = true zksync_shared_metrics.workspace = true +zksync_node_genesis.workspace = true vlog.workspace = true zksync_concurrency.workspace = true diff --git a/core/bin/external_node/src/tests.rs b/core/bin/external_node/src/tests.rs index 27024b68ced3..c31ec1c62b5a 100644 --- a/core/bin/external_node/src/tests.rs +++ b/core/bin/external_node/src/tests.rs @@ -3,8 +3,8 @@ use assert_matches::assert_matches; use test_casing::test_casing; use zksync_basic_types::protocol_version::ProtocolVersionId; -use zksync_core::genesis::{insert_genesis_batch, GenesisParams}; use zksync_eth_client::clients::MockEthereum; +use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use zksync_types::{api, ethabi, fee_model::FeeParams, L1BatchNumber, L2BlockNumber, H256}; use zksync_web3_decl::client::{BoxedL2Client, MockL2Client}; diff --git a/core/bin/genesis_generator/Cargo.toml b/core/bin/genesis_generator/Cargo.toml index 55b0cc24c2af..8b91505abf09 100644 --- a/core/bin/genesis_generator/Cargo.toml +++ b/core/bin/genesis_generator/Cargo.toml @@ -21,7 +21,7 @@ zksync_core.workspace = true zksync_dal.workspace = true zksync_contracts.workspace = true zksync_protobuf.workspace = true - +zksync_node_genesis.workspace = true anyhow.workspace = true serde_json.workspace = true diff --git a/core/bin/genesis_generator/src/main.rs b/core/bin/genesis_generator/src/main.rs index 31c4387f9fc7..dfad2bd13333 100644 --- a/core/bin/genesis_generator/src/main.rs +++ b/core/bin/genesis_generator/src/main.rs @@ -9,12 +9,10 @@ use clap::Parser; use serde_yaml::Serializer; use zksync_config::{GenesisConfig, PostgresConfig}; use zksync_contracts::BaseSystemContracts; -use zksync_core::{ - genesis::{insert_genesis_batch, GenesisParams}, - temp_config_store::decode_yaml_repr, -}; +use zksync_core::temp_config_store::decode_yaml_repr; use zksync_dal::{ConnectionPool, Core, CoreDal}; use zksync_env_config::FromEnv; +use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use zksync_protobuf::{ build::{prost_reflect, prost_reflect::ReflectMessage}, ProtoRepr, diff --git a/core/bin/zksync_server/Cargo.toml b/core/bin/zksync_server/Cargo.toml index 36dca6486fe1..deef059dc960 100644 --- a/core/bin/zksync_server/Cargo.toml +++ b/core/bin/zksync_server/Cargo.toml @@ -19,6 +19,7 @@ zksync_storage.workspace = true zksync_utils.workspace = true zksync_types.workspace = true zksync_core.workspace = true +zksync_node_genesis.workspace = true # Consensus dependenices zksync_consensus_crypto.workspace = true diff --git a/core/bin/zksync_server/src/main.rs b/core/bin/zksync_server/src/main.rs index 56c4c0c9b750..a2a3eba027b1 100644 --- a/core/bin/zksync_server/src/main.rs +++ b/core/bin/zksync_server/src/main.rs @@ -19,7 +19,7 @@ use zksync_config::{ GenesisConfig, ObjectStoreConfig, PostgresConfig, SnapshotsCreatorConfig, }; use zksync_core::{ - genesis, genesis_init, initialize_components, is_genesis_needed, setup_sigint_handler, + genesis_init, initialize_components, is_genesis_needed, setup_sigint_handler, temp_config_store::{decode_yaml, decode_yaml_repr, Secrets, TempConfigStore}, Component, Components, }; @@ -183,7 +183,7 @@ async fn main() -> anyhow::Result<()> { let eth_config = configs.eth.as_ref().context("eth config")?; let query_client = QueryClient::new(eth_config.web3_url.clone()).context("Ethereum client")?; - genesis::save_set_chain_id_tx( + zksync_node_genesis::save_set_chain_id_tx( &query_client, contracts_config.diamond_proxy_addr, ecosystem_contracts.state_transition_proxy_addr, diff --git a/core/lib/zksync_core/Cargo.toml b/core/lib/zksync_core/Cargo.toml index b05e1e1d5d75..dc7cb35593ec 100644 --- a/core/lib/zksync_core/Cargo.toml +++ b/core/lib/zksync_core/Cargo.toml @@ -47,7 +47,7 @@ zksync_shared_metrics.workspace = true zksync_proof_data_handler.workspace = true zksync_commitment_generator.workspace = true zksync_house_keeper.workspace = true - +zksync_node_genesis.workspace = true multivm.workspace = true # Consensus dependenices diff --git a/core/lib/zksync_core/src/api_server/execution_sandbox/tests.rs b/core/lib/zksync_core/src/api_server/execution_sandbox/tests.rs index 1eb427147ab6..25c8ddd6b9f1 100644 --- a/core/lib/zksync_core/src/api_server/execution_sandbox/tests.rs +++ b/core/lib/zksync_core/src/api_server/execution_sandbox/tests.rs @@ -2,11 +2,11 @@ use assert_matches::assert_matches; use zksync_dal::ConnectionPool; +use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use super::*; use crate::{ api_server::{execution_sandbox::apply::apply_vm_in_sandbox, tx_sender::ApiContracts}, - genesis::{insert_genesis_batch, GenesisParams}, utils::testonly::{create_l2_block, create_l2_transaction, prepare_recovery_snapshot}, }; diff --git a/core/lib/zksync_core/src/api_server/tx_sender/tests.rs b/core/lib/zksync_core/src/api_server/tx_sender/tests.rs index 529d5d087502..f617a3678105 100644 --- a/core/lib/zksync_core/src/api_server/tx_sender/tests.rs +++ b/core/lib/zksync_core/src/api_server/tx_sender/tests.rs @@ -3,13 +3,13 @@ use assert_matches::assert_matches; use multivm::interface::ExecutionResult; use zksync_config::configs::wallets::Wallets; +use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use zksync_types::{get_nonce_key, L1BatchNumber, L2BlockNumber, StorageLog}; use zksync_utils::u256_to_h256; use super::*; use crate::{ api_server::execution_sandbox::{testonly::MockTransactionExecutor, VmConcurrencyBarrier}, - genesis::{insert_genesis_batch, GenesisParams}, utils::testonly::{ create_l2_block, create_l2_transaction, prepare_recovery_snapshot, MockBatchFeeParamsProvider, diff --git a/core/lib/zksync_core/src/api_server/web3/tests/mod.rs b/core/lib/zksync_core/src/api_server/web3/tests/mod.rs index 45258d92074d..ddb4e5d73d34 100644 --- a/core/lib/zksync_core/src/api_server/web3/tests/mod.rs +++ b/core/lib/zksync_core/src/api_server/web3/tests/mod.rs @@ -26,6 +26,7 @@ use zksync_config::{ }; use zksync_dal::{transactions_dal::L2TxSubmissionResult, Connection, ConnectionPool, CoreDal}; use zksync_health_check::CheckHealth; +use zksync_node_genesis::{insert_genesis_batch, mock_genesis_config, GenesisParams}; use zksync_types::{ api, block::L2BlockHeader, @@ -53,7 +54,6 @@ use crate::{ execution_sandbox::testonly::MockTransactionExecutor, tx_sender::tests::create_test_tx_sender, }, - genesis::{insert_genesis_batch, mock_genesis_config, GenesisParams}, utils::testonly::{ create_l1_batch, create_l1_batch_metadata, create_l2_block, create_l2_transaction, l1_batch_metadata_to_commitment_artifacts, prepare_recovery_snapshot, diff --git a/core/lib/zksync_core/src/consensus/storage/testonly.rs b/core/lib/zksync_core/src/consensus/storage/testonly.rs index e0a802294e16..c9b28231a5b1 100644 --- a/core/lib/zksync_core/src/consensus/storage/testonly.rs +++ b/core/lib/zksync_core/src/consensus/storage/testonly.rs @@ -4,12 +4,10 @@ use anyhow::Context as _; use zksync_concurrency::{ctx, error::Wrap as _, time}; use zksync_consensus_roles::validator; use zksync_dal::ConnectionPool; +use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use super::Store; -use crate::{ - genesis::{insert_genesis_batch, GenesisParams}, - utils::testonly::{recover, snapshot, Snapshot}, -}; +use crate::utils::testonly::{recover, snapshot, Snapshot}; impl Store { /// Waits for the `number` L2 block to have a certificate. diff --git a/core/lib/zksync_core/src/consensus/testonly.rs b/core/lib/zksync_core/src/consensus/testonly.rs index bc3523c51673..18ba6710381a 100644 --- a/core/lib/zksync_core/src/consensus/testonly.rs +++ b/core/lib/zksync_core/src/consensus/testonly.rs @@ -9,6 +9,7 @@ use zksync_config::{configs, GenesisConfig}; use zksync_consensus_roles::validator; use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::{CoreDal, DalError}; +use zksync_node_genesis::{mock_genesis_config, GenesisParams}; use zksync_types::{ api, snapshots::SnapshotRecoveryStatus, Address, L1BatchNumber, L2BlockNumber, L2ChainId, ProtocolVersionId, H256, @@ -21,7 +22,6 @@ use zksync_web3_decl::{ use crate::{ api_server::web3::{state::InternalApiConfig, tests::spawn_http_server}, consensus::{fetcher::P2PConfig, Fetcher, Store}, - genesis::{mock_genesis_config, GenesisParams}, state_keeper::{ io::{IoCursor, L1BatchParams, L2BlockParams}, seal_criteria::NoopSealer, diff --git a/core/lib/zksync_core/src/consistency_checker/tests/mod.rs b/core/lib/zksync_core/src/consistency_checker/tests/mod.rs index c9aaf53a9fa4..8a532231f5f4 100644 --- a/core/lib/zksync_core/src/consistency_checker/tests/mod.rs +++ b/core/lib/zksync_core/src/consistency_checker/tests/mod.rs @@ -8,6 +8,7 @@ use tokio::sync::mpsc; use zksync_config::GenesisConfig; use zksync_dal::Connection; use zksync_eth_client::{clients::MockEthereum, Options}; +use zksync_node_genesis::{insert_genesis_batch, mock_genesis_config, GenesisParams}; use zksync_types::{ aggregated_operations::AggregatedActionType, commitment::L1BatchWithMetadata, Log, ProtocolVersion, ProtocolVersionId, H256, @@ -18,7 +19,6 @@ use crate::{ eth_sender::l1_batch_commit_data_generator::{ RollupModeL1BatchCommitDataGenerator, ValidiumModeL1BatchCommitDataGenerator, }, - genesis::{insert_genesis_batch, mock_genesis_config, GenesisParams}, utils::testonly::{ create_l1_batch, create_l1_batch_metadata, l1_batch_metadata_to_commitment_artifacts, DeploymentMode, diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 83e656de4fde..63bbe58d06d5 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -59,6 +59,7 @@ use zksync_house_keeper::{ periodic_job::PeriodicJob, waiting_to_queued_fri_witness_job_mover::WaitingToQueuedFriWitnessJobMover, }; +use zksync_node_genesis::{ensure_genesis_state, GenesisParams}; use zksync_object_store::{ObjectStore, ObjectStoreFactory}; use zksync_queued_job_processor::JobProcessor; use zksync_shared_metrics::{InitStage, APP_METRICS}; @@ -82,7 +83,6 @@ use crate::{ }, Aggregator, EthTxAggregator, EthTxManager, }, - genesis::GenesisParams, l1_gas_price::{ GasAdjusterSingleton, PubdataPricing, RollupPubdataPricing, ValidiumPubdataPricing, }, @@ -101,7 +101,6 @@ pub mod consistency_checker; pub mod db_pruner; pub mod eth_sender; pub mod fee_model; -pub mod genesis; pub mod l1_gas_price; pub mod metadata_calculator; pub mod proto; @@ -125,7 +124,7 @@ pub async fn genesis_init( let mut storage = pool.connection().await.context("connection()")?; let params = GenesisParams::load_genesis_params(genesis_config)?; - genesis::ensure_genesis_state(&mut storage, ¶ms).await?; + ensure_genesis_state(&mut storage, ¶ms).await?; Ok(()) } diff --git a/core/lib/zksync_core/src/metadata_calculator/helpers.rs b/core/lib/zksync_core/src/metadata_calculator/helpers.rs index 997c40a5ab9a..c09f3a8a3e1f 100644 --- a/core/lib/zksync_core/src/metadata_calculator/helpers.rs +++ b/core/lib/zksync_core/src/metadata_calculator/helpers.rs @@ -612,15 +612,13 @@ impl L1BatchWithLogs { mod tests { use tempfile::TempDir; use zksync_dal::{ConnectionPool, Core}; + use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use zksync_prover_interface::inputs::PrepareBasicCircuitsJob; use zksync_types::{StorageKey, StorageLog}; use super::*; - use crate::{ - genesis::{insert_genesis_batch, GenesisParams}, - metadata_calculator::tests::{ - extend_db_state, gen_storage_logs, mock_config, reset_db_state, - }, + use crate::metadata_calculator::tests::{ + extend_db_state, gen_storage_logs, mock_config, reset_db_state, }; impl L1BatchWithLogs { diff --git a/core/lib/zksync_core/src/metadata_calculator/mod.rs b/core/lib/zksync_core/src/metadata_calculator/mod.rs index 04d62e171f5d..cab3ceb27c87 100644 --- a/core/lib/zksync_core/src/metadata_calculator/mod.rs +++ b/core/lib/zksync_core/src/metadata_calculator/mod.rs @@ -17,7 +17,7 @@ use zksync_dal::{ConnectionPool, Core}; use zksync_health_check::{CheckHealth, HealthUpdater, ReactiveHealthCheck}; use zksync_object_store::ObjectStore; -pub(crate) use self::helpers::{AsyncTreeReader, L1BatchWithLogs, MerkleTreeInfo}; +pub(crate) use self::helpers::{AsyncTreeReader, MerkleTreeInfo}; pub use self::{helpers::LazyAsyncTreeReader, pruning::MerkleTreePruningTask}; use self::{ helpers::{create_db, Delayer, GenericAsyncTree, MerkleTreeHealth, MerkleTreeHealthCheck}, diff --git a/core/lib/zksync_core/src/metadata_calculator/pruning.rs b/core/lib/zksync_core/src/metadata_calculator/pruning.rs index 42f615de7728..76614316e62c 100644 --- a/core/lib/zksync_core/src/metadata_calculator/pruning.rs +++ b/core/lib/zksync_core/src/metadata_calculator/pruning.rs @@ -146,11 +146,11 @@ impl MerkleTreePruningTask { mod tests { use tempfile::TempDir; use test_casing::test_casing; + use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use zksync_types::{L1BatchNumber, L2BlockNumber}; use super::*; use crate::{ - genesis::{insert_genesis_batch, GenesisParams}, metadata_calculator::{ tests::{extend_db_state_from_l1_batch, gen_storage_logs, mock_config, reset_db_state}, MetadataCalculator, diff --git a/core/lib/zksync_core/src/metadata_calculator/recovery/tests.rs b/core/lib/zksync_core/src/metadata_calculator/recovery/tests.rs index b7b8f4acf067..c055d6cb2fe9 100644 --- a/core/lib/zksync_core/src/metadata_calculator/recovery/tests.rs +++ b/core/lib/zksync_core/src/metadata_calculator/recovery/tests.rs @@ -13,11 +13,11 @@ use zksync_config::configs::{ use zksync_dal::CoreDal; use zksync_health_check::{CheckHealth, HealthStatus, ReactiveHealthCheck}; use zksync_merkle_tree::{domain::ZkSyncTree, TreeInstruction}; +use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use zksync_types::{L1BatchNumber, ProtocolVersionId, StorageLog}; use super::*; use crate::{ - genesis::{insert_genesis_batch, GenesisParams}, metadata_calculator::{ helpers::create_db, tests::{ diff --git a/core/lib/zksync_core/src/metadata_calculator/tests.rs b/core/lib/zksync_core/src/metadata_calculator/tests.rs index 3f602d5e6258..5caad8560830 100644 --- a/core/lib/zksync_core/src/metadata_calculator/tests.rs +++ b/core/lib/zksync_core/src/metadata_calculator/tests.rs @@ -13,6 +13,7 @@ use zksync_config::configs::{ use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; use zksync_health_check::{CheckHealth, HealthStatus}; use zksync_merkle_tree::domain::ZkSyncTree; +use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use zksync_object_store::{ObjectStore, ObjectStoreFactory}; use zksync_prover_interface::inputs::PrepareBasicCircuitsJob; use zksync_storage::RocksDB; @@ -22,11 +23,10 @@ use zksync_types::{ }; use zksync_utils::u32_to_h256; -use super::{GenericAsyncTree, L1BatchWithLogs, MetadataCalculator, MetadataCalculatorConfig}; -use crate::{ - genesis::{insert_genesis_batch, GenesisParams}, - utils::testonly::{create_l1_batch, create_l2_block}, +use super::{ + helpers::L1BatchWithLogs, GenericAsyncTree, MetadataCalculator, MetadataCalculatorConfig, }; +use crate::utils::testonly::{create_l1_batch, create_l2_block}; const RUN_TIMEOUT: Duration = Duration::from_secs(30); @@ -116,6 +116,7 @@ async fn expected_tree_hash(pool: &ConnectionPool) -> H256 { .await .unwrap(); let logs = logs.expect("no L1 batch").storage_logs; + all_logs.extend(logs); } ZkSyncTree::process_genesis_batch(&all_logs).root_hash diff --git a/core/lib/zksync_core/src/reorg_detector/tests.rs b/core/lib/zksync_core/src/reorg_detector/tests.rs index 32b768b9c81c..9a586067dbfa 100644 --- a/core/lib/zksync_core/src/reorg_detector/tests.rs +++ b/core/lib/zksync_core/src/reorg_detector/tests.rs @@ -9,6 +9,7 @@ use assert_matches::assert_matches; use test_casing::{test_casing, Product}; use tokio::sync::mpsc; use zksync_dal::{Connection, CoreDal}; +use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use zksync_types::{ block::{L2BlockHasher, L2BlockHeader}, ProtocolVersion, @@ -16,10 +17,7 @@ use zksync_types::{ use zksync_web3_decl::jsonrpsee::core::ClientError as RpcError; use super::*; -use crate::{ - genesis::{insert_genesis_batch, GenesisParams}, - utils::testonly::{create_l1_batch, create_l2_block}, -}; +use crate::utils::testonly::{create_l1_batch, create_l2_block}; async fn store_l2_block(storage: &mut Connection<'_, Core>, number: u32, hash: H256) { let header = L2BlockHeader { diff --git a/core/lib/zksync_core/src/state_keeper/batch_executor/tests/tester.rs b/core/lib/zksync_core/src/state_keeper/batch_executor/tests/tester.rs index d3c230724808..b63a717bfb51 100644 --- a/core/lib/zksync_core/src/state_keeper/batch_executor/tests/tester.rs +++ b/core/lib/zksync_core/src/state_keeper/batch_executor/tests/tester.rs @@ -12,6 +12,7 @@ use tokio::{sync::watch, task::JoinHandle}; use zksync_config::configs::chain::StateKeeperConfig; use zksync_contracts::{get_loadnext_contract, test_contracts::LoadnextContractExecutionParams}; use zksync_dal::{ConnectionPool, Core, CoreDal}; +use zksync_node_genesis::create_genesis_l1_batch; use zksync_state::{ReadStorageFactory, RocksdbStorageOptions}; use zksync_test_account::{Account, DeployContractsTx, TxType}; use zksync_types::{ @@ -29,7 +30,6 @@ use super::{ StorageType, }; use crate::{ - genesis::create_genesis_l1_batch, state_keeper::{ batch_executor::{BatchExecutorHandle, TxExecutionResult}, tests::{default_l1_batch_env, default_system_env, BASE_SYSTEM_CONTRACTS}, diff --git a/core/lib/zksync_core/src/state_keeper/io/common/tests.rs b/core/lib/zksync_core/src/state_keeper/io/common/tests.rs index 5eaa122bcadc..8e094be73388 100644 --- a/core/lib/zksync_core/src/state_keeper/io/common/tests.rs +++ b/core/lib/zksync_core/src/state_keeper/io/common/tests.rs @@ -10,18 +10,16 @@ use vm_utils::storage::L1BatchParamsProvider; use zksync_config::GenesisConfig; use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::{ConnectionPool, Core}; +use zksync_node_genesis::{insert_genesis_batch, mock_genesis_config, GenesisParams}; use zksync_types::{ block::L2BlockHasher, fee::TransactionExecutionMetrics, L2ChainId, ProtocolVersion, ProtocolVersionId, }; use super::*; -use crate::{ - genesis::{insert_genesis_batch, mock_genesis_config, GenesisParams}, - utils::testonly::{ - create_l1_batch, create_l2_block, create_l2_transaction, execute_l2_transaction, - prepare_recovery_snapshot, - }, +use crate::utils::testonly::{ + create_l1_batch, create_l2_block, create_l2_transaction, execute_l2_transaction, + prepare_recovery_snapshot, }; #[test] diff --git a/core/lib/zksync_core/src/state_keeper/io/persistence.rs b/core/lib/zksync_core/src/state_keeper/io/persistence.rs index 322f143da5c7..47f3d1d62ed1 100644 --- a/core/lib/zksync_core/src/state_keeper/io/persistence.rs +++ b/core/lib/zksync_core/src/state_keeper/io/persistence.rs @@ -248,20 +248,18 @@ mod tests { use futures::FutureExt; use multivm::zk_evm_latest::ethereum_types::{H256, U256}; use zksync_dal::CoreDal; + use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use zksync_types::{ api::TransactionStatus, block::BlockGasCount, tx::ExecutionMetrics, L1BatchNumber, L2BlockNumber, }; use super::*; - use crate::{ - genesis::{insert_genesis_batch, GenesisParams}, - state_keeper::{ - io::L2BlockParams, - tests::{ - create_execution_result, create_transaction, create_updates_manager, - default_l1_batch_env, default_system_env, default_vm_batch_result, Query, - }, + use crate::state_keeper::{ + io::L2BlockParams, + tests::{ + create_execution_result, create_transaction, create_updates_manager, + default_l1_batch_env, default_system_env, default_vm_batch_result, Query, }, }; diff --git a/core/lib/zksync_core/src/state_keeper/io/tests/tester.rs b/core/lib/zksync_core/src/state_keeper/io/tests/tester.rs index b9010df95d83..e10d9b2b91d0 100644 --- a/core/lib/zksync_core/src/state_keeper/io/tests/tester.rs +++ b/core/lib/zksync_core/src/state_keeper/io/tests/tester.rs @@ -10,6 +10,7 @@ use zksync_config::{ use zksync_contracts::BaseSystemContracts; use zksync_dal::{ConnectionPool, Core, CoreDal}; use zksync_eth_client::clients::MockEthereum; +use zksync_node_genesis::create_genesis_l1_batch; use zksync_types::{ block::L2BlockHeader, fee::TransactionExecutionMetrics, @@ -23,7 +24,6 @@ use zksync_types::{ use crate::{ fee_model::MainNodeFeeInputProvider, - genesis::create_genesis_l1_batch, l1_gas_price::{GasAdjuster, PubdataPricing, RollupPubdataPricing, ValidiumPubdataPricing}, state_keeper::{MempoolGuard, MempoolIO}, utils::testonly::{ diff --git a/core/lib/zksync_core/src/state_keeper/mempool_actor.rs b/core/lib/zksync_core/src/state_keeper/mempool_actor.rs index 119c39d399fc..6a6f494b286d 100644 --- a/core/lib/zksync_core/src/state_keeper/mempool_actor.rs +++ b/core/lib/zksync_core/src/state_keeper/mempool_actor.rs @@ -156,6 +156,7 @@ async fn get_transaction_nonces( #[cfg(test)] mod tests { + use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use zksync_types::{ fee::TransactionExecutionMetrics, L2BlockNumber, PriorityOpId, ProtocolVersionId, StorageLog, H256, @@ -163,10 +164,7 @@ mod tests { use zksync_utils::u256_to_h256; use super::*; - use crate::{ - genesis::{insert_genesis_batch, GenesisParams}, - utils::testonly::{create_l2_transaction, MockBatchFeeParamsProvider}, - }; + use crate::utils::testonly::{create_l2_transaction, MockBatchFeeParamsProvider}; const TEST_MEMPOOL_CONFIG: MempoolConfig = MempoolConfig { sync_interval_ms: 10, diff --git a/core/lib/zksync_core/src/sync_layer/batch_status_updater/tests.rs b/core/lib/zksync_core/src/sync_layer/batch_status_updater/tests.rs index 8d9a06b31e50..01dd77b2a59c 100644 --- a/core/lib/zksync_core/src/sync_layer/batch_status_updater/tests.rs +++ b/core/lib/zksync_core/src/sync_layer/batch_status_updater/tests.rs @@ -6,11 +6,11 @@ use chrono::TimeZone; use test_casing::{test_casing, Product}; use tokio::sync::{watch, Mutex}; use zksync_contracts::BaseSystemContractsHashes; +use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use zksync_types::{Address, ProtocolVersionId}; use super::*; use crate::{ - genesis::{insert_genesis_batch, GenesisParams}, sync_layer::metrics::L1BatchStage, utils::testonly::{create_l1_batch, create_l2_block, prepare_recovery_snapshot}, }; diff --git a/core/lib/zksync_core/src/sync_layer/genesis.rs b/core/lib/zksync_core/src/sync_layer/genesis.rs index fb3ebdd074cc..c1b45f8ade93 100644 --- a/core/lib/zksync_core/src/sync_layer/genesis.rs +++ b/core/lib/zksync_core/src/sync_layer/genesis.rs @@ -1,12 +1,12 @@ use anyhow::Context as _; use zksync_contracts::{BaseSystemContracts, BaseSystemContractsHashes, SystemContractCode}; use zksync_dal::{Connection, Core, CoreDal}; +use zksync_node_genesis::{ensure_genesis_state, GenesisParams}; use zksync_types::{ block::DeployedContract, system_contracts::get_system_smart_contracts, AccountTreeId, L2ChainId, }; use super::client::MainNodeClient; -use crate::genesis::{ensure_genesis_state, GenesisParams}; pub async fn perform_genesis_if_needed( storage: &mut Connection<'_, Core>, diff --git a/core/lib/zksync_core/src/sync_layer/tests.rs b/core/lib/zksync_core/src/sync_layer/tests.rs index cb0813700431..4145231fde5e 100644 --- a/core/lib/zksync_core/src/sync_layer/tests.rs +++ b/core/lib/zksync_core/src/sync_layer/tests.rs @@ -6,6 +6,7 @@ use test_casing::test_casing; use tokio::{sync::watch, task::JoinHandle}; use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; +use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use zksync_types::{ api, block::L2BlockHasher, @@ -17,7 +18,6 @@ use zksync_types::{ use super::{fetcher::FetchedTransaction, sync_action::SyncAction, *}; use crate::{ consensus::testonly::MockMainNodeClient, - genesis::{insert_genesis_batch, GenesisParams}, state_keeper::{ io::{L1BatchParams, L2BlockParams}, seal_criteria::NoopSealer, diff --git a/core/lib/zksync_core/src/utils/mod.rs b/core/lib/zksync_core/src/utils/mod.rs index c4c8e986599b..999ce4945ffa 100644 --- a/core/lib/zksync_core/src/utils/mod.rs +++ b/core/lib/zksync_core/src/utils/mod.rs @@ -217,10 +217,10 @@ mod tests { use std::{mem, sync::Mutex}; use zksync_eth_client::clients::MockEthereum; + use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use zksync_types::U256; use super::*; - use crate::genesis::{insert_genesis_batch, GenesisParams}; #[tokio::test] async fn test_binary_search() { diff --git a/core/lib/zksync_core/src/utils/testonly.rs b/core/lib/zksync_core/src/utils/testonly.rs index 37a20c5e247f..27e231b486db 100644 --- a/core/lib/zksync_core/src/utils/testonly.rs +++ b/core/lib/zksync_core/src/utils/testonly.rs @@ -5,6 +5,7 @@ use multivm::utils::get_max_gas_per_pubdata_byte; use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::{Connection, Core, CoreDal}; use zksync_merkle_tree::{domain::ZkSyncTree, TreeInstruction}; +use zksync_node_genesis::GenesisParams; use zksync_system_constants::{get_intrinsic_constants, ZKPORTER_IS_AVAILABLE}; use zksync_types::{ block::{L1BatchHeader, L2BlockHeader}, @@ -22,7 +23,7 @@ use zksync_types::{ ProtocolVersionId, StorageLog, H256, U256, }; -use crate::{fee_model::BatchFeeModelInputProvider, genesis::GenesisParams}; +use crate::fee_model::BatchFeeModelInputProvider; /// Creates an L2 block header with the specified number and deterministic contents. pub(crate) fn create_l2_block(number: u32) -> L2BlockHeader { diff --git a/core/lib/zksync_core/src/vm_runner/tests/mod.rs b/core/lib/zksync_core/src/vm_runner/tests/mod.rs index bc56ead5d9da..50ac0bb7624d 100644 --- a/core/lib/zksync_core/src/vm_runner/tests/mod.rs +++ b/core/lib/zksync_core/src/vm_runner/tests/mod.rs @@ -11,6 +11,7 @@ use tokio::{ }; use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; +use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; use zksync_state::{PgOrRocksdbStorage, PostgresStorage, ReadStorage, ReadStorageFactory}; use zksync_types::{ block::{BlockGasCount, L1BatchHeader}, @@ -20,12 +21,9 @@ use zksync_types::{ }; use super::{BatchExecuteData, VmRunnerStorage, VmRunnerStorageLoader}; -use crate::{ - genesis::{insert_genesis_batch, GenesisParams}, - utils::testonly::{ - create_l1_batch_metadata, create_l2_block, create_l2_transaction, execute_l2_transaction, - l1_batch_metadata_to_commitment_artifacts, - }, +use crate::utils::testonly::{ + create_l1_batch_metadata, create_l2_block, create_l2_transaction, execute_l2_transaction, + l1_batch_metadata_to_commitment_artifacts, }; #[derive(Debug, Default)] diff --git a/core/node/genesis/Cargo.toml b/core/node/genesis/Cargo.toml new file mode 100644 index 000000000000..1f274cab877c --- /dev/null +++ b/core/node/genesis/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "zksync_node_genesis" +version.workspace = true +edition.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true + +[dependencies] +multivm.workspace = true +vise.workspace = true +zksync_types.workspace = true +zksync_dal.workspace = true +zksync_config.workspace = true +zksync_contracts.workspace = true +zksync_eth_client.workspace = true +zksync_merkle_tree.workspace = true +zksync_system_constants.workspace = true +zksync_utils.workspace = true + +tokio = { workspace = true, features = ["time"] } +anyhow.workspace = true +itertools.workspace = true +thiserror.workspace = true +tracing.workspace = true diff --git a/core/node/genesis/README.md b/core/node/genesis/README.md new file mode 100644 index 000000000000..2c27712a8983 --- /dev/null +++ b/core/node/genesis/README.md @@ -0,0 +1,3 @@ +# `zksync_node_genesis` + +Utilities to create Genesis block in ZK Stack chains. diff --git a/core/lib/zksync_core/src/genesis.rs b/core/node/genesis/src/lib.rs similarity index 57% rename from core/lib/zksync_core/src/genesis.rs rename to core/node/genesis/src/lib.rs index 860a1dcc041b..8037880cd185 100644 --- a/core/lib/zksync_core/src/genesis.rs +++ b/core/node/genesis/src/lib.rs @@ -5,38 +5,35 @@ use std::fmt::Formatter; use anyhow::Context as _; -use itertools::Itertools; -use multivm::{ - circuit_sequencer_api_latest::sort_storage_access::sort_storage_access_queries, - utils::get_max_gas_per_pubdata_byte, - zk_evm_latest::aux_structures::{LogQuery as MultiVmLogQuery, Timestamp as MultiVMTimestamp}, -}; -use zksync_config::{configs::database::MerkleTreeMode, GenesisConfig, PostgresConfig}; +use multivm::utils::get_max_gas_per_pubdata_byte; +use zksync_config::{GenesisConfig, PostgresConfig}; use zksync_contracts::{BaseSystemContracts, BaseSystemContractsHashes, SET_CHAIN_ID_EVENT}; use zksync_dal::{Connection, ConnectionPool, Core, CoreDal, DalError}; -use zksync_eth_client::EthInterface; -use zksync_merkle_tree::domain::ZkSyncTree; -use zksync_system_constants::{DEFAULT_ERA_CHAIN_ID, PRIORITY_EXPIRATION}; +use zksync_eth_client::{clients::QueryClient, EthInterface}; +use zksync_merkle_tree::{domain::ZkSyncTree, TreeInstruction}; +use zksync_system_constants::PRIORITY_EXPIRATION; use zksync_types::{ - block::{ - BlockGasCount, DeployedContract, L1BatchHeader, L1BatchTreeData, L2BlockHasher, - L2BlockHeader, - }, + block::{BlockGasCount, DeployedContract, L1BatchHeader, L2BlockHasher, L2BlockHeader}, commitment::{CommitmentInput, L1BatchCommitment}, fee_model::BatchFeeInput, - get_code_key, get_known_code_key, get_system_context_init_logs, protocol_upgrade::decode_set_chain_id_event, protocol_version::{L1VerifierConfig, VerifierParams}, system_contracts::get_system_smart_contracts, - tokens::{TokenInfo, TokenMetadata, ETHEREUM_ADDRESS}, web3::types::{BlockNumber, FilterBuilder}, - zk_evm_types::{LogQuery, Timestamp}, AccountTreeId, Address, L1BatchNumber, L2BlockNumber, L2ChainId, ProtocolVersion, - ProtocolVersionId, StorageKey, StorageLog, StorageLogKind, H256, + ProtocolVersionId, StorageKey, H256, }; -use zksync_utils::{be_words_to_bytes, bytecode::hash_bytecode, h256_to_u256, u256_to_h256}; +use zksync_utils::{bytecode::hash_bytecode, u256_to_h256}; -use crate::metadata_calculator::L1BatchWithLogs; +use crate::utils::{ + add_eth_token, get_deduped_log_queries, get_storage_logs, + insert_base_system_contracts_to_factory_deps, insert_system_contracts, + save_genesis_l1_batch_metadata, +}; + +#[cfg(test)] +mod tests; +mod utils; #[derive(Debug, Clone)] pub struct BaseContractsHashError { @@ -151,7 +148,13 @@ impl GenesisParams { } } -pub(crate) fn mock_genesis_config() -> GenesisConfig { +pub struct GenesisBatchParams { + pub root_hash: H256, + pub commitment: H256, + pub rollup_last_leaf_index: u64, +} + +pub fn mock_genesis_config() -> GenesisConfig { use zksync_types::L1ChainId; let base_system_contracts_hashes = BaseSystemContracts::load_from_disk().hashes(); @@ -179,12 +182,6 @@ pub(crate) fn mock_genesis_config() -> GenesisConfig { } } -pub struct GenesisBatchParams { - pub root_hash: H256, - pub commitment: H256, - pub rollup_last_leaf_index: u64, -} - // Insert genesis batch into the database pub async fn insert_genesis_batch( storage: &mut Connection<'_, Core>, @@ -210,15 +207,25 @@ pub async fn insert_genesis_batch( .await?; tracing::info!("chain_schema_genesis is complete"); - let storage_logs = L1BatchWithLogs::new( - &mut transaction, - L1BatchNumber(0), - MerkleTreeMode::Lightweight, - ) - .await - .context("failed fetching tree input for genesis L1 batch")? - .context("genesis L1 batch disappeared from Postgres")?; - let storage_logs = storage_logs.storage_logs; + let deduped_log_queries = + get_deduped_log_queries(&get_storage_logs(genesis_params.system_contracts())); + + let (deduplicated_writes, _): (Vec<_>, Vec<_>) = deduped_log_queries + .into_iter() + .partition(|log_query| log_query.rw_flag); + + let storage_logs: Vec> = deduplicated_writes + .iter() + .enumerate() + .map(|(index, log)| { + TreeInstruction::write( + StorageKey::new(AccountTreeId::new(log.address), u256_to_h256(log.key)), + (index + 1) as u64, + u256_to_h256(log.written_value), + ) + }) + .collect(); + let metadata = ZkSyncTree::process_genesis_batch(&storage_logs); let genesis_root_hash = metadata.root_hash; let rollup_last_leaf_index = metadata.leaf_count + 1; @@ -314,155 +321,8 @@ pub async fn ensure_genesis_state( Ok(root_hash) } -// Default account and bootloader are not a regular system contracts -// they have never been actually deployed anywhere, -// They are the initial code that is fed into the VM upon its start. -// Both are rather parameters of a block and not system contracts. -// The code of the bootloader should not be deployed anywhere anywhere in the kernel space (i.e. addresses below 2^16) -// because in this case we will have to worry about protecting it. -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(); - - Ok(storage - .factory_deps_dal() - .insert_factory_deps(L2BlockNumber(0), &factory_deps) - .await?) -} - -async fn insert_system_contracts( - storage: &mut Connection<'_, Core>, - contracts: &[DeployedContract], -) -> Result<(), GenesisError> { - let system_context_init_logs = ( - H256::default(), - // During the genesis all chains have the same id. - // TODO(EVM-579): make sure that the logic is compatible with Era. - get_system_context_init_logs(L2ChainId::from(DEFAULT_ERA_CHAIN_ID)), - ); - - let known_code_storage_logs: Vec<_> = contracts - .iter() - .map(|contract| { - let hash = hash_bytecode(&contract.bytecode); - let known_code_key = get_known_code_key(&hash); - let marked_known_value = H256::from_low_u64_be(1u64); - ( - H256::default(), - vec![StorageLog::new_write_log( - known_code_key, - marked_known_value, - )], - ) - }) - .dedup_by(|a, b| a.1 == b.1) - .collect(); - - let storage_logs: Vec<_> = contracts - .iter() - .map(|contract| { - let hash = hash_bytecode(&contract.bytecode); - let code_key = get_code_key(contract.account_id.address()); - ( - H256::default(), - vec![StorageLog::new_write_log(code_key, hash)], - ) - }) - .chain(Some(system_context_init_logs)) - .chain(known_code_storage_logs) - .collect(); - - let mut transaction = storage.start_transaction().await?; - transaction - .storage_logs_dal() - .insert_storage_logs(L2BlockNumber(0), &storage_logs) - .await?; - - // we don't produce proof for the genesis block, - // but we still need to populate the table - // to have the correct initial state of the merkle tree - let log_queries: Vec = storage_logs - .iter() - .enumerate() - .flat_map(|(tx_index, (_, storage_logs))| { - storage_logs - .iter() - .enumerate() - .map(move |(log_index, storage_log)| { - MultiVmLogQuery { - // Monotonically increasing Timestamp. Normally it's generated by the VM, but we don't have a VM in the genesis block. - timestamp: MultiVMTimestamp(((tx_index << 16) + log_index) as u32), - tx_number_in_block: tx_index as u16, - aux_byte: 0, - shard_id: 0, - address: *storage_log.key.address(), - key: h256_to_u256(*storage_log.key.key()), - read_value: h256_to_u256(H256::zero()), - written_value: h256_to_u256(storage_log.value), - rw_flag: storage_log.kind == StorageLogKind::Write, - rollback: false, - is_service: false, - } - }) - .collect::>() - }) - .collect(); - - let deduped_log_queries: Vec = sort_storage_access_queries(&log_queries) - .1 - .into_iter() - .map(|log_query| LogQuery { - timestamp: Timestamp(log_query.timestamp.0), - tx_number_in_block: log_query.tx_number_in_block, - aux_byte: log_query.aux_byte, - shard_id: log_query.shard_id, - address: log_query.address, - key: log_query.key, - read_value: log_query.read_value, - written_value: log_query.written_value, - rw_flag: log_query.rw_flag, - rollback: log_query.rollback, - is_service: log_query.is_service, - }) - .collect(); - - let (deduplicated_writes, protective_reads): (Vec<_>, Vec<_>) = deduped_log_queries - .into_iter() - .partition(|log_query| log_query.rw_flag); - transaction - .storage_logs_dedup_dal() - .insert_protective_reads(L1BatchNumber(0), &protective_reads) - .await?; - - let written_storage_keys: Vec<_> = deduplicated_writes - .iter() - .map(|log| StorageKey::new(AccountTreeId::new(log.address), u256_to_h256(log.key))) - .collect(); - transaction - .storage_logs_dedup_dal() - .insert_initial_writes(L1BatchNumber(0), &written_storage_keys) - .await?; - - let factory_deps = contracts - .iter() - .map(|c| (hash_bytecode(&c.bytecode), c.bytecode.clone())) - .collect(); - transaction - .factory_deps_dal() - .insert_factory_deps(L2BlockNumber(0), &factory_deps) - .await?; - - transaction.commit().await?; - Ok(()) -} - #[allow(clippy::too_many_arguments)] -pub(crate) async fn create_genesis_l1_batch( +pub async fn create_genesis_l1_batch( storage: &mut Connection<'_, Core>, protocol_version: ProtocolVersionId, base_system_contracts: &BaseSystemContracts, @@ -526,59 +386,16 @@ pub(crate) async fn create_genesis_l1_batch( .mark_l2_blocks_as_executed_in_l1_batch(L1BatchNumber(0)) .await?; - insert_base_system_contracts_to_factory_deps(&mut transaction, base_system_contracts).await?; - insert_system_contracts(&mut transaction, system_contracts).await?; - add_eth_token(&mut transaction).await?; - - transaction.commit().await?; - Ok(()) -} - -async fn add_eth_token(transaction: &mut Connection<'_, Core>) -> anyhow::Result<()> { - assert!(transaction.in_transaction()); // sanity check - let eth_token = TokenInfo { - l1_address: ETHEREUM_ADDRESS, - l2_address: ETHEREUM_ADDRESS, - metadata: TokenMetadata { - name: "Ether".to_string(), - symbol: "ETH".to_string(), - decimals: 18, - }, - }; - - transaction.tokens_dal().add_tokens(&[eth_token]).await?; - transaction - .tokens_dal() - .mark_token_as_well_known(ETHEREUM_ADDRESS) - .await?; - Ok(()) -} - -async fn save_genesis_l1_batch_metadata( - storage: &mut Connection<'_, Core>, - commitment: L1BatchCommitment, - genesis_root_hash: H256, - rollup_last_leaf_index: u64, -) -> Result<(), GenesisError> { - let mut transaction = storage.start_transaction().await?; + let storage_logs = get_storage_logs(system_contracts); - let tree_data = L1BatchTreeData { - hash: genesis_root_hash, - rollup_last_leaf_index, - }; - transaction - .blocks_dal() - .save_l1_batch_tree_data(L1BatchNumber(0), &tree_data) - .await?; - - let mut commitment_artifacts = commitment.artifacts(); - // `l2_l1_merkle_root` for genesis batch is set to 0 on L1 contract, same must be here. - commitment_artifacts.l2_l1_merkle_root = H256::zero(); + let factory_deps = system_contracts + .iter() + .map(|c| (hash_bytecode(&c.bytecode), c.bytecode.clone())) + .collect(); - transaction - .blocks_dal() - .save_l1_batch_commitment_artifacts(L1BatchNumber(0), &commitment_artifacts) - .await?; + insert_base_system_contracts_to_factory_deps(&mut transaction, base_system_contracts).await?; + insert_system_contracts(&mut transaction, factory_deps, &storage_logs).await?; + add_eth_token(&mut transaction).await?; transaction.commit().await?; Ok(()) @@ -587,7 +404,7 @@ async fn save_genesis_l1_batch_metadata( // Save chain id transaction into the database // We keep returning anyhow and will refactor it later pub async fn save_set_chain_id_tx( - query_client: &dyn EthInterface, + query_client: &QueryClient, diamond_proxy_address: Address, state_transition_manager_address: Address, postgres_config: &PostgresConfig, @@ -626,70 +443,3 @@ pub async fn save_set_chain_id_tx( .await?; Ok(()) } - -#[cfg(test)] -mod tests { - use zksync_config::GenesisConfig; - use zksync_dal::{ConnectionPool, Core, CoreDal}; - - use super::*; - - #[tokio::test] - async fn running_genesis() { - let pool = ConnectionPool::::test_pool().await; - let mut conn = pool.connection().await.unwrap(); - conn.blocks_dal().delete_genesis().await.unwrap(); - - let params = GenesisParams::mock(); - - insert_genesis_batch(&mut conn, ¶ms).await.unwrap(); - - assert!(!conn.blocks_dal().is_genesis_needed().await.unwrap()); - let metadata = conn - .blocks_dal() - .get_l1_batch_metadata(L1BatchNumber(0)) - .await - .unwrap(); - let root_hash = metadata.unwrap().metadata.root_hash; - assert_ne!(root_hash, H256::zero()); - - // Check that `genesis is not needed` - assert!(!conn.blocks_dal().is_genesis_needed().await.unwrap()); - } - - #[tokio::test] - async fn running_genesis_with_big_chain_id() { - let pool = ConnectionPool::::test_pool().await; - let mut conn = pool.connection().await.unwrap(); - conn.blocks_dal().delete_genesis().await.unwrap(); - - let params = GenesisParams::load_genesis_params(GenesisConfig { - l2_chain_id: L2ChainId::max(), - ..mock_genesis_config() - }) - .unwrap(); - insert_genesis_batch(&mut conn, ¶ms).await.unwrap(); - - assert!(!conn.blocks_dal().is_genesis_needed().await.unwrap()); - let metadata = conn - .blocks_dal() - .get_l1_batch_metadata(L1BatchNumber(0)) - .await; - let root_hash = metadata.unwrap().unwrap().metadata.root_hash; - assert_ne!(root_hash, H256::zero()); - } - - #[tokio::test] - async fn running_genesis_with_non_latest_protocol_version() { - let pool = ConnectionPool::::test_pool().await; - let mut conn = pool.connection().await.unwrap(); - let params = GenesisParams::load_genesis_params(GenesisConfig { - protocol_version: Some(ProtocolVersionId::Version10 as u16), - ..mock_genesis_config() - }) - .unwrap(); - - insert_genesis_batch(&mut conn, ¶ms).await.unwrap(); - assert!(!conn.blocks_dal().is_genesis_needed().await.unwrap()); - } -} diff --git a/core/node/genesis/src/tests.rs b/core/node/genesis/src/tests.rs new file mode 100644 index 000000000000..51300bf2a0a2 --- /dev/null +++ b/core/node/genesis/src/tests.rs @@ -0,0 +1,63 @@ +use zksync_config::GenesisConfig; +use zksync_dal::{ConnectionPool, Core, CoreDal}; + +use super::*; + +#[tokio::test] +async fn running_genesis() { + let pool = ConnectionPool::::test_pool().await; + let mut conn = pool.connection().await.unwrap(); + conn.blocks_dal().delete_genesis().await.unwrap(); + + let params = GenesisParams::mock(); + + insert_genesis_batch(&mut conn, ¶ms).await.unwrap(); + + assert!(!conn.blocks_dal().is_genesis_needed().await.unwrap()); + let metadata = conn + .blocks_dal() + .get_l1_batch_metadata(L1BatchNumber(0)) + .await + .unwrap(); + let root_hash = metadata.unwrap().metadata.root_hash; + assert_ne!(root_hash, H256::zero()); + + // Check that `genesis is not needed` + assert!(!conn.blocks_dal().is_genesis_needed().await.unwrap()); +} + +#[tokio::test] +async fn running_genesis_with_big_chain_id() { + let pool = ConnectionPool::::test_pool().await; + let mut conn = pool.connection().await.unwrap(); + conn.blocks_dal().delete_genesis().await.unwrap(); + + let params = GenesisParams::load_genesis_params(GenesisConfig { + l2_chain_id: L2ChainId::max(), + ..mock_genesis_config() + }) + .unwrap(); + insert_genesis_batch(&mut conn, ¶ms).await.unwrap(); + + assert!(!conn.blocks_dal().is_genesis_needed().await.unwrap()); + let metadata = conn + .blocks_dal() + .get_l1_batch_metadata(L1BatchNumber(0)) + .await; + let root_hash = metadata.unwrap().unwrap().metadata.root_hash; + assert_ne!(root_hash, H256::zero()); +} + +#[tokio::test] +async fn running_genesis_with_non_latest_protocol_version() { + let pool = ConnectionPool::::test_pool().await; + let mut conn = pool.connection().await.unwrap(); + let params = GenesisParams::load_genesis_params(GenesisConfig { + protocol_version: Some(ProtocolVersionId::Version10 as u16), + ..mock_genesis_config() + }) + .unwrap(); + + insert_genesis_batch(&mut conn, ¶ms).await.unwrap(); + assert!(!conn.blocks_dal().is_genesis_needed().await.unwrap()); +} diff --git a/core/node/genesis/src/utils.rs b/core/node/genesis/src/utils.rs new file mode 100644 index 000000000000..cc5abd18cd58 --- /dev/null +++ b/core/node/genesis/src/utils.rs @@ -0,0 +1,228 @@ +use std::collections::HashMap; + +use itertools::Itertools; +use multivm::{ + circuit_sequencer_api_latest::sort_storage_access::sort_storage_access_queries, + zk_evm_latest::aux_structures::{LogQuery as MultiVmLogQuery, Timestamp as MultiVMTimestamp}, +}; +use zksync_contracts::BaseSystemContracts; +use zksync_dal::{Connection, Core, CoreDal}; +use zksync_system_constants::{DEFAULT_ERA_CHAIN_ID, ETHEREUM_ADDRESS}; +use zksync_types::{ + block::{DeployedContract, L1BatchTreeData}, + commitment::L1BatchCommitment, + get_code_key, get_known_code_key, get_system_context_init_logs, + tokens::{TokenInfo, TokenMetadata}, + zk_evm_types::{LogQuery, Timestamp}, + AccountTreeId, L1BatchNumber, L2BlockNumber, L2ChainId, StorageKey, StorageLog, StorageLogKind, + H256, +}; +use zksync_utils::{be_words_to_bytes, bytecode::hash_bytecode, h256_to_u256, u256_to_h256}; + +use crate::GenesisError; + +pub(super) async fn add_eth_token(transaction: &mut Connection<'_, Core>) -> anyhow::Result<()> { + assert!(transaction.in_transaction()); // sanity check + let eth_token = TokenInfo { + l1_address: ETHEREUM_ADDRESS, + l2_address: ETHEREUM_ADDRESS, + metadata: TokenMetadata { + name: "Ether".to_string(), + symbol: "ETH".to_string(), + decimals: 18, + }, + }; + + transaction.tokens_dal().add_tokens(&[eth_token]).await?; + transaction + .tokens_dal() + .mark_token_as_well_known(ETHEREUM_ADDRESS) + .await?; + Ok(()) +} + +pub(super) fn get_storage_logs( + system_contracts: &[DeployedContract], +) -> Vec<(H256, Vec)> { + let system_context_init_logs = ( + H256::default(), + // During the genesis all chains have the same id. + // TODO(EVM-579): make sure that the logic is compatible with Era. + get_system_context_init_logs(L2ChainId::from(DEFAULT_ERA_CHAIN_ID)), + ); + + let known_code_storage_logs: Vec<_> = system_contracts + .iter() + .map(|contract| { + let hash = hash_bytecode(&contract.bytecode); + let known_code_key = get_known_code_key(&hash); + let marked_known_value = H256::from_low_u64_be(1u64); + ( + H256::default(), + vec![StorageLog::new_write_log( + known_code_key, + marked_known_value, + )], + ) + }) + .dedup_by(|a, b| a.1 == b.1) + .collect(); + + let storage_logs: Vec<_> = system_contracts + .iter() + .map(|contract| { + let hash = hash_bytecode(&contract.bytecode); + let code_key = get_code_key(contract.account_id.address()); + ( + H256::default(), + vec![StorageLog::new_write_log(code_key, hash)], + ) + }) + .chain(Some(system_context_init_logs)) + .chain(known_code_storage_logs) + .collect(); + + storage_logs +} + +pub(super) fn get_deduped_log_queries(storage_logs: &[(H256, Vec)]) -> Vec { + // we don't produce proof for the genesis block, + // but we still need to populate the table + // to have the correct initial state of the merkle tree + let log_queries: Vec = storage_logs + .iter() + .enumerate() + .flat_map(|(tx_index, (_, storage_logs))| { + storage_logs + .iter() + .enumerate() + .map(move |(log_index, storage_log)| { + MultiVmLogQuery { + // Monotonically increasing Timestamp. Normally it's generated by the VM, but we don't have a VM in the genesis block. + timestamp: MultiVMTimestamp(((tx_index << 16) + log_index) as u32), + tx_number_in_block: tx_index as u16, + aux_byte: 0, + shard_id: 0, + address: *storage_log.key.address(), + key: h256_to_u256(*storage_log.key.key()), + read_value: h256_to_u256(H256::zero()), + written_value: h256_to_u256(storage_log.value), + rw_flag: storage_log.kind == StorageLogKind::Write, + rollback: false, + is_service: false, + } + }) + .collect::>() + }) + .collect(); + + let deduped_log_queries: Vec = sort_storage_access_queries(&log_queries) + .1 + .into_iter() + .map(|log_query| LogQuery { + timestamp: Timestamp(log_query.timestamp.0), + tx_number_in_block: log_query.tx_number_in_block, + aux_byte: log_query.aux_byte, + shard_id: log_query.shard_id, + address: log_query.address, + key: log_query.key, + read_value: log_query.read_value, + written_value: log_query.written_value, + rw_flag: log_query.rw_flag, + rollback: log_query.rollback, + is_service: log_query.is_service, + }) + .collect(); + + deduped_log_queries +} + +// Default account and bootloader are not a regular system contracts +// they have never been actually deployed anywhere, +// They are the initial code that is fed into the VM upon its start. +// Both are rather parameters of a block and not system contracts. +// The code of the bootloader should not be deployed anywhere anywhere in the kernel space (i.e. addresses below 2^16) +// because in this case we will have to worry about protecting it. +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(); + + Ok(storage + .factory_deps_dal() + .insert_factory_deps(L2BlockNumber(0), &factory_deps) + .await?) +} + +pub(super) async fn save_genesis_l1_batch_metadata( + storage: &mut Connection<'_, Core>, + commitment: L1BatchCommitment, + genesis_root_hash: H256, + rollup_last_leaf_index: u64, +) -> Result<(), GenesisError> { + let mut transaction = storage.start_transaction().await?; + + let tree_data = L1BatchTreeData { + hash: genesis_root_hash, + rollup_last_leaf_index, + }; + transaction + .blocks_dal() + .save_l1_batch_tree_data(L1BatchNumber(0), &tree_data) + .await?; + + let mut commitment_artifacts = commitment.artifacts(); + // `l2_l1_merkle_root` for genesis batch is set to 0 on L1 contract, same must be here. + commitment_artifacts.l2_l1_merkle_root = H256::zero(); + + transaction + .blocks_dal() + .save_l1_batch_commitment_artifacts(L1BatchNumber(0), &commitment_artifacts) + .await?; + + transaction.commit().await?; + Ok(()) +} + +pub(super) async fn insert_system_contracts( + storage: &mut Connection<'_, Core>, + factory_deps: HashMap>, + storage_logs: &[(H256, Vec)], +) -> Result<(), GenesisError> { + let (deduplicated_writes, protective_reads): (Vec<_>, Vec<_>) = + get_deduped_log_queries(storage_logs) + .into_iter() + .partition(|log_query| log_query.rw_flag); + + let mut transaction = storage.start_transaction().await?; + transaction + .storage_logs_dal() + .insert_storage_logs(L2BlockNumber(0), storage_logs) + .await?; + + transaction + .storage_logs_dedup_dal() + .insert_protective_reads(L1BatchNumber(0), &protective_reads) + .await?; + + let written_storage_keys: Vec<_> = deduplicated_writes + .iter() + .map(|log| StorageKey::new(AccountTreeId::new(log.address), u256_to_h256(log.key))) + .collect(); + transaction + .storage_logs_dedup_dal() + .insert_initial_writes(L1BatchNumber(0), &written_storage_keys) + .await?; + + transaction + .factory_deps_dal() + .insert_factory_deps(L2BlockNumber(0), &factory_deps) + .await?; + + transaction.commit().await?; + Ok(()) +}