diff --git a/core/lib/dal/sqlx-data.json b/core/lib/dal/sqlx-data.json index 2d1773482ea1..65f7196c7b5b 100644 --- a/core/lib/dal/sqlx-data.json +++ b/core/lib/dal/sqlx-data.json @@ -5720,6 +5720,98 @@ }, "query": "SELECT id FROM prover_fri_protocol_versions WHERE recursion_circuits_set_vks_hash = $1 AND recursion_leaf_level_vk_hash = $2 AND recursion_node_level_vk_hash = $3 AND recursion_scheduler_level_vk_hash = $4 " }, + "6ad9309a48f387da7d437ba6ed94aa7b6a42813e5ee566104b904f0bee0dfde7": { + "describe": { + "columns": [ + { + "name": "number", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "l1_batch_number!", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "last_batch_miniblock?", + "ordinal": 2, + "type_info": "Int8" + }, + { + "name": "timestamp", + "ordinal": 3, + "type_info": "Int8" + }, + { + "name": "l1_gas_price", + "ordinal": 4, + "type_info": "Int8" + }, + { + "name": "l2_fair_gas_price", + "ordinal": 5, + "type_info": "Int8" + }, + { + "name": "bootloader_code_hash", + "ordinal": 6, + "type_info": "Bytea" + }, + { + "name": "default_aa_code_hash", + "ordinal": 7, + "type_info": "Bytea" + }, + { + "name": "virtual_blocks", + "ordinal": 8, + "type_info": "Int8" + }, + { + "name": "hash", + "ordinal": 9, + "type_info": "Bytea" + }, + { + "name": "consensus", + "ordinal": 10, + "type_info": "Jsonb" + }, + { + "name": "protocol_version!", + "ordinal": 11, + "type_info": "Int4" + }, + { + "name": "fee_account_address?", + "ordinal": 12, + "type_info": "Bytea" + } + ], + "nullable": [ + false, + null, + null, + false, + false, + false, + true, + true, + false, + false, + true, + true, + false + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "SELECT miniblocks.number, COALESCE(miniblocks.l1_batch_number, (SELECT (max(number) + 1) FROM l1_batches)) as \"l1_batch_number!\", (SELECT max(m2.number) FROM miniblocks m2 WHERE miniblocks.l1_batch_number = m2.l1_batch_number) as \"last_batch_miniblock?\", miniblocks.timestamp, miniblocks.l1_gas_price, miniblocks.l2_fair_gas_price, miniblocks.bootloader_code_hash, miniblocks.default_aa_code_hash, miniblocks.virtual_blocks, miniblocks.hash, miniblocks.consensus, miniblocks.protocol_version as \"protocol_version!\", l1_batches.fee_account_address as \"fee_account_address?\" FROM miniblocks LEFT JOIN l1_batches ON miniblocks.l1_batch_number = l1_batches.number WHERE miniblocks.number = $1" + }, "6b53e5cb619c9649d28ae33df6a43e6984e2d9320f894f3d04156a2d1235bb60": { "describe": { "columns": [ @@ -6043,104 +6135,6 @@ }, "query": "SELECT * FROM call_traces WHERE tx_hash IN (SELECT hash FROM transactions WHERE miniblock_number = $1)" }, - "7947dd8e7d6c138146f7ebe6b1e89fcd494b2679ac4e9fcff6aa2b2944aeed50": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_batch_number!", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "last_batch_miniblock?", - "ordinal": 2, - "type_info": "Int8" - }, - { - "name": "timestamp", - "ordinal": 3, - "type_info": "Int8" - }, - { - "name": "root_hash?", - "ordinal": 4, - "type_info": "Bytea" - }, - { - "name": "l1_gas_price", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 6, - "type_info": "Int8" - }, - { - "name": "bootloader_code_hash", - "ordinal": 7, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "virtual_blocks", - "ordinal": 9, - "type_info": "Int8" - }, - { - "name": "hash", - "ordinal": 10, - "type_info": "Bytea" - }, - { - "name": "consensus", - "ordinal": 11, - "type_info": "Jsonb" - }, - { - "name": "protocol_version!", - "ordinal": 12, - "type_info": "Int4" - }, - { - "name": "fee_account_address?", - "ordinal": 13, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - null, - null, - false, - false, - false, - false, - true, - true, - false, - false, - true, - true, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "SELECT miniblocks.number, COALESCE(miniblocks.l1_batch_number, (SELECT (max(number) + 1) FROM l1_batches)) as \"l1_batch_number!\", (SELECT max(m2.number) FROM miniblocks m2 WHERE miniblocks.l1_batch_number = m2.l1_batch_number) as \"last_batch_miniblock?\", miniblocks.timestamp, miniblocks.hash as \"root_hash?\", miniblocks.l1_gas_price, miniblocks.l2_fair_gas_price, miniblocks.bootloader_code_hash, miniblocks.default_aa_code_hash, miniblocks.virtual_blocks, miniblocks.hash, miniblocks.consensus, miniblocks.protocol_version as \"protocol_version!\", l1_batches.fee_account_address as \"fee_account_address?\" FROM miniblocks LEFT JOIN l1_batches ON miniblocks.l1_batch_number = l1_batches.number WHERE miniblocks.number = $1" - }, "79cdb4cdd3c47b3654e6240178985fb4b4420e0634f9482a6ef8169e90200b84": { "describe": { "columns": [ diff --git a/core/lib/dal/src/models/storage_sync.rs b/core/lib/dal/src/models/storage_sync.rs index dc15250671bd..e816e5a72ab7 100644 --- a/core/lib/dal/src/models/storage_sync.rs +++ b/core/lib/dal/src/models/storage_sync.rs @@ -5,12 +5,11 @@ use zksync_protobuf::{read_required, ProtoFmt}; use zksync_types::{api::en, Address, L1BatchNumber, MiniblockNumber, Transaction, H160, H256}; #[derive(Debug, Clone, sqlx::FromRow)] -pub struct StorageSyncBlock { +pub(crate) struct StorageSyncBlock { pub number: i64, pub l1_batch_number: i64, pub last_batch_miniblock: Option, pub timestamp: i64, - pub root_hash: Option>, // L1 gas price assumed in the corresponding batch pub l1_gas_price: i64, // L2 gas price assumed in the corresponding batch @@ -48,11 +47,6 @@ impl StorageSyncBlock { .map(|n| n == self.number) .unwrap_or(false), timestamp: self.timestamp.try_into().context("timestamp")?, - root_hash: self - .root_hash - .map(|h| parse_h256(&h)) - .transpose() - .context("root_hash")?, l1_gas_price: self.l1_gas_price.try_into().context("l1_gas_price")?, l2_fair_gas_price: self .l2_fair_gas_price @@ -106,22 +100,25 @@ pub struct ConsensusBlockFields { } impl ConsensusBlockFields { + pub fn decode(src: &en::ConsensusBlockFields) -> anyhow::Result { + zksync_protobuf::decode(&src.0 .0) + } + pub fn encode(&self) -> en::ConsensusBlockFields { en::ConsensusBlockFields(zksync_protobuf::encode(self).into()) } - pub fn decode(x: &en::ConsensusBlockFields) -> anyhow::Result { - zksync_protobuf::decode(&x.0 .0) - } } impl ProtoFmt for ConsensusBlockFields { type Proto = crate::models::proto::ConsensusBlockFields; + fn read(r: &Self::Proto) -> anyhow::Result { Ok(Self { parent: read_required(&r.parent).context("parent")?, justification: read_required(&r.justification).context("justification")?, }) } + fn build(&self) -> Self::Proto { Self::Proto { parent: Some(self.parent.build()), diff --git a/core/lib/dal/src/sync_dal.rs b/core/lib/dal/src/sync_dal.rs index 991469db4692..bf6eeb88cdbb 100644 --- a/core/lib/dal/src/sync_dal.rs +++ b/core/lib/dal/src/sync_dal.rs @@ -27,7 +27,6 @@ impl SyncDal<'_, '_> { COALESCE(miniblocks.l1_batch_number, (SELECT (max(number) + 1) FROM l1_batches)) as \"l1_batch_number!\", \ (SELECT max(m2.number) FROM miniblocks m2 WHERE miniblocks.l1_batch_number = m2.l1_batch_number) as \"last_batch_miniblock?\", \ miniblocks.timestamp, \ - miniblocks.hash as \"root_hash?\", \ miniblocks.l1_gas_price, \ miniblocks.l2_fair_gas_price, \ miniblocks.bootloader_code_hash, \ @@ -47,30 +46,152 @@ impl SyncDal<'_, '_> { .fetch_optional(self.storage.conn()) .await?; - let res = if let Some(storage_block_details) = storage_block_details { - let transactions = if include_transactions { - let block_transactions = sqlx::query_as!( - StorageTransaction, - r#"SELECT * FROM transactions WHERE miniblock_number = $1 ORDER BY index_in_block"#, - block_number.0 as i64 - ) - .instrument("sync_dal_sync_block.transactions") - .with_arg("block_number", &block_number) - .fetch_all(self.storage.conn()) - .await? - .into_iter() - .map(Transaction::from) - .collect(); - Some(block_transactions) - } else { - None - }; - Some(storage_block_details.into_sync_block(current_operator_address, transactions)?) + let Some(storage_block_details) = storage_block_details else { + return Ok(None); + }; + let transactions = if include_transactions { + let transactions = sqlx::query_as!( + StorageTransaction, + r#"SELECT * FROM transactions WHERE miniblock_number = $1 ORDER BY index_in_block"#, + block_number.0 as i64 + ) + .instrument("sync_dal_sync_block.transactions") + .with_arg("block_number", &block_number) + .fetch_all(self.storage.conn()) + .await?; + + Some(transactions.into_iter().map(Transaction::from).collect()) } else { None }; + let block = + storage_block_details.into_sync_block(current_operator_address, transactions)?; drop(latency); - Ok(res) + Ok(Some(block)) + } +} + +#[cfg(test)] +mod tests { + use zksync_types::{ + block::{BlockGasCount, L1BatchHeader}, + fee::TransactionExecutionMetrics, + L1BatchNumber, ProtocolVersion, ProtocolVersionId, + }; + + use super::*; + use crate::{ + tests::{create_miniblock_header, mock_execution_result, mock_l2_transaction}, + ConnectionPool, + }; + + #[tokio::test] + async fn sync_block_basics() { + let pool = ConnectionPool::test_pool().await; + let mut conn = pool.access_storage().await.unwrap(); + + // Simulate genesis. + conn.protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; + conn.blocks_dal() + .insert_miniblock(&create_miniblock_header(0)) + .await + .unwrap(); + let mut l1_batch_header = L1BatchHeader::new( + L1BatchNumber(0), + 0, + Address::repeat_byte(0x42), + Default::default(), + ProtocolVersionId::latest(), + ); + conn.blocks_dal() + .insert_l1_batch(&l1_batch_header, &[], BlockGasCount::default(), &[], &[]) + .await + .unwrap(); + conn.blocks_dal() + .mark_miniblocks_as_executed_in_l1_batch(L1BatchNumber(0)) + .await + .unwrap(); + + let operator_address = Address::repeat_byte(1); + assert!(conn + .sync_dal() + .sync_block(MiniblockNumber(1), operator_address, false) + .await + .unwrap() + .is_none()); + + // Insert another block in the store. + let miniblock_header = create_miniblock_header(1); + let tx = mock_l2_transaction(); + conn.transactions_dal() + .insert_transaction_l2(tx.clone(), TransactionExecutionMetrics::default()) + .await; + conn.blocks_dal() + .insert_miniblock(&miniblock_header) + .await + .unwrap(); + conn.transactions_dal() + .mark_txs_as_executed_in_miniblock( + MiniblockNumber(1), + &[mock_execution_result(tx.clone())], + 1.into(), + ) + .await; + + let block = conn + .sync_dal() + .sync_block(MiniblockNumber(1), operator_address, false) + .await + .unwrap() + .expect("no sync block"); + assert_eq!(block.number, MiniblockNumber(1)); + assert_eq!(block.l1_batch_number, L1BatchNumber(1)); + assert!(!block.last_in_batch); + assert_eq!(block.timestamp, miniblock_header.timestamp); + assert_eq!( + block.protocol_version, + miniblock_header.protocol_version.unwrap() + ); + assert_eq!( + block.virtual_blocks.unwrap(), + miniblock_header.virtual_blocks + ); + assert_eq!(block.l1_gas_price, miniblock_header.l1_gas_price); + assert_eq!(block.l2_fair_gas_price, miniblock_header.l2_fair_gas_price); + assert_eq!(block.operator_address, operator_address); + assert!(block.transactions.is_none()); + + let block = conn + .sync_dal() + .sync_block(MiniblockNumber(1), operator_address, true) + .await + .unwrap() + .expect("no sync block"); + let transactions = block.transactions.unwrap(); + assert_eq!(transactions, [Transaction::from(tx)]); + + l1_batch_header.number = L1BatchNumber(1); + l1_batch_header.timestamp = 1; + conn.blocks_dal() + .insert_l1_batch(&l1_batch_header, &[], BlockGasCount::default(), &[], &[]) + .await + .unwrap(); + conn.blocks_dal() + .mark_miniblocks_as_executed_in_l1_batch(L1BatchNumber(1)) + .await + .unwrap(); + + let block = conn + .sync_dal() + .sync_block(MiniblockNumber(1), operator_address, true) + .await + .unwrap() + .expect("no sync block"); + assert_eq!(block.l1_batch_number, L1BatchNumber(1)); + assert!(block.last_in_batch); + assert_eq!(block.operator_address, l1_batch_header.fee_account_address); } } diff --git a/core/lib/types/src/api/en.rs b/core/lib/types/src/api/en.rs index c1899c2bf3c7..24c92a458e37 100644 --- a/core/lib/types/src/api/en.rs +++ b/core/lib/types/src/api/en.rs @@ -30,8 +30,6 @@ pub struct SyncBlock { pub last_in_batch: bool, /// L2 block timestamp. pub timestamp: u64, - /// Hash of the L2 block (not the Merkle root hash). - pub root_hash: Option, /// L1 gas price used as VM parameter for the L1 batch corresponding to this L2 block. pub l1_gas_price: u64, /// L2 gas price used as VM parameter for the L1 batch corresponding to this L2 block. diff --git a/core/lib/zksync_core/src/sync_layer/tests.rs b/core/lib/zksync_core/src/sync_layer/tests.rs index 3c76e05d93f2..b75eae63f760 100644 --- a/core/lib/zksync_core/src/sync_layer/tests.rs +++ b/core/lib/zksync_core/src/sync_layer/tests.rs @@ -59,7 +59,6 @@ impl MockMainNodeClient { l1_batch_number, last_in_batch: is_fictive, timestamp: number.into(), - root_hash: Some(H256::repeat_byte(1)), l1_gas_price: 2, l2_fair_gas_price: 3, base_system_contracts_hashes: BaseSystemContractsHashes::default(),