1use crate::peer_handler::DumpError;
2use ethrex_common::{H256, H512, U256, types::AccountState, utils::keccak};
3use ethrex_rlp::encode::RLPEncode;
4use secp256k1::{PublicKey, SecretKey};
5use std::{
6 path::{Path, PathBuf},
7 time::{Duration, SystemTime, UNIX_EPOCH},
8};
9use tracing::error;
10
11pub fn node_id(public_key: &H512) -> H256 {
13 keccak(public_key)
14}
15
16pub fn current_unix_time() -> u64 {
17 SystemTime::now()
18 .duration_since(UNIX_EPOCH)
19 .unwrap_or_default()
20 .as_secs()
21}
22
23pub fn get_msg_expiration_from_seconds(seconds: u64) -> u64 {
24 (SystemTime::now() + Duration::from_secs(seconds))
25 .duration_since(UNIX_EPOCH)
26 .unwrap_or_default()
27 .as_secs()
28}
29
30pub fn is_msg_expired(expiration: u64) -> bool {
31 (expiration as i64) < (current_unix_time() as i64)
34}
35
36pub fn public_key_from_signing_key(signer: &SecretKey) -> H512 {
37 let public_key = PublicKey::from_secret_key(secp256k1::SECP256K1, signer);
38 let encoded = public_key.serialize_uncompressed();
39 H512::from_slice(&encoded[1..])
40}
41
42pub fn delete_leaves_folder(datadir: &Path) {
45 let _ = std::fs::remove_dir_all(get_account_state_snapshots_dir(datadir));
47 let _ = std::fs::remove_dir_all(get_account_storages_snapshots_dir(datadir));
48 let _ = std::fs::remove_dir_all(get_code_hashes_snapshots_dir(datadir));
49 #[cfg(feature = "rocksdb")]
50 {
51 let _ = std::fs::remove_dir_all(get_rocksdb_temp_accounts_dir(datadir));
52 let _ = std::fs::remove_dir_all(get_rocksdb_temp_storage_dir(datadir));
53 };
54}
55
56pub fn get_account_storages_snapshots_dir(datadir: &Path) -> PathBuf {
57 datadir.join("account_storages_snapshots")
58}
59
60pub fn get_account_state_snapshots_dir(datadir: &Path) -> PathBuf {
61 datadir.join("account_state_snapshots")
62}
63
64pub fn get_rocksdb_temp_accounts_dir(datadir: &Path) -> PathBuf {
65 datadir.join("temp_acc_dir")
66}
67
68pub fn get_rocksdb_temp_storage_dir(datadir: &Path) -> PathBuf {
69 datadir.join("temp_storage_dir")
70}
71
72pub fn get_account_state_snapshot_file(directory: &Path, chunk_index: u64) -> PathBuf {
73 directory.join(format!("account_state_chunk.rlp.{chunk_index}"))
74}
75
76pub fn get_account_storages_snapshot_file(directory: &Path, chunk_index: u64) -> PathBuf {
77 directory.join(format!("account_storages_chunk.rlp.{chunk_index}"))
78}
79
80#[cfg(feature = "rocksdb")]
81pub fn dump_accounts_to_rocks_db(
82 path: &Path,
83 mut contents: Vec<(H256, AccountState)>,
84) -> Result<(), rocksdb::Error> {
85 if contents.is_empty() {
88 return Ok(());
89 }
90 contents.sort_by_key(|(k, _)| *k);
91 contents.dedup_by_key(|(k, _)| {
92 let mut buf = [0u8; 32];
93 buf[..32].copy_from_slice(&k.0);
94 buf
95 });
96 let mut buffer: Vec<u8> = Vec::new();
97 let writer_options = rocksdb::Options::default();
98 let mut writer = rocksdb::SstFileWriter::create(&writer_options);
99 writer.open(std::path::Path::new(&path))?;
100 for (key, account) in contents {
101 buffer.clear();
102 account.encode(&mut buffer);
103 writer.put(key.0.as_ref(), buffer.as_slice())?;
104 }
105 writer.finish()
106}
107
108#[cfg(feature = "rocksdb")]
109pub fn dump_storages_to_rocks_db(
110 path: &Path,
111 mut contents: Vec<(H256, H256, U256)>,
112) -> Result<(), rocksdb::Error> {
113 if contents.is_empty() {
116 return Ok(());
117 }
118 contents.sort();
119 contents.dedup_by_key(|(k0, k1, _)| {
120 let mut buffer = [0_u8; 64];
121 buffer[0..32].copy_from_slice(&k0.0);
122 buffer[32..64].copy_from_slice(&k1.0);
123 buffer
124 });
125 let writer_options = rocksdb::Options::default();
126 let mut writer = rocksdb::SstFileWriter::create(&writer_options);
127 let mut buffer_key = [0_u8; 64];
128 let mut buffer_storage: Vec<u8> = Vec::new();
129 writer.open(std::path::Path::new(&path))?;
130 for (account, slot_hash, slot_value) in contents {
131 buffer_key[0..32].copy_from_slice(&account.0);
132 buffer_key[32..64].copy_from_slice(&slot_hash.0);
133 buffer_storage.clear();
134 slot_value.encode(&mut buffer_storage);
135 writer.put(buffer_key.as_ref(), buffer_storage.as_slice())?;
136 }
137 writer.finish()
138}
139
140pub fn get_code_hashes_snapshots_dir(datadir: &Path) -> PathBuf {
141 datadir.join("bytecode_hashes_snapshots")
142}
143
144pub fn get_code_hashes_snapshot_file(directory: &Path, chunk_index: u64) -> PathBuf {
145 directory.join(format!("bytecode_hashes_chunk.rlp.{chunk_index}"))
146}
147
148pub fn dump_to_file(path: &Path, contents: Vec<u8>) -> Result<(), DumpError> {
149 std::fs::write(path, &contents)
150 .inspect_err(|err| error!(%err, ?path, "Failed to dump snapshot to file"))
151 .map_err(|err| DumpError {
152 path: path.to_path_buf(),
153 error: err.kind(),
154 })
155}
156
157pub fn dump_accounts_to_file(
158 path: &Path,
159 accounts: Vec<(H256, AccountState)>,
160) -> Result<(), DumpError> {
161 #[cfg(feature = "rocksdb")]
162 return dump_accounts_to_rocks_db(path, accounts)
163 .inspect_err(|err| error!("RocksDB SST write error: {err:?}"))
164 .map_err(|_| DumpError {
165 path: path.to_path_buf(),
166 error: std::io::ErrorKind::Other,
167 });
168 #[cfg(not(feature = "rocksdb"))]
169 dump_to_file(path, accounts.encode_to_vec())
170}
171
172pub struct AccountsWithStorage {
174 pub accounts: Vec<H256>,
176 pub storages: Vec<(H256, U256)>,
178}
179
180pub fn dump_storages_to_file(
181 path: &Path,
182 storages: Vec<AccountsWithStorage>,
183) -> Result<(), DumpError> {
184 #[cfg(feature = "rocksdb")]
185 return dump_storages_to_rocks_db(
186 path,
187 storages
188 .into_iter()
189 .flat_map(|accounts_with_slots| {
190 accounts_with_slots
191 .accounts
192 .into_iter()
193 .map(|hash| {
194 accounts_with_slots
195 .storages
196 .iter()
197 .map(move |(slot_hash, slot_value)| (hash, *slot_hash, *slot_value))
198 .collect::<Vec<_>>()
199 })
200 .collect::<Vec<_>>()
201 })
202 .flatten()
203 .collect::<Vec<_>>(),
204 )
205 .inspect_err(|err| error!("RocksDB SST write error: {err:?}"))
206 .map_err(|_| DumpError {
207 path: path.to_path_buf(),
208 error: std::io::ErrorKind::Other,
209 });
210
211 #[cfg(not(feature = "rocksdb"))]
212 dump_to_file(
213 path,
214 storages
215 .into_iter()
216 .map(|accounts_with_slots| (accounts_with_slots.accounts, accounts_with_slots.storages))
217 .collect::<Vec<_>>()
218 .encode_to_vec(),
219 )
220}
221
222pub fn distance(node_id_1: &H256, node_id_2: &H256) -> usize {
226 let xor = node_id_1 ^ node_id_2;
227 let distance = U256::from_big_endian(xor.as_bytes());
228 distance.bits()
229}