Skip to content

Commit faa9186

Browse files
authored
feat: get l2 block number from storage write logs (#110)
* feat: get l2 block number from storage write logs * doc: make comment into code doc * doc: clarify `l1_batch_number` * chore: don't panic on missing l2 batch number * fix: set l1 batch number not l2 batch number
1 parent 6be1288 commit faa9186

File tree

6 files changed

+86
-40
lines changed

6 files changed

+86
-40
lines changed

src/processor/snapshot/exporter.rs

+16-10
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use std::path::{Path, PathBuf};
22

3-
use ethers::types::U256;
4-
use eyre::Result;
5-
use state_reconstruct_fetcher::constants::ethereum::GENESIS_BLOCK;
3+
use ethers::types::{U256, U64};
4+
use eyre::{OptionExt, Result};
65
use state_reconstruct_storage::{
76
snapshot::SnapshotDatabase,
87
snapshot_columns,
@@ -37,14 +36,21 @@ impl SnapshotExporter {
3736
}
3837

3938
pub fn export_snapshot(&self, num_chunks: usize) -> Result<()> {
40-
let latest_l1_batch_number = self.database.get_latest_l1_batch_number()?;
41-
// L1 batch number is calculated from the batch number where the
42-
// DiamondProxy contract was deployed (`GENESIS_BLOCK`).
43-
let l1_batch_number = latest_l1_batch_number - GENESIS_BLOCK;
44-
let l2_batch_number = self.database.get_latest_l2_batch_number()?;
39+
let l2_batch_number = self
40+
.database
41+
.get_latest_l2_batch_number()?
42+
.ok_or_eyre("no latest l2 batch number in snapshot db")?;
43+
let l2_block_number = self.database.get_latest_l2_block_number()?.unwrap_or({
44+
tracing::warn!("WARNING: the database contains no l2 block number entry and will not be compatible with the ZKSync External Node! To export a compatible snapshot, please let the prepare-snapshot command run until an l2 block number can be found.");
45+
U64::from(0)
46+
});
4547
let mut header = SnapshotHeader {
46-
l1_batch_number: l1_batch_number.as_u64(),
47-
miniblock_number: l2_batch_number.as_u64(),
48+
// NOTE: `l1_batch_number` in the snapshot header actually refers
49+
// to the ZKsync batch number and not the Ethereum batch height we
50+
// store in the snapshot database. In the snapshot database this
51+
// field is referred to as `l2_batch_number`.
52+
l1_batch_number: l2_batch_number.as_u64(),
53+
miniblock_number: l2_block_number.as_u64(),
4854
..Default::default()
4955
};
5056

src/processor/snapshot/mod.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use blake2::{Blake2s256, Digest};
1010
use ethers::types::{Address, H256, U256, U64};
1111
use eyre::Result;
1212
use state_reconstruct_fetcher::{
13-
constants::{ethereum, storage},
13+
constants::{ethereum, storage, zksync::L2_BLOCK_NUMBER_ADDRESS},
1414
types::CommitBlock,
1515
};
1616
use state_reconstruct_storage::{
@@ -20,6 +20,7 @@ use state_reconstruct_storage::{
2020
use tokio::sync::mpsc;
2121

2222
use super::Processor;
23+
use crate::util::{h256_to_u256, unpack_block_info};
2324

2425
pub const DEFAULT_DB_PATH: &str = "snapshot_db";
2526
pub const SNAPSHOT_HEADER_FILE_NAME: &str = "snapshot-header.json";
@@ -54,7 +55,9 @@ impl SnapshotBuilder {
5455

5556
// Gets the next L1 batch number to be processed for ues in state recovery.
5657
pub fn get_latest_l1_batch_number(&self) -> Result<U64> {
57-
self.database.get_latest_l1_batch_number()
58+
self.database
59+
.get_latest_l1_batch_number()
60+
.map(|o| o.unwrap_or(U64::from(0)))
5861
}
5962
}
6063

@@ -93,6 +96,14 @@ impl Processor for SnapshotBuilder {
9396
.process_value(U256::from_big_endian(&key[0..32]), *value)
9497
.expect("failed to get key from database");
9598

99+
// We make sure to track writes to the L2 block number address.
100+
if hex::encode(key) == L2_BLOCK_NUMBER_ADDRESS {
101+
let (block_number, _timestamp) = unpack_block_info(h256_to_u256(value));
102+
self.database
103+
.set_latest_l2_block_number(block_number)
104+
.expect("failed to insert latest l2 block number");
105+
}
106+
96107
if self
97108
.database
98109
.update_storage_log_value(index as u64, &value.to_fixed_bytes())
@@ -122,7 +133,7 @@ impl Processor for SnapshotBuilder {
122133

123134
let _ = self
124135
.database
125-
.set_latest_l2_batch_number(block.l2_block_number);
136+
.set_latest_l2_block_number(block.l2_block_number);
126137

127138
if let Some(number) = block.l1_block_number {
128139
let _ = self.database.set_latest_l1_batch_number(number);

src/util/mod.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1 +1,16 @@
1+
use primitive_types::{H256, U256};
2+
13
pub mod json;
4+
5+
pub const SYSTEM_BLOCK_INFO_BLOCK_NUMBER_MULTIPLIER: U256 = U256([0, 0, 1, 0]);
6+
7+
pub fn h256_to_u256(num: H256) -> U256 {
8+
U256::from_big_endian(num.as_bytes())
9+
}
10+
11+
/// Returns block.number/timestamp based on the block's information
12+
pub fn unpack_block_info(info: U256) -> (u64, u64) {
13+
let block_number = (info / SYSTEM_BLOCK_INFO_BLOCK_NUMBER_MULTIPLIER).as_u64();
14+
let block_timestamp = (info % SYSTEM_BLOCK_INFO_BLOCK_NUMBER_MULTIPLIER).as_u64();
15+
(block_number, block_timestamp)
16+
}

state-reconstruct-fetcher/src/constants.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,16 @@ pub mod storage {
3232
pub mod zksync {
3333
/// Bytes in raw L2 to L1 log.
3434
pub const L2_TO_L1_LOG_SERIALIZE_SIZE: usize = 88;
35-
// The bitmask by applying which to the compressed state diff metadata we retrieve its operation.
35+
/// The bitmask by applying which to the compressed state diff metadata we retrieve its operation.
3636
pub const OPERATION_BITMASK: u8 = 7;
37-
// The number of bits shifting the compressed state diff metadata by which we retrieve its length.
37+
/// The number of bits shifting the compressed state diff metadata by which we retrieve its length.
3838
pub const LENGTH_BITS_OFFSET: u8 = 3;
39-
// Size of `CommitBatchInfo.pubdataCommitments` item.
39+
/// Size of `CommitBatchInfo.pubdataCommitments` item.
4040
pub const PUBDATA_COMMITMENT_SIZE: usize = 144;
41-
// The number of trailing bytes to ignore when using calldata post-blobs. Contains unused blob commitments.
41+
/// The number of trailing bytes to ignore when using calldata post-blobs. Contains unused blob commitments.
4242
pub const CALLDATA_SOURCE_TAIL_SIZE: usize = 32;
43+
44+
/// The storage address where the latest L2 block number is written to.
45+
pub const L2_BLOCK_NUMBER_ADDRESS: &str =
46+
"5e5a67d1b864c576f39bb2b77c6537744c0f03515abce63b473bb7c56ad07d8e";
4347
}

state-reconstruct-storage/src/lib.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ pub mod snapshot_columns {
2424
pub const FACTORY_DEPS: &str = "factory_deps";
2525

2626
pub const LAST_REPEATED_KEY_INDEX: &str = "SNAPSHOT_LAST_REPEATED_KEY_INDEX";
27-
/// The latest l1 block number that was processed.
27+
/// The latest l1 batch number that was processed.
2828
pub const LATEST_L1_BATCH: &str = "SNAPSHOT_LATEST_L1_BATCH";
29-
/// The latest l2 block number that was processed.
29+
/// The latest l2 batch number that was processed.
3030
pub const LATEST_L2_BATCH: &str = "SNAPSHOT_LATEST_L2_BATCH";
31+
/// The latest l2 block number that was processed.
32+
pub const LATEST_L2_BLOCK: &str = "SNAPSHOT_LATEST_L2_BLOCK";
3133
}
3234

3335
// NOTE: This is moved here as a temporary measure to resolve a cyclic dependency issue.

state-reconstruct-storage/src/snapshot.rs

+29-21
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ impl SnapshotDatabase {
3838
snapshot_columns::FACTORY_DEPS,
3939
snapshot_columns::LATEST_L1_BATCH,
4040
snapshot_columns::LATEST_L2_BATCH,
41+
snapshot_columns::LATEST_L2_BLOCK,
4142
],
4243
)?;
4344

@@ -60,6 +61,7 @@ impl SnapshotDatabase {
6061
snapshot_columns::FACTORY_DEPS,
6162
snapshot_columns::LATEST_L1_BATCH,
6263
snapshot_columns::LATEST_L2_BATCH,
64+
snapshot_columns::LATEST_L2_BLOCK,
6365
],
6466
false,
6567
)?;
@@ -154,50 +156,56 @@ impl SnapshotDatabase {
154156
.map_err(Into::into)
155157
}
156158

157-
pub fn get_latest_l1_batch_number(&self) -> Result<U64> {
159+
pub fn get_latest_l1_batch_number(&self) -> Result<Option<U64>> {
158160
self.get_metadata_value(snapshot_columns::LATEST_L1_BATCH)
159-
.map(U64::from)
161+
.map(|o| o.map(U64::from))
160162
}
161163

162164
pub fn set_latest_l1_batch_number(&self, number: u64) -> Result<()> {
163165
self.set_metadata_value(snapshot_columns::LATEST_L1_BATCH, number)
164166
}
165167

166-
pub fn get_latest_l2_batch_number(&self) -> Result<U64> {
168+
pub fn get_latest_l2_batch_number(&self) -> Result<Option<U64>> {
167169
self.get_metadata_value(snapshot_columns::LATEST_L2_BATCH)
168-
.map(U64::from)
170+
.map(|o| o.map(U64::from))
169171
}
170172

171173
pub fn set_latest_l2_batch_number(&self, number: u64) -> Result<()> {
172174
self.set_metadata_value(snapshot_columns::LATEST_L2_BATCH, number)
173175
}
174176

177+
pub fn get_latest_l2_block_number(&self) -> Result<Option<U64>> {
178+
self.get_metadata_value(snapshot_columns::LATEST_L2_BLOCK)
179+
.map(|o| o.map(U64::from))
180+
}
181+
182+
pub fn set_latest_l2_block_number(&self, number: u64) -> Result<()> {
183+
self.set_metadata_value(snapshot_columns::LATEST_L2_BLOCK, number)
184+
}
185+
175186
pub fn get_last_repeated_key_index(&self) -> Result<u64> {
176187
self.get_metadata_value(snapshot_columns::LAST_REPEATED_KEY_INDEX)
188+
.map(|o| o.unwrap_or(0))
177189
}
178190

179191
pub fn set_last_repeated_key_index(&self, idx: u64) -> Result<()> {
180192
self.set_metadata_value(snapshot_columns::LAST_REPEATED_KEY_INDEX, idx)
181193
}
182194

183-
fn get_metadata_value(&self, value_name: &str) -> Result<u64> {
195+
fn get_metadata_value(&self, value_name: &str) -> Result<Option<u64>> {
184196
let metadata = self.cf_handle(METADATA).unwrap();
185-
Ok(
186-
if let Some(idx_bytes) = self.get_cf(metadata, value_name)? {
187-
u64::from_be_bytes([
188-
idx_bytes[0],
189-
idx_bytes[1],
190-
idx_bytes[2],
191-
idx_bytes[3],
192-
idx_bytes[4],
193-
idx_bytes[5],
194-
idx_bytes[6],
195-
idx_bytes[7],
196-
])
197-
} else {
198-
0
199-
},
200-
)
197+
Ok(self.get_cf(metadata, value_name)?.map(|idx_bytes| {
198+
u64::from_be_bytes([
199+
idx_bytes[0],
200+
idx_bytes[1],
201+
idx_bytes[2],
202+
idx_bytes[3],
203+
idx_bytes[4],
204+
idx_bytes[5],
205+
idx_bytes[6],
206+
idx_bytes[7],
207+
])
208+
}))
201209
}
202210

203211
fn set_metadata_value(&self, value_name: &str, value: u64) -> Result<()> {

0 commit comments

Comments
 (0)