Skip to content

Commit b8b945b

Browse files
authored
feat: support importing legacy snapshots (#114)
* feat: support legacy storage logs when importing snapshots * chore: endianness * chore: update snapshot header file name
1 parent ab79f68 commit b8b945b

File tree

11 files changed

+1116
-105
lines changed

11 files changed

+1116
-105
lines changed

Cargo.lock

+1,006-66
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ edition = "2021"
55
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
66

77
[workspace]
8-
members = ["state-reconstruct-fetcher", "state-reconstruct-storage"]
8+
members = [
9+
"state-reconstruct-fetcher",
10+
"state-reconstruct-storage",
11+
"state-reconstruct-utils",
12+
]
913

1014
[dependencies]
1115
async-trait = "0.1.74"
@@ -24,6 +28,7 @@ serde = { version = "1.0.189", features = ["derive"] }
2428
serde_json = { version = "1.0.107", features = ["std"] }
2529
state-reconstruct-fetcher = { path = "./state-reconstruct-fetcher" }
2630
state-reconstruct-storage = { path = "./state-reconstruct-storage" }
31+
state-reconstruct-utils = { path = "./state-reconstruct-utils" }
2732
thiserror = "1.0.50"
2833
tikv-jemallocator = "0.5"
2934
tokio = { version = "1.33.0", features = ["macros"] }

src/main.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
mod cli;
55
mod processor;
6-
mod util;
76

87
use std::{
98
env,
@@ -23,17 +22,15 @@ use state_reconstruct_fetcher::{
2322
l1_fetcher::{L1Fetcher, L1FetcherOptions},
2423
types::CommitBlock,
2524
};
25+
use state_reconstruct_utils::json;
2626
use tikv_jemallocator::Jemalloc;
2727
use tokio::sync::mpsc;
2828
use tracing_subscriber::{filter::LevelFilter, EnvFilter};
2929

30-
use crate::{
31-
processor::{
32-
json::JsonSerializationProcessor,
33-
tree::{query_tree::QueryTree, TreeProcessor},
34-
Processor,
35-
},
36-
util::json,
30+
use crate::processor::{
31+
json::JsonSerializationProcessor,
32+
tree::{query_tree::QueryTree, TreeProcessor},
33+
Processor,
3734
};
3835

3936
#[global_allocator]

src/processor/snapshot/importer.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ use ethers::types::U64;
77
use eyre::Result;
88
use regex::{Captures, Regex};
99
use state_reconstruct_storage::types::{
10-
Proto, SnapshotFactoryDependencies, SnapshotHeader, SnapshotStorageLogsChunk,
10+
LegacyProto, Proto, SnapshotFactoryDependencies, SnapshotHeader, SnapshotStorageLogsChunk,
1111
SnapshotStorageLogsChunkMetadata,
12+
SnapshotVersion::{Version0, Version1},
1213
};
1314
use tokio::sync::mpsc::{self, Sender};
1415

@@ -87,7 +88,11 @@ impl SnapshotImporter {
8788
let total_chunks = filepaths.len();
8889
for (i, path) in filepaths.into_iter().enumerate() {
8990
let bytes = fs::read(path)?;
90-
let storage_logs_chunk = SnapshotStorageLogsChunk::decode(&bytes)?;
91+
92+
let storage_logs_chunk = match header.version {
93+
Version0 => SnapshotStorageLogsChunk::decode_legacy(&bytes)?,
94+
Version1 => SnapshotStorageLogsChunk::decode(&bytes)?,
95+
};
9196
tracing::info!("Read chunk {}/{}, processing...", i + 1, total_chunks);
9297
tx.send(storage_logs_chunk).await?;
9398
}

src/processor/snapshot/mod.rs

+2-14
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ pub mod exporter;
66
pub mod importer;
77

88
use async_trait::async_trait;
9-
use blake2::{Blake2s256, Digest};
109
use ethers::types::{Address, H256, U256, U64};
1110
use eyre::Result;
1211
use state_reconstruct_fetcher::{
@@ -17,13 +16,13 @@ use state_reconstruct_storage::{
1716
bytecode,
1817
types::{SnapshotFactoryDependency, SnapshotStorageLog},
1918
};
19+
use state_reconstruct_utils::{derive_final_address_for_params, h256_to_u256, unpack_block_info};
2020
use tokio::sync::mpsc;
2121

2222
use super::Processor;
23-
use crate::util::{h256_to_u256, unpack_block_info};
2423

2524
pub const DEFAULT_DB_PATH: &str = "snapshot_db";
26-
pub const SNAPSHOT_HEADER_FILE_NAME: &str = "snapshot-header.json";
25+
pub const SNAPSHOT_HEADER_FILE_NAME: &str = "snapshot_header.json";
2726
pub const SNAPSHOT_FACTORY_DEPS_FILE_NAME_SUFFIX: &str = "factory_deps.proto.gzip";
2827

2928
pub struct SnapshotBuilder {
@@ -235,17 +234,6 @@ fn reconstruct_genesis_state(database: &mut SnapshotDatabase, path: &str) -> Res
235234
Ok(())
236235
}
237236

238-
fn derive_final_address_for_params(address: &Address, key: &U256) -> [u8; 32] {
239-
let mut buffer = [0u8; 64];
240-
buffer[12..32].copy_from_slice(&address.0);
241-
key.to_big_endian(&mut buffer[32..64]);
242-
243-
let mut result = [0u8; 32];
244-
result.copy_from_slice(Blake2s256::digest(buffer).as_slice());
245-
246-
result
247-
}
248-
249237
#[cfg(test)]
250238
mod tests {
251239
use std::fs;

src/processor/tree/tree_wrapper.rs

+1-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::{collections::HashMap, fs, num::NonZeroU32, path::Path, str::FromStr, sync::Arc};
22

3-
use blake2::{Blake2s256, Digest};
43
use ethers::types::{Address, H256, U256, U64};
54
use eyre::Result;
65
use state_reconstruct_fetcher::{
@@ -10,6 +9,7 @@ use state_reconstruct_fetcher::{
109
use state_reconstruct_storage::{
1110
reconstruction::ReconstructionDatabase, types::SnapshotStorageLogsChunk, PackingType,
1211
};
12+
use state_reconstruct_utils::derive_final_address_for_params;
1313
use thiserror::Error;
1414
use tokio::sync::{
1515
mpsc::{self, Receiver},
@@ -326,14 +326,3 @@ fn reconstruct_genesis_state<D: Database>(
326326

327327
Ok(())
328328
}
329-
330-
fn derive_final_address_for_params(address: &Address, key: &U256) -> [u8; 32] {
331-
let mut buffer = [0u8; 64];
332-
buffer[12..32].copy_from_slice(&address.0);
333-
key.to_big_endian(&mut buffer[32..64]);
334-
335-
let mut result = [0u8; 32];
336-
result.copy_from_slice(Blake2s256::digest(buffer).as_slice());
337-
338-
result
339-
}

state-reconstruct-storage/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ prost = "0.12.4"
1818
rocksdb = "0.21.0"
1919
thiserror = "1.0.50"
2020
zkevm_opcode_defs = { git = "https://github.com/matter-labs/era-zkevm_opcode_defs.git" }
21+
state-reconstruct-utils = { path = "../state-reconstruct-utils" }
2122

2223
[build-dependencies]
2324
prost-build = "0.12.4"

state-reconstruct-storage/src/types.rs

+59-2
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ use std::{
44
};
55

66
use bytes::BytesMut;
7-
use ethers::types::{H256, U256, U64};
7+
use ethers::types::{Address, H256, U256, U64};
88
use eyre::Result;
99
use flate2::{read::GzDecoder, write::GzEncoder, Compression};
1010
use prost::Message;
1111
use serde::{Deserialize, Serialize};
1212
use serde_repr::{Deserialize_repr, Serialize_repr};
13+
use state_reconstruct_utils::derive_final_address_for_params;
1314

1415
use super::bytecode;
1516

@@ -73,6 +74,27 @@ pub trait Proto {
7374
}
7475
}
7576

77+
pub trait LegacyProto {
78+
type ProtoStruct: Message + Default;
79+
80+
fn from_legacy_proto(proto: Self::ProtoStruct) -> Result<Self>
81+
where
82+
Self: Sized;
83+
84+
/// Decode a slice of gzip-compressed bytes into [`Self`].
85+
fn decode_legacy(bytes: &[u8]) -> Result<Self>
86+
where
87+
Self: Sized,
88+
{
89+
let mut decoder = GzDecoder::new(bytes);
90+
let mut decompressed_bytes = Vec::new();
91+
decoder.read_to_end(&mut decompressed_bytes)?;
92+
93+
let proto = Self::ProtoStruct::decode(&decompressed_bytes[..])?;
94+
Self::from_legacy_proto(proto)
95+
}
96+
}
97+
7698
/// Version of snapshot influencing the format of data stored in GCS.
7799
#[derive(Clone, Default, Debug, Serialize_repr, Deserialize_repr)]
78100
#[repr(u16)]
@@ -140,6 +162,20 @@ impl Proto for SnapshotStorageLogsChunk {
140162
}
141163
}
142164

165+
impl LegacyProto for SnapshotStorageLogsChunk {
166+
type ProtoStruct = protobuf::SnapshotStorageLogsChunk;
167+
168+
fn from_legacy_proto(proto: Self::ProtoStruct) -> Result<Self> {
169+
Ok(Self {
170+
storage_logs: proto
171+
.storage_logs
172+
.into_iter()
173+
.map(SnapshotStorageLog::from_legacy_proto)
174+
.collect::<Result<Vec<_>>>()?,
175+
})
176+
}
177+
}
178+
143179
// "most recent" for each key together with info when the key was first used
144180
#[derive(Default, Debug, Serialize, Deserialize)]
145181
pub struct SnapshotStorageLog {
@@ -169,7 +205,28 @@ impl Proto for SnapshotStorageLog {
169205
fn from_proto(proto: Self::ProtoStruct) -> Result<Self> {
170206
let value_bytes: [u8; 32] = proto.storage_value().try_into()?;
171207
Ok(Self {
172-
key: U256::from_big_endian(proto.hashed_key()),
208+
key: StorageKey::from_big_endian(proto.hashed_key()),
209+
value: StorageValue::from(&value_bytes),
210+
l1_batch_number_of_initial_write: proto.l1_batch_number_of_initial_write().into(),
211+
enumeration_index: proto.enumeration_index(),
212+
})
213+
}
214+
}
215+
216+
impl LegacyProto for SnapshotStorageLog {
217+
type ProtoStruct = protobuf::SnapshotStorageLog;
218+
219+
fn from_legacy_proto(proto: Self::ProtoStruct) -> Result<Self> {
220+
let address_bytes: [u8; 20] = proto.account_address().try_into()?;
221+
let address = Address::from(address_bytes);
222+
let storage_key = StorageKey::from_big_endian(proto.storage_key());
223+
let hashed_key = StorageKey::from_little_endian(&derive_final_address_for_params(
224+
&address,
225+
&storage_key,
226+
));
227+
let value_bytes: [u8; 32] = proto.storage_value().try_into()?;
228+
Ok(Self {
229+
key: hashed_key,
173230
value: StorageValue::from(&value_bytes),
174231
l1_batch_number_of_initial_write: proto.l1_batch_number_of_initial_write().into(),
175232
enumeration_index: proto.enumeration_index(),

state-reconstruct-utils/Cargo.toml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[package]
2+
name = "state-reconstruct-utils"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
blake2 = "0.10.6"
10+
ethers = "2.0.14"
11+
primitive-types = "0.12.2"
12+
serde = "1.0.204"
13+
serde_json = "1.0.122"
14+
zksync_storage = { git = "https://github.com/matter-labs/zksync-era.git" }
15+
16+
[build-dependencies]
File renamed without changes.

src/util/mod.rs renamed to state-reconstruct-utils/src/lib.rs

+13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use blake2::{Blake2s256, Digest};
2+
use ethers::types::Address;
13
use primitive_types::{H256, U256};
24

35
pub mod json;
@@ -14,3 +16,14 @@ pub fn unpack_block_info(info: U256) -> (u64, u64) {
1416
let block_timestamp = (info % SYSTEM_BLOCK_INFO_BLOCK_NUMBER_MULTIPLIER).as_u64();
1517
(block_number, block_timestamp)
1618
}
19+
20+
pub fn derive_final_address_for_params(address: &Address, key: &U256) -> [u8; 32] {
21+
let mut buffer = [0u8; 64];
22+
buffer[12..32].copy_from_slice(&address.0);
23+
key.to_big_endian(&mut buffer[32..64]);
24+
25+
let mut result = [0u8; 32];
26+
result.copy_from_slice(Blake2s256::digest(buffer).as_slice());
27+
28+
result
29+
}

0 commit comments

Comments
 (0)