From 650361ae456f67fd7e10d1c4ab92647d7f397fc1 Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Fri, 18 Oct 2024 23:09:37 +0200 Subject: [PATCH 1/5] chore: Update EVM emulator-related code (#3127) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Updates after latest changes. ## Why ❔ ## Checklist - [ ] 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. - [ ] Code has been formatted via `zkstack dev fmt` and `zkstack dev lint`. --- .../system-constants-generator/src/utils.rs | 8 ++++---- core/lib/contracts/src/lib.rs | 19 ++++++++++--------- core/lib/types/src/api/mod.rs | 2 +- core/lib/types/src/system_contracts.rs | 2 +- core/node/node_sync/src/genesis.rs | 2 +- core/node/vm_runner/src/impls/bwip.rs | 2 +- 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/core/bin/system-constants-generator/src/utils.rs b/core/bin/system-constants-generator/src/utils.rs index ce7182a3aa4a..800da68ee50d 100644 --- a/core/bin/system-constants-generator/src/utils.rs +++ b/core/bin/system-constants-generator/src/utils.rs @@ -3,7 +3,7 @@ use std::{cell::RefCell, rc::Rc}; use once_cell::sync::Lazy; use zksync_contracts::{ load_sys_contract, read_bootloader_code, read_bytecode_from_path, read_sys_contract_bytecode, - read_zbin_bytecode, BaseSystemContracts, ContractLanguage, SystemContractCode, + read_yul_bytecode, BaseSystemContracts, ContractLanguage, SystemContractCode, }; use zksync_multivm::{ interface::{ @@ -176,10 +176,10 @@ fn read_bootloader_test_code(test: &str) -> Vec { )){ contract } else { - read_zbin_bytecode(format!( - "contracts/system-contracts/bootloader/tests/artifacts/{}.yul.zbin", + read_yul_bytecode( + "contracts/system-contracts/bootloader/tests/artifacts", test - )) + ) } } diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index a9e7324d5af6..0ee773abcd4a 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -295,10 +295,11 @@ impl SystemContractsRepo { ))) { contract } else { - read_zbin_bytecode_from_path(self.root.join(format!( - "contracts-preprocessed/{0}artifacts/{1}.yul.zbin", - directory, name - ))) + read_yul_bytecode_by_path( + self.root + .join(format!("contracts-preprocessed/{directory}artifacts")), + name, + ) } } } @@ -313,10 +314,10 @@ pub fn read_bootloader_code(bootloader_type: &str) -> Vec { { return contract; }; - read_zbin_bytecode(format!( - "contracts/system-contracts/bootloader/build/artifacts/{}.yul.zbin", - bootloader_type - )) + read_yul_bytecode( + "contracts/system-contracts/bootloader/build/artifacts", + bootloader_type, + ) } fn read_proved_batch_bootloader_bytecode() -> Vec { @@ -438,7 +439,7 @@ impl BaseSystemContracts { /// Loads the latest EVM emulator for these base system contracts. Logically, it only makes sense to do for the latest protocol version. pub fn with_latest_evm_emulator(mut self) -> Self { - let bytecode = read_sys_contract_bytecode("", "EvmInterpreter", ContractLanguage::Yul); + let bytecode = read_sys_contract_bytecode("", "EvmEmulator", ContractLanguage::Yul); let hash = hash_bytecode(&bytecode); self.evm_emulator = Some(SystemContractCode { code: bytes_to_be_words(bytecode), diff --git a/core/lib/types/src/api/mod.rs b/core/lib/types/src/api/mod.rs index 1c7672264cb4..b8f8a2f05841 100644 --- a/core/lib/types/src/api/mod.rs +++ b/core/lib/types/src/api/mod.rs @@ -644,7 +644,7 @@ pub struct ProtocolVersion { /// Verifier configuration #[deprecated] pub verification_keys_hashes: Option, - /// Hashes of base system contracts (bootloader, default account and evm simulator) + /// Hashes of base system contracts (bootloader, default account and evm emulator) #[deprecated] pub base_system_contracts: Option, /// Bootloader code hash diff --git a/core/lib/types/src/system_contracts.rs b/core/lib/types/src/system_contracts.rs index 4329680991c8..4d1ff9b554ea 100644 --- a/core/lib/types/src/system_contracts.rs +++ b/core/lib/types/src/system_contracts.rs @@ -151,7 +151,7 @@ static SYSTEM_CONTRACT_LIST: [(&str, &str, Address, ContractLanguage); 26] = [ "", "EvmGasManager", EVM_GAS_MANAGER_ADDRESS, - ContractLanguage::Sol, + ContractLanguage::Yul, ), // 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. diff --git a/core/node/node_sync/src/genesis.rs b/core/node/node_sync/src/genesis.rs index 0ff8d0d448c0..c5d4869175df 100644 --- a/core/node/node_sync/src/genesis.rs +++ b/core/node/node_sync/src/genesis.rs @@ -109,7 +109,7 @@ async fn fetch_base_system_contracts( let bytes = client .fetch_system_contract_by_hash(hash) .await? - .context("EVM Simulator bytecode is missing on main node")?; + .context("EVM emulator bytecode is missing on main node")?; Some(SystemContractCode { code: zksync_utils::bytes_to_be_words(bytes), hash, diff --git a/core/node/vm_runner/src/impls/bwip.rs b/core/node/vm_runner/src/impls/bwip.rs index dc94752d9886..a2cf126f5499 100644 --- a/core/node/vm_runner/src/impls/bwip.rs +++ b/core/node/vm_runner/src/impls/bwip.rs @@ -248,7 +248,7 @@ async fn get_updates_manager_witness_input_data( .factory_deps_dal() .get_sealed_factory_dep(evm_emulator) .await? - .ok_or_else(|| anyhow!("EVM Simulator bytecode should exist"))?; + .ok_or_else(|| anyhow!("EVM emulator bytecode should exist"))?; let evm_emulator_bytecode = bytes_to_chunks(&evm_emulator_bytecode); used_bytecodes.insert(evm_emulator_code_hash, evm_emulator_bytecode); } From 30ceee8a48046e349ff0234ebb24d468a0e0876c Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Mon, 21 Oct 2024 11:21:05 +0200 Subject: [PATCH 2/5] feat(tee_verifier): speedup SQL query for new jobs (#3133) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Speedup SQL queries for new TEE prover jobs. ## Why ❔ Testing the L1Batch table also gives nothing, as missing data would be caught later anyway, when assembling the TEE prover input data. Catching it later also means, that we can apply different error handling strategies depending on the L1Batch age. ## Checklist - [ ] 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. - [ ] Code has been formatted via `zkstack dev fmt` and `zkstack dev lint`. Signed-off-by: Harald Hoyer --- ...7dc982c8cfb0e2277aff8dfaa9654255451ac.json | 26 ------------------- ...81b01395cfd2a3e95fb4593229bd878163320.json | 26 +++++++++++++++++++ core/lib/dal/src/tee_proof_generation_dal.rs | 6 ----- 3 files changed, 26 insertions(+), 32 deletions(-) delete mode 100644 core/lib/dal/.sqlx/query-4498e1c1ff179eacd03bd9ec24a7dc982c8cfb0e2277aff8dfaa9654255451ac.json create mode 100644 core/lib/dal/.sqlx/query-cee7a608bd77815e9582531383481b01395cfd2a3e95fb4593229bd878163320.json diff --git a/core/lib/dal/.sqlx/query-4498e1c1ff179eacd03bd9ec24a7dc982c8cfb0e2277aff8dfaa9654255451ac.json b/core/lib/dal/.sqlx/query-4498e1c1ff179eacd03bd9ec24a7dc982c8cfb0e2277aff8dfaa9654255451ac.json deleted file mode 100644 index 4d006b6d1d5d..000000000000 --- a/core/lib/dal/.sqlx/query-4498e1c1ff179eacd03bd9ec24a7dc982c8cfb0e2277aff8dfaa9654255451ac.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n WITH upsert AS (\n SELECT\n p.l1_batch_number\n FROM\n proof_generation_details p\n LEFT JOIN\n l1_batches l1\n ON p.l1_batch_number = l1.number\n LEFT JOIN\n tee_proof_generation_details tee\n ON\n p.l1_batch_number = tee.l1_batch_number\n AND tee.tee_type = $1\n WHERE\n (\n p.l1_batch_number >= $5\n AND p.vm_run_data_blob_url IS NOT NULL\n AND p.proof_gen_data_blob_url IS NOT NULL\n AND l1.hash IS NOT NULL\n AND l1.aux_data_hash IS NOT NULL\n AND l1.meta_parameters_hash IS NOT NULL\n )\n AND (\n tee.l1_batch_number IS NULL\n OR (\n tee.status = $3\n OR (\n tee.status = $2\n AND tee.prover_taken_at < NOW() - $4::INTERVAL\n )\n )\n )\n FETCH FIRST ROW ONLY\n )\n \n INSERT INTO\n tee_proof_generation_details (\n l1_batch_number, tee_type, status, created_at, updated_at, prover_taken_at\n )\n SELECT\n l1_batch_number,\n $1,\n $2,\n NOW(),\n NOW(),\n NOW()\n FROM\n upsert\n ON CONFLICT (l1_batch_number, tee_type) DO\n UPDATE\n SET\n status = $2,\n updated_at = NOW(),\n prover_taken_at = NOW()\n RETURNING\n l1_batch_number\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "l1_batch_number", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "Text", - "Text", - "Text", - "Interval", - "Int8" - ] - }, - "nullable": [ - false - ] - }, - "hash": "4498e1c1ff179eacd03bd9ec24a7dc982c8cfb0e2277aff8dfaa9654255451ac" -} diff --git a/core/lib/dal/.sqlx/query-cee7a608bd77815e9582531383481b01395cfd2a3e95fb4593229bd878163320.json b/core/lib/dal/.sqlx/query-cee7a608bd77815e9582531383481b01395cfd2a3e95fb4593229bd878163320.json new file mode 100644 index 000000000000..4b219bfee0a5 --- /dev/null +++ b/core/lib/dal/.sqlx/query-cee7a608bd77815e9582531383481b01395cfd2a3e95fb4593229bd878163320.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "\n WITH upsert AS (\n SELECT\n p.l1_batch_number\n FROM\n proof_generation_details p\n LEFT JOIN\n tee_proof_generation_details tee\n ON\n p.l1_batch_number = tee.l1_batch_number\n AND tee.tee_type = $1\n WHERE\n (\n p.l1_batch_number >= $5\n AND p.vm_run_data_blob_url IS NOT NULL\n AND p.proof_gen_data_blob_url IS NOT NULL\n )\n AND (\n tee.l1_batch_number IS NULL\n OR (\n tee.status = $3\n OR (\n tee.status = $2\n AND tee.prover_taken_at < NOW() - $4::INTERVAL\n )\n )\n )\n FETCH FIRST ROW ONLY\n )\n \n INSERT INTO\n tee_proof_generation_details (\n l1_batch_number, tee_type, status, created_at, updated_at, prover_taken_at\n )\n SELECT\n l1_batch_number,\n $1,\n $2,\n NOW(),\n NOW(),\n NOW()\n FROM\n upsert\n ON CONFLICT (l1_batch_number, tee_type) DO\n UPDATE\n SET\n status = $2,\n updated_at = NOW(),\n prover_taken_at = NOW()\n RETURNING\n l1_batch_number\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text", + "Text", + "Text", + "Interval", + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "cee7a608bd77815e9582531383481b01395cfd2a3e95fb4593229bd878163320" +} diff --git a/core/lib/dal/src/tee_proof_generation_dal.rs b/core/lib/dal/src/tee_proof_generation_dal.rs index d865212f190c..bde07f732802 100644 --- a/core/lib/dal/src/tee_proof_generation_dal.rs +++ b/core/lib/dal/src/tee_proof_generation_dal.rs @@ -43,9 +43,6 @@ impl TeeProofGenerationDal<'_, '_> { p.l1_batch_number FROM proof_generation_details p - LEFT JOIN - l1_batches l1 - ON p.l1_batch_number = l1.number LEFT JOIN tee_proof_generation_details tee ON @@ -56,9 +53,6 @@ impl TeeProofGenerationDal<'_, '_> { p.l1_batch_number >= $5 AND p.vm_run_data_blob_url IS NOT NULL AND p.proof_gen_data_blob_url IS NOT NULL - AND l1.hash IS NOT NULL - AND l1.aux_data_hash IS NOT NULL - AND l1.meta_parameters_hash IS NOT NULL ) AND ( tee.l1_batch_number IS NULL From e1c363f8f5e03c8d62bba1523f17b87d6a0e25ad Mon Sep 17 00:00:00 2001 From: perekopskiy <53865202+perekopskiy@users.noreply.github.com> Date: Mon, 21 Oct 2024 12:22:58 +0300 Subject: [PATCH 3/5] fix(state-keeper): save call trace for upgrade txs (#3132) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ save call trace for upgrade txs ## Why ❔ save call trace for upgrade txs ## Checklist - [ ] 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. - [ ] Code has been formatted via `zkstack dev fmt` and `zkstack dev lint`. --- core/node/state_keeper/src/keeper.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/node/state_keeper/src/keeper.rs b/core/node/state_keeper/src/keeper.rs index 22f24573070b..bd102daa3080 100644 --- a/core/node/state_keeper/src/keeper.rs +++ b/core/node/state_keeper/src/keeper.rs @@ -687,6 +687,7 @@ impl ZkSyncStateKeeper { tx_result, tx_metrics, compressed_bytecodes, + call_tracer_result, .. } = exec_result else { @@ -711,7 +712,7 @@ impl ZkSyncStateKeeper { tx_result.new_known_factory_deps.unwrap_or_default(), tx_l1_gas_this_tx, tx_execution_metrics, - vec![], + call_tracer_result, ); Ok(()) } From 78839e9713773aa8940d2aa0c87e165b25ec7ebe Mon Sep 17 00:00:00 2001 From: Devashish Dixit Date: Mon, 21 Oct 2024 17:23:57 +0800 Subject: [PATCH 4/5] docs: Remove link to old witness generator documentation which is now obsolete (#3093) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ ## Why ❔ ## Checklist - [ ] 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. - [ ] Code has been formatted via `zkstack dev fmt` and `zkstack dev lint`. --- prover/crates/bin/witness_generator/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/prover/crates/bin/witness_generator/README.md b/prover/crates/bin/witness_generator/README.md index dc476ca44fc3..6063c29b3348 100644 --- a/prover/crates/bin/witness_generator/README.md +++ b/prover/crates/bin/witness_generator/README.md @@ -1,9 +1,5 @@ # WitnessGenerator -Please read this -[doc](https://www.notion.so/matterlabs/Draft-FRI-Prover-Integration-Prover-Shadowing-c4b1373786eb43779a93118be4be5d99) -for rationale of this binary, alongside the existing one in zk-core. - The component is responsible for generating prover jobs and saving artifacts needed for the next round of proof aggregation. That is, every aggregation round needs two sets of input: From cfbcc11be0826e8c55fafa84ae01b2aead25d127 Mon Sep 17 00:00:00 2001 From: Alex Ostrovski Date: Mon, 21 Oct 2024 13:04:29 +0300 Subject: [PATCH 5/5] refactor: Refactor fee-related types (#3121) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ - Moves basic logic for fee types close to the type declaration (i.e., to `zksync_types`). - Unifies `PubdataSendingMode` and `PubdataDA`. - Removes dependency of `zksync_types` on `zksync_config`. ## Why ❔ This allows external apps depending on fee types (e.g., the test node) to not have behemoths like `zksync_dal` in their dependency graph. ## Checklist - [x] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [x] Tests for the changes have been added / updated. - [x] Documentation comments have been added / updated. - [x] Code has been formatted via `zkstack dev fmt` and `zkstack dev lint`. --- Cargo.lock | 4 - core/bin/zksync_server/src/node_builder.rs | 10 +- core/lib/basic_types/src/lib.rs | 1 + .../{types => basic_types}/src/pubdata_da.rs | 23 +- core/lib/config/src/configs/eth_sender.rs | 11 +- core/lib/config/src/testonly.rs | 15 +- core/lib/env_config/src/eth_sender.rs | 3 +- .../src/i_executor/methods/commit_batches.rs | 4 +- .../structures/commit_batch_info.rs | 18 +- core/lib/protobuf_config/src/eth.rs | 23 +- core/lib/types/Cargo.toml | 3 +- core/lib/types/src/fee_model.rs | 463 +++++++++++++++++- core/lib/types/src/lib.rs | 1 - core/node/api_server/src/testonly.rs | 7 +- core/node/api_server/src/web3/tests/mod.rs | 7 +- core/node/consistency_checker/src/lib.rs | 14 +- .../node/consistency_checker/src/tests/mod.rs | 4 +- .../eth_sender/src/aggregated_operations.rs | 8 +- core/node/eth_sender/src/aggregator.rs | 9 +- core/node/eth_sender/src/eth_tx_aggregator.rs | 13 +- core/node/eth_sender/src/publish_criterion.rs | 4 +- core/node/eth_sender/src/tester.rs | 8 +- core/node/fee_model/Cargo.toml | 2 - .../src/l1_gas_price/gas_adjuster/mod.rs | 7 +- .../src/l1_gas_price/gas_adjuster/tests.rs | 6 +- core/node/fee_model/src/lib.rs | 459 +---------------- .../implementations/layers/gas_adjuster.rs | 3 +- .../src/implementations/layers/l1_gas.rs | 28 +- core/node/state_keeper/src/io/tests/tester.rs | 3 +- prover/Cargo.lock | 2 - zkstack_cli/Cargo.lock | 2 - 31 files changed, 564 insertions(+), 601 deletions(-) rename core/lib/{types => basic_types}/src/pubdata_da.rs (54%) diff --git a/Cargo.lock b/Cargo.lock index a5e51346bdf4..5da4cc8c1439 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10645,7 +10645,6 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "bigdecimal", "test-casing", "tokio", "tracing", @@ -10654,7 +10653,6 @@ dependencies = [ "zksync_dal", "zksync_eth_client", "zksync_types", - "zksync_utils", "zksync_web3_decl", ] @@ -11235,7 +11233,6 @@ dependencies = [ "once_cell", "prost 0.12.6", "rlp", - "secp256k1", "serde", "serde_json", "serde_with", @@ -11244,7 +11241,6 @@ dependencies = [ "tokio", "tracing", "zksync_basic_types", - "zksync_config", "zksync_contracts", "zksync_crypto_primitives", "zksync_mini_merkle_tree", diff --git a/core/bin/zksync_server/src/node_builder.rs b/core/bin/zksync_server/src/node_builder.rs index c87bf3ce2dda..234e22894240 100644 --- a/core/bin/zksync_server/src/node_builder.rs +++ b/core/bin/zksync_server/src/node_builder.rs @@ -4,8 +4,8 @@ use anyhow::Context; use zksync_config::{ configs::{ - da_client::DAClientConfig, eth_sender::PubdataSendingMode, - secrets::DataAvailabilitySecrets, wallets::Wallets, GeneralConfig, Secrets, + da_client::DAClientConfig, secrets::DataAvailabilitySecrets, wallets::Wallets, + GeneralConfig, Secrets, }, ContractsConfig, GenesisConfig, }; @@ -69,7 +69,9 @@ use zksync_node_framework::{ }, service::{ZkStackService, ZkStackServiceBuilder}, }; -use zksync_types::{settlement::SettlementMode, SHARED_BRIDGE_ETHER_TOKEN_ADDRESS}; +use zksync_types::{ + pubdata_da::PubdataSendingMode, settlement::SettlementMode, SHARED_BRIDGE_ETHER_TOKEN_ADDRESS, +}; use zksync_vlog::prometheus::PrometheusExporterConfig; /// Macro that looks into a path to fetch an optional config, @@ -189,7 +191,7 @@ impl MainNodeBuilder { .add_layer(BaseTokenRatioProviderLayer::new(base_token_adjuster_config)); } let state_keeper_config = try_load_config!(self.configs.state_keeper_config); - let l1_gas_layer = L1GasLayer::new(state_keeper_config); + let l1_gas_layer = L1GasLayer::new(&state_keeper_config); self.node.add_layer(l1_gas_layer); Ok(self) } diff --git a/core/lib/basic_types/src/lib.rs b/core/lib/basic_types/src/lib.rs index 197bd8eb7aa2..79c7b3924e34 100644 --- a/core/lib/basic_types/src/lib.rs +++ b/core/lib/basic_types/src/lib.rs @@ -29,6 +29,7 @@ pub mod commitment; pub mod network; pub mod protocol_version; pub mod prover_dal; +pub mod pubdata_da; pub mod seed_phrase; pub mod settlement; pub mod tee_types; diff --git a/core/lib/types/src/pubdata_da.rs b/core/lib/basic_types/src/pubdata_da.rs similarity index 54% rename from core/lib/types/src/pubdata_da.rs rename to core/lib/basic_types/src/pubdata_da.rs index bc7dc55e53de..3f042da98ac1 100644 --- a/core/lib/types/src/pubdata_da.rs +++ b/core/lib/basic_types/src/pubdata_da.rs @@ -1,15 +1,17 @@ +//! Types related to data availability. + use chrono::{DateTime, Utc}; use num_enum::TryFromPrimitive; use serde::{Deserialize, Serialize}; -use zksync_basic_types::L1BatchNumber; -use zksync_config::configs::eth_sender::PubdataSendingMode; + +use crate::L1BatchNumber; /// Enum holding the current values used for DA Layers. #[repr(u8)] -#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] -#[derive(TryFromPrimitive)] -pub enum PubdataDA { +#[derive(Debug, Clone, Copy, Default, PartialEq, Deserialize, Serialize, TryFromPrimitive)] +pub enum PubdataSendingMode { /// Pubdata is sent to the L1 as a tx calldata. + #[default] Calldata = 0, /// Pubdata is sent to L1 as EIP-4844 blobs. Blobs, @@ -19,17 +21,6 @@ pub enum PubdataDA { RelayedL2Calldata, } -impl From for PubdataDA { - fn from(value: PubdataSendingMode) -> Self { - match value { - PubdataSendingMode::Calldata => PubdataDA::Calldata, - PubdataSendingMode::Blobs => PubdataDA::Blobs, - PubdataSendingMode::Custom => PubdataDA::Custom, - PubdataSendingMode::RelayedL2Calldata => PubdataDA::RelayedL2Calldata, - } - } -} - /// Represents a blob in the data availability layer. #[derive(Debug, Clone)] pub struct DataAvailabilityBlob { diff --git a/core/lib/config/src/configs/eth_sender.rs b/core/lib/config/src/configs/eth_sender.rs index 3a1a0505728c..7b67f015238d 100644 --- a/core/lib/config/src/configs/eth_sender.rs +++ b/core/lib/config/src/configs/eth_sender.rs @@ -2,7 +2,7 @@ use std::time::Duration; use anyhow::Context as _; use serde::Deserialize; -use zksync_basic_types::{settlement::SettlementMode, H256}; +use zksync_basic_types::{pubdata_da::PubdataSendingMode, settlement::SettlementMode, H256}; use zksync_crypto_primitives::K256PrivateKey; use crate::EthWatchConfig; @@ -80,15 +80,6 @@ pub enum ProofLoadingMode { FriProofFromGcs, } -#[derive(Debug, Deserialize, Clone, Copy, PartialEq, Default)] -pub enum PubdataSendingMode { - #[default] - Calldata, - Blobs, - Custom, - RelayedL2Calldata, -} - #[derive(Debug, Deserialize, Clone, PartialEq)] pub struct SenderConfig { pub aggregated_proof_sizes: Vec, diff --git a/core/lib/config/src/testonly.rs b/core/lib/config/src/testonly.rs index 0fdd927d19f0..9b1ec13e2d2e 100644 --- a/core/lib/config/src/testonly.rs +++ b/core/lib/config/src/testonly.rs @@ -7,6 +7,7 @@ use zksync_basic_types::{ commitment::L1BatchCommitmentMode, network::Network, protocol_version::{ProtocolSemanticVersion, ProtocolVersionId, VersionPatch}, + pubdata_da::PubdataSendingMode, seed_phrase::SeedPhrase, vm::FastVmMode, L1BatchNumber, L1ChainId, L2ChainId, @@ -16,8 +17,7 @@ use zksync_crypto_primitives::K256PrivateKey; use crate::{ configs::{ - self, da_client::DAClientConfig::Avail, eth_sender::PubdataSendingMode, - external_price_api_client::ForcedPriceClientConfig, + self, da_client::DAClientConfig::Avail, external_price_api_client::ForcedPriceClientConfig, }, AvailConfig, }; @@ -388,17 +388,6 @@ impl Distribution for EncodeDist { } } -impl Distribution for EncodeDist { - fn sample(&self, rng: &mut R) -> configs::eth_sender::PubdataSendingMode { - type T = configs::eth_sender::PubdataSendingMode; - match rng.gen_range(0..3) { - 0 => T::Calldata, - 1 => T::Blobs, - _ => T::Custom, - } - } -} - impl Distribution for EncodeDist { fn sample(&self, rng: &mut R) -> configs::eth_sender::SenderConfig { configs::eth_sender::SenderConfig { diff --git a/core/lib/env_config/src/eth_sender.rs b/core/lib/env_config/src/eth_sender.rs index e5132eb7d91f..0fd61fd173b6 100644 --- a/core/lib/env_config/src/eth_sender.rs +++ b/core/lib/env_config/src/eth_sender.rs @@ -41,7 +41,8 @@ impl FromEnv for GasAdjusterConfig { #[cfg(test)] mod tests { - use zksync_config::configs::eth_sender::{ProofSendingMode, PubdataSendingMode}; + use zksync_basic_types::pubdata_da::PubdataSendingMode; + use zksync_config::configs::eth_sender::ProofSendingMode; use super::*; use crate::test_utils::{hash, EnvMutex}; diff --git a/core/lib/l1_contract_interface/src/i_executor/methods/commit_batches.rs b/core/lib/l1_contract_interface/src/i_executor/methods/commit_batches.rs index 883804f0bd6f..67819f7d7ccd 100644 --- a/core/lib/l1_contract_interface/src/i_executor/methods/commit_batches.rs +++ b/core/lib/l1_contract_interface/src/i_executor/methods/commit_batches.rs @@ -1,7 +1,7 @@ use zksync_types::{ commitment::{L1BatchCommitmentMode, L1BatchWithMetadata}, ethabi::Token, - pubdata_da::PubdataDA, + pubdata_da::PubdataSendingMode, }; use crate::{ @@ -14,7 +14,7 @@ use crate::{ pub struct CommitBatches<'a> { pub last_committed_l1_batch: &'a L1BatchWithMetadata, pub l1_batches: &'a [L1BatchWithMetadata], - pub pubdata_da: PubdataDA, + pub pubdata_da: PubdataSendingMode, pub mode: L1BatchCommitmentMode, } diff --git a/core/lib/l1_contract_interface/src/i_executor/structures/commit_batch_info.rs b/core/lib/l1_contract_interface/src/i_executor/structures/commit_batch_info.rs index 179c04748d3b..6438aeb7f55c 100644 --- a/core/lib/l1_contract_interface/src/i_executor/structures/commit_batch_info.rs +++ b/core/lib/l1_contract_interface/src/i_executor/structures/commit_batch_info.rs @@ -4,7 +4,7 @@ use zksync_types::{ L1BatchWithMetadata, }, ethabi::Token, - pubdata_da::PubdataDA, + pubdata_da::PubdataSendingMode, web3::contract::Error as ContractError, ProtocolVersionId, U256, }; @@ -24,14 +24,14 @@ const PUBDATA_SOURCE_CUSTOM: u8 = 2; pub struct CommitBatchInfo<'a> { mode: L1BatchCommitmentMode, l1_batch_with_metadata: &'a L1BatchWithMetadata, - pubdata_da: PubdataDA, + pubdata_da: PubdataSendingMode, } impl<'a> CommitBatchInfo<'a> { pub fn new( mode: L1BatchCommitmentMode, l1_batch_with_metadata: &'a L1BatchWithMetadata, - pubdata_da: PubdataDA, + pubdata_da: PubdataSendingMode, ) -> Self { Self { mode, @@ -204,24 +204,24 @@ impl Tokenizable for CommitBatchInfo<'_> { // Here we're not pushing any pubdata on purpose; no pubdata is sent in Validium mode. ( L1BatchCommitmentMode::Validium, - PubdataDA::Calldata | PubdataDA::RelayedL2Calldata, + PubdataSendingMode::Calldata | PubdataSendingMode::RelayedL2Calldata, ) => { vec![PUBDATA_SOURCE_CALLDATA] } - (L1BatchCommitmentMode::Validium, PubdataDA::Blobs) => { + (L1BatchCommitmentMode::Validium, PubdataSendingMode::Blobs) => { vec![PUBDATA_SOURCE_BLOBS] } - (L1BatchCommitmentMode::Rollup, PubdataDA::Custom) => { + (L1BatchCommitmentMode::Rollup, PubdataSendingMode::Custom) => { panic!("Custom pubdata DA is incompatible with Rollup mode") } - (L1BatchCommitmentMode::Validium, PubdataDA::Custom) => { + (L1BatchCommitmentMode::Validium, PubdataSendingMode::Custom) => { vec![PUBDATA_SOURCE_CUSTOM] } ( L1BatchCommitmentMode::Rollup, - PubdataDA::Calldata | PubdataDA::RelayedL2Calldata, + PubdataSendingMode::Calldata | PubdataSendingMode::RelayedL2Calldata, ) => { // We compute and add the blob commitment to the pubdata payload so that we can verify the proof // even if we are not using blobs. @@ -232,7 +232,7 @@ impl Tokenizable for CommitBatchInfo<'_> { .chain(blob_commitment) .collect() } - (L1BatchCommitmentMode::Rollup, PubdataDA::Blobs) => { + (L1BatchCommitmentMode::Rollup, PubdataSendingMode::Blobs) => { let pubdata = self.pubdata_input(); let pubdata_commitments = pubdata.chunks(ZK_SYNC_BYTES_PER_BLOB).flat_map(|blob| { diff --git a/core/lib/protobuf_config/src/eth.rs b/core/lib/protobuf_config/src/eth.rs index c1d95bd30d2b..d4ea1d9f2697 100644 --- a/core/lib/protobuf_config/src/eth.rs +++ b/core/lib/protobuf_config/src/eth.rs @@ -1,6 +1,7 @@ use anyhow::Context as _; use zksync_config::configs::{self}; use zksync_protobuf::{required, ProtoRepr}; +use zksync_types::pubdata_da::PubdataSendingMode; use crate::{proto::eth as proto, read_optional_repr}; @@ -25,23 +26,21 @@ impl proto::ProofSendingMode { } impl proto::PubdataSendingMode { - fn new(x: &configs::eth_sender::PubdataSendingMode) -> Self { - use configs::eth_sender::PubdataSendingMode as From; + fn new(x: &PubdataSendingMode) -> Self { match x { - From::Calldata => Self::Calldata, - From::Blobs => Self::Blobs, - From::Custom => Self::Custom, - From::RelayedL2Calldata => Self::RelayedL2Calldata, + PubdataSendingMode::Calldata => Self::Calldata, + PubdataSendingMode::Blobs => Self::Blobs, + PubdataSendingMode::Custom => Self::Custom, + PubdataSendingMode::RelayedL2Calldata => Self::RelayedL2Calldata, } } - fn parse(&self) -> configs::eth_sender::PubdataSendingMode { - use configs::eth_sender::PubdataSendingMode as To; + fn parse(&self) -> PubdataSendingMode { match self { - Self::Calldata => To::Calldata, - Self::Blobs => To::Blobs, - Self::Custom => To::Custom, - Self::RelayedL2Calldata => To::RelayedL2Calldata, + Self::Calldata => PubdataSendingMode::Calldata, + Self::Blobs => PubdataSendingMode::Blobs, + Self::Custom => PubdataSendingMode::Custom, + Self::RelayedL2Calldata => PubdataSendingMode::RelayedL2Calldata, } } } diff --git a/core/lib/types/Cargo.toml b/core/lib/types/Cargo.toml index 54c38384a7ad..ffa9d219f084 100644 --- a/core/lib/types/Cargo.toml +++ b/core/lib/types/Cargo.toml @@ -11,12 +11,12 @@ keywords.workspace = true categories.workspace = true [dependencies] +# **IMPORTANT.** Please do not add dependency on `zksync_config` etc. This crate has a heavy dependency graph as is. zksync_system_constants.workspace = true zksync_utils.workspace = true zksync_basic_types.workspace = true zksync_contracts.workspace = true zksync_mini_merkle_tree.workspace = true -zksync_config.workspace = true zksync_protobuf.workspace = true zksync_crypto_primitives.workspace = true @@ -39,7 +39,6 @@ itertools.workspace = true tracing.workspace = true # Crypto stuff -secp256k1.workspace = true blake2.workspace = true [dev-dependencies] diff --git a/core/lib/types/src/fee_model.rs b/core/lib/types/src/fee_model.rs index b59aa65b04e0..ae346656ea6f 100644 --- a/core/lib/types/src/fee_model.rs +++ b/core/lib/types/src/fee_model.rs @@ -1,11 +1,13 @@ +// FIXME: separate crate together with node_fee_model interfaces? + use std::num::NonZeroU64; use bigdecimal::{BigDecimal, ToPrimitive}; use serde::{Deserialize, Serialize}; -use zksync_config::configs::chain::{FeeModelVersion, StateKeeperConfig}; use zksync_system_constants::L1_GAS_PER_PUBDATA_BYTE; +use zksync_utils::ceil_div_u256; -use crate::ProtocolVersionId; +use crate::{ProtocolVersionId, U256}; /// Fee input to be provided into the VM. It contains two options: /// - `L1Pegged`: L1 gas price is provided to the VM, and the pubdata price is derived from it. Using this option is required for the @@ -203,6 +205,7 @@ pub struct FeeModelConfigV2 { /// The maximum amount of pubdata that can be used by the batch. Note that if the calldata is used as pubdata, this variable should not exceed 128kb. pub max_pubdata_per_batch: u64, } + impl Default for FeeModelConfig { /// Config with all zeroes is not a valid config (since for instance having 0 max gas per batch may incur division by zero), /// so we implement a sensible default config here. @@ -213,24 +216,6 @@ impl Default for FeeModelConfig { } } -impl FeeModelConfig { - pub fn from_state_keeper_config(state_keeper_config: &StateKeeperConfig) -> Self { - match state_keeper_config.fee_model_version { - FeeModelVersion::V1 => Self::V1(FeeModelConfigV1 { - minimal_l2_gas_price: state_keeper_config.minimal_l2_gas_price, - }), - FeeModelVersion::V2 => Self::V2(FeeModelConfigV2 { - minimal_l2_gas_price: state_keeper_config.minimal_l2_gas_price, - compute_overhead_part: state_keeper_config.compute_overhead_part, - pubdata_overhead_part: state_keeper_config.pubdata_overhead_part, - batch_overhead_l1_gas: state_keeper_config.batch_overhead_l1_gas, - max_gas_per_batch: state_keeper_config.max_gas_per_batch, - max_pubdata_per_batch: state_keeper_config.max_pubdata_per_batch, - }), - } - } -} - #[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub struct FeeParamsV1 { pub config: FeeModelConfigV1, @@ -337,4 +322,442 @@ impl FeeParams { l1_gas_price: 1_000_000_000, }) } + + /// Provides scaled [`BatchFeeInput`] based on these parameters. + pub fn scale( + self, + l1_gas_price_scale_factor: f64, + l1_pubdata_price_scale_factor: f64, + ) -> BatchFeeInput { + match self { + Self::V1(params) => BatchFeeInput::L1Pegged(compute_batch_fee_model_input_v1( + params, + l1_gas_price_scale_factor, + )), + Self::V2(params) => BatchFeeInput::PubdataIndependent(clip_batch_fee_model_input_v2( + compute_batch_fee_model_input_v2( + params, + l1_gas_price_scale_factor, + l1_pubdata_price_scale_factor, + ), + )), + } + } +} + +/// Calculates the batch fee input based on the main node parameters. +/// This function uses the `V1` fee model, i.e. where the pubdata price does not include the proving costs. +fn compute_batch_fee_model_input_v1( + params: FeeParamsV1, + l1_gas_price_scale_factor: f64, +) -> L1PeggedBatchFeeModelInput { + let l1_gas_price = (params.l1_gas_price as f64 * l1_gas_price_scale_factor) as u64; + + L1PeggedBatchFeeModelInput { + l1_gas_price, + fair_l2_gas_price: params.config.minimal_l2_gas_price, + } +} + +/// Calculates the batch fee input based on the main node parameters. +/// This function uses the `V2` fee model, i.e. where the pubdata price does not include the proving costs. +fn compute_batch_fee_model_input_v2( + params: FeeParamsV2, + l1_gas_price_scale_factor: f64, + l1_pubdata_price_scale_factor: f64, +) -> PubdataIndependentBatchFeeModelInput { + let config = params.config(); + let l1_gas_price = params.l1_gas_price(); + let l1_pubdata_price = params.l1_pubdata_price(); + + let FeeModelConfigV2 { + minimal_l2_gas_price, + compute_overhead_part, + pubdata_overhead_part, + batch_overhead_l1_gas, + max_gas_per_batch, + max_pubdata_per_batch, + } = config; + + // Firstly, we scale the gas price and pubdata price in case it is needed. + let l1_gas_price = (l1_gas_price as f64 * l1_gas_price_scale_factor) as u64; + let l1_pubdata_price = (l1_pubdata_price as f64 * l1_pubdata_price_scale_factor) as u64; + + // While the final results of the calculations are not expected to have any overflows, the intermediate computations + // might, so we use U256 for them. + let l1_batch_overhead_wei = U256::from(l1_gas_price) * U256::from(batch_overhead_l1_gas); + + let fair_l2_gas_price = { + // Firstly, we calculate which part of the overall overhead each unit of L2 gas should cover. + let l1_batch_overhead_per_gas = + ceil_div_u256(l1_batch_overhead_wei, U256::from(max_gas_per_batch)); + + // Then, we multiply by the `compute_overhead_part` to get the overhead for the computation for each gas. + // Also, this means that if we almost never close batches because of compute, the `compute_overhead_part` should be zero and so + // it is possible that the computation costs include for no overhead. + let gas_overhead_wei = + (l1_batch_overhead_per_gas.as_u64() as f64 * compute_overhead_part) as u64; + + // We sum up the minimal L2 gas price (i.e. the raw prover/compute cost of a single L2 gas) and the overhead for batch being closed. + minimal_l2_gas_price + gas_overhead_wei + }; + + let fair_pubdata_price = { + // Firstly, we calculate which part of the overall overhead each pubdata byte should cover. + let l1_batch_overhead_per_pubdata = + ceil_div_u256(l1_batch_overhead_wei, U256::from(max_pubdata_per_batch)); + + // Then, we multiply by the `pubdata_overhead_part` to get the overhead for each pubdata byte. + // Also, this means that if we almost never close batches because of pubdata, the `pubdata_overhead_part` should be zero and so + // it is possible that the pubdata costs include no overhead. + let pubdata_overhead_wei = + (l1_batch_overhead_per_pubdata.as_u64() as f64 * pubdata_overhead_part) as u64; + + // We sum up the raw L1 pubdata price (i.e. the expected price of publishing a single pubdata byte) and the overhead for batch being closed. + l1_pubdata_price + pubdata_overhead_wei + }; + + PubdataIndependentBatchFeeModelInput { + l1_gas_price, + fair_l2_gas_price, + fair_pubdata_price, + } +} + +/// Bootloader places limitations on fair_l2_gas_price and fair_pubdata_price. +/// (MAX_ALLOWED_FAIR_L2_GAS_PRICE and MAX_ALLOWED_FAIR_PUBDATA_PRICE in bootloader code respectively) +/// Server needs to clip this prices in order to allow chain continues operation at a loss. The alternative +/// would be to stop accepting the transactions until the conditions improve. +/// TODO (PE-153): to be removed when bootloader limitation is removed +fn clip_batch_fee_model_input_v2( + fee_model: PubdataIndependentBatchFeeModelInput, +) -> PubdataIndependentBatchFeeModelInput { + /// MAX_ALLOWED_FAIR_L2_GAS_PRICE + const MAXIMUM_L2_GAS_PRICE: u64 = 10_000_000_000_000; + /// MAX_ALLOWED_FAIR_PUBDATA_PRICE + const MAXIMUM_PUBDATA_PRICE: u64 = 1_000_000_000_000_000; + PubdataIndependentBatchFeeModelInput { + l1_gas_price: fee_model.l1_gas_price, + fair_l2_gas_price: if fee_model.fair_l2_gas_price < MAXIMUM_L2_GAS_PRICE { + fee_model.fair_l2_gas_price + } else { + tracing::warn!( + "Fair l2 gas price {} exceeds maximum. Limitting to {}", + fee_model.fair_l2_gas_price, + MAXIMUM_L2_GAS_PRICE + ); + MAXIMUM_L2_GAS_PRICE + }, + fair_pubdata_price: if fee_model.fair_pubdata_price < MAXIMUM_PUBDATA_PRICE { + fee_model.fair_pubdata_price + } else { + tracing::warn!( + "Fair pubdata price {} exceeds maximum. Limitting to {}", + fee_model.fair_pubdata_price, + MAXIMUM_PUBDATA_PRICE + ); + MAXIMUM_PUBDATA_PRICE + }, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // To test that overflow never happens, we'll use giant L1 gas price, i.e. + // almost realistic very large value of 100k gwei. Since it is so large, we'll also + // use it for the L1 pubdata price. + const GWEI: u64 = 1_000_000_000; + const GIANT_L1_GAS_PRICE: u64 = 100_000 * GWEI; + + // As a small L2 gas price we'll use the value of 1 wei. + const SMALL_L1_GAS_PRICE: u64 = 1; + + #[test] + fn test_compute_batch_fee_model_input_v2_giant_numbers() { + let config = FeeModelConfigV2 { + minimal_l2_gas_price: GIANT_L1_GAS_PRICE, + // We generally don't expect those values to be larger than 1. Still, in theory the operator + // may need to set higher values in extreme cases. + compute_overhead_part: 5.0, + pubdata_overhead_part: 5.0, + // The batch overhead would likely never grow beyond that + batch_overhead_l1_gas: 1_000_000, + // Let's imagine that for some reason the limit is relatively small + max_gas_per_batch: 50_000_000, + // The pubdata will likely never go below that + max_pubdata_per_batch: 100_000, + }; + + let params = FeeParamsV2::new( + config, + GIANT_L1_GAS_PRICE, + GIANT_L1_GAS_PRICE, + BaseTokenConversionRatio::default(), + ); + + // We'll use scale factor of 3.0 + let input = compute_batch_fee_model_input_v2(params, 3.0, 3.0); + + assert_eq!(input.l1_gas_price, GIANT_L1_GAS_PRICE * 3); + assert_eq!(input.fair_l2_gas_price, 130_000_000_000_000); + assert_eq!(input.fair_pubdata_price, 15_300_000_000_000_000); + } + + #[test] + fn test_compute_batch_fee_model_input_v2_small_numbers() { + // Here we assume that the operator wants to make the lives of users as cheap as possible. + let config = FeeModelConfigV2 { + minimal_l2_gas_price: SMALL_L1_GAS_PRICE, + compute_overhead_part: 0.0, + pubdata_overhead_part: 0.0, + batch_overhead_l1_gas: 0, + max_gas_per_batch: 50_000_000, + max_pubdata_per_batch: 100_000, + }; + + let params = FeeParamsV2::new( + config, + SMALL_L1_GAS_PRICE, + SMALL_L1_GAS_PRICE, + BaseTokenConversionRatio::default(), + ); + + let input = + clip_batch_fee_model_input_v2(compute_batch_fee_model_input_v2(params, 1.0, 1.0)); + + assert_eq!(input.l1_gas_price, SMALL_L1_GAS_PRICE); + assert_eq!(input.fair_l2_gas_price, SMALL_L1_GAS_PRICE); + assert_eq!(input.fair_pubdata_price, SMALL_L1_GAS_PRICE); + } + + #[test] + fn test_compute_batch_fee_model_input_v2_only_pubdata_overhead() { + // Here we use sensible config, but when only pubdata is used to close the batch + let config = FeeModelConfigV2 { + minimal_l2_gas_price: 100_000_000_000, + compute_overhead_part: 0.0, + pubdata_overhead_part: 1.0, + batch_overhead_l1_gas: 700_000, + max_gas_per_batch: 500_000_000, + max_pubdata_per_batch: 100_000, + }; + + let params = FeeParamsV2::new( + config, + GIANT_L1_GAS_PRICE, + GIANT_L1_GAS_PRICE, + BaseTokenConversionRatio::default(), + ); + + let input = + clip_batch_fee_model_input_v2(compute_batch_fee_model_input_v2(params, 1.0, 1.0)); + assert_eq!(input.l1_gas_price, GIANT_L1_GAS_PRICE); + // The fair L2 gas price is identical to the minimal one. + assert_eq!(input.fair_l2_gas_price, 100_000_000_000); + // The fair pubdata price is the minimal one plus the overhead. + assert_eq!(input.fair_pubdata_price, 800_000_000_000_000); + } + + #[test] + fn test_compute_baxtch_fee_model_input_v2_only_compute_overhead() { + // Here we use sensible config, but when only compute is used to close the batch + let config = FeeModelConfigV2 { + minimal_l2_gas_price: 100_000_000_000, + compute_overhead_part: 1.0, + pubdata_overhead_part: 0.0, + batch_overhead_l1_gas: 700_000, + max_gas_per_batch: 500_000_000, + max_pubdata_per_batch: 100_000, + }; + + let params = FeeParamsV2::new( + config, + GIANT_L1_GAS_PRICE, + GIANT_L1_GAS_PRICE, + BaseTokenConversionRatio::default(), + ); + + let input = compute_batch_fee_model_input_v2(params, 1.0, 1.0); + assert_eq!(input.l1_gas_price, GIANT_L1_GAS_PRICE); + // The fair L2 gas price is identical to the minimal one, plus the overhead + assert_eq!(input.fair_l2_gas_price, 240_000_000_000); + // The fair pubdata price is equal to the original one. + assert_eq!(input.fair_pubdata_price, GIANT_L1_GAS_PRICE); + } + + #[test] + fn test_compute_batch_fee_model_input_v2_param_tweaking() { + // In this test we generally checking that each param behaves as expected + let base_config = FeeModelConfigV2 { + minimal_l2_gas_price: 100_000_000_000, + compute_overhead_part: 0.5, + pubdata_overhead_part: 0.5, + batch_overhead_l1_gas: 700_000, + max_gas_per_batch: 500_000_000, + max_pubdata_per_batch: 100_000, + }; + + let base_params = FeeParamsV2::new( + base_config, + 1_000_000_000, + 1_000_000_000, + BaseTokenConversionRatio::default(), + ); + + let base_input = compute_batch_fee_model_input_v2(base_params, 1.0, 1.0); + + let base_input_larger_l1_gas_price = compute_batch_fee_model_input_v2( + FeeParamsV2::new( + base_config, + 2_000_000_000, // double the L1 gas price + 1_000_000_000, + BaseTokenConversionRatio::default(), + ), + 1.0, + 1.0, + ); + let base_input_scaled_l1_gas_price = + compute_batch_fee_model_input_v2(base_params, 2.0, 1.0); + assert_eq!( + base_input_larger_l1_gas_price, base_input_scaled_l1_gas_price, + "Scaling has the correct effect for the L1 gas price" + ); + assert!( + base_input.fair_l2_gas_price < base_input_larger_l1_gas_price.fair_l2_gas_price, + "L1 gas price increase raises L2 gas price" + ); + assert!( + base_input.fair_pubdata_price < base_input_larger_l1_gas_price.fair_pubdata_price, + "L1 gas price increase raises pubdata price" + ); + + let base_input_larger_pubdata_price = compute_batch_fee_model_input_v2( + FeeParamsV2::new( + base_config, + 1_000_000_000, + 2_000_000_000, // double the L1 pubdata price + BaseTokenConversionRatio::default(), + ), + 1.0, + 1.0, + ); + let base_input_scaled_pubdata_price = + compute_batch_fee_model_input_v2(base_params, 1.0, 2.0); + assert_eq!( + base_input_larger_pubdata_price, base_input_scaled_pubdata_price, + "Scaling has the correct effect for the pubdata price" + ); + assert_eq!( + base_input.fair_l2_gas_price, base_input_larger_pubdata_price.fair_l2_gas_price, + "L1 pubdata increase has no effect on L2 gas price" + ); + assert!( + base_input.fair_pubdata_price < base_input_larger_pubdata_price.fair_pubdata_price, + "Pubdata price increase raises pubdata price" + ); + + let base_input_larger_max_gas = compute_batch_fee_model_input_v2( + FeeParamsV2::new( + FeeModelConfigV2 { + max_gas_per_batch: base_config.max_gas_per_batch * 2, + ..base_config + }, + base_params.l1_gas_price(), + base_params.l1_pubdata_price(), + BaseTokenConversionRatio::default(), + ), + 1.0, + 1.0, + ); + assert!( + base_input.fair_l2_gas_price > base_input_larger_max_gas.fair_l2_gas_price, + "Max gas increase lowers L2 gas price" + ); + assert_eq!( + base_input.fair_pubdata_price, base_input_larger_max_gas.fair_pubdata_price, + "Max gas increase has no effect on pubdata price" + ); + + let base_input_larger_max_pubdata = compute_batch_fee_model_input_v2( + FeeParamsV2::new( + FeeModelConfigV2 { + max_pubdata_per_batch: base_config.max_pubdata_per_batch * 2, + ..base_config + }, + base_params.l1_gas_price(), + base_params.l1_pubdata_price(), + BaseTokenConversionRatio::default(), + ), + 1.0, + 1.0, + ); + assert_eq!( + base_input.fair_l2_gas_price, base_input_larger_max_pubdata.fair_l2_gas_price, + "Max pubdata increase has no effect on L2 gas price" + ); + assert!( + base_input.fair_pubdata_price > base_input_larger_max_pubdata.fair_pubdata_price, + "Max pubdata increase lowers pubdata price" + ); + } + + #[test] + fn test_compute_batch_fee_model_input_v2_gas_price_over_limit_due_to_l1_gas() { + // In this test we check the gas price limit works as expected + let config = FeeModelConfigV2 { + minimal_l2_gas_price: 100 * GWEI, + compute_overhead_part: 0.5, + pubdata_overhead_part: 0.5, + batch_overhead_l1_gas: 700_000, + max_gas_per_batch: 500_000_000, + max_pubdata_per_batch: 100_000, + }; + + let l1_gas_price = 1_000_000_000 * GWEI; + let params = FeeParamsV2::new( + config, + l1_gas_price, + GIANT_L1_GAS_PRICE, + BaseTokenConversionRatio::default(), + ); + + let input = + clip_batch_fee_model_input_v2(compute_batch_fee_model_input_v2(params, 1.0, 1.0)); + assert_eq!(input.l1_gas_price, l1_gas_price); + // The fair L2 gas price is identical to the maximum + assert_eq!(input.fair_l2_gas_price, 10_000 * GWEI); + assert_eq!(input.fair_pubdata_price, 1_000_000 * GWEI); + } + + #[test] + fn test_compute_batch_fee_model_input_v2_gas_price_over_limit_due_to_conversion_rate() { + // In this test we check the gas price limit works as expected + let config = FeeModelConfigV2 { + minimal_l2_gas_price: GWEI, + compute_overhead_part: 0.5, + pubdata_overhead_part: 0.5, + batch_overhead_l1_gas: 700_000, + max_gas_per_batch: 500_000_000, + max_pubdata_per_batch: 100_000, + }; + + let params = FeeParamsV2::new( + config, + GWEI, + 2 * GWEI, + BaseTokenConversionRatio { + numerator: NonZeroU64::new(3_000_000).unwrap(), + denominator: NonZeroU64::new(1).unwrap(), + }, + ); + + let input = + clip_batch_fee_model_input_v2(compute_batch_fee_model_input_v2(params, 1.0, 1.0)); + assert_eq!(input.l1_gas_price, 3_000_000 * GWEI); + // The fair L2 gas price is identical to the maximum + assert_eq!(input.fair_l2_gas_price, 10_000 * GWEI); + assert_eq!(input.fair_pubdata_price, 1_000_000 * GWEI); + } } diff --git a/core/lib/types/src/lib.rs b/core/lib/types/src/lib.rs index a50fc8a655b7..69e6e42fd51c 100644 --- a/core/lib/types/src/lib.rs +++ b/core/lib/types/src/lib.rs @@ -43,7 +43,6 @@ pub mod l2; pub mod l2_to_l1_log; pub mod priority_op_onchain_data; pub mod protocol_upgrade; -pub mod pubdata_da; pub mod snapshots; pub mod storage; pub mod system_contracts; diff --git a/core/node/api_server/src/testonly.rs b/core/node/api_server/src/testonly.rs index 13e5ecc08ead..6da8e333495f 100644 --- a/core/node/api_server/src/testonly.rs +++ b/core/node/api_server/src/testonly.rs @@ -10,7 +10,6 @@ use zksync_contracts::{ }; use zksync_dal::{Connection, Core, CoreDal}; use zksync_multivm::utils::derive_base_fee_and_gas_per_pubdata; -use zksync_node_fee_model::BatchFeeModelInputProvider; use zksync_system_constants::L2_BASE_TOKEN_ADDRESS; use zksync_types::{ api::state_override::{Bytecode, OverrideAccount, OverrideState, StateOverride}, @@ -72,11 +71,7 @@ fn inflate_bytecode(bytecode: &mut Vec, nop_count: usize) { } fn default_fee() -> Fee { - let fee_input = ::default_batch_fee_input_scaled( - FeeParams::sensible_v1_default(), - 1.0, - 1.0, - ); + let fee_input = FeeParams::sensible_v1_default().scale(1.0, 1.0); let (max_fee_per_gas, gas_per_pubdata_limit) = derive_base_fee_and_gas_per_pubdata(fee_input, ProtocolVersionId::default().into()); Fee { diff --git a/core/node/api_server/src/web3/tests/mod.rs b/core/node/api_server/src/web3/tests/mod.rs index c83279709a30..d8080f1dba59 100644 --- a/core/node/api_server/src/web3/tests/mod.rs +++ b/core/node/api_server/src/web3/tests/mod.rs @@ -22,7 +22,6 @@ use zksync_multivm::interface::{ TransactionExecutionMetrics, TransactionExecutionResult, TxExecutionStatus, VmEvent, VmExecutionMetrics, }; -use zksync_node_fee_model::BatchFeeModelInputProvider; use zksync_node_genesis::{insert_genesis_batch, mock_genesis_config, GenesisParams}; use zksync_node_test_utils::{ create_l1_batch, create_l1_batch_metadata, create_l2_block, create_l2_transaction, @@ -476,11 +475,7 @@ async fn store_events( } fn scaled_sensible_fee_input(scale: f64) -> BatchFeeInput { - ::default_batch_fee_input_scaled( - FeeParams::sensible_v1_default(), - scale, - scale, - ) + FeeParams::sensible_v1_default().scale(scale, scale) } #[derive(Debug)] diff --git a/core/node/consistency_checker/src/lib.rs b/core/node/consistency_checker/src/lib.rs index 20ba43a4166e..e13e479117cc 100644 --- a/core/node/consistency_checker/src/lib.rs +++ b/core/node/consistency_checker/src/lib.rs @@ -19,7 +19,7 @@ use zksync_types::{ commitment::{L1BatchCommitmentMode, L1BatchWithMetadata}, ethabi, ethabi::Token, - pubdata_da::PubdataDA, + pubdata_da::PubdataSendingMode, Address, L1BatchNumber, ProtocolVersionId, H256, U256, }; @@ -224,7 +224,7 @@ impl LocalL1BatchCommitData { .context("cannot detect DA source from reference commitment token")?; // For `PubdataDA::Calldata`, it's required that the pubdata fits into a single blob. - if matches!(da, PubdataDA::Calldata) { + if matches!(da, PubdataSendingMode::Calldata) { let pubdata_len = self .l1_batch .header @@ -258,7 +258,7 @@ impl LocalL1BatchCommitData { pub fn detect_da( protocol_version: ProtocolVersionId, reference: &Token, -) -> Result { +) -> Result { /// These are used by the L1 Contracts to indicate what DA layer is used for pubdata const PUBDATA_SOURCE_CALLDATA: u8 = 0; const PUBDATA_SOURCE_BLOBS: u8 = 1; @@ -269,7 +269,7 @@ pub fn detect_da( } if protocol_version.is_pre_1_4_2() { - return Ok(PubdataDA::Calldata); + return Ok(PubdataSendingMode::Calldata); } let reference = match reference { @@ -291,9 +291,9 @@ pub fn detect_da( ))), }; match last_reference_token.first() { - Some(&byte) if byte == PUBDATA_SOURCE_CALLDATA => Ok(PubdataDA::Calldata), - Some(&byte) if byte == PUBDATA_SOURCE_BLOBS => Ok(PubdataDA::Blobs), - Some(&byte) if byte == PUBDATA_SOURCE_CUSTOM => Ok(PubdataDA::Custom), + Some(&byte) if byte == PUBDATA_SOURCE_CALLDATA => Ok(PubdataSendingMode::Calldata), + Some(&byte) if byte == PUBDATA_SOURCE_BLOBS => Ok(PubdataSendingMode::Blobs), + Some(&byte) if byte == PUBDATA_SOURCE_CUSTOM => Ok(PubdataSendingMode::Custom), Some(&byte) => Err(parse_error(format!( "unexpected first byte of the last reference token; expected one of [{PUBDATA_SOURCE_CALLDATA}, {PUBDATA_SOURCE_BLOBS}], \ got {byte}" diff --git a/core/node/consistency_checker/src/tests/mod.rs b/core/node/consistency_checker/src/tests/mod.rs index 40c447071cf4..b09ef2b2272c 100644 --- a/core/node/consistency_checker/src/tests/mod.rs +++ b/core/node/consistency_checker/src/tests/mod.rs @@ -64,7 +64,7 @@ pub(crate) fn build_commit_tx_input_data( let tokens = CommitBatches { last_committed_l1_batch: &batches[0], l1_batches: batches, - pubdata_da: PubdataDA::Calldata, + pubdata_da: PubdataSendingMode::Calldata, mode, } .into_tokens(); @@ -167,7 +167,7 @@ fn build_commit_tx_input_data_is_correct(commitment_mode: L1BatchCommitmentMode) .unwrap(); assert_eq!( commit_data, - CommitBatchInfo::new(commitment_mode, batch, PubdataDA::Calldata).into_token(), + CommitBatchInfo::new(commitment_mode, batch, PubdataSendingMode::Calldata).into_token(), ); } } diff --git a/core/node/eth_sender/src/aggregated_operations.rs b/core/node/eth_sender/src/aggregated_operations.rs index 2dfaf5942659..5271d42d3b75 100644 --- a/core/node/eth_sender/src/aggregated_operations.rs +++ b/core/node/eth_sender/src/aggregated_operations.rs @@ -3,13 +3,17 @@ use std::ops; use zksync_l1_contract_interface::i_executor::methods::{ExecuteBatches, ProveBatches}; use zksync_types::{ aggregated_operations::AggregatedActionType, commitment::L1BatchWithMetadata, - pubdata_da::PubdataDA, L1BatchNumber, ProtocolVersionId, + pubdata_da::PubdataSendingMode, L1BatchNumber, ProtocolVersionId, }; #[allow(clippy::large_enum_variant)] #[derive(Debug, Clone)] pub enum AggregatedOperation { - Commit(L1BatchWithMetadata, Vec, PubdataDA), + Commit( + L1BatchWithMetadata, + Vec, + PubdataSendingMode, + ), PublishProofOnchain(ProveBatches), Execute(ExecuteBatches), } diff --git a/core/node/eth_sender/src/aggregator.rs b/core/node/eth_sender/src/aggregator.rs index 4045e9ca3d80..432804a21b2e 100644 --- a/core/node/eth_sender/src/aggregator.rs +++ b/core/node/eth_sender/src/aggregator.rs @@ -11,7 +11,7 @@ use zksync_types::{ commitment::{L1BatchCommitmentMode, L1BatchWithMetadata}, helpers::unix_timestamp_ms, protocol_version::{L1VerifierConfig, ProtocolSemanticVersion}, - pubdata_da::PubdataDA, + pubdata_da::PubdataSendingMode, L1BatchNumber, ProtocolVersionId, }; @@ -36,7 +36,7 @@ pub struct Aggregator { /// means no wait is needed: nonces will still provide the correct ordering of /// transactions. operate_4844_mode: bool, - pubdata_da: PubdataDA, + pubdata_da: PubdataSendingMode, commitment_mode: L1BatchCommitmentMode, } @@ -47,8 +47,7 @@ impl Aggregator { operate_4844_mode: bool, commitment_mode: L1BatchCommitmentMode, ) -> Self { - let pubdata_da = config.pubdata_sending_mode.into(); - + let pubdata_da = config.pubdata_sending_mode; Self { commit_criteria: vec![ Box::from(NumberCriterion { @@ -476,7 +475,7 @@ impl Aggregator { } } - pub fn pubdata_da(&self) -> PubdataDA { + pub fn pubdata_da(&self) -> PubdataSendingMode { self.pubdata_da } diff --git a/core/node/eth_sender/src/eth_tx_aggregator.rs b/core/node/eth_sender/src/eth_tx_aggregator.rs index a08d16f456a9..ac9ed4aaaadb 100644 --- a/core/node/eth_sender/src/eth_tx_aggregator.rs +++ b/core/node/eth_sender/src/eth_tx_aggregator.rs @@ -19,7 +19,7 @@ use zksync_types::{ ethabi::{Function, Token}, l2_to_l1_log::UserL2ToL1Log, protocol_version::{L1VerifierConfig, PACKED_SEMVER_MINOR_MASK}, - pubdata_da::PubdataDA, + pubdata_da::PubdataSendingMode, settlement::SettlementMode, web3::{contract::Error as Web3ContractError, BlockNumber}, Address, L2ChainId, ProtocolVersionId, SLChainId, H256, U256, @@ -505,11 +505,12 @@ impl EthTxAggregator { ) }; - let l1_batch_for_sidecar = if PubdataDA::Blobs == self.aggregator.pubdata_da() { - Some(l1_batches[0].clone()) - } else { - None - }; + let l1_batch_for_sidecar = + if PubdataSendingMode::Blobs == self.aggregator.pubdata_da() { + Some(l1_batches[0].clone()) + } else { + None + }; Self::encode_commit_data(encoding_fn, &commit_data, l1_batch_for_sidecar) } diff --git a/core/node/eth_sender/src/publish_criterion.rs b/core/node/eth_sender/src/publish_criterion.rs index 52d861ce0af6..30f0820b148a 100644 --- a/core/node/eth_sender/src/publish_criterion.rs +++ b/core/node/eth_sender/src/publish_criterion.rs @@ -8,7 +8,7 @@ use zksync_types::{ aggregated_operations::AggregatedActionType, commitment::{L1BatchCommitmentMode, L1BatchWithMetadata}, ethabi, - pubdata_da::PubdataDA, + pubdata_da::PubdataSendingMode, L1BatchNumber, }; @@ -202,7 +202,7 @@ impl L1BatchPublishCriterion for GasCriterion { pub struct DataSizeCriterion { pub op: AggregatedActionType, pub data_limit: usize, - pub pubdata_da: PubdataDA, + pub pubdata_da: PubdataSendingMode, pub commitment_mode: L1BatchCommitmentMode, } diff --git a/core/node/eth_sender/src/tester.rs b/core/node/eth_sender/src/tester.rs index 86a8c477f9fe..646df1dc1a7b 100644 --- a/core/node/eth_sender/src/tester.rs +++ b/core/node/eth_sender/src/tester.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use zksync_config::{ - configs::eth_sender::{ProofSendingMode, PubdataSendingMode, SenderConfig}, + configs::eth_sender::{ProofSendingMode, SenderConfig}, ContractsConfig, EthConfig, GasAdjusterConfig, }; use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; @@ -12,7 +12,7 @@ use zksync_node_test_utils::{create_l1_batch, l1_batch_metadata_to_commitment_ar use zksync_object_store::MockObjectStore; use zksync_types::{ aggregated_operations::AggregatedActionType, block::L1BatchHeader, - commitment::L1BatchCommitmentMode, eth_sender::EthTx, pubdata_da::PubdataDA, + commitment::L1BatchCommitmentMode, eth_sender::EthTx, pubdata_da::PubdataSendingMode, settlement::SettlementMode, Address, L1BatchNumber, ProtocolVersion, H256, }; @@ -485,9 +485,9 @@ impl EthSenderTester { pub async fn save_commit_tx(&mut self, l1_batch_number: L1BatchNumber) -> EthTx { assert_eq!(l1_batch_number, self.next_l1_batch_number_to_commit); let pubdata_mode = if self.pubdata_sending_mode == PubdataSendingMode::Blobs { - PubdataDA::Blobs + PubdataSendingMode::Blobs } else { - PubdataDA::Calldata + PubdataSendingMode::Calldata }; let operation = AggregatedOperation::Commit( l1_batch_with_metadata( diff --git a/core/node/fee_model/Cargo.toml b/core/node/fee_model/Cargo.toml index 8760b97d9db3..a84a7c5c2173 100644 --- a/core/node/fee_model/Cargo.toml +++ b/core/node/fee_model/Cargo.toml @@ -16,9 +16,7 @@ zksync_types.workspace = true zksync_dal.workspace = true zksync_config.workspace = true zksync_eth_client.workspace = true -zksync_utils.workspace = true zksync_web3_decl.workspace = true -bigdecimal.workspace = true tokio = { workspace = true, features = ["time"] } anyhow.workspace = true diff --git a/core/node/fee_model/src/l1_gas_price/gas_adjuster/mod.rs b/core/node/fee_model/src/l1_gas_price/gas_adjuster/mod.rs index 27cdc7f5d5e0..459b8855b961 100644 --- a/core/node/fee_model/src/l1_gas_price/gas_adjuster/mod.rs +++ b/core/node/fee_model/src/l1_gas_price/gas_adjuster/mod.rs @@ -6,9 +6,12 @@ use std::{ }; use tokio::sync::watch; -use zksync_config::{configs::eth_sender::PubdataSendingMode, GasAdjusterConfig}; +use zksync_config::GasAdjusterConfig; use zksync_eth_client::EthFeeInterface; -use zksync_types::{commitment::L1BatchCommitmentMode, L1_GAS_PER_PUBDATA_BYTE, U256}; +use zksync_types::{ + commitment::L1BatchCommitmentMode, pubdata_da::PubdataSendingMode, L1_GAS_PER_PUBDATA_BYTE, + U256, +}; use zksync_web3_decl::client::{DynClient, L1, L2}; use self::metrics::METRICS; diff --git a/core/node/fee_model/src/l1_gas_price/gas_adjuster/tests.rs b/core/node/fee_model/src/l1_gas_price/gas_adjuster/tests.rs index 47023203de0e..ab649e2d7c90 100644 --- a/core/node/fee_model/src/l1_gas_price/gas_adjuster/tests.rs +++ b/core/node/fee_model/src/l1_gas_price/gas_adjuster/tests.rs @@ -1,9 +1,11 @@ use std::{collections::VecDeque, sync::RwLockReadGuard}; use test_casing::test_casing; -use zksync_config::{configs::eth_sender::PubdataSendingMode, GasAdjusterConfig}; +use zksync_config::GasAdjusterConfig; use zksync_eth_client::{clients::MockSettlementLayer, BaseFees}; -use zksync_types::{commitment::L1BatchCommitmentMode, settlement::SettlementMode}; +use zksync_types::{ + commitment::L1BatchCommitmentMode, pubdata_da::PubdataSendingMode, settlement::SettlementMode, +}; use zksync_web3_decl::client::L2; use super::{GasAdjuster, GasStatistics, GasStatisticsInner}; diff --git a/core/node/fee_model/src/lib.rs b/core/node/fee_model/src/lib.rs index fe4f6a27ce29..380a279cccc1 100644 --- a/core/node/fee_model/src/lib.rs +++ b/core/node/fee_model/src/lib.rs @@ -3,14 +3,9 @@ use std::{fmt, fmt::Debug, sync::Arc}; use anyhow::Context as _; use async_trait::async_trait; use zksync_dal::{ConnectionPool, Core, CoreDal}; -use zksync_types::{ - fee_model::{ - BaseTokenConversionRatio, BatchFeeInput, FeeModelConfig, FeeModelConfigV2, FeeParams, - FeeParamsV1, FeeParamsV2, L1PeggedBatchFeeModelInput, PubdataIndependentBatchFeeModelInput, - }, - U256, +use zksync_types::fee_model::{ + BaseTokenConversionRatio, BatchFeeInput, FeeModelConfig, FeeParams, FeeParamsV1, FeeParamsV2, }; -use zksync_utils::ceil_div_u256; use crate::l1_gas_price::GasAdjuster; @@ -34,13 +29,7 @@ pub trait BatchFeeModelInputProvider: fmt::Debug + 'static + Send + Sync { l1_pubdata_price_scale_factor: f64, ) -> anyhow::Result { let params = self.get_fee_model_params(); - Ok( - ::default_batch_fee_input_scaled( - params, - l1_gas_price_scale_factor, - l1_pubdata_price_scale_factor, - ), - ) + Ok(params.scale(l1_gas_price_scale_factor, l1_pubdata_price_scale_factor)) } /// Returns the fee model parameters using the denomination of the base token used (WEI for ETH). @@ -48,27 +37,6 @@ pub trait BatchFeeModelInputProvider: fmt::Debug + 'static + Send + Sync { } impl dyn BatchFeeModelInputProvider { - /// Provides the default implementation of `get_batch_fee_input_scaled()` given [`FeeParams`]. - pub fn default_batch_fee_input_scaled( - params: FeeParams, - l1_gas_price_scale_factor: f64, - l1_pubdata_price_scale_factor: f64, - ) -> BatchFeeInput { - match params { - FeeParams::V1(params) => BatchFeeInput::L1Pegged(compute_batch_fee_model_input_v1( - params, - l1_gas_price_scale_factor, - )), - FeeParams::V2(params) => BatchFeeInput::PubdataIndependent( - clip_batch_fee_model_input_v2(compute_batch_fee_model_input_v2( - params, - l1_gas_price_scale_factor, - l1_pubdata_price_scale_factor, - )), - ), - } - } - /// Returns the batch fee input as-is, i.e. without any scaling for the L1 gas and pubdata prices. pub async fn get_batch_fee_input(&self) -> anyhow::Result { self.get_batch_fee_input_scaled(1.0, 1.0).await @@ -168,122 +136,6 @@ impl BatchFeeModelInputProvider for ApiFeeInputProvider { } } -/// Calculates the batch fee input based on the main node parameters. -/// This function uses the `V1` fee model, i.e. where the pubdata price does not include the proving costs. -fn compute_batch_fee_model_input_v1( - params: FeeParamsV1, - l1_gas_price_scale_factor: f64, -) -> L1PeggedBatchFeeModelInput { - let l1_gas_price = (params.l1_gas_price as f64 * l1_gas_price_scale_factor) as u64; - - L1PeggedBatchFeeModelInput { - l1_gas_price, - fair_l2_gas_price: params.config.minimal_l2_gas_price, - } -} - -/// Calculates the batch fee input based on the main node parameters. -/// This function uses the `V2` fee model, i.e. where the pubdata price does not include the proving costs. -fn compute_batch_fee_model_input_v2( - params: FeeParamsV2, - l1_gas_price_scale_factor: f64, - l1_pubdata_price_scale_factor: f64, -) -> PubdataIndependentBatchFeeModelInput { - let config = params.config(); - let l1_gas_price = params.l1_gas_price(); - let l1_pubdata_price = params.l1_pubdata_price(); - - let FeeModelConfigV2 { - minimal_l2_gas_price, - compute_overhead_part, - pubdata_overhead_part, - batch_overhead_l1_gas, - max_gas_per_batch, - max_pubdata_per_batch, - } = config; - - // Firstly, we scale the gas price and pubdata price in case it is needed. - let l1_gas_price = (l1_gas_price as f64 * l1_gas_price_scale_factor) as u64; - let l1_pubdata_price = (l1_pubdata_price as f64 * l1_pubdata_price_scale_factor) as u64; - - // While the final results of the calculations are not expected to have any overflows, the intermediate computations - // might, so we use U256 for them. - let l1_batch_overhead_wei = U256::from(l1_gas_price) * U256::from(batch_overhead_l1_gas); - - let fair_l2_gas_price = { - // Firstly, we calculate which part of the overall overhead each unit of L2 gas should cover. - let l1_batch_overhead_per_gas = - ceil_div_u256(l1_batch_overhead_wei, U256::from(max_gas_per_batch)); - - // Then, we multiply by the `compute_overhead_part` to get the overhead for the computation for each gas. - // Also, this means that if we almost never close batches because of compute, the `compute_overhead_part` should be zero and so - // it is possible that the computation costs include for no overhead. - let gas_overhead_wei = - (l1_batch_overhead_per_gas.as_u64() as f64 * compute_overhead_part) as u64; - - // We sum up the minimal L2 gas price (i.e. the raw prover/compute cost of a single L2 gas) and the overhead for batch being closed. - minimal_l2_gas_price + gas_overhead_wei - }; - - let fair_pubdata_price = { - // Firstly, we calculate which part of the overall overhead each pubdata byte should cover. - let l1_batch_overhead_per_pubdata = - ceil_div_u256(l1_batch_overhead_wei, U256::from(max_pubdata_per_batch)); - - // Then, we multiply by the `pubdata_overhead_part` to get the overhead for each pubdata byte. - // Also, this means that if we almost never close batches because of pubdata, the `pubdata_overhead_part` should be zero and so - // it is possible that the pubdata costs include no overhead. - let pubdata_overhead_wei = - (l1_batch_overhead_per_pubdata.as_u64() as f64 * pubdata_overhead_part) as u64; - - // We sum up the raw L1 pubdata price (i.e. the expected price of publishing a single pubdata byte) and the overhead for batch being closed. - l1_pubdata_price + pubdata_overhead_wei - }; - - PubdataIndependentBatchFeeModelInput { - l1_gas_price, - fair_l2_gas_price, - fair_pubdata_price, - } -} - -/// Bootloader places limitations on fair_l2_gas_price and fair_pubdata_price. -/// (MAX_ALLOWED_FAIR_L2_GAS_PRICE and MAX_ALLOWED_FAIR_PUBDATA_PRICE in bootloader code respectively) -/// Server needs to clip this prices in order to allow chain continues operation at a loss. The alternative -/// would be to stop accepting the transactions until the conditions improve. -/// TODO (PE-153): to be removed when bootloader limitation is removed -fn clip_batch_fee_model_input_v2( - fee_model: PubdataIndependentBatchFeeModelInput, -) -> PubdataIndependentBatchFeeModelInput { - /// MAX_ALLOWED_FAIR_L2_GAS_PRICE - const MAXIMUM_L2_GAS_PRICE: u64 = 10_000_000_000_000; - /// MAX_ALLOWED_FAIR_PUBDATA_PRICE - const MAXIMUM_PUBDATA_PRICE: u64 = 1_000_000_000_000_000; - PubdataIndependentBatchFeeModelInput { - l1_gas_price: fee_model.l1_gas_price, - fair_l2_gas_price: if fee_model.fair_l2_gas_price < MAXIMUM_L2_GAS_PRICE { - fee_model.fair_l2_gas_price - } else { - tracing::warn!( - "Fair l2 gas price {} exceeds maximum. Limitting to {}", - fee_model.fair_l2_gas_price, - MAXIMUM_L2_GAS_PRICE - ); - MAXIMUM_L2_GAS_PRICE - }, - fair_pubdata_price: if fee_model.fair_pubdata_price < MAXIMUM_PUBDATA_PRICE { - fee_model.fair_pubdata_price - } else { - tracing::warn!( - "Fair pubdata price {} exceeds maximum. Limitting to {}", - fee_model.fair_pubdata_price, - MAXIMUM_PUBDATA_PRICE - ); - MAXIMUM_PUBDATA_PRICE - }, - } -} - /// Mock [`BatchFeeModelInputProvider`] implementation that returns a constant value. /// Intended to be used in tests only. #[derive(Debug)] @@ -307,308 +159,17 @@ mod tests { use std::num::NonZeroU64; use l1_gas_price::GasAdjusterClient; - use zksync_config::{configs::eth_sender::PubdataSendingMode, GasAdjusterConfig}; + use zksync_config::GasAdjusterConfig; use zksync_eth_client::{clients::MockSettlementLayer, BaseFees}; - use zksync_types::{commitment::L1BatchCommitmentMode, fee_model::BaseTokenConversionRatio}; + use zksync_types::{ + commitment::L1BatchCommitmentMode, + fee_model::{BaseTokenConversionRatio, FeeModelConfigV2}, + pubdata_da::PubdataSendingMode, + U256, + }; use super::*; - // To test that overflow never happens, we'll use giant L1 gas price, i.e. - // almost realistic very large value of 100k gwei. Since it is so large, we'll also - // use it for the L1 pubdata price. - const GWEI: u64 = 1_000_000_000; - const GIANT_L1_GAS_PRICE: u64 = 100_000 * GWEI; - - // As a small L2 gas price we'll use the value of 1 wei. - const SMALL_L1_GAS_PRICE: u64 = 1; - - #[test] - fn test_compute_batch_fee_model_input_v2_giant_numbers() { - let config = FeeModelConfigV2 { - minimal_l2_gas_price: GIANT_L1_GAS_PRICE, - // We generally don't expect those values to be larger than 1. Still, in theory the operator - // may need to set higher values in extreme cases. - compute_overhead_part: 5.0, - pubdata_overhead_part: 5.0, - // The batch overhead would likely never grow beyond that - batch_overhead_l1_gas: 1_000_000, - // Let's imagine that for some reason the limit is relatively small - max_gas_per_batch: 50_000_000, - // The pubdata will likely never go below that - max_pubdata_per_batch: 100_000, - }; - - let params = FeeParamsV2::new( - config, - GIANT_L1_GAS_PRICE, - GIANT_L1_GAS_PRICE, - BaseTokenConversionRatio::default(), - ); - - // We'll use scale factor of 3.0 - let input = compute_batch_fee_model_input_v2(params, 3.0, 3.0); - - assert_eq!(input.l1_gas_price, GIANT_L1_GAS_PRICE * 3); - assert_eq!(input.fair_l2_gas_price, 130_000_000_000_000); - assert_eq!(input.fair_pubdata_price, 15_300_000_000_000_000); - } - - #[test] - fn test_compute_batch_fee_model_input_v2_small_numbers() { - // Here we assume that the operator wants to make the lives of users as cheap as possible. - let config = FeeModelConfigV2 { - minimal_l2_gas_price: SMALL_L1_GAS_PRICE, - compute_overhead_part: 0.0, - pubdata_overhead_part: 0.0, - batch_overhead_l1_gas: 0, - max_gas_per_batch: 50_000_000, - max_pubdata_per_batch: 100_000, - }; - - let params = FeeParamsV2::new( - config, - SMALL_L1_GAS_PRICE, - SMALL_L1_GAS_PRICE, - BaseTokenConversionRatio::default(), - ); - - let input = - clip_batch_fee_model_input_v2(compute_batch_fee_model_input_v2(params, 1.0, 1.0)); - - assert_eq!(input.l1_gas_price, SMALL_L1_GAS_PRICE); - assert_eq!(input.fair_l2_gas_price, SMALL_L1_GAS_PRICE); - assert_eq!(input.fair_pubdata_price, SMALL_L1_GAS_PRICE); - } - - #[test] - fn test_compute_batch_fee_model_input_v2_only_pubdata_overhead() { - // Here we use sensible config, but when only pubdata is used to close the batch - let config = FeeModelConfigV2 { - minimal_l2_gas_price: 100_000_000_000, - compute_overhead_part: 0.0, - pubdata_overhead_part: 1.0, - batch_overhead_l1_gas: 700_000, - max_gas_per_batch: 500_000_000, - max_pubdata_per_batch: 100_000, - }; - - let params = FeeParamsV2::new( - config, - GIANT_L1_GAS_PRICE, - GIANT_L1_GAS_PRICE, - BaseTokenConversionRatio::default(), - ); - - let input = - clip_batch_fee_model_input_v2(compute_batch_fee_model_input_v2(params, 1.0, 1.0)); - assert_eq!(input.l1_gas_price, GIANT_L1_GAS_PRICE); - // The fair L2 gas price is identical to the minimal one. - assert_eq!(input.fair_l2_gas_price, 100_000_000_000); - // The fair pubdata price is the minimal one plus the overhead. - assert_eq!(input.fair_pubdata_price, 800_000_000_000_000); - } - - #[test] - fn test_compute_baxtch_fee_model_input_v2_only_compute_overhead() { - // Here we use sensible config, but when only compute is used to close the batch - let config = FeeModelConfigV2 { - minimal_l2_gas_price: 100_000_000_000, - compute_overhead_part: 1.0, - pubdata_overhead_part: 0.0, - batch_overhead_l1_gas: 700_000, - max_gas_per_batch: 500_000_000, - max_pubdata_per_batch: 100_000, - }; - - let params = FeeParamsV2::new( - config, - GIANT_L1_GAS_PRICE, - GIANT_L1_GAS_PRICE, - BaseTokenConversionRatio::default(), - ); - - let input = compute_batch_fee_model_input_v2(params, 1.0, 1.0); - assert_eq!(input.l1_gas_price, GIANT_L1_GAS_PRICE); - // The fair L2 gas price is identical to the minimal one, plus the overhead - assert_eq!(input.fair_l2_gas_price, 240_000_000_000); - // The fair pubdata price is equal to the original one. - assert_eq!(input.fair_pubdata_price, GIANT_L1_GAS_PRICE); - } - - #[test] - fn test_compute_batch_fee_model_input_v2_param_tweaking() { - // In this test we generally checking that each param behaves as expected - let base_config = FeeModelConfigV2 { - minimal_l2_gas_price: 100_000_000_000, - compute_overhead_part: 0.5, - pubdata_overhead_part: 0.5, - batch_overhead_l1_gas: 700_000, - max_gas_per_batch: 500_000_000, - max_pubdata_per_batch: 100_000, - }; - - let base_params = FeeParamsV2::new( - base_config, - 1_000_000_000, - 1_000_000_000, - BaseTokenConversionRatio::default(), - ); - - let base_input = compute_batch_fee_model_input_v2(base_params, 1.0, 1.0); - - let base_input_larger_l1_gas_price = compute_batch_fee_model_input_v2( - FeeParamsV2::new( - base_config, - 2_000_000_000, // double the L1 gas price - 1_000_000_000, - BaseTokenConversionRatio::default(), - ), - 1.0, - 1.0, - ); - let base_input_scaled_l1_gas_price = - compute_batch_fee_model_input_v2(base_params, 2.0, 1.0); - assert_eq!( - base_input_larger_l1_gas_price, base_input_scaled_l1_gas_price, - "Scaling has the correct effect for the L1 gas price" - ); - assert!( - base_input.fair_l2_gas_price < base_input_larger_l1_gas_price.fair_l2_gas_price, - "L1 gas price increase raises L2 gas price" - ); - assert!( - base_input.fair_pubdata_price < base_input_larger_l1_gas_price.fair_pubdata_price, - "L1 gas price increase raises pubdata price" - ); - - let base_input_larger_pubdata_price = compute_batch_fee_model_input_v2( - FeeParamsV2::new( - base_config, - 1_000_000_000, - 2_000_000_000, // double the L1 pubdata price - BaseTokenConversionRatio::default(), - ), - 1.0, - 1.0, - ); - let base_input_scaled_pubdata_price = - compute_batch_fee_model_input_v2(base_params, 1.0, 2.0); - assert_eq!( - base_input_larger_pubdata_price, base_input_scaled_pubdata_price, - "Scaling has the correct effect for the pubdata price" - ); - assert_eq!( - base_input.fair_l2_gas_price, base_input_larger_pubdata_price.fair_l2_gas_price, - "L1 pubdata increase has no effect on L2 gas price" - ); - assert!( - base_input.fair_pubdata_price < base_input_larger_pubdata_price.fair_pubdata_price, - "Pubdata price increase raises pubdata price" - ); - - let base_input_larger_max_gas = compute_batch_fee_model_input_v2( - FeeParamsV2::new( - FeeModelConfigV2 { - max_gas_per_batch: base_config.max_gas_per_batch * 2, - ..base_config - }, - base_params.l1_gas_price(), - base_params.l1_pubdata_price(), - BaseTokenConversionRatio::default(), - ), - 1.0, - 1.0, - ); - assert!( - base_input.fair_l2_gas_price > base_input_larger_max_gas.fair_l2_gas_price, - "Max gas increase lowers L2 gas price" - ); - assert_eq!( - base_input.fair_pubdata_price, base_input_larger_max_gas.fair_pubdata_price, - "Max gas increase has no effect on pubdata price" - ); - - let base_input_larger_max_pubdata = compute_batch_fee_model_input_v2( - FeeParamsV2::new( - FeeModelConfigV2 { - max_pubdata_per_batch: base_config.max_pubdata_per_batch * 2, - ..base_config - }, - base_params.l1_gas_price(), - base_params.l1_pubdata_price(), - BaseTokenConversionRatio::default(), - ), - 1.0, - 1.0, - ); - assert_eq!( - base_input.fair_l2_gas_price, base_input_larger_max_pubdata.fair_l2_gas_price, - "Max pubdata increase has no effect on L2 gas price" - ); - assert!( - base_input.fair_pubdata_price > base_input_larger_max_pubdata.fair_pubdata_price, - "Max pubdata increase lowers pubdata price" - ); - } - - #[test] - fn test_compute_batch_fee_model_input_v2_gas_price_over_limit_due_to_l1_gas() { - // In this test we check the gas price limit works as expected - let config = FeeModelConfigV2 { - minimal_l2_gas_price: 100 * GWEI, - compute_overhead_part: 0.5, - pubdata_overhead_part: 0.5, - batch_overhead_l1_gas: 700_000, - max_gas_per_batch: 500_000_000, - max_pubdata_per_batch: 100_000, - }; - - let l1_gas_price = 1_000_000_000 * GWEI; - let params = FeeParamsV2::new( - config, - l1_gas_price, - GIANT_L1_GAS_PRICE, - BaseTokenConversionRatio::default(), - ); - - let input = - clip_batch_fee_model_input_v2(compute_batch_fee_model_input_v2(params, 1.0, 1.0)); - assert_eq!(input.l1_gas_price, l1_gas_price); - // The fair L2 gas price is identical to the maximum - assert_eq!(input.fair_l2_gas_price, 10_000 * GWEI); - assert_eq!(input.fair_pubdata_price, 1_000_000 * GWEI); - } - - #[test] - fn test_compute_batch_fee_model_input_v2_gas_price_over_limit_due_to_conversion_rate() { - // In this test we check the gas price limit works as expected - let config = FeeModelConfigV2 { - minimal_l2_gas_price: GWEI, - compute_overhead_part: 0.5, - pubdata_overhead_part: 0.5, - batch_overhead_l1_gas: 700_000, - max_gas_per_batch: 500_000_000, - max_pubdata_per_batch: 100_000, - }; - - let params = FeeParamsV2::new( - config, - GWEI, - 2 * GWEI, - BaseTokenConversionRatio { - numerator: NonZeroU64::new(3_000_000).unwrap(), - denominator: NonZeroU64::new(1).unwrap(), - }, - ); - - let input = - clip_batch_fee_model_input_v2(compute_batch_fee_model_input_v2(params, 1.0, 1.0)); - assert_eq!(input.l1_gas_price, 3_000_000 * GWEI); - // The fair L2 gas price is identical to the maximum - assert_eq!(input.fair_l2_gas_price, 10_000 * GWEI); - assert_eq!(input.fair_pubdata_price, 1_000_000 * GWEI); - } - #[derive(Debug, Clone)] struct DummyTokenRatioProvider { ratio: BaseTokenConversionRatio, diff --git a/core/node/node_framework/src/implementations/layers/gas_adjuster.rs b/core/node/node_framework/src/implementations/layers/gas_adjuster.rs index 229700289a71..241c4d829beb 100644 --- a/core/node/node_framework/src/implementations/layers/gas_adjuster.rs +++ b/core/node/node_framework/src/implementations/layers/gas_adjuster.rs @@ -1,8 +1,9 @@ use std::sync::Arc; use anyhow::Context; -use zksync_config::{configs::eth_sender::PubdataSendingMode, GasAdjusterConfig, GenesisConfig}; +use zksync_config::{GasAdjusterConfig, GenesisConfig}; use zksync_node_fee_model::l1_gas_price::GasAdjuster; +use zksync_types::pubdata_da::PubdataSendingMode; use crate::{ implementations::resources::{ diff --git a/core/node/node_framework/src/implementations/layers/l1_gas.rs b/core/node/node_framework/src/implementations/layers/l1_gas.rs index 35c4bc3fc205..28f81bb45438 100644 --- a/core/node/node_framework/src/implementations/layers/l1_gas.rs +++ b/core/node/node_framework/src/implementations/layers/l1_gas.rs @@ -1,8 +1,8 @@ use std::sync::Arc; -use zksync_config::configs::chain::StateKeeperConfig; +use zksync_config::configs::chain::{FeeModelVersion, StateKeeperConfig}; use zksync_node_fee_model::{ApiFeeInputProvider, MainNodeFeeInputProvider}; -use zksync_types::fee_model::FeeModelConfig; +use zksync_types::fee_model::{FeeModelConfig, FeeModelConfigV1, FeeModelConfigV2}; use crate::{ implementations::resources::{ @@ -20,7 +20,7 @@ use crate::{ /// Adds several resources that depend on L1 gas price. #[derive(Debug)] pub struct L1GasLayer { - state_keeper_config: StateKeeperConfig, + fee_model_config: FeeModelConfig, } #[derive(Debug, FromContext)] @@ -42,9 +42,25 @@ pub struct Output { } impl L1GasLayer { - pub fn new(state_keeper_config: StateKeeperConfig) -> Self { + pub fn new(state_keeper_config: &StateKeeperConfig) -> Self { Self { - state_keeper_config, + fee_model_config: Self::map_config(state_keeper_config), + } + } + + fn map_config(state_keeper_config: &StateKeeperConfig) -> FeeModelConfig { + match state_keeper_config.fee_model_version { + FeeModelVersion::V1 => FeeModelConfig::V1(FeeModelConfigV1 { + minimal_l2_gas_price: state_keeper_config.minimal_l2_gas_price, + }), + FeeModelVersion::V2 => FeeModelConfig::V2(FeeModelConfigV2 { + minimal_l2_gas_price: state_keeper_config.minimal_l2_gas_price, + compute_overhead_part: state_keeper_config.compute_overhead_part, + pubdata_overhead_part: state_keeper_config.pubdata_overhead_part, + batch_overhead_l1_gas: state_keeper_config.batch_overhead_l1_gas, + max_gas_per_batch: state_keeper_config.max_gas_per_batch, + max_pubdata_per_batch: state_keeper_config.max_pubdata_per_batch, + }), } } } @@ -64,7 +80,7 @@ impl WiringLayer for L1GasLayer { let main_fee_input_provider = Arc::new(MainNodeFeeInputProvider::new( input.gas_adjuster.0.clone(), ratio_provider.0, - FeeModelConfig::from_state_keeper_config(&self.state_keeper_config), + self.fee_model_config, )); let replica_pool = input.replica_pool.get().await?; diff --git a/core/node/state_keeper/src/io/tests/tester.rs b/core/node/state_keeper/src/io/tests/tester.rs index 062fc426e8cc..ad189831bad7 100644 --- a/core/node/state_keeper/src/io/tests/tester.rs +++ b/core/node/state_keeper/src/io/tests/tester.rs @@ -4,7 +4,7 @@ use std::{slice, sync::Arc, time::Duration}; use zksync_base_token_adjuster::NoOpRatioProvider; use zksync_config::{ - configs::{chain::StateKeeperConfig, eth_sender::PubdataSendingMode, wallets::Wallets}, + configs::{chain::StateKeeperConfig, wallets::Wallets}, GasAdjusterConfig, }; use zksync_contracts::BaseSystemContracts; @@ -28,6 +28,7 @@ use zksync_types::{ fee_model::{BatchFeeInput, FeeModelConfig, FeeModelConfigV2}, l2::L2Tx, protocol_version::{L1VerifierConfig, ProtocolSemanticVersion}, + pubdata_da::PubdataSendingMode, system_contracts::get_system_smart_contracts, L2BlockNumber, L2ChainId, PriorityOpId, ProtocolVersionId, H256, }; diff --git a/prover/Cargo.lock b/prover/Cargo.lock index 1408f2b23cd9..dd2df67902ff 100644 --- a/prover/Cargo.lock +++ b/prover/Cargo.lock @@ -8522,7 +8522,6 @@ dependencies = [ "once_cell", "prost 0.12.6", "rlp", - "secp256k1", "serde", "serde_json", "serde_with", @@ -8530,7 +8529,6 @@ dependencies = [ "thiserror", "tracing", "zksync_basic_types", - "zksync_config", "zksync_contracts", "zksync_crypto_primitives", "zksync_mini_merkle_tree", diff --git a/zkstack_cli/Cargo.lock b/zkstack_cli/Cargo.lock index 8750de36c753..63561c02b9d8 100644 --- a/zkstack_cli/Cargo.lock +++ b/zkstack_cli/Cargo.lock @@ -6977,7 +6977,6 @@ dependencies = [ "once_cell", "prost 0.12.6", "rlp", - "secp256k1", "serde", "serde_json", "serde_with", @@ -6985,7 +6984,6 @@ dependencies = [ "thiserror", "tracing", "zksync_basic_types", - "zksync_config", "zksync_contracts", "zksync_crypto_primitives", "zksync_mini_merkle_tree",