From f30aca00962aa34c8a7acd6e4116290a2b214dcb Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Mon, 13 Jan 2025 20:08:10 +1100 Subject: [PATCH] feat(api_server): report gas price based on open batch (#2868) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ `api_server` should report gas price based on the currently open L1 batch as opposed to the latest sealed L2 block. Note: adding `BatchFeeInput` to L1 batch models did not end up being necessary but I think it still makes sense. ## Why ❔ To avoid gas fluctuation issues on chains with low amount of traffic ## 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 `zk fmt` and `zk lint`. --- Cargo.lock | 2 + ...e235deae9a0c54b9713207d53918eb4973600.json | 62 +++++++++++++ ...d30a258bdf36ed98b1422084ef682b29c8cc.json} | 24 ++++- ...33d22c94aa47b7a8863da2afa5ab1a8502bf.json} | 22 ++++- ...eaa79e05b443995c819db0befdcb1449691f.json} | 24 ++++- ...9b01a237f4d0f74c2d387099a3766bf7364b.json} | 24 ++++- ...91f9887cc7dcf456c79bb22edb22cf27682f.json} | 24 ++++- ...635d692a748021ed20b657b6d8f0dfcad5bc.json} | 24 ++++- ...b654bdb1c4139c453889b5fe43902300c361.json} | 24 ++++- ...d94bb65d35ad4b0c819fa7b4afe07d9769e9.json} | 24 ++++- ...95ab975d3e06a6004e01b86b8d4e14788b95.json} | 24 ++++- core/lib/dal/src/blocks_dal.rs | 92 +++++++++++++++---- core/lib/dal/src/models/storage_block.rs | 90 +++++++++++++----- core/lib/types/src/block.rs | 17 +++- core/lib/types/src/fee_model.rs | 24 +++++ core/node/api_server/src/web3/tests/mod.rs | 14 ++- core/node/api_server/src/web3/tests/vm.rs | 88 ++++++++++++++---- core/node/block_reverter/src/tests.rs | 4 +- core/node/fee_model/Cargo.toml | 2 + core/node/fee_model/src/lib.rs | 67 +++++++++++--- core/node/genesis/src/lib.rs | 2 +- .../state_keeper/src/io/seal_logic/mod.rs | 1 + core/node/state_keeper/src/updates/mod.rs | 2 +- core/tests/ts-integration/src/helpers.ts | 47 +++++++++- core/tests/ts-integration/tests/fees.test.ts | 3 + 25 files changed, 627 insertions(+), 104 deletions(-) create mode 100644 core/lib/dal/.sqlx/query-24aca24f8811d87f5ff54757903e235deae9a0c54b9713207d53918eb4973600.json rename core/lib/dal/.sqlx/{query-4bd1a4e612d10f2ca26068c140442f38816f163a3e3fba4fdbb81076b969e970.json => query-442d1b4604c7a4202811d250a531d30a258bdf36ed98b1422084ef682b29c8cc.json} (82%) rename core/lib/dal/.sqlx/{query-4e994d519b9c75e64a74423f8c19fbde6eb6634d7a63005081ffc1eb6c28e9ec.json => query-54f41fccbe8c100015ccf4d87e0e33d22c94aa47b7a8863da2afa5ab1a8502bf.json} (77%) rename core/lib/dal/.sqlx/{query-a42121cd85daeb95ee268ba5cff1806fcc54d73216a7dc54be6ba210ef02d789.json => query-7203b56390ec3768b7f8ed221756eaa79e05b443995c819db0befdcb1449691f.json} (77%) rename core/lib/dal/.sqlx/{query-77864e5eb5eada8edf8f4457aa153369701d7cd5f75ca031bf77ca27d0437cb9.json => query-7cf174da6228113a27dacbcc0eac9b01a237f4d0f74c2d387099a3766bf7364b.json} (84%) rename core/lib/dal/.sqlx/{query-45154c2efc8d07c4f83ae3e229f9892118f5732374e62f35e27800422afb5746.json => query-881ea0a611d35d4a6cc6893067a791f9887cc7dcf456c79bb22edb22cf27682f.json} (75%) rename core/lib/dal/.sqlx/{query-c5aedd2b1871d8f6276a31482caa673e4b5bba059ebe07bbbb64578881db030b.json => query-c70a2e9d09f93b510cb726d6d420635d692a748021ed20b657b6d8f0dfcad5bc.json} (90%) rename core/lib/dal/.sqlx/{query-62e8330881b73917394384adbf73911add046315e5f8877bc57a34e3dadf9e37.json => query-cb1a078ba867415f27a50bdccfbfb654bdb1c4139c453889b5fe43902300c361.json} (82%) rename core/lib/dal/.sqlx/{query-1cb61327bed4d65a3fc81aa2229e01396dacefc0cea8cbcf5807185eb00fc0f7.json => query-d62f8d10c7b469067e20e56d2e58d94bb65d35ad4b0c819fa7b4afe07d9769e9.json} (82%) rename core/lib/dal/.sqlx/{query-b7d448837439a3e3dfe73070d3c20e9c138d0a6d35e9ce7fc396c5e76fbc25dd.json => query-e90a364528fab11f4b0d0e5d069395ab975d3e06a6004e01b86b8d4e14788b95.json} (78%) diff --git a/Cargo.lock b/Cargo.lock index abdd3fb6a5cf..d6e7503bd20f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12439,6 +12439,8 @@ dependencies = [ "zksync_config", "zksync_dal", "zksync_eth_client", + "zksync_node_genesis", + "zksync_node_test_utils", "zksync_types", "zksync_web3_decl", ] diff --git a/core/lib/dal/.sqlx/query-24aca24f8811d87f5ff54757903e235deae9a0c54b9713207d53918eb4973600.json b/core/lib/dal/.sqlx/query-24aca24f8811d87f5ff54757903e235deae9a0c54b9713207d53918eb4973600.json new file mode 100644 index 000000000000..b25eff8b4f55 --- /dev/null +++ b/core/lib/dal/.sqlx/query-24aca24f8811d87f5ff54757903e235deae9a0c54b9713207d53918eb4973600.json @@ -0,0 +1,62 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number,\n is_sealed,\n timestamp,\n protocol_version,\n fee_address,\n l1_gas_price,\n l2_fair_gas_price,\n fair_pubdata_price\n FROM\n l1_batches\n ORDER BY\n number DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "is_sealed", + "type_info": "Bool" + }, + { + "ordinal": 2, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 3, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "fee_address", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "l1_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "l2_fair_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 7, + "name": "fair_pubdata_price", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + true, + false, + false, + false, + false + ] + }, + "hash": "24aca24f8811d87f5ff54757903e235deae9a0c54b9713207d53918eb4973600" +} diff --git a/core/lib/dal/.sqlx/query-4bd1a4e612d10f2ca26068c140442f38816f163a3e3fba4fdbb81076b969e970.json b/core/lib/dal/.sqlx/query-442d1b4604c7a4202811d250a531d30a258bdf36ed98b1422084ef682b29c8cc.json similarity index 82% rename from core/lib/dal/.sqlx/query-4bd1a4e612d10f2ca26068c140442f38816f163a3e3fba4fdbb81076b969e970.json rename to core/lib/dal/.sqlx/query-442d1b4604c7a4202811d250a531d30a258bdf36ed98b1422084ef682b29c8cc.json index 66d3e18075bf..39de8d246376 100644 --- a/core/lib/dal/.sqlx/query-4bd1a4e612d10f2ca26068c140442f38816f163a3e3fba4fdbb81076b969e970.json +++ b/core/lib/dal/.sqlx/query-442d1b4604c7a4202811d250a531d30a258bdf36ed98b1422084ef682b29c8cc.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n LEFT JOIN\n data_availability\n ON data_availability.l1_batch_number = l1_batches.number\n WHERE\n number BETWEEN $1 AND $2\n ORDER BY\n number\n LIMIT\n $3\n ", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data,\n l1_gas_price,\n l2_fair_gas_price,\n fair_pubdata_price\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n LEFT JOIN\n data_availability\n ON data_availability.l1_batch_number = l1_batches.number\n WHERE\n number BETWEEN $1 AND $2\n ORDER BY\n number\n LIMIT\n $3\n ", "describe": { "columns": [ { @@ -162,6 +162,21 @@ "ordinal": 31, "name": "inclusion_data", "type_info": "Bytea" + }, + { + "ordinal": 32, + "name": "l1_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 33, + "name": "l2_fair_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 34, + "name": "fair_pubdata_price", + "type_info": "Int8" } ], "parameters": { @@ -203,8 +218,11 @@ true, true, true, - true + true, + false, + false, + false ] }, - "hash": "4bd1a4e612d10f2ca26068c140442f38816f163a3e3fba4fdbb81076b969e970" + "hash": "442d1b4604c7a4202811d250a531d30a258bdf36ed98b1422084ef682b29c8cc" } diff --git a/core/lib/dal/.sqlx/query-4e994d519b9c75e64a74423f8c19fbde6eb6634d7a63005081ffc1eb6c28e9ec.json b/core/lib/dal/.sqlx/query-54f41fccbe8c100015ccf4d87e0e33d22c94aa47b7a8863da2afa5ab1a8502bf.json similarity index 77% rename from core/lib/dal/.sqlx/query-4e994d519b9c75e64a74423f8c19fbde6eb6634d7a63005081ffc1eb6c28e9ec.json rename to core/lib/dal/.sqlx/query-54f41fccbe8c100015ccf4d87e0e33d22c94aa47b7a8863da2afa5ab1a8502bf.json index 804318120fcc..2cdfad08c830 100644 --- a/core/lib/dal/.sqlx/query-4e994d519b9c75e64a74423f8c19fbde6eb6634d7a63005081ffc1eb6c28e9ec.json +++ b/core/lib/dal/.sqlx/query-54f41fccbe8c100015ccf4d87e0e33d22c94aa47b7a8863da2afa5ab1a8502bf.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n l1_tx_count,\n l2_tx_count,\n timestamp,\n l2_to_l1_messages,\n bloom,\n priority_ops_onchain_data,\n used_contract_hashes,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_emulator_code_hash,\n protocol_version,\n system_logs,\n pubdata_input,\n fee_address\n FROM\n l1_batches\n WHERE\n is_sealed\n AND number = $1\n ", + "query": "\n SELECT\n number,\n l1_tx_count,\n l2_tx_count,\n timestamp,\n l2_to_l1_messages,\n bloom,\n priority_ops_onchain_data,\n used_contract_hashes,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_emulator_code_hash,\n protocol_version,\n system_logs,\n pubdata_input,\n fee_address,\n l1_gas_price,\n l2_fair_gas_price,\n fair_pubdata_price\n FROM\n l1_batches\n WHERE\n is_sealed\n AND number = $1\n ", "describe": { "columns": [ { @@ -77,6 +77,21 @@ "ordinal": 14, "name": "fee_address", "type_info": "Bytea" + }, + { + "ordinal": 15, + "name": "l1_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 16, + "name": "l2_fair_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 17, + "name": "fair_pubdata_price", + "type_info": "Int8" } ], "parameters": { @@ -99,8 +114,11 @@ true, false, true, + false, + false, + false, false ] }, - "hash": "4e994d519b9c75e64a74423f8c19fbde6eb6634d7a63005081ffc1eb6c28e9ec" + "hash": "54f41fccbe8c100015ccf4d87e0e33d22c94aa47b7a8863da2afa5ab1a8502bf" } diff --git a/core/lib/dal/.sqlx/query-a42121cd85daeb95ee268ba5cff1806fcc54d73216a7dc54be6ba210ef02d789.json b/core/lib/dal/.sqlx/query-7203b56390ec3768b7f8ed221756eaa79e05b443995c819db0befdcb1449691f.json similarity index 77% rename from core/lib/dal/.sqlx/query-a42121cd85daeb95ee268ba5cff1806fcc54d73216a7dc54be6ba210ef02d789.json rename to core/lib/dal/.sqlx/query-7203b56390ec3768b7f8ed221756eaa79e05b443995c819db0befdcb1449691f.json index 9a93ba45978e..8a29dbe2158e 100644 --- a/core/lib/dal/.sqlx/query-a42121cd85daeb95ee268ba5cff1806fcc54d73216a7dc54be6ba210ef02d789.json +++ b/core/lib/dal/.sqlx/query-7203b56390ec3768b7f8ed221756eaa79e05b443995c819db0befdcb1449691f.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n system_logs,\n compressed_state_diffs,\n protocol_version,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data\n FROM\n (\n SELECT\n l1_batches.*,\n ROW_NUMBER() OVER (\n ORDER BY\n number ASC\n ) AS row_number\n FROM\n l1_batches\n WHERE\n eth_commit_tx_id IS NOT NULL\n AND l1_batches.skip_proof = TRUE\n AND l1_batches.number > $1\n ORDER BY\n number\n LIMIT\n $2\n ) inn\n LEFT JOIN commitments ON commitments.l1_batch_number = inn.number\n LEFT JOIN data_availability ON data_availability.l1_batch_number = inn.number\n WHERE\n number - row_number = $1\n ", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n system_logs,\n compressed_state_diffs,\n protocol_version,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data,\n l1_gas_price,\n l2_fair_gas_price,\n fair_pubdata_price\n FROM\n (\n SELECT\n l1_batches.*,\n ROW_NUMBER() OVER (\n ORDER BY\n number ASC\n ) AS row_number\n FROM\n l1_batches\n WHERE\n eth_commit_tx_id IS NOT NULL\n AND l1_batches.skip_proof = TRUE\n AND l1_batches.number > $1\n ORDER BY\n number\n LIMIT\n $2\n ) inn\n LEFT JOIN commitments ON commitments.l1_batch_number = inn.number\n LEFT JOIN data_availability ON data_availability.l1_batch_number = inn.number\n WHERE\n number - row_number = $1\n ", "describe": { "columns": [ { @@ -162,6 +162,21 @@ "ordinal": 31, "name": "inclusion_data", "type_info": "Bytea" + }, + { + "ordinal": 32, + "name": "l1_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 33, + "name": "l2_fair_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 34, + "name": "fair_pubdata_price", + "type_info": "Int8" } ], "parameters": { @@ -202,8 +217,11 @@ true, true, true, - true + true, + false, + false, + false ] }, - "hash": "a42121cd85daeb95ee268ba5cff1806fcc54d73216a7dc54be6ba210ef02d789" + "hash": "7203b56390ec3768b7f8ed221756eaa79e05b443995c819db0befdcb1449691f" } diff --git a/core/lib/dal/.sqlx/query-77864e5eb5eada8edf8f4457aa153369701d7cd5f75ca031bf77ca27d0437cb9.json b/core/lib/dal/.sqlx/query-7cf174da6228113a27dacbcc0eac9b01a237f4d0f74c2d387099a3766bf7364b.json similarity index 84% rename from core/lib/dal/.sqlx/query-77864e5eb5eada8edf8f4457aa153369701d7cd5f75ca031bf77ca27d0437cb9.json rename to core/lib/dal/.sqlx/query-7cf174da6228113a27dacbcc0eac9b01a237f4d0f74c2d387099a3766bf7364b.json index f4e08abe31c5..c8548e37a5f6 100644 --- a/core/lib/dal/.sqlx/query-77864e5eb5eada8edf8f4457aa153369701d7cd5f75ca031bf77ca27d0437cb9.json +++ b/core/lib/dal/.sqlx/query-7cf174da6228113a27dacbcc0eac9b01a237f4d0f74c2d387099a3766bf7364b.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n system_logs,\n compressed_state_diffs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n LEFT JOIN\n data_availability\n ON data_availability.l1_batch_number = l1_batches.number\n WHERE\n is_sealed\n AND number = $1\n ", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n system_logs,\n compressed_state_diffs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data,\n l1_gas_price,\n l2_fair_gas_price,\n fair_pubdata_price\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n LEFT JOIN\n data_availability\n ON data_availability.l1_batch_number = l1_batches.number\n WHERE\n is_sealed\n AND number = $1\n ", "describe": { "columns": [ { @@ -162,6 +162,21 @@ "ordinal": 31, "name": "inclusion_data", "type_info": "Bytea" + }, + { + "ordinal": 32, + "name": "l1_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 33, + "name": "l2_fair_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 34, + "name": "fair_pubdata_price", + "type_info": "Int8" } ], "parameters": { @@ -201,8 +216,11 @@ true, true, true, - true + true, + false, + false, + false ] }, - "hash": "77864e5eb5eada8edf8f4457aa153369701d7cd5f75ca031bf77ca27d0437cb9" + "hash": "7cf174da6228113a27dacbcc0eac9b01a237f4d0f74c2d387099a3766bf7364b" } diff --git a/core/lib/dal/.sqlx/query-45154c2efc8d07c4f83ae3e229f9892118f5732374e62f35e27800422afb5746.json b/core/lib/dal/.sqlx/query-881ea0a611d35d4a6cc6893067a791f9887cc7dcf456c79bb22edb22cf27682f.json similarity index 75% rename from core/lib/dal/.sqlx/query-45154c2efc8d07c4f83ae3e229f9892118f5732374e62f35e27800422afb5746.json rename to core/lib/dal/.sqlx/query-881ea0a611d35d4a6cc6893067a791f9887cc7dcf456c79bb22edb22cf27682f.json index 11bff1102932..7eb653119357 100644 --- a/core/lib/dal/.sqlx/query-45154c2efc8d07c4f83ae3e229f9892118f5732374e62f35e27800422afb5746.json +++ b/core/lib/dal/.sqlx/query-881ea0a611d35d4a6cc6893067a791f9887cc7dcf456c79bb22edb22cf27682f.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n l1_batches.timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash,\n l1_batches.evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n LEFT JOIN\n data_availability\n ON data_availability.l1_batch_number = l1_batches.number\n JOIN protocol_versions ON protocol_versions.id = l1_batches.protocol_version\n WHERE\n eth_commit_tx_id IS NULL\n AND number != 0\n AND protocol_versions.bootloader_code_hash = $1\n AND protocol_versions.default_account_code_hash = $2\n AND commitment IS NOT NULL\n AND (\n protocol_versions.id = $3\n OR protocol_versions.upgrade_tx_hash IS NULL\n )\n AND events_queue_commitment IS NOT NULL\n AND bootloader_initial_content_commitment IS NOT NULL\n AND (\n data_availability.inclusion_data IS NOT NULL\n OR $4 IS FALSE\n )\n ORDER BY\n number\n LIMIT\n $5\n ", + "query": "\n SELECT\n number,\n l1_batches.timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash,\n l1_batches.evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data,\n l1_gas_price,\n l2_fair_gas_price,\n fair_pubdata_price\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n LEFT JOIN\n data_availability\n ON data_availability.l1_batch_number = l1_batches.number\n JOIN protocol_versions ON protocol_versions.id = l1_batches.protocol_version\n WHERE\n eth_commit_tx_id IS NULL\n AND number != 0\n AND protocol_versions.bootloader_code_hash = $1\n AND protocol_versions.default_account_code_hash = $2\n AND commitment IS NOT NULL\n AND (\n protocol_versions.id = $3\n OR protocol_versions.upgrade_tx_hash IS NULL\n )\n AND events_queue_commitment IS NOT NULL\n AND bootloader_initial_content_commitment IS NOT NULL\n AND (\n data_availability.inclusion_data IS NOT NULL\n OR $4 IS FALSE\n )\n ORDER BY\n number\n LIMIT\n $5\n ", "describe": { "columns": [ { @@ -162,6 +162,21 @@ "ordinal": 31, "name": "inclusion_data", "type_info": "Bytea" + }, + { + "ordinal": 32, + "name": "l1_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 33, + "name": "l2_fair_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 34, + "name": "fair_pubdata_price", + "type_info": "Int8" } ], "parameters": { @@ -205,8 +220,11 @@ true, true, true, - true + true, + false, + false, + false ] }, - "hash": "45154c2efc8d07c4f83ae3e229f9892118f5732374e62f35e27800422afb5746" + "hash": "881ea0a611d35d4a6cc6893067a791f9887cc7dcf456c79bb22edb22cf27682f" } diff --git a/core/lib/dal/.sqlx/query-c5aedd2b1871d8f6276a31482caa673e4b5bba059ebe07bbbb64578881db030b.json b/core/lib/dal/.sqlx/query-c70a2e9d09f93b510cb726d6d420635d692a748021ed20b657b6d8f0dfcad5bc.json similarity index 90% rename from core/lib/dal/.sqlx/query-c5aedd2b1871d8f6276a31482caa673e4b5bba059ebe07bbbb64578881db030b.json rename to core/lib/dal/.sqlx/query-c70a2e9d09f93b510cb726d6d420635d692a748021ed20b657b6d8f0dfcad5bc.json index f97ea8a6ccd5..1f6a3dfec6ea 100644 --- a/core/lib/dal/.sqlx/query-c5aedd2b1871d8f6276a31482caa673e4b5bba059ebe07bbbb64578881db030b.json +++ b/core/lib/dal/.sqlx/query-c70a2e9d09f93b510cb726d6d420635d692a748021ed20b657b6d8f0dfcad5bc.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n LEFT JOIN\n data_availability\n ON data_availability.l1_batch_number = l1_batches.number\n WHERE\n eth_prove_tx_id IS NOT NULL\n AND eth_execute_tx_id IS NULL\n ORDER BY\n number\n LIMIT\n $1\n ", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data,\n l1_gas_price,\n l2_fair_gas_price,\n fair_pubdata_price\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n LEFT JOIN\n data_availability\n ON data_availability.l1_batch_number = l1_batches.number\n WHERE\n eth_prove_tx_id IS NOT NULL\n AND eth_execute_tx_id IS NULL\n ORDER BY\n number\n LIMIT\n $1\n ", "describe": { "columns": [ { @@ -162,6 +162,21 @@ "ordinal": 31, "name": "inclusion_data", "type_info": "Bytea" + }, + { + "ordinal": 32, + "name": "l1_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 33, + "name": "l2_fair_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 34, + "name": "fair_pubdata_price", + "type_info": "Int8" } ], "parameters": { @@ -201,8 +216,11 @@ true, true, true, - true + true, + false, + false, + false ] }, - "hash": "c5aedd2b1871d8f6276a31482caa673e4b5bba059ebe07bbbb64578881db030b" + "hash": "c70a2e9d09f93b510cb726d6d420635d692a748021ed20b657b6d8f0dfcad5bc" } diff --git a/core/lib/dal/.sqlx/query-62e8330881b73917394384adbf73911add046315e5f8877bc57a34e3dadf9e37.json b/core/lib/dal/.sqlx/query-cb1a078ba867415f27a50bdccfbfb654bdb1c4139c453889b5fe43902300c361.json similarity index 82% rename from core/lib/dal/.sqlx/query-62e8330881b73917394384adbf73911add046315e5f8877bc57a34e3dadf9e37.json rename to core/lib/dal/.sqlx/query-cb1a078ba867415f27a50bdccfbfb654bdb1c4139c453889b5fe43902300c361.json index dfdb4b6c82e7..ab9a270abc7b 100644 --- a/core/lib/dal/.sqlx/query-62e8330881b73917394384adbf73911add046315e5f8877bc57a34e3dadf9e37.json +++ b/core/lib/dal/.sqlx/query-cb1a078ba867415f27a50bdccfbfb654bdb1c4139c453889b5fe43902300c361.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n LEFT JOIN\n data_availability\n ON data_availability.l1_batch_number = l1_batches.number\n WHERE\n eth_commit_tx_id IS NOT NULL\n AND eth_prove_tx_id IS NULL\n ORDER BY\n number\n LIMIT\n $1\n ", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data,\n l1_gas_price,\n l2_fair_gas_price,\n fair_pubdata_price\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n LEFT JOIN\n data_availability\n ON data_availability.l1_batch_number = l1_batches.number\n WHERE\n eth_commit_tx_id IS NOT NULL\n AND eth_prove_tx_id IS NULL\n ORDER BY\n number\n LIMIT\n $1\n ", "describe": { "columns": [ { @@ -162,6 +162,21 @@ "ordinal": 31, "name": "inclusion_data", "type_info": "Bytea" + }, + { + "ordinal": 32, + "name": "l1_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 33, + "name": "l2_fair_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 34, + "name": "fair_pubdata_price", + "type_info": "Int8" } ], "parameters": { @@ -201,8 +216,11 @@ true, true, true, - true + true, + false, + false, + false ] }, - "hash": "62e8330881b73917394384adbf73911add046315e5f8877bc57a34e3dadf9e37" + "hash": "cb1a078ba867415f27a50bdccfbfb654bdb1c4139c453889b5fe43902300c361" } diff --git a/core/lib/dal/.sqlx/query-1cb61327bed4d65a3fc81aa2229e01396dacefc0cea8cbcf5807185eb00fc0f7.json b/core/lib/dal/.sqlx/query-d62f8d10c7b469067e20e56d2e58d94bb65d35ad4b0c819fa7b4afe07d9769e9.json similarity index 82% rename from core/lib/dal/.sqlx/query-1cb61327bed4d65a3fc81aa2229e01396dacefc0cea8cbcf5807185eb00fc0f7.json rename to core/lib/dal/.sqlx/query-d62f8d10c7b469067e20e56d2e58d94bb65d35ad4b0c819fa7b4afe07d9769e9.json index 48adcd412676..5d40770fcf1d 100644 --- a/core/lib/dal/.sqlx/query-1cb61327bed4d65a3fc81aa2229e01396dacefc0cea8cbcf5807185eb00fc0f7.json +++ b/core/lib/dal/.sqlx/query-d62f8d10c7b469067e20e56d2e58d94bb65d35ad4b0c819fa7b4afe07d9769e9.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n LEFT JOIN\n data_availability\n ON data_availability.l1_batch_number = l1_batches.number\n WHERE\n number = 0\n OR eth_commit_tx_id IS NOT NULL\n AND commitment IS NOT NULL\n ORDER BY\n number DESC\n LIMIT\n 1\n ", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data,\n l1_gas_price,\n l2_fair_gas_price,\n fair_pubdata_price\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n LEFT JOIN\n data_availability\n ON data_availability.l1_batch_number = l1_batches.number\n WHERE\n number = 0\n OR eth_commit_tx_id IS NOT NULL\n AND commitment IS NOT NULL\n ORDER BY\n number DESC\n LIMIT\n 1\n ", "describe": { "columns": [ { @@ -162,6 +162,21 @@ "ordinal": 31, "name": "inclusion_data", "type_info": "Bytea" + }, + { + "ordinal": 32, + "name": "l1_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 33, + "name": "l2_fair_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 34, + "name": "fair_pubdata_price", + "type_info": "Int8" } ], "parameters": { @@ -199,8 +214,11 @@ true, true, true, - true + true, + false, + false, + false ] }, - "hash": "1cb61327bed4d65a3fc81aa2229e01396dacefc0cea8cbcf5807185eb00fc0f7" + "hash": "d62f8d10c7b469067e20e56d2e58d94bb65d35ad4b0c819fa7b4afe07d9769e9" } diff --git a/core/lib/dal/.sqlx/query-b7d448837439a3e3dfe73070d3c20e9c138d0a6d35e9ce7fc396c5e76fbc25dd.json b/core/lib/dal/.sqlx/query-e90a364528fab11f4b0d0e5d069395ab975d3e06a6004e01b86b8d4e14788b95.json similarity index 78% rename from core/lib/dal/.sqlx/query-b7d448837439a3e3dfe73070d3c20e9c138d0a6d35e9ce7fc396c5e76fbc25dd.json rename to core/lib/dal/.sqlx/query-e90a364528fab11f4b0d0e5d069395ab975d3e06a6004e01b86b8d4e14788b95.json index 8a68b1a9b9bd..69ac542a8a9a 100644 --- a/core/lib/dal/.sqlx/query-b7d448837439a3e3dfe73070d3c20e9c138d0a6d35e9ce7fc396c5e76fbc25dd.json +++ b/core/lib/dal/.sqlx/query-e90a364528fab11f4b0d0e5d069395ab975d3e06a6004e01b86b8d4e14788b95.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n number,\n l1_batches.timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash,\n l1_batches.evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n JOIN protocol_versions ON protocol_versions.id = l1_batches.protocol_version\n LEFT JOIN\n data_availability\n ON data_availability.l1_batch_number = l1_batches.number\n WHERE\n eth_commit_tx_id IS NULL\n AND number != 0\n AND protocol_versions.bootloader_code_hash = $1\n AND protocol_versions.default_account_code_hash = $2\n AND commitment IS NOT NULL\n AND (\n protocol_versions.id = $3\n OR protocol_versions.upgrade_tx_hash IS NULL\n )\n ORDER BY\n number\n LIMIT\n $4\n ", + "query": "\n SELECT\n number,\n l1_batches.timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n commitment,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash,\n l1_batches.evm_emulator_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input,\n fee_address,\n aggregation_root,\n local_root,\n state_diff_hash,\n data_availability.inclusion_data,\n l1_gas_price,\n l2_fair_gas_price,\n fair_pubdata_price\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n JOIN protocol_versions ON protocol_versions.id = l1_batches.protocol_version\n LEFT JOIN\n data_availability\n ON data_availability.l1_batch_number = l1_batches.number\n WHERE\n eth_commit_tx_id IS NULL\n AND number != 0\n AND protocol_versions.bootloader_code_hash = $1\n AND protocol_versions.default_account_code_hash = $2\n AND commitment IS NOT NULL\n AND (\n protocol_versions.id = $3\n OR protocol_versions.upgrade_tx_hash IS NULL\n )\n ORDER BY\n number\n LIMIT\n $4\n ", "describe": { "columns": [ { @@ -162,6 +162,21 @@ "ordinal": 31, "name": "inclusion_data", "type_info": "Bytea" + }, + { + "ordinal": 32, + "name": "l1_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 33, + "name": "l2_fair_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 34, + "name": "fair_pubdata_price", + "type_info": "Int8" } ], "parameters": { @@ -204,8 +219,11 @@ true, true, true, - true + true, + false, + false, + false ] }, - "hash": "b7d448837439a3e3dfe73070d3c20e9c138d0a6d35e9ce7fc396c5e76fbc25dd" + "hash": "e90a364528fab11f4b0d0e5d069395ab975d3e06a6004e01b86b8d4e14788b95" } diff --git a/core/lib/dal/src/blocks_dal.rs b/core/lib/dal/src/blocks_dal.rs index 9404f4d14332..f39a9c582df9 100644 --- a/core/lib/dal/src/blocks_dal.rs +++ b/core/lib/dal/src/blocks_dal.rs @@ -16,11 +16,10 @@ use zksync_db_connection::{ use zksync_types::{ aggregated_operations::AggregatedActionType, block::{ - L1BatchHeader, L1BatchStatistics, L1BatchTreeData, L2BlockHeader, StorageOracleInfo, - UnsealedL1BatchHeader, + CommonL1BatchHeader, L1BatchHeader, L1BatchStatistics, L1BatchTreeData, L2BlockHeader, + StorageOracleInfo, UnsealedL1BatchHeader, }, commitment::{L1BatchCommitmentArtifacts, L1BatchWithMetadata}, - fee_model::BatchFeeInput, l2_to_l1_log::{BatchAndChainMerklePath, UserL2ToL1Log}, writes::TreeWrite, Address, Bloom, L1BatchNumber, L2BlockNumber, ProtocolVersionId, SLChainId, H256, U256, @@ -32,7 +31,8 @@ use crate::{ models::{ parse_protocol_version, storage_block::{ - StorageL1Batch, StorageL1BatchHeader, StorageL2BlockHeader, UnsealedStorageL1Batch, + CommonStorageL1BatchHeader, StorageL1Batch, StorageL1BatchHeader, StorageL2BlockHeader, + UnsealedStorageL1Batch, }, storage_event::StorageL2ToL1Log, storage_oracle_info::DbStorageOracleInfo, @@ -103,6 +103,7 @@ impl BlocksDal<'_, '_> { Ok(count == 0) } + /// Returns the number of the last sealed L1 batch present in the DB, or `None` if there are no L1 batches. pub async fn get_sealed_l1_batch_number(&mut self) -> DalResult> { let row = sqlx::query!( r#" @@ -122,6 +123,39 @@ impl BlocksDal<'_, '_> { Ok(row.number.map(|num| L1BatchNumber(num as u32))) } + /// Returns latest L1 batch's header (could be unsealed). The header contains fields that are + /// common for both unsealed and sealed batches. Returns `None` if there are no L1 batches. + pub async fn get_latest_l1_batch_header(&mut self) -> DalResult> { + let Some(header) = sqlx::query_as!( + CommonStorageL1BatchHeader, + r#" + SELECT + number, + is_sealed, + timestamp, + protocol_version, + fee_address, + l1_gas_price, + l2_fair_gas_price, + fair_pubdata_price + FROM + l1_batches + ORDER BY + number DESC + LIMIT + 1 + "#, + ) + .instrument("get_latest_l1_batch_header") + .fetch_optional(self.storage) + .await? + else { + return Ok(None); + }; + + Ok(Some(header.into())) + } + pub async fn get_sealed_l2_block_number(&mut self) -> DalResult> { let row = sqlx::query!( r#" @@ -348,7 +382,10 @@ impl BlocksDal<'_, '_> { aggregation_root, local_root, state_diff_hash, - data_availability.inclusion_data + data_availability.inclusion_data, + l1_gas_price, + l2_fair_gas_price, + fair_pubdata_price FROM l1_batches LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number @@ -389,7 +426,10 @@ impl BlocksDal<'_, '_> { protocol_version, system_logs, pubdata_input, - fee_address + fee_address, + l1_gas_price, + l2_fair_gas_price, + fair_pubdata_price FROM l1_batches WHERE @@ -1213,7 +1253,10 @@ impl BlocksDal<'_, '_> { aggregation_root, local_root, state_diff_hash, - data_availability.inclusion_data + data_availability.inclusion_data, + l1_gas_price, + l2_fair_gas_price, + fair_pubdata_price FROM l1_batches LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number @@ -1408,7 +1451,10 @@ impl BlocksDal<'_, '_> { aggregation_root, local_root, state_diff_hash, - data_availability.inclusion_data + data_availability.inclusion_data, + l1_gas_price, + l2_fair_gas_price, + fair_pubdata_price FROM l1_batches LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number @@ -1497,7 +1543,10 @@ impl BlocksDal<'_, '_> { aggregation_root, local_root, state_diff_hash, - data_availability.inclusion_data + data_availability.inclusion_data, + l1_gas_price, + l2_fair_gas_price, + fair_pubdata_price FROM ( SELECT @@ -1577,7 +1626,10 @@ impl BlocksDal<'_, '_> { aggregation_root, local_root, state_diff_hash, - data_availability.inclusion_data + data_availability.inclusion_data, + l1_gas_price, + l2_fair_gas_price, + fair_pubdata_price FROM l1_batches LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number @@ -1737,7 +1789,10 @@ impl BlocksDal<'_, '_> { aggregation_root, local_root, state_diff_hash, - data_availability.inclusion_data + data_availability.inclusion_data, + l1_gas_price, + l2_fair_gas_price, + fair_pubdata_price FROM l1_batches LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number @@ -1810,7 +1865,10 @@ impl BlocksDal<'_, '_> { aggregation_root, local_root, state_diff_hash, - data_availability.inclusion_data + data_availability.inclusion_data, + l1_gas_price, + l2_fair_gas_price, + fair_pubdata_price FROM l1_batches LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number @@ -1897,7 +1955,10 @@ impl BlocksDal<'_, '_> { aggregation_root, local_root, state_diff_hash, - data_availability.inclusion_data + data_availability.inclusion_data, + l1_gas_price, + l2_fair_gas_price, + fair_pubdata_price FROM l1_batches LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number @@ -2910,10 +2971,7 @@ impl BlocksDal<'_, '_> { } pub async fn insert_mock_l1_batch(&mut self, header: &L1BatchHeader) -> anyhow::Result<()> { - self.insert_l1_batch( - header.to_unsealed_header(BatchFeeInput::pubdata_independent(100, 100, 100)), - ) - .await?; + self.insert_l1_batch(header.to_unsealed_header()).await?; self.mark_l1_batch_as_sealed(header, &[], &[], &[], Default::default()) .await } diff --git a/core/lib/dal/src/models/storage_block.rs b/core/lib/dal/src/models/storage_block.rs index 1aea27a497f0..cb61c29190eb 100644 --- a/core/lib/dal/src/models/storage_block.rs +++ b/core/lib/dal/src/models/storage_block.rs @@ -6,9 +6,9 @@ use thiserror::Error; use zksync_contracts::BaseSystemContractsHashes; use zksync_types::{ api, - block::{L1BatchHeader, L2BlockHeader, UnsealedL1BatchHeader}, + block::{CommonL1BatchHeader, L1BatchHeader, L2BlockHeader, UnsealedL1BatchHeader}, commitment::{L1BatchMetaParameters, L1BatchMetadata, PubdataParams, PubdataType}, - fee_model::{BatchFeeInput, L1PeggedBatchFeeModelInput, PubdataIndependentBatchFeeModelInput}, + fee_model::BatchFeeInput, l2_to_l1_log::{L2ToL1Log, SystemL2ToL1Log, UserL2ToL1Log}, Address, Bloom, L1BatchNumber, L2BlockNumber, ProtocolVersionId, SLChainId, H256, }; @@ -54,6 +54,10 @@ pub(crate) struct StorageL1BatchHeader { pub system_logs: Vec>, pub pubdata_input: Option>, pub fee_address: Vec, + + pub l1_gas_price: i64, + pub l2_fair_gas_price: i64, + pub fair_pubdata_price: Option, } impl StorageL1BatchHeader { @@ -69,6 +73,14 @@ impl StorageL1BatchHeader { let system_logs = convert_l2_to_l1_logs(self.system_logs); + let batch_fee_input = BatchFeeInput::from_protocol_version( + self.protocol_version + .map(|v| (v as u16).try_into().unwrap()), + self.l1_gas_price as u64, + self.l2_fair_gas_price as u64, + self.fair_pubdata_price.map(|p| p as u64), + ); + L1BatchHeader { number: L1BatchNumber(self.number as u32), timestamp: self.timestamp as u64, @@ -92,6 +104,7 @@ impl StorageL1BatchHeader { .map(|v| (v as u16).try_into().unwrap()), pubdata_input: self.pubdata_input, fee_address: Address::from_slice(&self.fee_address), + batch_fee_input, } } } @@ -159,6 +172,10 @@ pub(crate) struct StorageL1Batch { pub local_root: Option>, pub state_diff_hash: Option>, pub inclusion_data: Option>, + + pub l1_gas_price: i64, + pub l2_fair_gas_price: i64, + pub fair_pubdata_price: Option, } impl StorageL1Batch { @@ -174,6 +191,14 @@ impl StorageL1Batch { let system_logs = convert_l2_to_l1_logs(self.system_logs); + let batch_fee_input = BatchFeeInput::from_protocol_version( + self.protocol_version + .map(|v| (v as u16).try_into().unwrap()), + self.l1_gas_price as u64, + self.l2_fair_gas_price as u64, + self.fair_pubdata_price.map(|p| p as u64), + ); + L1BatchHeader { number: L1BatchNumber(self.number as u32), timestamp: self.timestamp as u64, @@ -197,6 +222,7 @@ impl StorageL1Batch { .map(|v| (v as u16).try_into().unwrap()), pubdata_input: self.pubdata_input, fee_address: Address::from_slice(&self.fee_address), + batch_fee_input, } } } @@ -307,6 +333,39 @@ impl From for UnsealedL1BatchHeader { } } +/// Partial projection of the columns common to both [`L1BatchHeader`] and [`UnsealedL1BatchHeader`]. +pub(crate) struct CommonStorageL1BatchHeader { + pub number: i64, + pub is_sealed: bool, + pub timestamp: i64, + pub protocol_version: Option, + pub fee_address: Vec, + pub l1_gas_price: i64, + pub l2_fair_gas_price: i64, + pub fair_pubdata_price: Option, +} + +impl From for CommonL1BatchHeader { + fn from(batch: CommonStorageL1BatchHeader) -> Self { + let protocol_version: Option = batch + .protocol_version + .map(|v| (v as u16).try_into().unwrap()); + Self { + number: L1BatchNumber(batch.number as u32), + is_sealed: batch.is_sealed, + timestamp: batch.timestamp as u64, + protocol_version, + fee_address: Address::from_slice(&batch.fee_address), + fee_input: BatchFeeInput::for_protocol_version( + protocol_version.unwrap_or_else(ProtocolVersionId::last_potentially_undefined), + batch.l2_fair_gas_price as u64, + batch.fair_pubdata_price.map(|p| p as u64), + batch.l1_gas_price as u64, + ), + } + } +} + #[derive(Debug, Clone, sqlx::FromRow)] pub(crate) struct StorageBlockDetails { pub number: i64, @@ -512,25 +571,12 @@ pub(crate) struct StorageL2BlockHeader { impl From for L2BlockHeader { fn from(row: StorageL2BlockHeader) -> Self { let protocol_version = row.protocol_version.map(|v| (v as u16).try_into().unwrap()); - - let fee_input = protocol_version - .filter(|version: &ProtocolVersionId| version.is_post_1_4_1()) - .map(|_| { - BatchFeeInput::PubdataIndependent(PubdataIndependentBatchFeeModelInput { - fair_pubdata_price: row - .fair_pubdata_price - .expect("No fair pubdata price for 1.4.1 miniblock") - as u64, - fair_l2_gas_price: row.l2_fair_gas_price as u64, - l1_gas_price: row.l1_gas_price as u64, - }) - }) - .unwrap_or_else(|| { - BatchFeeInput::L1Pegged(L1PeggedBatchFeeModelInput { - fair_l2_gas_price: row.l2_fair_gas_price as u64, - l1_gas_price: row.l1_gas_price as u64, - }) - }); + let batch_fee_input = BatchFeeInput::from_protocol_version( + protocol_version, + row.l1_gas_price as u64, + row.l2_fair_gas_price as u64, + row.fair_pubdata_price.map(|p| p as u64), + ); L2BlockHeader { number: L2BlockNumber(row.number as u32), @@ -540,7 +586,7 @@ impl From for L2BlockHeader { l2_tx_count: row.l2_tx_count as u16, fee_account_address: Address::from_slice(&row.fee_account_address), base_fee_per_gas: row.base_fee_per_gas.to_u64().unwrap(), - batch_fee_input: fee_input, + batch_fee_input, base_system_contracts_hashes: convert_base_system_contracts_hashes( row.bootloader_code_hash, row.default_aa_code_hash, diff --git a/core/lib/types/src/block.rs b/core/lib/types/src/block.rs index c4fd3306f2d5..4ae665656ee1 100644 --- a/core/lib/types/src/block.rs +++ b/core/lib/types/src/block.rs @@ -63,20 +63,22 @@ pub struct L1BatchHeader { pub protocol_version: Option, pub pubdata_input: Option>, pub fee_address: Address, + pub batch_fee_input: BatchFeeInput, } impl L1BatchHeader { - pub fn to_unsealed_header(&self, fee_input: BatchFeeInput) -> UnsealedL1BatchHeader { + pub fn to_unsealed_header(&self) -> UnsealedL1BatchHeader { UnsealedL1BatchHeader { number: self.number, timestamp: self.timestamp, protocol_version: self.protocol_version, fee_address: self.fee_address, - fee_input, + fee_input: self.batch_fee_input, } } } +/// Holder for the metadata that is relevant for unsealed batches. #[derive(Debug, Clone, PartialEq)] pub struct UnsealedL1BatchHeader { pub number: L1BatchNumber, @@ -86,6 +88,16 @@ pub struct UnsealedL1BatchHeader { pub fee_input: BatchFeeInput, } +/// Holder for the metadata that is relevant for both sealed and unsealed batches. +pub struct CommonL1BatchHeader { + pub number: L1BatchNumber, + pub is_sealed: bool, + pub timestamp: u64, + pub protocol_version: Option, + pub fee_address: Address, + pub fee_input: BatchFeeInput, +} + /// Holder for the L2 block metadata that is not available from transactions themselves. #[derive(Debug, Clone, PartialEq)] pub struct L2BlockHeader { @@ -153,6 +165,7 @@ impl L1BatchHeader { protocol_version: Some(protocol_version), pubdata_input: Some(vec![]), fee_address: Default::default(), + batch_fee_input: BatchFeeInput::pubdata_independent(0, 0, 0), } } diff --git a/core/lib/types/src/fee_model.rs b/core/lib/types/src/fee_model.rs index 79515e6f63a9..414295071746 100644 --- a/core/lib/types/src/fee_model.rs +++ b/core/lib/types/src/fee_model.rs @@ -45,6 +45,30 @@ impl BatchFeeInput { fair_pubdata_price, }) } + + pub fn from_protocol_version( + protocol_version: Option, + l1_gas_price: u64, + fair_l2_gas_price: u64, + fair_pubdata_price: Option, + ) -> Self { + protocol_version + .filter(|version: &ProtocolVersionId| version.is_post_1_4_1()) + .map(|_| { + Self::PubdataIndependent(PubdataIndependentBatchFeeModelInput { + fair_pubdata_price: fair_pubdata_price + .expect("No fair pubdata price for 1.4.1"), + fair_l2_gas_price, + l1_gas_price, + }) + }) + .unwrap_or_else(|| { + Self::L1Pegged(L1PeggedBatchFeeModelInput { + fair_l2_gas_price, + l1_gas_price, + }) + }) + } } impl Default for BatchFeeInput { diff --git a/core/node/api_server/src/web3/tests/mod.rs b/core/node/api_server/src/web3/tests/mod.rs index 9c5730a23386..25405b50c508 100644 --- a/core/node/api_server/src/web3/tests/mod.rs +++ b/core/node/api_server/src/web3/tests/mod.rs @@ -32,7 +32,7 @@ use zksync_system_constants::{ }; use zksync_types::{ api, - block::{pack_block_info, L2BlockHasher, L2BlockHeader}, + block::{pack_block_info, L2BlockHasher, L2BlockHeader, UnsealedL1BatchHeader}, bytecode::{ testonly::{PADDED_EVM_BYTECODE, PROCESSED_EVM_BYTECODE}, BytecodeHash, @@ -397,6 +397,18 @@ async fn store_custom_l2_block( Ok(()) } +async fn open_l1_batch( + storage: &mut Connection<'_, Core>, + number: L1BatchNumber, + batch_fee_input: BatchFeeInput, +) -> anyhow::Result { + let mut header = create_l1_batch(number.0); + header.batch_fee_input = batch_fee_input; + let header = header.to_unsealed_header(); + storage.blocks_dal().insert_l1_batch(header.clone()).await?; + Ok(header) +} + async fn seal_l1_batch( storage: &mut Connection<'_, Core>, number: L1BatchNumber, diff --git a/core/node/api_server/src/web3/tests/vm.rs b/core/node/api_server/src/web3/tests/vm.rs index a82ca3b9e347..76c49f7ad6db 100644 --- a/core/node/api_server/src/web3/tests/vm.rs +++ b/core/node/api_server/src/web3/tests/vm.rs @@ -212,20 +212,44 @@ impl HttpTest for CallTest { panic!("Unexpected error: {error:?}"); } - // Check that the method handler fetches fee inputs for recent blocks. To do that, we create a new block - // with a large fee input; it should be loaded by `ApiFeeInputProvider` and override the input provided by the wrapped mock provider. - let mut block_header = create_l2_block(2); - block_header.batch_fee_input = scaled_sensible_fee_input(2.5); - store_custom_l2_block(&mut connection, &block_header, &[]).await?; + // Check that the method handler fetches fee input from the open batch. To do that, we open a new batch + // with a large fee input; it should be loaded by `ApiFeeInputProvider` and used instead of the input + // provided by the wrapped mock provider. + let batch_header = open_l1_batch( + &mut connection, + L1BatchNumber(1), + scaled_sensible_fee_input(3.0), + ) + .await?; // Fee input is not scaled further as per `ApiFeeInputProvider` implementation - self.fee_input.expect_custom(block_header.batch_fee_input); - let call_request = Self::call_request(b"block=3"); - let call_result = client.call(call_request, None, None).await?; + self.fee_input.expect_custom(batch_header.fee_input); + let call_request = Self::call_request(b"block=2"); + let call_result = client.call(call_request.clone(), None, None).await?; + assert_eq!(call_result.0, b"output"); + let call_result = client + .call( + call_request, + Some(api::BlockIdVariant::BlockNumber(api::BlockNumber::Pending)), + None, + ) + .await?; + assert_eq!(call_result.0, b"output"); + + // Logic here is arguable, but we consider "latest" requests to be interested in the newly + // open batch's fee input even if the latest block was sealed in the previous batch. + let call_request = Self::call_request(b"block=1"); + let call_result = client + .call( + call_request.clone(), + Some(api::BlockIdVariant::BlockNumber(api::BlockNumber::Latest)), + None, + ) + .await?; assert_eq!(call_result.0, b"output"); let call_request_without_target = CallRequest { to: None, - ..Self::call_request(b"block=3") + ..Self::call_request(b"block=2") }; let err = client .call(call_request_without_target, None, None) @@ -728,8 +752,11 @@ impl HttpTest for TraceCallTest { pool: &ConnectionPool, ) -> anyhow::Result<()> { // Store an additional L2 block because L2 block #0 has some special processing making it work incorrectly. + // First half of the test asserts API server's behavior when there is no open batch. In other words, + // when `ApiFeeInputProvider` is forced to fetch fee params from the main fee provider. let mut connection = pool.connection().await?; store_l2_block(&mut connection, L2BlockNumber(1), &[]).await?; + seal_l1_batch(&mut connection, L1BatchNumber(1)).await?; self.fee_input.expect_default(Self::FEE_SCALE); let call_request = CallTest::call_request(b"pending"); @@ -775,20 +802,44 @@ impl HttpTest for TraceCallTest { panic!("Unexpected error: {error:?}"); } - // Check that the method handler fetches fee inputs for recent blocks. To do that, we create a new block - // with a large fee input; it should be loaded by `ApiFeeInputProvider` and override the input provided by the wrapped mock provider. - let mut block_header = create_l2_block(2); - block_header.batch_fee_input = scaled_sensible_fee_input(3.0); - store_custom_l2_block(&mut connection, &block_header, &[]).await?; + // Check that the method handler fetches fee input from the open batch. To do that, we open a new batch + // with a large fee input; it should be loaded by `ApiFeeInputProvider` and used instead of the input + // provided by the wrapped mock provider. + let batch_header = open_l1_batch( + &mut connection, + L1BatchNumber(2), + scaled_sensible_fee_input(3.0), + ) + .await?; // Fee input is not scaled further as per `ApiFeeInputProvider` implementation - self.fee_input.expect_custom(block_header.batch_fee_input); - let call_request = CallTest::call_request(b"block=3"); + self.fee_input.expect_custom(batch_header.fee_input); + let call_request = CallTest::call_request(b"block=2"); let call_result = client.trace_call(call_request.clone(), None, None).await?; Self::assert_debug_call(&call_request, &call_result.unwrap_default()); + let call_result = client + .trace_call( + call_request.clone(), + Some(api::BlockId::Number(api::BlockNumber::Pending)), + None, + ) + .await?; + Self::assert_debug_call(&call_request, &call_result.unwrap_default()); + + // Logic here is arguable, but we consider "latest" requests to be interested in the newly + // open batch's fee input even if the latest block was sealed in the previous batch. + let call_request = CallTest::call_request(b"block=1"); + let call_result = client + .trace_call( + call_request.clone(), + Some(api::BlockId::Number(api::BlockNumber::Latest)), + None, + ) + .await?; + Self::assert_debug_call(&call_request, &call_result.unwrap_default()); let call_request_without_target = CallRequest { to: None, - ..CallTest::call_request(b"block=3") + ..CallTest::call_request(b"block=2") }; let err = client .call(call_request_without_target, None, None) @@ -897,12 +948,15 @@ impl HttpTest for TraceCallTestWithEvmEmulator { pool: &ConnectionPool, ) -> anyhow::Result<()> { // Store an additional L2 block because L2 block #0 has some special processing making it work incorrectly. + // And make sure there is no open batch so that `ApiFeeInputProvider` is forced to fetch fee params from + // the main fee provider. let mut connection = pool.connection().await?; let block_header = L2BlockHeader { base_system_contracts_hashes: genesis_contract_hashes(&mut connection).await?, ..create_l2_block(1) }; store_custom_l2_block(&mut connection, &block_header, &[]).await?; + seal_l1_batch(&mut connection, L1BatchNumber(1)).await?; client .trace_call(CallTest::call_request(&[]), None, None) diff --git a/core/node/block_reverter/src/tests.rs b/core/node/block_reverter/src/tests.rs index b2c4ee6465f6..21265e7fb0c6 100644 --- a/core/node/block_reverter/src/tests.rs +++ b/core/node/block_reverter/src/tests.rs @@ -12,6 +12,7 @@ use zksync_object_store::{Bucket, MockObjectStore}; use zksync_state::interface::ReadStorage; use zksync_types::{ block::{L1BatchHeader, L2BlockHeader}, + fee_model::BatchFeeInput, snapshots::SnapshotVersion, AccountTreeId, L2BlockNumber, ProtocolVersion, ProtocolVersionId, StorageKey, StorageLog, }; @@ -60,7 +61,7 @@ async fn setup_storage(storage: &mut Connection<'_, Core>, storage_logs: &[Stora l2_tx_count: 0, fee_account_address: Address::default(), base_fee_per_gas: 0, - batch_fee_input: Default::default(), + batch_fee_input: BatchFeeInput::pubdata_independent(0, 0, 0), gas_per_pubdata_limit: 0, base_system_contracts_hashes: Default::default(), protocol_version: Some(ProtocolVersionId::latest()), @@ -89,6 +90,7 @@ async fn setup_storage(storage: &mut Connection<'_, Core>, storage_logs: &[Stora protocol_version: Some(ProtocolVersionId::latest()), pubdata_input: None, fee_address: Default::default(), + batch_fee_input: BatchFeeInput::pubdata_independent(0, 0, 0), }; storage .blocks_dal() diff --git a/core/node/fee_model/Cargo.toml b/core/node/fee_model/Cargo.toml index a84a7c5c2173..5b40164a029f 100644 --- a/core/node/fee_model/Cargo.toml +++ b/core/node/fee_model/Cargo.toml @@ -25,3 +25,5 @@ tracing.workspace = true [dev-dependencies] test-casing.workspace = true +zksync_node_test_utils.workspace = true +zksync_node_genesis.workspace = true diff --git a/core/node/fee_model/src/lib.rs b/core/node/fee_model/src/lib.rs index 380a279cccc1..a66d05f7cb2e 100644 --- a/core/node/fee_model/src/lib.rs +++ b/core/node/fee_model/src/lib.rs @@ -1,6 +1,6 @@ use std::{fmt, fmt::Debug, sync::Arc}; -use anyhow::Context as _; +use anyhow::Context; use async_trait::async_trait; use zksync_dal::{ConnectionPool, Core, CoreDal}; use zksync_types::fee_model::{ @@ -112,22 +112,34 @@ impl BatchFeeModelInputProvider for ApiFeeInputProvider { l1_gas_price_scale_factor: f64, l1_pubdata_price_scale_factor: f64, ) -> anyhow::Result { + let mut conn = self + .connection_pool + .connection_tagged("api_fee_input_provider") + .await?; + let latest_batch_header = conn + .blocks_dal() + .get_latest_l1_batch_header() + .await? + .context("no batches were found in the DB")?; + + if !latest_batch_header.is_sealed { + tracing::trace!( + latest_batch_number = %latest_batch_header.number, + "Found an open batch; reporting its fee input" + ); + return Ok(latest_batch_header.fee_input); + } + + tracing::trace!( + latest_batch_number = %latest_batch_header.number, + "No open batch found; fetching from base provider" + ); let inner_input = self .inner .get_batch_fee_input_scaled(l1_gas_price_scale_factor, l1_pubdata_price_scale_factor) .await .context("cannot get batch fee input from base provider")?; - let last_l2_block_params = self - .connection_pool - .connection_tagged("api_fee_input_provider") - .await? - .blocks_dal() - .get_last_sealed_l2_block_header() - .await?; - - Ok(last_l2_block_params - .map(|header| inner_input.stricter(header.batch_fee_input)) - .unwrap_or(inner_input)) + Ok(inner_input) } /// Returns the fee model parameters. @@ -161,6 +173,8 @@ mod tests { use l1_gas_price::GasAdjusterClient; use zksync_config::GasAdjusterConfig; use zksync_eth_client::{clients::MockSettlementLayer, BaseFees}; + use zksync_node_genesis::{insert_genesis_batch, GenesisParams}; + use zksync_node_test_utils::create_l1_batch; use zksync_types::{ commitment::L1BatchCommitmentMode, fee_model::{BaseTokenConversionRatio, FeeModelConfigV2}, @@ -378,4 +392,33 @@ mod tests { .await .expect("Failed to create GasAdjuster") } + + #[tokio::test] + async fn test_take_fee_input_from_unsealed_batch() { + let sealed_batch_fee_input = BatchFeeInput::pubdata_independent(1, 2, 3); + let unsealed_batch_fee_input = BatchFeeInput::pubdata_independent(101, 102, 103); + + let pool = ConnectionPool::::test_pool().await; + let mut conn = pool.connection().await.unwrap(); + insert_genesis_batch(&mut conn, &GenesisParams::mock()) + .await + .unwrap(); + + let mut l1_batch_header = create_l1_batch(1); + l1_batch_header.batch_fee_input = sealed_batch_fee_input; + conn.blocks_dal() + .insert_mock_l1_batch(&l1_batch_header) + .await + .unwrap(); + let mut l1_batch_header = create_l1_batch(2); + l1_batch_header.batch_fee_input = unsealed_batch_fee_input; + conn.blocks_dal() + .insert_l1_batch(l1_batch_header.to_unsealed_header()) + .await + .unwrap(); + let provider: &dyn BatchFeeModelInputProvider = + &ApiFeeInputProvider::new(Arc::new(MockBatchFeeParamsProvider::default()), pool); + let fee_input = provider.get_batch_fee_input().await.unwrap(); + assert_eq!(fee_input, unsealed_batch_fee_input); + } } diff --git a/core/node/genesis/src/lib.rs b/core/node/genesis/src/lib.rs index 87457f3b1c01..e68aa59b7696 100644 --- a/core/node/genesis/src/lib.rs +++ b/core/node/genesis/src/lib.rs @@ -517,7 +517,7 @@ pub(crate) async fn create_genesis_l1_batch_from_storage_logs_and_factory_deps( .await?; transaction .blocks_dal() - .insert_l1_batch(genesis_l1_batch_header.to_unsealed_header(batch_fee_input)) + .insert_l1_batch(genesis_l1_batch_header.to_unsealed_header()) .await?; transaction .blocks_dal() diff --git a/core/node/state_keeper/src/io/seal_logic/mod.rs b/core/node/state_keeper/src/io/seal_logic/mod.rs index 655bf182ba8f..475be3319efa 100644 --- a/core/node/state_keeper/src/io/seal_logic/mod.rs +++ b/core/node/state_keeper/src/io/seal_logic/mod.rs @@ -133,6 +133,7 @@ impl UpdatesManager { system_logs: finished_batch.final_execution_state.system_logs.clone(), pubdata_input: finished_batch.pubdata_input.clone(), fee_address: self.fee_account_address, + batch_fee_input: self.batch_fee_input, }; let final_bootloader_memory = finished_batch diff --git a/core/node/state_keeper/src/updates/mod.rs b/core/node/state_keeper/src/updates/mod.rs index 06ac4bcd5de0..b4f548527652 100644 --- a/core/node/state_keeper/src/updates/mod.rs +++ b/core/node/state_keeper/src/updates/mod.rs @@ -30,7 +30,7 @@ pub mod l2_block_updates; pub struct UpdatesManager { batch_timestamp: u64, pub fee_account_address: Address, - batch_fee_input: BatchFeeInput, + pub batch_fee_input: BatchFeeInput, base_fee_per_gas: u64, base_system_contract_hashes: BaseSystemContractsHashes, protocol_version: ProtocolVersionId, diff --git a/core/tests/ts-integration/src/helpers.ts b/core/tests/ts-integration/src/helpers.ts index 40d18f1bad63..d1d84d54a545 100644 --- a/core/tests/ts-integration/src/helpers.ts +++ b/core/tests/ts-integration/src/helpers.ts @@ -3,6 +3,7 @@ import * as zksync from 'zksync-ethers'; import * as ethers from 'ethers'; import * as hre from 'hardhat'; import { ZkSyncArtifact } from '@matterlabs/hardhat-zksync-solc/dist/src/types'; +import { TransactionReceipt } from 'ethers'; export const SYSTEM_CONTEXT_ADDRESS = '0x000000000000000000000000000000000000800b'; @@ -71,13 +72,51 @@ export async function anyTransaction(wallet: zksync.Wallet): Promise { - // Send a dummy transaction and wait until the new L1 batch is created. - const oldReceipt = await anyTransaction(wallet); + const MAX_ATTEMPTS = 3; + + let txResponse = null; + let txReceipt: TransactionReceipt | null = null; + let nonce = Number(await wallet.getNonce()); + for (let i = 0; i < MAX_ATTEMPTS; i++) { + // Send a dummy transaction and wait for it to execute. We override `maxFeePerGas` as the default ethers behavior + // is to fetch `maxFeePerGas` from the latest sealed block and double it which is not enough for scenarios with + // extreme gas price fluctuations. + let gasPrice = await wallet.provider.getGasPrice(); + if (!txResponse || !txResponse.maxFeePerGas || txResponse.maxFeePerGas < gasPrice) { + txResponse = await wallet.transfer({ + to: wallet.address, + amount: 0, + overrides: { maxFeePerGas: gasPrice, nonce: nonce, maxPriorityFeePerGas: 0 } + }); + } else { + console.log('Gas price has not gone up, waiting longer'); + } + txReceipt = await wallet.provider.waitForTransaction(txResponse.hash, 1, 3000).catch((e) => { + if (ethers.isError(e, 'TIMEOUT')) { + console.log(`Transaction timed out, potentially gas price went up (attempt ${i + 1}/${MAX_ATTEMPTS})`); + return null; + } else if (ethers.isError(e, 'UNKNOWN_ERROR') && e.message.match(/Not enough gas/)) { + console.log( + `Transaction did not have enough gas, likely gas price went up (attempt ${i + 1}/${MAX_ATTEMPTS})` + ); + return null; + } else { + return Promise.reject(e); + } + }); + if (txReceipt) { + // Transaction got executed, so we can safely assume it will be sealed in the next batch + break; + } + } + if (!txReceipt) { + throw new Error('Failed to force an L1 batch to seal'); + } // Invariant: even with 1 transaction, l1 batch must be eventually sealed, so this loop must exit. - while (!(await wallet.provider.getTransactionReceipt(oldReceipt.hash))?.l1BatchNumber) { + while (!(await wallet.provider.getTransactionReceipt(txReceipt.hash))?.l1BatchNumber) { await zksync.utils.sleep(wallet.provider.pollingInterval); } - return (await wallet.provider.getTransactionReceipt(oldReceipt.hash))!; + return (await wallet.provider.getTransactionReceipt(txReceipt.hash))!; } /** diff --git a/core/tests/ts-integration/tests/fees.test.ts b/core/tests/ts-integration/tests/fees.test.ts index 765dc8b73a81..628a17febd76 100644 --- a/core/tests/ts-integration/tests/fees.test.ts +++ b/core/tests/ts-integration/tests/fees.test.ts @@ -362,6 +362,9 @@ testFees('Test fees', function () { newPubdataPrice: requiredPubdataPrice }); + // Wait for current batch to close so gas price is updated with the new config set above + await waitForNewL1Batch(alice); + const l1Messenger = new ethers.Contract(zksync.utils.L1_MESSENGER_ADDRESS, zksync.utils.L1_MESSENGER, alice); // Firstly, let's test a successful transaction.