1#[cfg(feature = "rocksdb")]
2use crate::backend::rocksdb::RocksDBBackend;
3use crate::{
4 STORE_METADATA_FILENAME, STORE_SCHEMA_VERSION,
5 api::{
6 StorageBackend, StorageReadView, StorageWriteBatch,
7 tables::{
8 ACCOUNT_CODE_METADATA, ACCOUNT_CODES, ACCOUNT_FLATKEYVALUE, ACCOUNT_TRIE_NODES,
9 BAD_BLOCKS, BLOCK_ACCESS_LISTS, BLOCK_NUMBERS, BODIES, CANONICAL_BLOCK_HASHES,
10 CHAIN_DATA, EXECUTION_WITNESSES, FULLSYNC_HEADERS, HEADERS, INVALID_CHAINS,
11 MISC_VALUES, PENDING_BLOCKS, RECEIPTS_V2, SNAP_STATE, STORAGE_FLATKEYVALUE,
12 STORAGE_TRIE_NODES, TRANSACTION_LOCATIONS,
13 },
14 },
15 apply_prefix,
16 backend::in_memory::InMemoryBackend,
17 block_data_buffer::BlockDataBuffer,
18 error::StoreError,
19 layering::{TrieLayerCache, TrieWrapper},
20 rlp::{BlockBodyRLP, BlockHeaderRLP, BlockRLP},
21 trie::{BackendTrieDB, BackendTrieDBLocked},
22 utils::{ChainDataIndex, SnapStateIndex},
23};
24
25use ethrex_common::{
26 Address, H256, U256,
27 types::{
28 AccountInfo, AccountState, AccountUpdate, Block, BlockBody, BlockHash, BlockHeader,
29 BlockNumber, ChainConfig, Code, CodeMetadata, ForkId, Genesis, GenesisAccount, Index,
30 Receipt, Transaction,
31 block_access_list::BlockAccessList,
32 block_execution_witness::{ExecutionWitness, RpcExecutionWitness},
33 },
34 utils::keccak,
35};
36use ethrex_crypto::{NativeCrypto, keccak::keccak_hash};
37use ethrex_rlp::{
38 decode::{RLPDecode, decode_bytes},
39 encode::RLPEncode,
40};
41use ethrex_trie::{EMPTY_TRIE_HASH, Nibbles, Trie, TrieLogger, TrieNode, TrieWitness};
42use ethrex_trie::{Node, NodeRLP};
43use lru::LruCache;
44use rayon::prelude::*;
45use rustc_hash::FxBuildHasher;
46use serde::{Deserialize, Serialize};
47use std::{
48 collections::{BTreeMap, HashMap, HashSet, hash_map::Entry},
49 fmt::Debug,
50 io::Write,
51 path::{Path, PathBuf},
52 sync::{
53 Arc, Condvar, Mutex, RwLock,
54 atomic::{AtomicUsize, Ordering},
55 mpsc::{SyncSender, TryRecvError, sync_channel},
56 },
57 thread::JoinHandle,
58};
59use tracing::{debug, error, info, warn};
60
61pub const MAX_WITNESSES: u64 = 128;
63
64pub const DB_COMMIT_THRESHOLD: usize = 128;
68const IN_MEMORY_COMMIT_THRESHOLD: usize = 10000;
69
70const BATCH_COMMIT_THRESHOLD: usize = 4;
76
77pub const DEFAULT_ROCKSDB_BLOCK_CACHE_SIZE_BYTES: usize = 12 * 1024 * 1024 * 1024;
87
88#[derive(Debug, Clone, Copy)]
93pub struct StoreConfig {
94 pub rocksdb_block_cache_size: usize,
99 pub persist_channel_capacity: usize,
104}
105
106impl Default for StoreConfig {
107 fn default() -> Self {
108 Self {
109 rocksdb_block_cache_size: DEFAULT_ROCKSDB_BLOCK_CACHE_SIZE_BYTES,
110 persist_channel_capacity: DEFAULT_PERSIST_CHANNEL_CAPACITY,
111 }
112 }
113}
114
115#[derive(Debug, PartialEq)]
117enum FKVGeneratorControlMessage {
118 Stop,
119 Continue,
120}
121
122const CODE_CACHE_MAX_SIZE: u64 = 64 * 1024 * 1024;
124
125const FLUSHED_UPTO_KEY: &[u8] = b"bodies_flushed_upto";
127
128const BAD_BLOCKS_KEY: &[u8] = b"bad_blocks";
130
131const MAX_BAD_BLOCKS: usize = 16;
133
134#[derive(Debug)]
135struct CodeCache {
136 inner_cache: LruCache<H256, Code, FxBuildHasher>,
137 cache_size: u64,
138}
139
140impl Default for CodeCache {
141 fn default() -> Self {
142 Self {
143 inner_cache: LruCache::unbounded_with_hasher(FxBuildHasher),
144 cache_size: 0,
145 }
146 }
147}
148
149impl CodeCache {
150 fn get(&mut self, code_hash: &H256) -> Result<Option<Code>, StoreError> {
151 Ok(self.inner_cache.get(code_hash).cloned())
152 }
153
154 fn insert(&mut self, code: &Code) -> Result<(), StoreError> {
155 let code_size = code.size();
156 let cache_len = self.inner_cache.len() + 1;
157 self.cache_size += code_size as u64;
158 let current_size = self.cache_size;
159 debug!(
160 "[ACCOUNT CODE CACHE] cache elements (): {cache_len}, total size: {current_size} bytes"
161 );
162
163 while self.cache_size > CODE_CACHE_MAX_SIZE {
164 if let Some((_, code)) = self.inner_cache.pop_lru() {
165 self.cache_size -= code.size() as u64;
166 } else {
167 break;
168 }
169 }
170
171 self.inner_cache.get_or_insert(code.hash, || code.clone());
172 Ok(())
173 }
174}
175
176#[derive(Debug, Clone)]
182pub struct Store {
183 db_path: PathBuf,
185 backend: Arc<dyn StorageBackend>,
187 chain_config: ChainConfig,
189 trie_cache: Arc<RwLock<Arc<TrieLayerCache>>>,
191 flatkeyvalue_control_tx: std::sync::mpsc::SyncSender<FKVGeneratorControlMessage>,
193 block_data_buffer: Arc<RwLock<Arc<BlockDataBuffer>>>,
195 persist_tx: std::sync::mpsc::SyncSender<PersistMessage>,
199 pending_trie_roots: Arc<PendingTrieRoots>,
203 latest_block_header: LatestBlockHeaderCache,
206 last_computed_flatkeyvalue: Arc<RwLock<Vec<u8>>>,
208
209 account_code_cache: Arc<Mutex<CodeCache>>,
214
215 code_metadata_cache: Arc<Mutex<rustc_hash::FxHashMap<H256, CodeMetadata>>>,
218
219 fcu_lock: Arc<tokio::sync::Mutex<()>>,
222
223 safe_commit_root: Arc<RwLock<H256>>,
229
230 background_threads: Arc<ThreadList>,
231}
232
233#[derive(Debug, Default)]
234struct ThreadList {
235 list: Vec<JoinHandle<()>>,
236}
237
238impl Drop for ThreadList {
239 fn drop(&mut self) {
240 for handle in self.list.drain(..) {
241 let _ = handle.join();
242 }
243 }
244}
245
246pub type StorageTrieNodes = Vec<(H256, Vec<(Nibbles, Vec<u8>)>)>;
251type StorageTries = HashMap<Address, (TrieWitness, Trie)>;
252
253#[derive(Debug, Clone, Copy, PartialEq, Eq)]
257pub enum EngineType {
258 InMemory,
260 #[cfg(feature = "rocksdb")]
262 RocksDB,
263}
264
265pub struct UpdateBatch {
270 pub account_updates: Vec<TrieNode>,
272 pub storage_updates: Vec<(H256, Vec<TrieNode>)>,
274 pub blocks: Vec<Block>,
276 pub receipts: Vec<(H256, Vec<Receipt>)>,
278 pub code_updates: Vec<(H256, Code)>,
280 pub batch_mode: bool,
284}
285
286pub type StorageUpdates = Vec<(H256, Vec<(Nibbles, Vec<u8>)>)>;
288
289pub struct AccountUpdatesList {
294 pub state_trie_hash: H256,
296 pub state_updates: Vec<(Nibbles, Vec<u8>)>,
298 pub storage_updates: StorageUpdates,
300 pub code_updates: Vec<(H256, Code)>,
302}
303
304pub(crate) fn encode_tx_location_operand(
315 block_number: BlockNumber,
316 block_hash: BlockHash,
317 index: Index,
318) -> Vec<u8> {
319 vec![(block_number, block_hash, index)].encode_to_vec()
320}
321
322pub fn tx_locations_merge(
340 existing: Option<&[u8]>,
341 operands: impl IntoIterator<Item = impl AsRef<[u8]>>,
342) -> Option<Vec<u8>> {
343 fn fold_chunk(
347 list: &mut Vec<(BlockNumber, BlockHash, Index)>,
348 bytes: &[u8],
349 what: &str,
350 ) -> bool {
351 match <Vec<(BlockNumber, BlockHash, Index)>>::decode(bytes) {
352 Ok(entries) => {
353 for (bn, bh, idx) in entries {
354 list.retain(|(_, existing_bh, _)| *existing_bh != bh);
355 list.push((bn, bh, idx));
356 }
357 true
358 }
359 Err(e) => {
360 error!(
361 "tx_locations_merge: failed to decode {what} ({} bytes): {e}; \
362 aborting merge to avoid silent data loss",
363 bytes.len()
364 );
365 false
366 }
367 }
368 }
369
370 let mut list: Vec<(BlockNumber, BlockHash, Index)> = Vec::new();
371
372 if let Some(bytes) = existing
374 && !fold_chunk(&mut list, bytes, "existing value")
375 {
376 return None;
377 }
378 for op in operands {
379 if !fold_chunk(&mut list, op.as_ref(), "operand") {
380 return None;
381 }
382 }
383 Some(list.encode_to_vec())
384}
385
386impl Store {
387 pub async fn wait_for_persistence_idle(&self) -> Result<(), StoreError> {
398 let tx = self.persist_tx.clone();
399 tokio::task::spawn_blocking(move || {
400 let (ack_tx, ack_rx) = sync_channel::<Result<(), StoreError>>(1);
401 tx.send(PersistMessage::Ping(ack_tx))
402 .map_err(|e| StoreError::Custom(format!("wait_for_persistence_idle send: {e}")))?;
403 ack_rx
404 .recv()
405 .map_err(|e| StoreError::Custom(format!("wait_for_persistence_idle ack: {e}")))?
406 })
407 .await
408 .map_err(|e| StoreError::Custom(format!("wait_for_persistence_idle join: {e}")))?
409 }
410
411 pub async fn shutdown(&self) -> Result<(), StoreError> {
430 let tx = self.persist_tx.clone();
431 let backend = self.backend.clone();
432 tokio::task::spawn_blocking(move || {
433 let (ack_tx, ack_rx) = sync_channel::<Result<(), StoreError>>(1);
434 tx.send(PersistMessage::Shutdown { ack: ack_tx })
435 .map_err(|e| StoreError::Custom(format!("shutdown send: {e}")))?;
436 ack_rx
437 .recv()
438 .map_err(|e| StoreError::Custom(format!("shutdown ack: {e}")))??;
439 backend.flush()
442 })
443 .await
444 .map_err(|e| StoreError::Custom(format!("shutdown join: {e}")))?
445 }
446
447 pub async fn add_block(&self, block: Block) -> Result<(), StoreError> {
450 self.add_blocks(vec![block]).await
451 }
452
453 pub async fn add_blocks(&self, blocks: Vec<Block>) -> Result<(), StoreError> {
456 let db = self.backend.clone();
457 tokio::task::spawn_blocking(move || {
458 let mut tx = db.begin_write()?;
459
460 for block in blocks {
461 write_block_data(
462 tx.as_mut(),
463 block.header.number,
464 block.hash(),
465 &block.header,
466 &block.body,
467 )?;
468 }
469
470 tx.commit()
471 })
472 .await
473 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
474 }
475
476 pub async fn add_block_header(
478 &self,
479 block_hash: BlockHash,
480 block_header: BlockHeader,
481 ) -> Result<(), StoreError> {
482 let hash_key = block_hash.encode_to_vec();
483 let header_value = BlockHeaderRLP::from(block_header).into_vec();
484 self.write_async(HEADERS, hash_key, header_value).await
485 }
486
487 pub async fn add_block_headers(
489 &self,
490 block_headers: Vec<BlockHeader>,
491 ) -> Result<(), StoreError> {
492 let mut txn = self.backend.begin_write()?;
493
494 for header in block_headers {
495 let block_hash = header.hash();
496 let block_number = header.number;
497 let hash_key = block_hash.encode_to_vec();
498 let header_value = BlockHeaderRLP::from(header).into_vec();
499
500 txn.put(HEADERS, &hash_key, &header_value)?;
501
502 let number_key = block_number.to_le_bytes().to_vec();
503 txn.put(BLOCK_NUMBERS, &hash_key, &number_key)?;
504 }
505 txn.commit()?;
506 Ok(())
507 }
508
509 pub fn get_block_header(
511 &self,
512 block_number: BlockNumber,
513 ) -> Result<Option<BlockHeader>, StoreError> {
514 let latest = self.latest_block_header.get();
515 if block_number == latest.number {
516 return Ok(Some((*latest).clone()));
517 }
518 let Some(block_hash) = self.get_canonical_block_hash_sync(block_number)? else {
523 return Ok(None);
524 };
525 self.get_block_header_by_hash(block_hash)
526 }
527
528 pub async fn add_block_body(
530 &self,
531 block_hash: BlockHash,
532 block_body: BlockBody,
533 ) -> Result<(), StoreError> {
534 let hash_key = block_hash.encode_to_vec();
535 let body_value = BlockBodyRLP::from(block_body).into_vec();
536 self.write_async(BODIES, hash_key, body_value).await
537 }
538
539 pub async fn get_block_body(
541 &self,
542 block_number: BlockNumber,
543 ) -> Result<Option<BlockBody>, StoreError> {
544 let Some(block_hash) = self.get_canonical_block_hash_sync(block_number)? else {
545 return Ok(None);
546 };
547
548 self.get_block_body_by_hash(block_hash).await
549 }
550
551 pub async fn remove_block(&self, block_number: BlockNumber) -> Result<(), StoreError> {
553 let Some(hash) = self.get_canonical_block_hash_sync(block_number)? else {
554 return Ok(());
555 };
556
557 let backend = self.backend.clone();
558 tokio::task::spawn_blocking(move || {
559 let hash_key = hash.encode_to_vec();
560
561 let mut txn = backend.begin_write()?;
562 txn.delete(
563 CANONICAL_BLOCK_HASHES,
564 block_number.to_le_bytes().as_slice(),
565 )?;
566 txn.delete(BODIES, &hash_key)?;
567 txn.delete(HEADERS, &hash_key)?;
568 txn.delete(BLOCK_NUMBERS, &hash_key)?;
569 txn.commit()
570 })
571 .await
572 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
573 }
574
575 pub async fn get_block_bodies(
577 &self,
578 from: BlockNumber,
579 to: BlockNumber,
580 ) -> Result<Vec<Option<BlockBody>>, StoreError> {
581 let buffer = self.buffer()?;
583 let backend = self.backend.clone();
584 tokio::task::spawn_blocking(move || {
585 let numbers: Vec<BlockNumber> = (from..=to).collect();
586 let mut block_bodies = Vec::new();
587
588 let txn = backend.begin_read()?;
589 for number in numbers {
590 let Some(hash) = txn
591 .get(CANONICAL_BLOCK_HASHES, number.to_le_bytes().as_slice())?
592 .map(|bytes| H256::decode(bytes.as_slice()))
593 .transpose()?
594 else {
595 block_bodies.push(None);
596 continue;
597 };
598 if let Some(body) = buffer.get_body(&hash) {
601 block_bodies.push(Some(body));
602 continue;
603 }
604 let hash_key = hash.encode_to_vec();
605 let block_body_opt = txn
606 .get(BODIES, &hash_key)?
607 .map(|bytes| BlockBodyRLP::from_bytes(bytes).to())
608 .transpose()
609 .map_err(StoreError::from)?;
610
611 block_bodies.push(block_body_opt);
612 }
613
614 Ok(block_bodies)
615 })
616 .await
617 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
618 }
619
620 pub async fn get_block_bodies_by_hash(
622 &self,
623 hashes: Vec<BlockHash>,
624 ) -> Result<Vec<BlockBody>, StoreError> {
625 let buffer = self.buffer()?;
626 let backend = self.backend.clone();
627 tokio::task::spawn_blocking(move || {
629 let txn = backend.begin_read()?;
630 let mut block_bodies = Vec::new();
631 for hash in hashes {
632 if let Some(body) = buffer.get_body(&hash) {
635 block_bodies.push(body);
636 continue;
637 }
638 let hash_key = hash.encode_to_vec();
639
640 let Some(block_body) = txn
641 .get(BODIES, &hash_key)?
642 .map(|bytes| BlockBodyRLP::from_bytes(bytes).to())
643 .transpose()
644 .map_err(StoreError::from)?
645 else {
646 return Err(StoreError::Custom(format!(
647 "Block body not found for hash: {hash}"
648 )));
649 };
650 block_bodies.push(block_body);
651 }
652 Ok(block_bodies)
653 })
654 .await
655 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
656 }
657
658 pub async fn get_block_body_by_hash(
660 &self,
661 block_hash: BlockHash,
662 ) -> Result<Option<BlockBody>, StoreError> {
663 if let Some(b) = self.buffer()?.get_body(&block_hash) {
664 return Ok(Some(b));
665 }
666 self.read_async(BODIES, block_hash.encode_to_vec())
667 .await?
668 .map(|bytes| BlockBodyRLP::from_bytes(bytes).to())
669 .transpose()
670 .map_err(StoreError::from)
671 }
672
673 pub fn get_block_header_by_hash(
674 &self,
675 block_hash: BlockHash,
676 ) -> Result<Option<BlockHeader>, StoreError> {
677 let latest = self.latest_block_header.get();
678 if block_hash == latest.hash() {
679 return Ok(Some((*latest).clone()));
680 }
681 if let Some(h) = self.buffer()?.get_header(&block_hash) {
682 return Ok(Some(h));
683 }
684 self.load_block_header_by_hash(block_hash)
685 }
686
687 pub fn add_pending_block(&self, block: Block) -> Result<(), StoreError> {
688 let block_hash = block.hash();
689 let block_value = BlockRLP::from(block).into_vec();
690 self.write(PENDING_BLOCKS, block_hash.as_bytes().to_vec(), block_value)
691 }
692
693 pub async fn get_pending_block(
694 &self,
695 block_hash: BlockHash,
696 ) -> Result<Option<Block>, StoreError> {
697 self.read_async(PENDING_BLOCKS, block_hash.as_bytes().to_vec())
698 .await?
699 .map(|bytes| BlockRLP::from_bytes(bytes).to())
700 .transpose()
701 .map_err(StoreError::from)
702 }
703
704 pub async fn add_block_number(
706 &self,
707 block_hash: BlockHash,
708 block_number: BlockNumber,
709 ) -> Result<(), StoreError> {
710 let number_value = block_number.to_le_bytes().to_vec();
711 self.write_async(BLOCK_NUMBERS, block_hash.encode_to_vec(), number_value)
712 .await
713 }
714
715 pub async fn get_block_number(
717 &self,
718 block_hash: BlockHash,
719 ) -> Result<Option<BlockNumber>, StoreError> {
720 if let Some(n) = self.buffer()?.get_number(&block_hash) {
721 return Ok(Some(n));
722 }
723 self.read_async(BLOCK_NUMBERS, block_hash.encode_to_vec())
724 .await?
725 .map(|bytes| -> Result<BlockNumber, StoreError> {
726 let array: [u8; 8] = bytes
727 .try_into()
728 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
729 Ok(BlockNumber::from_le_bytes(array))
730 })
731 .transpose()
732 }
733
734 pub async fn add_transaction_location(
736 &self,
737 transaction_hash: H256,
738 block_number: BlockNumber,
739 block_hash: BlockHash,
740 index: Index,
741 ) -> Result<(), StoreError> {
742 self.add_transaction_locations(vec![(transaction_hash, block_number, block_hash, index)])
743 .await
744 }
745
746 pub async fn add_transaction_locations(
748 &self,
749 locations: Vec<(H256, BlockNumber, BlockHash, Index)>,
750 ) -> Result<(), StoreError> {
751 let db = self.backend.clone();
752 tokio::task::spawn_blocking(move || {
753 let mut tx = db.begin_write()?;
754 for (tx_hash, block_number, block_hash, index) in locations {
755 tx.merge(
756 TRANSACTION_LOCATIONS,
757 tx_hash.as_bytes(),
758 &encode_tx_location_operand(block_number, block_hash, index),
759 )?;
760 }
761 tx.commit()
762 })
763 .await
764 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
765 }
766
767 pub async fn get_transaction_location(
769 &self,
770 transaction_hash: H256,
771 ) -> Result<Option<(BlockNumber, BlockHash, Index)>, StoreError> {
772 let buffered = self.buffer()?.get_tx_locations(&transaction_hash);
773 let db = self.backend.clone();
774 tokio::task::spawn_blocking(move || {
775 let tx = db.begin_read()?;
776 let mut locations = buffered;
777 if let Some(bytes) = tx.get(TRANSACTION_LOCATIONS, transaction_hash.as_bytes())? {
778 locations.extend(<Vec<(BlockNumber, BlockHash, Index)>>::decode(&bytes)?);
779 }
780 for (block_number, block_hash, index) in locations {
781 let canonical_hash = tx
782 .get(
783 CANONICAL_BLOCK_HASHES,
784 block_number.to_le_bytes().as_slice(),
785 )?
786 .map(|bytes| H256::decode(bytes.as_slice()))
787 .transpose()?;
788 if canonical_hash == Some(block_hash) {
789 return Ok(Some((block_number, block_hash, index)));
790 }
791 }
792 Ok(None)
793 })
794 .await
795 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
796 }
797
798 pub async fn add_receipt(
800 &self,
801 block_hash: BlockHash,
802 index: Index,
803 receipt: Receipt,
804 ) -> Result<(), StoreError> {
805 let key = receipt_key(&block_hash, index);
806 let value = receipt.encode_storage();
810 self.write_async(RECEIPTS_V2, key, value).await
811 }
812
813 pub async fn add_receipts(
815 &self,
816 block_hash: BlockHash,
817 receipts: Vec<Receipt>,
818 ) -> Result<(), StoreError> {
819 let batch_items: Vec<_> = receipts
820 .into_iter()
821 .enumerate()
822 .map(|(index, receipt)| {
823 let key = receipt_key(&block_hash, index as u64);
824 let value = receipt.encode_storage();
825 (key, value)
826 })
827 .collect();
828 self.write_batch_async(RECEIPTS_V2, batch_items).await
829 }
830
831 pub async fn get_receipt(
833 &self,
834 block_number: BlockNumber,
835 index: Index,
836 ) -> Result<Option<Receipt>, StoreError> {
837 let Some(block_hash) = self.get_canonical_block_hash(block_number).await? else {
839 return Ok(None);
840 };
841 self.get_receipt_by_block_hash(block_hash, index).await
842 }
843
844 async fn get_receipt_by_block_hash(
846 &self,
847 block_hash: BlockHash,
848 index: Index,
849 ) -> Result<Option<Receipt>, StoreError> {
850 if let Some(r) = self.buffer()?.get_receipt(&block_hash, index) {
851 return Ok(Some(r));
852 }
853 let key = receipt_key(&block_hash, index);
854 self.read_async(RECEIPTS_V2, key)
855 .await?
856 .map(|bytes| Receipt::decode_storage(bytes.as_slice()))
857 .transpose()
858 .map_err(StoreError::from)
859 }
860
861 pub fn get_account_code(&self, code_hash: H256) -> Result<Option<Code>, StoreError> {
868 if let Some(code) = self.buffer()?.get_code(&code_hash) {
869 return Ok(Some(code));
870 }
871 if let Some(code) = self
873 .account_code_cache
874 .lock()
875 .map_err(|_| StoreError::LockError)?
876 .get(&code_hash)?
877 {
878 return Ok(Some(code));
879 }
880
881 let Some(bytes) = self
882 .backend
883 .begin_read()?
884 .get(ACCOUNT_CODES, code_hash.as_bytes())?
885 else {
886 return Ok(None);
887 };
888 let (bytecode_slice, targets) = decode_bytes(&bytes)?;
889 let code = Code::from_parts_unchecked(
890 code_hash,
891 bytecode_slice,
892 <Vec<u32>>::decode(targets)?.into(),
893 );
894
895 self.account_code_cache
897 .lock()
898 .map_err(|_| StoreError::LockError)?
899 .insert(&code)?;
900
901 Ok(Some(code))
902 }
903
904 pub fn code_exists(&self, code_hash: H256) -> Result<bool, StoreError> {
909 if self.buffer()?.get_code(&code_hash).is_some() {
913 return Ok(true);
914 }
915 if self
917 .account_code_cache
918 .lock()
919 .map_err(|_| StoreError::LockError)?
920 .get(&code_hash)?
921 .is_some()
922 {
923 return Ok(true);
924 }
925 Ok(self
927 .backend
928 .begin_read()?
929 .get(ACCOUNT_CODES, code_hash.as_bytes())?
930 .is_some())
931 }
932
933 pub fn get_code_metadata(&self, code_hash: H256) -> Result<Option<CodeMetadata>, StoreError> {
938 use ethrex_common::constants::EMPTY_KECCAK_HASH;
939
940 if code_hash == *EMPTY_KECCAK_HASH {
942 return Ok(Some(CodeMetadata { length: 0 }));
943 }
944
945 if let Some(metadata) = self
947 .code_metadata_cache
948 .lock()
949 .map_err(|_| StoreError::LockError)?
950 .get(&code_hash)
951 .copied()
952 {
953 return Ok(Some(metadata));
954 }
955
956 let metadata = if let Some(bytes) = self
958 .backend
959 .begin_read()?
960 .get(ACCOUNT_CODE_METADATA, code_hash.as_bytes())?
961 {
962 let length =
963 u64::from_be_bytes(bytes.try_into().map_err(|_| {
964 StoreError::Custom("Invalid metadata length encoding".to_string())
965 })?);
966 CodeMetadata { length }
967 } else {
968 let Some(code) = self.get_account_code(code_hash)? else {
970 return Ok(None);
971 };
972 let metadata = CodeMetadata {
973 length: code.len() as u64,
974 };
975
976 let metadata_buf = metadata.length.to_be_bytes().to_vec();
978 let hash_key = code_hash.0.to_vec();
979 let backend = self.backend.clone();
980 tokio::task::spawn(async move {
981 if let Err(e) = async {
982 let mut tx = backend.begin_write()?;
983 tx.put(ACCOUNT_CODE_METADATA, &hash_key, &metadata_buf)?;
984 tx.commit()
985 }
986 .await
987 {
988 tracing::warn!("Failed to write code metadata during auto-migration: {}", e);
989 }
990 });
991
992 metadata
993 };
994
995 self.code_metadata_cache
997 .lock()
998 .map_err(|_| StoreError::LockError)?
999 .insert(code_hash, metadata);
1000
1001 Ok(Some(metadata))
1002 }
1003
1004 pub async fn add_account_code(&self, code: Code) -> Result<(), StoreError> {
1006 let hash_key = code.hash.0.to_vec();
1007 let buf = encode_code(&code);
1008 let metadata_buf = (code.len() as u64).to_be_bytes();
1009
1010 let backend = self.backend.clone();
1012 tokio::task::spawn_blocking(move || {
1013 let mut tx = backend.begin_write()?;
1014 tx.put(ACCOUNT_CODES, &hash_key, &buf)?;
1015 tx.put(ACCOUNT_CODE_METADATA, &hash_key, &metadata_buf)?;
1016 tx.commit()
1017 })
1018 .await
1019 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1020 }
1021
1022 pub async fn clear_snap_state(&self) -> Result<(), StoreError> {
1024 let db = self.backend.clone();
1025 tokio::task::spawn_blocking(move || db.clear_table(SNAP_STATE))
1026 .await
1027 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1028 }
1029
1030 pub async fn get_transaction_by_hash(
1031 &self,
1032 transaction_hash: H256,
1033 ) -> Result<Option<Transaction>, StoreError> {
1034 let (_block_number, block_hash, index) =
1035 match self.get_transaction_location(transaction_hash).await? {
1036 Some(location) => location,
1037 None => return Ok(None),
1038 };
1039 self.get_transaction_by_location(block_hash, index).await
1040 }
1041
1042 pub async fn get_transaction_by_location(
1043 &self,
1044 block_hash: H256,
1045 index: u64,
1046 ) -> Result<Option<Transaction>, StoreError> {
1047 let block_body = match self.get_block_body_by_hash(block_hash).await? {
1048 Some(body) => body,
1049 None => return Ok(None),
1050 };
1051 let index: usize = index.try_into()?;
1052 Ok(block_body.transactions.get(index).cloned())
1053 }
1054
1055 pub async fn get_block_by_hash(
1056 &self,
1057 block_hash: BlockHash,
1058 ) -> Result<Option<Block>, StoreError> {
1059 let header = match self.get_block_header_by_hash(block_hash)? {
1060 Some(header) => header,
1061 None => return Ok(None),
1062 };
1063 let body = match self.get_block_body_by_hash(block_hash).await? {
1064 Some(body) => body,
1065 None => return Ok(None),
1066 };
1067 Ok(Some(Block::new(header, body)))
1068 }
1069
1070 pub async fn get_block_by_number(
1071 &self,
1072 block_number: BlockNumber,
1073 ) -> Result<Option<Block>, StoreError> {
1074 let Some(block_hash) = self.get_canonical_block_hash(block_number).await? else {
1075 return Ok(None);
1076 };
1077 self.get_block_by_hash(block_hash).await
1078 }
1079
1080 pub async fn get_canonical_block_hash(
1082 &self,
1083 block_number: BlockNumber,
1084 ) -> Result<Option<BlockHash>, StoreError> {
1085 let last = self.latest_block_header.get();
1086 if last.number == block_number {
1087 return Ok(Some(last.hash()));
1088 }
1089 let backend = self.backend.clone();
1090 tokio::task::spawn_blocking(move || {
1091 backend
1092 .begin_read()?
1093 .get(
1094 CANONICAL_BLOCK_HASHES,
1095 block_number.to_le_bytes().as_slice(),
1096 )?
1097 .map(|bytes| H256::decode(bytes.as_slice()))
1098 .transpose()
1099 .map_err(StoreError::from)
1100 })
1101 .await
1102 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1103 }
1104
1105 pub async fn set_chain_config(&mut self, chain_config: &ChainConfig) -> Result<(), StoreError> {
1108 self.chain_config = *chain_config;
1109 let key = chain_data_key(ChainDataIndex::ChainConfig);
1110 let value = serde_json::to_string(chain_config)
1111 .map_err(|_| StoreError::Custom("Failed to serialize chain config".to_string()))?
1112 .into_bytes();
1113 self.write_async(CHAIN_DATA, key, value).await
1114 }
1115
1116 pub async fn update_earliest_block_number(
1118 &self,
1119 block_number: BlockNumber,
1120 ) -> Result<(), StoreError> {
1121 let key = chain_data_key(ChainDataIndex::EarliestBlockNumber);
1122 let value = block_number.to_le_bytes().to_vec();
1123 self.write_async(CHAIN_DATA, key, value).await
1124 }
1125
1126 pub async fn get_earliest_block_number(&self) -> Result<BlockNumber, StoreError> {
1128 let key = chain_data_key(ChainDataIndex::EarliestBlockNumber);
1129 self.read_async(CHAIN_DATA, key)
1130 .await?
1131 .map(|bytes| -> Result<BlockNumber, StoreError> {
1132 let array: [u8; 8] = bytes
1133 .try_into()
1134 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
1135 Ok(BlockNumber::from_le_bytes(array))
1136 })
1137 .ok_or(StoreError::MissingEarliestBlockNumber)?
1138 }
1139
1140 pub async fn get_finalized_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
1142 let key = chain_data_key(ChainDataIndex::FinalizedBlockNumber);
1143 self.read_async(CHAIN_DATA, key)
1144 .await?
1145 .map(|bytes| -> Result<BlockNumber, StoreError> {
1146 let array: [u8; 8] = bytes
1147 .try_into()
1148 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
1149 Ok(BlockNumber::from_le_bytes(array))
1150 })
1151 .transpose()
1152 }
1153
1154 pub async fn get_safe_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
1156 let key = chain_data_key(ChainDataIndex::SafeBlockNumber);
1157 self.read_async(CHAIN_DATA, key)
1158 .await?
1159 .map(|bytes| -> Result<BlockNumber, StoreError> {
1160 let array: [u8; 8] = bytes
1161 .try_into()
1162 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
1163 Ok(BlockNumber::from_le_bytes(array))
1164 })
1165 .transpose()
1166 }
1167
1168 pub async fn get_latest_block_number(&self) -> Result<BlockNumber, StoreError> {
1170 Ok(self.latest_block_header.get().number)
1171 }
1172
1173 pub async fn update_pending_block_number(
1175 &self,
1176 block_number: BlockNumber,
1177 ) -> Result<(), StoreError> {
1178 let key = chain_data_key(ChainDataIndex::PendingBlockNumber);
1179 let value = block_number.to_le_bytes().to_vec();
1180 self.write_async(CHAIN_DATA, key, value).await
1181 }
1182
1183 pub async fn get_pending_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
1185 let key = chain_data_key(ChainDataIndex::PendingBlockNumber);
1186 self.read_async(CHAIN_DATA, key)
1187 .await?
1188 .map(|bytes| -> Result<BlockNumber, StoreError> {
1189 let array: [u8; 8] = bytes
1190 .try_into()
1191 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
1192 Ok(BlockNumber::from_le_bytes(array))
1193 })
1194 .transpose()
1195 }
1196
1197 async fn forkchoice_update_inner(
1203 &self,
1204 new_canonical_blocks: Vec<(BlockNumber, BlockHash)>,
1205 head_number: BlockNumber,
1206 head_hash: BlockHash,
1207 safe: Option<BlockNumber>,
1208 finalized: Option<BlockNumber>,
1209 ) -> Result<(), StoreError> {
1210 let latest = self.load_latest_block_number().await?.unwrap_or(0);
1211 let db = self.backend.clone();
1212 tokio::task::spawn_blocking(move || {
1213 let mut txn = db.begin_write()?;
1214
1215 for (block_number, block_hash) in new_canonical_blocks {
1216 let head_key = block_number.to_le_bytes();
1217 let head_value = block_hash.encode_to_vec();
1218 txn.put(CANONICAL_BLOCK_HASHES, &head_key, &head_value)?;
1219 }
1220
1221 for number in (head_number + 1)..=(latest) {
1228 txn.delete(CANONICAL_BLOCK_HASHES, number.to_le_bytes().as_slice())?;
1229 }
1230
1231 let head_key = head_number.to_le_bytes();
1233 let head_value = head_hash.encode_to_vec();
1234 txn.put(CANONICAL_BLOCK_HASHES, &head_key, &head_value)?;
1235
1236 let latest_key = chain_data_key(ChainDataIndex::LatestBlockNumber);
1238 txn.put(CHAIN_DATA, &latest_key, &head_number.to_le_bytes())?;
1239
1240 if let Some(safe) = safe {
1241 let safe_key = chain_data_key(ChainDataIndex::SafeBlockNumber);
1242 txn.put(CHAIN_DATA, &safe_key, &safe.to_le_bytes())?;
1243 }
1244
1245 if let Some(finalized) = finalized {
1246 let finalized_key = chain_data_key(ChainDataIndex::FinalizedBlockNumber);
1247 txn.put(CHAIN_DATA, &finalized_key, &finalized.to_le_bytes())?;
1248 }
1249
1250 txn.commit()
1251 })
1252 .await
1253 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1254 }
1255
1256 pub async fn get_receipts_for_block(
1257 &self,
1258 block_hash: &BlockHash,
1259 ) -> Result<Vec<Receipt>, StoreError> {
1260 self.get_receipts_for_block_from_index(block_hash, 0, None)
1261 .await
1262 }
1263
1264 pub async fn get_receipts_for_block_from_index(
1273 &self,
1274 block_hash: &BlockHash,
1275 start_index: u64,
1276 max_count: Option<usize>,
1277 ) -> Result<Vec<Receipt>, StoreError> {
1278 if let Some(all) = self.buffer()?.get_receipts(block_hash) {
1279 let start = start_index as usize;
1280 let slice = all.into_iter().skip(start);
1281 return Ok(match max_count {
1282 Some(max) => slice.take(max).collect(),
1283 None => slice.collect(),
1284 });
1285 }
1286 let backend = self.backend.clone();
1287 let block_hash = *block_hash;
1288
1289 tokio::task::spawn_blocking(move || {
1290 let txn = backend.begin_read()?;
1291 let prefix = block_hash.as_bytes().to_vec();
1292 let mut seek_key = prefix.clone();
1295 seek_key.extend_from_slice(&start_index.to_be_bytes());
1296 let iter = txn.prefix_iterator(RECEIPTS_V2, &seek_key)?;
1297 let mut receipts = Vec::new();
1298 for result in iter {
1299 let (k, v) = result?;
1300 if !k.starts_with(&prefix) {
1301 break;
1302 }
1303 if k.len() != 40 {
1304 continue;
1305 }
1306 receipts.push(Receipt::decode_storage(v.as_ref())?);
1307 if let Some(max) = max_count
1308 && receipts.len() >= max
1309 {
1310 break;
1311 }
1312 }
1313 Ok(receipts)
1314 })
1315 .await
1316 .map_err(|e| StoreError::Custom(format!("Task panicked: {e}")))?
1317 }
1318
1319 pub async fn set_header_download_checkpoint(
1323 &self,
1324 block_hash: BlockHash,
1325 ) -> Result<(), StoreError> {
1326 let key = snap_state_key(SnapStateIndex::HeaderDownloadCheckpoint);
1327 let value = block_hash.encode_to_vec();
1328 self.write_async(SNAP_STATE, key, value).await
1329 }
1330
1331 pub async fn get_header_download_checkpoint(&self) -> Result<Option<BlockHash>, StoreError> {
1333 let key = snap_state_key(SnapStateIndex::HeaderDownloadCheckpoint);
1334 self.backend
1335 .begin_read()?
1336 .get(SNAP_STATE, &key)?
1337 .map(|bytes| H256::decode(bytes.as_slice()))
1338 .transpose()
1339 .map_err(StoreError::from)
1340 }
1341
1342 pub async fn set_latest_valid_ancestor(
1348 &self,
1349 bad_block: BlockHash,
1350 latest_valid: BlockHash,
1351 ) -> Result<(), StoreError> {
1352 let value = latest_valid.encode_to_vec();
1353 self.write_async(INVALID_CHAINS, bad_block.as_bytes().to_vec(), value)
1354 .await
1355 }
1356
1357 pub async fn get_latest_valid_ancestor(
1360 &self,
1361 block: BlockHash,
1362 ) -> Result<Option<BlockHash>, StoreError> {
1363 self.read_async(INVALID_CHAINS, block.as_bytes().to_vec())
1364 .await?
1365 .map(|bytes| H256::decode(bytes.as_slice()))
1366 .transpose()
1367 .map_err(StoreError::from)
1368 }
1369
1370 pub async fn add_bad_block(&self, block: Block) -> Result<(), StoreError> {
1375 let mut bad_blocks = self.get_bad_blocks().await?;
1376 let block_number = block.header.number;
1377 let block_hash = block.hash();
1378 if bad_blocks
1379 .iter()
1380 .any(|b| b.header.number == block_number && b.hash() == block_hash)
1381 {
1382 return Ok(());
1383 }
1384 bad_blocks.push(block);
1385 bad_blocks.sort_by(|a, b| b.header.number.cmp(&a.header.number));
1386 bad_blocks.truncate(MAX_BAD_BLOCKS);
1387 self.write_async(
1388 BAD_BLOCKS,
1389 BAD_BLOCKS_KEY.to_vec(),
1390 bad_blocks.encode_to_vec(),
1391 )
1392 .await
1393 }
1394
1395 pub async fn get_bad_blocks(&self) -> Result<Vec<Block>, StoreError> {
1398 match self.read_async(BAD_BLOCKS, BAD_BLOCKS_KEY.to_vec()).await? {
1399 Some(bytes) => Vec::<Block>::decode(&bytes).map_err(StoreError::from),
1400 None => Ok(Vec::new()),
1401 }
1402 }
1403
1404 pub fn get_block_number_sync(
1406 &self,
1407 block_hash: BlockHash,
1408 ) -> Result<Option<BlockNumber>, StoreError> {
1409 if let Some(n) = self.buffer()?.get_number(&block_hash) {
1410 return Ok(Some(n));
1411 }
1412 let txn = self.backend.begin_read()?;
1413 txn.get(BLOCK_NUMBERS, &block_hash.encode_to_vec())?
1414 .map(|bytes| -> Result<BlockNumber, StoreError> {
1415 let array: [u8; 8] = bytes
1416 .try_into()
1417 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
1418 Ok(BlockNumber::from_le_bytes(array))
1419 })
1420 .transpose()
1421 }
1422
1423 pub fn get_canonical_block_hash_sync(
1425 &self,
1426 block_number: BlockNumber,
1427 ) -> Result<Option<BlockHash>, StoreError> {
1428 let last = self.latest_block_header.get();
1429 if last.number == block_number {
1430 return Ok(Some(last.hash()));
1431 }
1432 let txn = self.backend.begin_read()?;
1433 txn.get(
1434 CANONICAL_BLOCK_HASHES,
1435 block_number.to_le_bytes().as_slice(),
1436 )?
1437 .map(|bytes| H256::decode(bytes.as_slice()))
1438 .transpose()
1439 .map_err(StoreError::from)
1440 }
1441
1442 pub async fn write_storage_trie_nodes_batch(
1445 &self,
1446 storage_trie_nodes: StorageUpdates,
1447 ) -> Result<(), StoreError> {
1448 let mut txn = self.backend.begin_write()?;
1449 tokio::task::spawn_blocking(move || {
1450 for (address_hash, nodes) in storage_trie_nodes {
1451 for (node_path, node_data) in nodes {
1452 let key = apply_prefix(Some(address_hash), node_path);
1453 if node_data.is_empty() {
1454 txn.delete(STORAGE_TRIE_NODES, key.as_ref())?;
1455 } else {
1456 txn.put(STORAGE_TRIE_NODES, key.as_ref(), &node_data)?;
1457 }
1458 }
1459 }
1460 txn.commit()
1461 })
1462 .await
1463 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1464 }
1465
1466 pub async fn write_account_code_batch(
1469 &self,
1470 account_codes: Vec<(H256, Code)>,
1471 ) -> Result<(), StoreError> {
1472 let mut code_batch_items = Vec::new();
1473 let mut metadata_batch_items = Vec::new();
1474
1475 for (code_hash, code) in account_codes {
1476 let buf = encode_code(&code);
1477 let metadata_buf = (code.len() as u64).to_be_bytes().to_vec();
1478 code_batch_items.push((code_hash.as_bytes().to_vec(), buf));
1479 metadata_batch_items.push((code_hash.as_bytes().to_vec(), metadata_buf));
1480 }
1481
1482 self.write_batch_async(ACCOUNT_CODES, code_batch_items)
1484 .await?;
1485 self.write_batch_async(ACCOUNT_CODE_METADATA, metadata_batch_items)
1486 .await
1487 }
1488
1489 fn buffer(&self) -> Result<Arc<BlockDataBuffer>, StoreError> {
1491 Ok(self
1492 .block_data_buffer
1493 .read()
1494 .map_err(|_| StoreError::LockError)?
1495 .clone())
1496 }
1497
1498 pub fn write(
1504 &self,
1505 table: &'static str,
1506 key: Vec<u8>,
1507 value: Vec<u8>,
1508 ) -> Result<(), StoreError> {
1509 let backend = self.backend.clone();
1510 let mut txn = backend.begin_write()?;
1511 txn.put(table, &key, &value)?;
1512 txn.commit()
1513 }
1514
1515 async fn write_async(
1518 &self,
1519 table: &'static str,
1520 key: Vec<u8>,
1521 value: Vec<u8>,
1522 ) -> Result<(), StoreError> {
1523 let backend = self.backend.clone();
1524
1525 tokio::task::spawn_blocking(move || {
1526 let mut txn = backend.begin_write()?;
1527 txn.put(table, &key, &value)?;
1528 txn.commit()
1529 })
1530 .await
1531 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1532 }
1533
1534 pub async fn read_async(
1537 &self,
1538 table: &'static str,
1539 key: Vec<u8>,
1540 ) -> Result<Option<Vec<u8>>, StoreError> {
1541 let backend = self.backend.clone();
1542
1543 tokio::task::spawn_blocking(move || {
1544 let txn = backend.begin_read()?;
1545 txn.get(table, &key)
1546 })
1547 .await
1548 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1549 }
1550
1551 pub fn read(&self, table: &'static str, key: Vec<u8>) -> Result<Option<Vec<u8>>, StoreError> {
1554 let backend = self.backend.clone();
1555 let txn = backend.begin_read()?;
1556 txn.get(table, &key)
1557 }
1558
1559 pub async fn write_batch_async(
1563 &self,
1564 table: &'static str,
1565 batch_ops: Vec<(Vec<u8>, Vec<u8>)>,
1566 ) -> Result<(), StoreError> {
1567 let backend = self.backend.clone();
1568
1569 tokio::task::spawn_blocking(move || {
1570 let mut txn = backend.begin_write()?;
1571 txn.put_batch(table, batch_ops)?;
1572 txn.commit()
1573 })
1574 .await
1575 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1576 }
1577
1578 pub fn write_batch(
1580 &self,
1581 table: &'static str,
1582 batch_ops: Vec<(Vec<u8>, Vec<u8>)>,
1583 ) -> Result<(), StoreError> {
1584 let backend = self.backend.clone();
1585 let mut txn = backend.begin_write()?;
1586 txn.put_batch(table, batch_ops)?;
1587 txn.commit()
1588 }
1589
1590 pub async fn add_fullsync_batch(&self, headers: Vec<BlockHeader>) -> Result<(), StoreError> {
1591 self.write_batch_async(
1592 FULLSYNC_HEADERS,
1593 headers
1594 .into_iter()
1595 .map(|header| (header.number.to_le_bytes().to_vec(), header.encode_to_vec()))
1596 .collect(),
1597 )
1598 .await
1599 }
1600
1601 pub async fn read_fullsync_batch(
1602 &self,
1603 start: BlockNumber,
1604 limit: u64,
1605 ) -> Result<Vec<Option<BlockHeader>>, StoreError> {
1606 let mut res = vec![];
1607 let read_tx = self.backend.begin_read()?;
1608 for key in start..start + limit {
1610 let header_opt = read_tx
1611 .get(FULLSYNC_HEADERS, &key.to_le_bytes())?
1612 .map(|header| BlockHeader::decode(&header))
1613 .transpose()?;
1614 res.push(header_opt);
1615 }
1616 Ok(res)
1617 }
1618
1619 pub async fn clear_fullsync_headers(&self) -> Result<(), StoreError> {
1620 self.backend.clear_table(FULLSYNC_HEADERS)
1621 }
1622
1623 pub fn delete(&self, table: &'static str, key: Vec<u8>) -> Result<(), StoreError> {
1625 let mut txn = self.backend.begin_write()?;
1626 txn.delete(table, &key)?;
1627 txn.commit()
1628 }
1629
1630 pub fn store_block_updates(&self, update_batch: UpdateBatch) -> Result<(), StoreError> {
1631 self.apply_updates(update_batch)
1632 }
1633
1634 fn batch_state_roots(&self, update_batch: &UpdateBatch) -> Result<(H256, H256), StoreError> {
1639 let parent_state_root = self
1640 .get_block_header_by_hash(
1641 update_batch
1642 .blocks
1643 .first()
1644 .ok_or(StoreError::UpdateBatchNoBlocks)?
1645 .header
1646 .parent_hash,
1647 )?
1648 .map(|header| header.state_root)
1649 .unwrap_or_default();
1650 let last_state_root = update_batch
1651 .blocks
1652 .last()
1653 .ok_or(StoreError::UpdateBatchNoBlocks)?
1654 .header
1655 .state_root;
1656 Ok((parent_state_root, last_state_root))
1657 }
1658
1659 fn apply_updates(&self, update_batch: UpdateBatch) -> Result<(), StoreError> {
1664 let (parent_state_root, last_state_root) = self.batch_state_roots(&update_batch)?;
1665
1666 let UpdateBatch {
1667 account_updates,
1668 storage_updates,
1669 blocks,
1670 receipts,
1671 code_updates,
1672 batch_mode,
1673 } = update_batch;
1674
1675 self.pending_trie_roots.register(last_state_root)?;
1679
1680 let blocks_with_receipts: Vec<(Block, Vec<Receipt>)> = if blocks.len() == 1 {
1683 let block = blocks.into_iter().next().expect("len == 1");
1684 let hash = block.hash();
1685 let r = receipts
1686 .into_iter()
1687 .find(|(h, _)| *h == hash)
1688 .map(|(_, r)| r)
1689 .unwrap_or_default();
1690 vec![(block, r)]
1691 } else {
1692 let mut receipts_by_hash: std::collections::HashMap<BlockHash, Vec<Receipt>> =
1693 receipts.into_iter().collect();
1694 blocks
1695 .into_iter()
1696 .map(|b| {
1697 let r = receipts_by_hash.remove(&b.hash()).unwrap_or_default();
1698 (b, r)
1699 })
1700 .collect()
1701 };
1702
1703 let (ack_tx, ack_rx) = sync_channel(1);
1709 self.persist_tx
1710 .send(PersistMessage::Block(BlockPersist {
1711 blocks: blocks_with_receipts,
1712 codes: code_updates,
1713 parent_state_root,
1714 child_state_root: last_state_root,
1715 account_updates,
1716 storage_updates,
1717 wait_for_flush: batch_mode,
1718 ack: ack_tx,
1719 }))
1720 .map_err(|e| StoreError::Custom(format!("failed to send block persist: {e}")))?;
1721 ack_rx
1722 .recv()
1723 .map_err(|e| StoreError::Custom(format!("block persist ack failed: {e}")))??;
1724
1725 Ok(())
1726 }
1727
1728 pub fn new(path: impl AsRef<Path>, engine_type: EngineType) -> Result<Self, StoreError> {
1733 Self::new_with_config(path, engine_type, StoreConfig::default())
1734 }
1735
1736 pub fn new_with_config(
1738 path: impl AsRef<Path>,
1739 engine_type: EngineType,
1740 #[cfg_attr(not(feature = "rocksdb"), allow(unused_variables))] config: StoreConfig,
1742 ) -> Result<Self, StoreError> {
1743 let db_path = path.as_ref().to_path_buf();
1744
1745 if engine_type != EngineType::InMemory {
1746 let version = read_store_schema_version(&db_path)?;
1747
1748 match version {
1749 None if db_path.exists() && dir_contains_legacy_db(&db_path)? => {
1750 return Err(StoreError::NotFoundDBVersion);
1752 }
1753 None => {
1754 init_metadata_file(&db_path)?;
1760 }
1761 Some(v) if v < 1 => {
1762 return Err(StoreError::MigrationFailed {
1763 from: v,
1764 to: STORE_SCHEMA_VERSION,
1765 reason: format!("DB version v{v} is invalid (predates migrations)"),
1766 });
1767 }
1768 Some(v) if v > STORE_SCHEMA_VERSION => {
1769 return Err(StoreError::MigrationFailed {
1770 from: v,
1771 to: STORE_SCHEMA_VERSION,
1772 reason: format!(
1773 "DB version v{v} is more recent than the client expects (v{STORE_SCHEMA_VERSION}). Rolling back is not supported"
1774 ),
1775 });
1776 }
1777 #[cfg(feature = "rocksdb")]
1778 Some(v) if v < STORE_SCHEMA_VERSION => {
1779 let rocksdb = Arc::new(RocksDBBackend::open(
1783 &path,
1784 config.rocksdb_block_cache_size,
1785 )?);
1786 crate::migrations::run_pending_migrations(rocksdb.as_ref(), &db_path, v)?;
1787 rocksdb.drop_obsolete_cfs(&path);
1788 let backend: Arc<dyn crate::api::StorageBackend> = rocksdb;
1789 return Self::from_backend(
1790 backend,
1791 db_path,
1792 DB_COMMIT_THRESHOLD,
1793 config.persist_channel_capacity,
1794 );
1795 }
1796 Some(_) => {
1797 }
1802 }
1803 }
1804
1805 match engine_type {
1806 #[cfg(feature = "rocksdb")]
1807 EngineType::RocksDB => {
1808 let rocksdb = RocksDBBackend::open(&path, config.rocksdb_block_cache_size)?;
1809 rocksdb.drop_obsolete_cfs(&path);
1810 let backend: Arc<dyn StorageBackend> = Arc::new(rocksdb);
1811 Self::from_backend(
1812 backend,
1813 db_path,
1814 DB_COMMIT_THRESHOLD,
1815 config.persist_channel_capacity,
1816 )
1817 }
1818 EngineType::InMemory => {
1819 let backend = Arc::new(InMemoryBackend::open()?);
1820 Self::from_backend(
1821 backend,
1822 db_path,
1823 IN_MEMORY_COMMIT_THRESHOLD,
1824 config.persist_channel_capacity,
1825 )
1826 }
1827 }
1828 }
1829
1830 fn from_backend(
1831 backend: Arc<dyn StorageBackend>,
1832 db_path: PathBuf,
1833 commit_threshold: usize,
1834 persist_channel_capacity: usize,
1835 ) -> Result<Self, StoreError> {
1836 debug!("Initializing Store with {commit_threshold} in-memory diff-layers");
1837 let (fkv_tx, fkv_rx) = std::sync::mpsc::sync_channel(0);
1838 let persist_cap = persist_channel_capacity.max(1); let (persist_tx, persist_rx) = std::sync::mpsc::sync_channel(persist_cap);
1840
1841 let (last_written, initial_flushed_upto) = {
1842 let tx = backend.begin_read()?;
1843 let last_written = tx
1844 .get(MISC_VALUES, "last_written".as_bytes())?
1845 .unwrap_or_else(|| vec![0u8; 64]);
1846 let last_written = if last_written == [0xff] {
1847 vec![0xff; 64]
1848 } else {
1849 last_written
1850 };
1851 let initial_flushed_upto = match tx.get(MISC_VALUES, FLUSHED_UPTO_KEY)? {
1852 Some(bytes) => decode_flushed_upto(&bytes)?,
1853 None => 0,
1854 };
1855 (last_written, initial_flushed_upto)
1856 };
1857 let mut initial_buffer = BlockDataBuffer::new();
1858 initial_buffer.set_flushed_upto(initial_flushed_upto);
1859
1860 let mut background_threads = Vec::new();
1861 let safe_commit_root = Arc::new(RwLock::new(H256::zero()));
1862 let mut store = Self {
1863 db_path,
1864 backend,
1865 chain_config: Default::default(),
1866 latest_block_header: Default::default(),
1867 trie_cache: Arc::new(RwLock::new(Arc::new(TrieLayerCache::new_with_safe_commit(
1868 commit_threshold,
1869 safe_commit_root.clone(),
1870 )))),
1871 flatkeyvalue_control_tx: fkv_tx,
1872 block_data_buffer: Arc::new(RwLock::new(Arc::new(initial_buffer))),
1873 persist_tx,
1874 pending_trie_roots: Arc::new(PendingTrieRoots::default()),
1875 last_computed_flatkeyvalue: Arc::new(RwLock::new(last_written)),
1876 account_code_cache: Arc::new(Mutex::new(CodeCache::default())),
1877 code_metadata_cache: Arc::new(Mutex::new(rustc_hash::FxHashMap::default())),
1878 fcu_lock: Arc::new(tokio::sync::Mutex::new(())),
1879 safe_commit_root,
1880 background_threads: Default::default(),
1881 };
1882 let backend_clone = store.backend.clone();
1883 let last_computed_fkv = store.last_computed_flatkeyvalue.clone();
1884 background_threads.push(std::thread::spawn(move || {
1885 let rx = fkv_rx;
1886 loop {
1888 match rx.recv() {
1889 Ok(FKVGeneratorControlMessage::Continue) => break,
1890 Ok(FKVGeneratorControlMessage::Stop) => {}
1891 Err(std::sync::mpsc::RecvError) => {
1892 debug!("Closing FlatKeyValue generator.");
1893 return;
1894 }
1895 }
1896 }
1897
1898 let _ = flatkeyvalue_generator(&backend_clone, &last_computed_fkv, &rx)
1899 .inspect_err(|err| error!("Error while generating FlatKeyValue: {err}"));
1900 }));
1901 let persist_backend = store.backend.clone();
1904 let persist_buffer = store.block_data_buffer.clone();
1905 let persist_trie_cache = store.trie_cache.clone();
1906 let persist_pending_roots = store.pending_trie_roots.clone();
1907 let persist_fkv_ctl = store.flatkeyvalue_control_tx.clone();
1908 background_threads.push(std::thread::spawn(move || {
1909 let rx = persist_rx;
1910 let mut last_flush_result: Result<(), StoreError> = Ok(());
1913 loop {
1914 match rx.recv() {
1915 Ok(PersistMessage::Block(bp)) => {
1916 let staged = mutate_block_buffer(&persist_buffer, move |b| {
1919 let mut codes = Some(bp.codes);
1920 for (block, receipts) in bp.blocks {
1921 b.insert(block, receipts, codes.take().unwrap_or_default());
1922 }
1923 });
1924 if let Err(e) = staged {
1925 persist_pending_roots.clear(bp.child_state_root);
1930 let _ = bp.ack.send(Err(e));
1931 continue;
1932 }
1933 if !bp.wait_for_flush {
1942 let _ = bp
1943 .ack
1944 .send(std::mem::replace(&mut last_flush_result, Ok(())));
1945 }
1946 if let Err(err) = apply_trie_phase1(
1948 &persist_trie_cache,
1949 &persist_pending_roots,
1950 bp.parent_state_root,
1951 bp.child_state_root,
1952 bp.account_updates,
1953 bp.storage_updates,
1954 ) {
1955 error!("persist worker trie phase-1 failed: {err}");
1956 if bp.wait_for_flush {
1957 let _ = bp.ack.send(Err(err));
1958 } else {
1959 last_flush_result = Err(err);
1960 }
1961 continue;
1962 }
1963 let flushed = flush_block_data(persist_backend.as_ref(), &persist_buffer)
1965 .inspect_err(|err| error!("flush_block_data failed: {err}"))
1966 .and_then(|_| {
1967 commit_trie_if_due(
1968 persist_backend.as_ref(),
1969 &persist_trie_cache,
1970 &persist_fkv_ctl,
1971 bp.parent_state_root,
1972 bp.wait_for_flush,
1973 )
1974 });
1975 if bp.wait_for_flush {
1978 let prior = std::mem::replace(&mut last_flush_result, Ok(()));
1979 let _ = bp.ack.send(prior.and(flushed));
1980 } else {
1981 last_flush_result = flushed;
1982 }
1983 }
1984 Ok(PersistMessage::Commit(root)) => match persist_trie_cache.read() {
1985 Ok(guard) => {
1986 let trie = guard.clone();
1987 drop(guard);
1988 let _ = commit_to_disk(
1989 persist_backend.as_ref(),
1990 &persist_fkv_ctl,
1991 &persist_trie_cache,
1992 &trie,
1993 root,
1994 )
1995 .inspect_err(|err| error!("commit_to_disk failed: {err}"));
1996 }
1997 Err(_) => error!("trie cache lock poisoned during commit"),
1998 },
1999 Ok(PersistMessage::Ping(ack)) => {
2000 let _ = ack.send(std::mem::replace(&mut last_flush_result, Ok(())));
2004 }
2005 Ok(PersistMessage::Shutdown { ack }) => {
2006 let result = flush_block_data(persist_backend.as_ref(), &persist_buffer);
2013 let prior = std::mem::replace(&mut last_flush_result, Ok(()));
2014 let _ = ack.send(prior.and(result));
2015 return;
2017 }
2018 Err(_) => return,
2019 }
2020 }
2021 }));
2022 store.background_threads = Arc::new(ThreadList {
2023 list: background_threads,
2024 });
2025 Ok(store)
2026 }
2027
2028 pub async fn new_from_genesis(
2031 store_path: &Path,
2032 engine_type: EngineType,
2033 genesis_path: &str,
2034 ) -> Result<Self, StoreError> {
2035 Self::new_from_genesis_with_config(
2036 store_path,
2037 engine_type,
2038 genesis_path,
2039 StoreConfig::default(),
2040 )
2041 .await
2042 }
2043
2044 pub async fn new_from_genesis_with_config(
2047 store_path: &Path,
2048 engine_type: EngineType,
2049 genesis_path: &str,
2050 config: StoreConfig,
2051 ) -> Result<Self, StoreError> {
2052 let file = std::fs::File::open(genesis_path)
2053 .map_err(|error| StoreError::Custom(format!("Failed to open genesis file: {error}")))?;
2054 let reader = std::io::BufReader::new(file);
2055 let genesis: Genesis = serde_json::from_reader(reader)
2056 .map_err(|e| StoreError::Custom(format!("Failed to deserialize genesis file: {e}")))?;
2057 let mut store = Self::new_with_config(store_path, engine_type, config)?;
2058 store.add_initial_state(genesis).await?;
2059 Ok(store)
2060 }
2061
2062 pub async fn get_account_info(
2063 &self,
2064 block_number: BlockNumber,
2065 address: Address,
2066 ) -> Result<Option<AccountInfo>, StoreError> {
2067 match self.get_canonical_block_hash(block_number).await? {
2068 Some(block_hash) => self.get_account_info_by_hash(block_hash, address),
2069 None => Ok(None),
2070 }
2071 }
2072
2073 pub fn get_account_info_by_hash(
2074 &self,
2075 block_hash: BlockHash,
2076 address: Address,
2077 ) -> Result<Option<AccountInfo>, StoreError> {
2078 let Some(state_trie) = self.state_trie(block_hash)? else {
2079 return Ok(None);
2080 };
2081 let hashed_address = hash_address_fixed(&address);
2082
2083 let Some(encoded_state) = state_trie.get(hashed_address.as_bytes())? else {
2084 return Ok(None);
2085 };
2086
2087 let account_state = AccountState::decode(&encoded_state)?;
2088 Ok(Some(AccountInfo {
2089 code_hash: account_state.code_hash,
2090 balance: account_state.balance,
2091 nonce: account_state.nonce,
2092 }))
2093 }
2094
2095 pub fn get_account_state_by_acc_hash(
2096 &self,
2097 block_hash: BlockHash,
2098 account_hash: H256,
2099 ) -> Result<Option<AccountState>, StoreError> {
2100 let Some(state_trie) = self.state_trie(block_hash)? else {
2101 return Ok(None);
2102 };
2103 let Some(encoded_state) = state_trie.get(account_hash.as_bytes())? else {
2104 return Ok(None);
2105 };
2106 let account_state = AccountState::decode(&encoded_state)?;
2107 Ok(Some(account_state))
2108 }
2109
2110 pub async fn get_fork_id(&self) -> Result<ForkId, StoreError> {
2111 let chain_config = self.get_chain_config();
2112 let genesis_header = self
2113 .load_block_header(0)?
2114 .ok_or(StoreError::MissingEarliestBlockNumber)?;
2115 let block_header = self.latest_block_header.get();
2116
2117 Ok(ForkId::new(
2118 chain_config,
2119 genesis_header,
2120 block_header.timestamp,
2121 block_header.number,
2122 ))
2123 }
2124
2125 pub async fn get_code_by_account_address(
2126 &self,
2127 block_number: BlockNumber,
2128 address: Address,
2129 ) -> Result<Option<Code>, StoreError> {
2130 let Some(block_hash) = self.get_canonical_block_hash(block_number).await? else {
2131 return Ok(None);
2132 };
2133 let Some(state_trie) = self.state_trie(block_hash)? else {
2134 return Ok(None);
2135 };
2136 let hashed_address = hash_address_fixed(&address);
2137 let Some(encoded_state) = state_trie.get(hashed_address.as_bytes())? else {
2138 return Ok(None);
2139 };
2140 let account_state = AccountState::decode(&encoded_state)?;
2141 self.get_account_code(account_state.code_hash)
2142 }
2143
2144 pub async fn get_nonce_by_account_address(
2145 &self,
2146 block_number: BlockNumber,
2147 address: Address,
2148 ) -> Result<Option<u64>, StoreError> {
2149 let Some(block_hash) = self.get_canonical_block_hash(block_number).await? else {
2150 return Ok(None);
2151 };
2152 let Some(state_trie) = self.state_trie(block_hash)? else {
2153 return Ok(None);
2154 };
2155 let hashed_address = hash_address_fixed(&address);
2156 let Some(encoded_state) = state_trie.get(hashed_address.as_bytes())? else {
2157 return Ok(None);
2158 };
2159 let account_state = AccountState::decode(&encoded_state)?;
2160 Ok(Some(account_state.nonce))
2161 }
2162
2163 pub fn apply_account_updates_batch(
2166 &self,
2167 block_hash: BlockHash,
2168 account_updates: &[AccountUpdate],
2169 ) -> Result<Option<AccountUpdatesList>, StoreError> {
2170 let Some(mut state_trie) = self.state_trie(block_hash)? else {
2171 return Ok(None);
2172 };
2173
2174 Ok(Some(self.apply_account_updates_from_trie_batch(
2175 &mut state_trie,
2176 account_updates,
2177 )?))
2178 }
2179
2180 pub fn apply_account_updates_from_trie_batch<'a>(
2181 &self,
2182 state_trie: &mut Trie,
2183 account_updates: impl IntoIterator<Item = &'a AccountUpdate>,
2184 ) -> Result<AccountUpdatesList, StoreError> {
2185 let mut ret_storage_updates = Vec::new();
2186 let mut code_updates = Vec::new();
2187 let state_root = state_trie.hash_no_commit(&NativeCrypto);
2188 for update in account_updates {
2189 let hashed_address = hash_address_fixed(&update.address);
2190 if update.removed {
2191 state_trie.remove(hashed_address.as_bytes())?;
2193 continue;
2194 }
2195 let mut account_state = match state_trie.get(hashed_address.as_bytes())? {
2198 Some(encoded_state) => AccountState::decode(&encoded_state)?,
2199 None => AccountState::default(),
2200 };
2201 if update.removed_storage {
2202 account_state.storage_root = *EMPTY_TRIE_HASH;
2203 }
2204 if let Some(info) = &update.info {
2205 account_state.nonce = info.nonce;
2206 account_state.balance = info.balance;
2207 account_state.code_hash = info.code_hash;
2208 if let Some(code) = &update.code {
2210 code_updates.push((info.code_hash, code.clone()));
2211 }
2212 }
2213 if !update.added_storage.is_empty() {
2215 let mut storage_trie =
2216 self.open_storage_trie(hashed_address, state_root, account_state.storage_root)?;
2217 for (storage_key, storage_value) in &update.added_storage {
2218 let hashed_key = hash_key(storage_key);
2219 if storage_value.is_zero() {
2220 storage_trie.remove(&hashed_key)?;
2221 } else {
2222 storage_trie.insert(hashed_key, storage_value.encode_to_vec())?;
2223 }
2224 }
2225 let (storage_hash, storage_updates) =
2226 storage_trie.collect_changes_since_last_hash(&NativeCrypto);
2227 account_state.storage_root = storage_hash;
2228 ret_storage_updates.push((hashed_address, storage_updates));
2229 }
2230 state_trie.insert(
2231 hashed_address.as_bytes().to_vec(),
2232 account_state.encode_to_vec(),
2233 )?;
2234 }
2235 let (state_trie_hash, state_updates) =
2236 state_trie.collect_changes_since_last_hash(&NativeCrypto);
2237
2238 Ok(AccountUpdatesList {
2239 state_trie_hash,
2240 state_updates,
2241 storage_updates: ret_storage_updates,
2242 code_updates,
2243 })
2244 }
2245
2246 pub fn apply_account_updates_from_trie_with_witness(
2249 &self,
2250 mut state_trie: Trie,
2251 account_updates: &[AccountUpdate],
2252 mut storage_tries: StorageTries,
2253 ) -> Result<(StorageTries, AccountUpdatesList), StoreError> {
2254 let mut ret_storage_updates = Vec::new();
2255
2256 let mut code_updates = Vec::new();
2257
2258 let state_root = state_trie.hash_no_commit(&NativeCrypto);
2259
2260 for update in account_updates.iter() {
2261 let hashed_address = hash_address(&update.address);
2262
2263 if update.removed {
2264 state_trie.remove(&hashed_address)?;
2266
2267 continue;
2268 }
2269
2270 let mut account_state = match state_trie.get(&hashed_address)? {
2273 Some(encoded_state) => AccountState::decode(&encoded_state)?,
2274 None => AccountState::default(),
2275 };
2276
2277 if update.removed_storage {
2278 account_state.storage_root = *EMPTY_TRIE_HASH;
2279 }
2280
2281 if let Some(info) = &update.info {
2282 account_state.nonce = info.nonce;
2283
2284 account_state.balance = info.balance;
2285
2286 account_state.code_hash = info.code_hash;
2287
2288 if let Some(code) = &update.code {
2290 code_updates.push((info.code_hash, code.clone()));
2291 }
2292 }
2293
2294 if !update.added_storage.is_empty() {
2296 let (_witness, storage_trie) = match storage_tries.entry(update.address) {
2297 Entry::Occupied(value) => value.into_mut(),
2298 Entry::Vacant(vacant) => {
2299 let trie = self.open_storage_trie(
2300 H256::from_slice(&hashed_address),
2301 state_root,
2302 account_state.storage_root,
2303 )?;
2304 vacant.insert(TrieLogger::open_trie(trie))
2305 }
2306 };
2307
2308 for (storage_key, storage_value) in &update.added_storage {
2309 let hashed_key = hash_key(storage_key);
2310
2311 if storage_value.is_zero() {
2312 storage_trie.remove(&hashed_key)?;
2313 } else {
2314 storage_trie.insert(hashed_key, storage_value.encode_to_vec())?;
2315 }
2316 }
2317
2318 let (storage_hash, storage_updates) =
2319 storage_trie.collect_changes_since_last_hash(&NativeCrypto);
2320
2321 account_state.storage_root = storage_hash;
2322
2323 ret_storage_updates.push((H256::from_slice(&hashed_address), storage_updates));
2324 }
2325
2326 state_trie.insert(hashed_address, account_state.encode_to_vec())?;
2327 }
2328
2329 let (state_trie_hash, state_updates) =
2330 state_trie.collect_changes_since_last_hash(&NativeCrypto);
2331
2332 let account_updates_list = AccountUpdatesList {
2333 state_trie_hash,
2334 state_updates,
2335 storage_updates: ret_storage_updates,
2336 code_updates,
2337 };
2338
2339 Ok((storage_tries, account_updates_list))
2340 }
2341
2342 pub async fn setup_genesis_state_trie(
2344 &self,
2345 genesis_accounts: BTreeMap<Address, GenesisAccount>,
2346 ) -> Result<H256, StoreError> {
2347 let mut storage_trie_nodes = vec![];
2348 let mut genesis_state_trie = self.open_direct_state_trie(*EMPTY_TRIE_HASH)?;
2349 for (address, account) in genesis_accounts {
2350 let hashed_address = hash_address(&address);
2351 let h256_hashed_address = H256::from_slice(&hashed_address);
2352
2353 let code = Code::from_bytecode(account.code, &NativeCrypto);
2355 let code_hash = code.hash;
2356 self.add_account_code(code).await?;
2357
2358 let mut storage_trie =
2360 self.open_direct_storage_trie(h256_hashed_address, *EMPTY_TRIE_HASH)?;
2361 for (storage_key, storage_value) in account.storage {
2362 if !storage_value.is_zero() {
2363 let hashed_key = hash_key(&H256(storage_key.to_big_endian()));
2364 storage_trie.insert(hashed_key, storage_value.encode_to_vec())?;
2365 }
2366 }
2367
2368 let (storage_root, storage_nodes) =
2369 storage_trie.collect_changes_since_last_hash(&NativeCrypto);
2370
2371 storage_trie_nodes.extend(
2372 storage_nodes
2373 .into_iter()
2374 .map(|(path, n)| (apply_prefix(Some(h256_hashed_address), path).into_vec(), n)),
2375 );
2376
2377 let account_state = AccountState {
2379 nonce: account.nonce,
2380 balance: account.balance,
2381 storage_root,
2382 code_hash,
2383 };
2384 genesis_state_trie.insert(hashed_address, account_state.encode_to_vec())?;
2385 }
2386
2387 let (state_root, account_trie_nodes) =
2388 genesis_state_trie.collect_changes_since_last_hash(&NativeCrypto);
2389 let account_trie_nodes = account_trie_nodes
2390 .into_iter()
2391 .map(|(path, n)| (apply_prefix(None, path).into_vec(), n))
2392 .collect::<Vec<_>>();
2393
2394 let mut tx = self.backend.begin_write()?;
2395 tx.put_batch(ACCOUNT_TRIE_NODES, account_trie_nodes)?;
2396 tx.put_batch(STORAGE_TRIE_NODES, storage_trie_nodes)?;
2397 tx.commit()?;
2398
2399 Ok(state_root)
2400 }
2401
2402 fn make_witness_key(block_number: u64, block_hash: &BlockHash) -> Vec<u8> {
2404 let mut composite_key = Vec::with_capacity(8 + 32);
2405 composite_key.extend_from_slice(&block_number.to_be_bytes());
2406 composite_key.extend_from_slice(block_hash.as_bytes());
2407 composite_key
2408 }
2409
2410 pub fn store_witness(
2416 &self,
2417 block_hash: BlockHash,
2418 block_number: u64,
2419 witness: ExecutionWitness,
2420 ) -> Result<(), StoreError> {
2421 let rpc_witness = RpcExecutionWitness::try_from(witness)?;
2423 let key = Self::make_witness_key(block_number, &block_hash);
2424 let value = serde_json::to_vec(&rpc_witness)?;
2425 self.write(EXECUTION_WITNESSES, key, value)?;
2426 self.cleanup_old_witnesses(block_number)
2428 }
2429
2430 fn cleanup_old_witnesses(&self, latest_block_number: u64) -> Result<(), StoreError> {
2431 if latest_block_number <= MAX_WITNESSES {
2433 return Ok(());
2434 }
2435
2436 let threshold = latest_block_number - MAX_WITNESSES;
2437
2438 if let Some(oldest_block_number) = self.get_oldest_witness_number()? {
2439 let prefix = oldest_block_number.to_be_bytes();
2440 let mut to_delete = Vec::new();
2441
2442 {
2443 let read_txn = self.backend.begin_read()?;
2444 let iter = read_txn.prefix_iterator(EXECUTION_WITNESSES, &prefix)?;
2445
2446 for item in iter {
2448 let (key, _value) = item?;
2449 let mut block_number_bytes = [0u8; 8];
2450 block_number_bytes.copy_from_slice(&key[0..8]);
2451 let block_number = u64::from_be_bytes(block_number_bytes);
2452 if block_number > threshold {
2453 break;
2454 }
2455 to_delete.push(key.to_vec());
2456 }
2457 }
2458
2459 for key in to_delete {
2460 self.delete(EXECUTION_WITNESSES, key)?;
2461 }
2462 };
2463
2464 self.update_oldest_witness_number(threshold + 1)?;
2465
2466 Ok(())
2467 }
2468
2469 fn update_oldest_witness_number(&self, oldest_block_number: u64) -> Result<(), StoreError> {
2470 self.write(
2471 MISC_VALUES,
2472 b"oldest_witness_block_number".to_vec(),
2473 oldest_block_number.to_le_bytes().to_vec(),
2474 )?;
2475 Ok(())
2476 }
2477
2478 fn get_oldest_witness_number(&self) -> Result<Option<u64>, StoreError> {
2479 let Some(value) = self.read(MISC_VALUES, b"oldest_witness_block_number".to_vec())? else {
2480 return Ok(None);
2481 };
2482
2483 let array: [u8; 8] = value.as_slice().try_into().map_err(|_| {
2484 StoreError::Custom("Invalid oldest witness block number bytes".to_string())
2485 })?;
2486 Ok(Some(u64::from_le_bytes(array)))
2487 }
2488
2489 pub fn get_witness_json_bytes(
2495 &self,
2496 block_number: u64,
2497 block_hash: BlockHash,
2498 ) -> Result<Option<Vec<u8>>, StoreError> {
2499 let key = Self::make_witness_key(block_number, &block_hash);
2500 self.read(EXECUTION_WITNESSES, key)
2501 }
2502
2503 pub fn get_witness_by_number_and_hash(
2508 &self,
2509 block_number: u64,
2510 block_hash: BlockHash,
2511 ) -> Result<Option<RpcExecutionWitness>, StoreError> {
2512 let key = Self::make_witness_key(block_number, &block_hash);
2513 match self.read(EXECUTION_WITNESSES, key)? {
2514 Some(value) => {
2515 let witness: RpcExecutionWitness = serde_json::from_slice(&value)?;
2516 Ok(Some(witness))
2517 }
2518 None => Ok(None),
2519 }
2520 }
2521
2522 pub fn store_block_access_list(
2524 &self,
2525 block_hash: BlockHash,
2526 bal: &BlockAccessList,
2527 ) -> Result<(), StoreError> {
2528 let key = block_hash.as_bytes().to_vec();
2529 let mut value = vec![];
2530 bal.encode(&mut value);
2531 self.write(BLOCK_ACCESS_LISTS, key, value)
2532 }
2533
2534 pub fn get_block_access_list(
2536 &self,
2537 block_hash: BlockHash,
2538 ) -> Result<Option<BlockAccessList>, StoreError> {
2539 let key = block_hash.as_bytes().to_vec();
2540 match self.read(BLOCK_ACCESS_LISTS, key)? {
2541 Some(value) => {
2542 let bal = BlockAccessList::decode(&value)
2543 .map_err(|e| StoreError::Custom(format!("Failed to decode BAL: {e}")))?;
2544 Ok(Some(bal))
2545 }
2546 None => Ok(None),
2547 }
2548 }
2549
2550 pub async fn add_initial_state(&mut self, genesis: Genesis) -> Result<(), StoreError> {
2551 self.add_initial_state_inner(genesis, false).await
2552 }
2553
2554 pub async fn add_initial_state_skip_validation(
2565 &mut self,
2566 genesis: Genesis,
2567 ) -> Result<(), StoreError> {
2568 self.add_initial_state_inner(genesis, true).await
2569 }
2570
2571 async fn add_initial_state_inner(
2572 &mut self,
2573 genesis: Genesis,
2574 skip_genesis_validation: bool,
2575 ) -> Result<(), StoreError> {
2576 debug!("Storing initial state from genesis");
2577
2578 let genesis_block = genesis.get_block();
2580 let genesis_block_number = genesis_block.header.number;
2581
2582 let genesis_hash = genesis_block.hash();
2583
2584 let stored_genesis_header = self.load_block_header(genesis_block_number)?;
2585
2586 self.set_chain_config(&genesis.config).await?;
2593
2594 if let Some(latest) = self.load_latest_block_number().await? {
2599 self.anchor_to_durable_head(latest).await?;
2600 }
2601
2602 match stored_genesis_header {
2603 Some(header) if skip_genesis_validation => {
2604 info!(
2605 stored_genesis = %header.hash(),
2606 "Skipping genesis state validation; trusting the genesis header and state already stored in the datadir"
2607 );
2608 return Ok(());
2609 }
2610 Some(header) if header.hash() == genesis_hash => {
2611 info!("Received genesis file matching a previously stored one, nothing to do");
2612 return Ok(());
2613 }
2614 Some(_) => {
2615 error!(
2616 "The chain configuration stored in the database is incompatible with the provided configuration. If you intended to switch networks, choose another datadir or clear the database (e.g., run `ethrex removedb`) and try again."
2617 );
2618 return Err(StoreError::IncompatibleChainConfig);
2619 }
2620 None => {
2621 self.add_block_header(genesis_hash, genesis_block.header.clone())
2622 .await?
2623 }
2624 }
2625 let genesis_state_root = self.setup_genesis_state_trie(genesis.alloc).await?;
2628 debug_assert_eq!(genesis_state_root, genesis_block.header.state_root);
2629
2630 info!(hash = %genesis_hash, "Storing genesis block");
2632
2633 self.add_block(genesis_block).await?;
2634 self.update_earliest_block_number(genesis_block_number)
2635 .await?;
2636 self.forkchoice_update(vec![], genesis_block_number, genesis_hash, None, None)
2637 .await?;
2638 Ok(())
2639 }
2640
2641 pub async fn load_initial_state(&self) -> Result<(), StoreError> {
2642 info!("Loading initial state from DB");
2643 let Some(latest) = self.load_latest_block_number().await? else {
2644 return Err(StoreError::MissingLatestBlockNumber);
2645 };
2646 self.anchor_to_durable_head(latest).await?;
2650 Ok(())
2651 }
2652
2653 pub fn get_storage_at(
2654 &self,
2655 block_number: BlockNumber,
2656 address: Address,
2657 storage_key: H256,
2658 ) -> Result<Option<U256>, StoreError> {
2659 match self.get_block_header(block_number)? {
2660 Some(header) => self.get_storage_at_root(header.state_root, address, storage_key),
2661 None => Ok(None),
2662 }
2663 }
2664
2665 pub fn get_storage_at_root(
2666 &self,
2667 state_root: H256,
2668 address: Address,
2669 storage_key: H256,
2670 ) -> Result<Option<U256>, StoreError> {
2671 let account_hash = hash_address_fixed(&address);
2672
2673 let read_view = self.backend.begin_read()?;
2675 let cache = self.gated_snapshot(state_root)?;
2676 let last_written = self.last_written()?;
2677 let use_fkv = Self::flatkeyvalue_computed_with_last_written(account_hash, &last_written);
2678
2679 let storage_root = if use_fkv {
2680 *EMPTY_TRIE_HASH
2682 } else {
2683 let state_trie = self.open_state_trie_shared(
2684 state_root,
2685 read_view.clone(),
2686 cache.clone(),
2687 last_written.clone(),
2688 )?;
2689 let Some(encoded_account) = state_trie.get(account_hash.as_bytes())? else {
2690 return Ok(None);
2691 };
2692 let account = AccountState::decode(&encoded_account)?;
2693 account.storage_root
2694 };
2695 let storage_trie = self.open_storage_trie_shared(
2696 account_hash,
2697 state_root,
2698 storage_root,
2699 read_view,
2700 cache,
2701 last_written,
2702 )?;
2703
2704 let hashed_key = hash_key_fixed(&storage_key);
2705 storage_trie
2706 .get(&hashed_key)?
2707 .map(|rlp| U256::decode(&rlp).map_err(StoreError::RLPDecode))
2708 .transpose()
2709 }
2710
2711 pub fn get_storage_at_root_with_known_storage_root(
2716 &self,
2717 state_root: H256,
2718 account_hash: H256,
2719 storage_root: H256,
2720 storage_key: H256,
2721 ) -> Result<Option<U256>, StoreError> {
2722 let read_view = self.backend.begin_read()?;
2723 let cache = self.gated_snapshot(state_root)?;
2724 let last_written = self.last_written()?;
2725 let storage_root =
2729 if Self::flatkeyvalue_computed_with_last_written(account_hash, &last_written) {
2730 *EMPTY_TRIE_HASH
2731 } else {
2732 storage_root
2733 };
2734 let storage_trie = self.open_storage_trie_shared(
2735 account_hash,
2736 state_root,
2737 storage_root,
2738 read_view,
2739 cache,
2740 last_written,
2741 )?;
2742
2743 let hashed_key = hash_key_fixed(&storage_key);
2744 storage_trie
2745 .get(&hashed_key)?
2746 .map(|rlp| U256::decode(&rlp).map_err(StoreError::RLPDecode))
2747 .transpose()
2748 }
2749
2750 pub fn get_chain_config(&self) -> ChainConfig {
2751 self.chain_config
2752 }
2753
2754 pub async fn get_latest_canonical_block_hash(&self) -> Result<Option<BlockHash>, StoreError> {
2755 Ok(Some(self.latest_block_header.get().hash()))
2756 }
2757
2758 pub async fn forkchoice_update(
2763 &self,
2764 new_canonical_blocks: Vec<(BlockNumber, BlockHash)>,
2765 head_number: BlockNumber,
2766 head_hash: BlockHash,
2767 safe: Option<BlockNumber>,
2768 finalized: Option<BlockNumber>,
2769 ) -> Result<(), StoreError> {
2770 let _guard = self.fcu_lock.lock().await;
2776
2777 let previous_head = self.latest_block_header.get();
2782 let new_head = self
2783 .get_block_header_by_hash(head_hash)?
2784 .ok_or_else(|| StoreError::MissingLatestBlockNumber)?;
2785 self.latest_block_header.update(new_head);
2786 if let Err(err) = self
2787 .forkchoice_update_inner(
2788 new_canonical_blocks,
2789 head_number,
2790 head_hash,
2791 safe,
2792 finalized,
2793 )
2794 .await
2795 {
2796 self.latest_block_header.update((*previous_head).clone());
2797 return Err(err);
2798 }
2799
2800 if let Some(root) = self.compute_safe_commit_root(head_number)? {
2806 if self.set_safe_commit_root(root)? {
2811 let tx = self.persist_tx.clone();
2812 let _ = tokio::task::spawn_blocking(move || tx.send(PersistMessage::Commit(root)))
2813 .await;
2814 }
2815 }
2816
2817 Ok(())
2818 }
2819
2820 pub(crate) fn set_safe_commit_root(&self, root: H256) -> Result<bool, StoreError> {
2828 let mut guard = self
2829 .safe_commit_root
2830 .write()
2831 .map_err(|_| StoreError::LockError)?;
2832 let changed = *guard != root;
2833 *guard = root;
2834 Ok(changed)
2835 }
2836
2837 pub(crate) fn compute_safe_commit_root(
2846 &self,
2847 head: BlockNumber,
2848 ) -> Result<Option<H256>, StoreError> {
2849 let commit_threshold = self
2850 .trie_cache
2851 .read()
2852 .map_err(|_| StoreError::LockError)?
2853 .commit_threshold;
2854 let Some(target) = head.checked_sub(commit_threshold as u64) else {
2855 return Ok(None);
2856 };
2857 let Some(hash) = self.get_canonical_block_hash_sync(target)? else {
2858 return Ok(None);
2859 };
2860 let Some(header) = self.get_block_header_by_hash(hash)? else {
2861 return Ok(None);
2862 };
2863 Ok(Some(header.state_root))
2864 }
2865
2866 pub fn state_trie(&self, block_hash: BlockHash) -> Result<Option<Trie>, StoreError> {
2868 let Some(header) = self.get_block_header_by_hash(block_hash)? else {
2869 return Ok(None);
2870 };
2871 Ok(Some(self.open_state_trie(header.state_root)?))
2872 }
2873
2874 pub fn storage_trie(
2876 &self,
2877 block_hash: BlockHash,
2878 address: Address,
2879 ) -> Result<Option<Trie>, StoreError> {
2880 let Some(header) = self.get_block_header_by_hash(block_hash)? else {
2881 return Ok(None);
2882 };
2883 let Some(state_trie) = self.state_trie(block_hash)? else {
2885 return Ok(None);
2886 };
2887 let hashed_address = hash_address_fixed(&address);
2888 let Some(encoded_account) = state_trie.get(hashed_address.as_bytes())? else {
2889 return Ok(None);
2890 };
2891 let account = AccountState::decode(&encoded_account)?;
2892 let storage_root = account.storage_root;
2894 Ok(Some(self.open_storage_trie(
2895 hashed_address,
2896 header.state_root,
2897 storage_root,
2898 )?))
2899 }
2900
2901 pub async fn get_account_state(
2902 &self,
2903 block_number: BlockNumber,
2904 address: Address,
2905 ) -> Result<Option<AccountState>, StoreError> {
2906 let Some(block_hash) = self.get_canonical_block_hash(block_number).await? else {
2907 return Ok(None);
2908 };
2909 let Some(state_trie) = self.state_trie(block_hash)? else {
2910 return Ok(None);
2911 };
2912 self.get_account_state_from_trie(&state_trie, address)
2913 }
2914
2915 pub fn get_account_state_by_root(
2916 &self,
2917 state_root: H256,
2918 address: Address,
2919 ) -> Result<Option<AccountState>, StoreError> {
2920 let state_trie = self.open_state_trie(state_root)?;
2921 self.get_account_state_from_trie(&state_trie, address)
2922 }
2923
2924 pub fn get_account_state_from_trie(
2925 &self,
2926 state_trie: &Trie,
2927 address: Address,
2928 ) -> Result<Option<AccountState>, StoreError> {
2929 let hashed_address = hash_address_fixed(&address);
2930 let Some(encoded_state) = state_trie.get(hashed_address.as_bytes())? else {
2931 return Ok(None);
2932 };
2933 Ok(Some(AccountState::decode(&encoded_state)?))
2934 }
2935
2936 pub fn get_account_states_batch_by_root(
2945 &self,
2946 state_root: H256,
2947 addresses: &[Address],
2948 ) -> Result<Vec<Option<AccountState>>, StoreError> {
2949 if addresses.is_empty() {
2950 return Ok(Vec::new());
2951 }
2952
2953 let last_written = self.last_written()?;
2954 let trie_cache = self
2955 .trie_cache
2956 .read()
2957 .map_err(|_| StoreError::LockError)?
2958 .clone();
2959
2960 let mut results: Vec<Option<AccountState>> = vec![None; addresses.len()];
2961 let leaf_paths: Vec<Vec<u8>> = addresses
2963 .iter()
2964 .map(|addr| {
2965 let hashed = hash_address_fixed(addr);
2966 Nibbles::from_bytes(hashed.as_bytes()).into_vec()
2967 })
2968 .collect();
2969
2970 let mut fkv_indices: Vec<usize> = Vec::new();
2971 let mut trie_indices: Vec<usize> = Vec::new();
2972
2973 let fkv_cursor: &[u8] = last_written.as_slice();
2982 for (i, path) in leaf_paths.iter().enumerate() {
2983 if let Some(value) = trie_cache.get(state_root, path.as_slice()) {
2984 if !value.is_empty() {
2985 results[i] = Some(AccountState::decode(&value)?);
2986 }
2987 continue;
2988 }
2989 if fkv_cursor >= path.as_slice() {
2990 fkv_indices.push(i);
2991 } else {
2992 trie_indices.push(i);
2993 }
2994 }
2995
2996 if !fkv_indices.is_empty() {
2997 let read_view = self.backend.begin_read()?;
2998 let keys: Vec<&[u8]> = fkv_indices
2999 .iter()
3000 .map(|&i| leaf_paths[i].as_slice())
3001 .collect();
3002 let raw = read_view.multi_get(ACCOUNT_FLATKEYVALUE, &keys);
3003 for (slot, res) in fkv_indices.iter().zip(raw.into_iter()) {
3004 let Some(encoded) = res? else { continue };
3005 if encoded.is_empty() {
3006 continue;
3007 }
3008 results[*slot] = Some(AccountState::decode(&encoded)?);
3009 }
3010 }
3011
3012 if !trie_indices.is_empty() {
3013 let state_trie = self.open_state_trie(state_root)?;
3019 let fetched: Result<Vec<(usize, Option<AccountState>)>, StoreError> = trie_indices
3020 .par_iter()
3021 .map(|&i| {
3022 self.get_account_state_from_trie(&state_trie, addresses[i])
3023 .map(|s| (i, s))
3024 })
3025 .collect();
3026 for (i, s) in fetched? {
3027 results[i] = s;
3028 }
3029 }
3030
3031 Ok(results)
3032 }
3033
3034 pub async fn get_account_proof(
3039 &self,
3040 state_root: H256,
3041 address: Address,
3042 storage_keys: &[H256],
3043 ) -> Result<Option<AccountProof>, StoreError> {
3044 let state_trie = self.open_state_trie(state_root)?;
3049 let address_path = hash_address_fixed(&address);
3050 let proof = state_trie.get_proof(address_path.as_bytes())?;
3051 let account_opt = state_trie
3052 .get(address_path.as_bytes())?
3053 .map(|encoded_state| AccountState::decode(&encoded_state))
3054 .transpose()?;
3055
3056 let mut storage_proof = Vec::with_capacity(storage_keys.len());
3057
3058 if let Some(account) = &account_opt {
3059 let storage_trie =
3060 self.open_storage_trie(address_path, state_root, account.storage_root)?;
3061
3062 for key in storage_keys {
3063 let hashed_key = hash_key(key);
3064 let proof = storage_trie.get_proof(&hashed_key)?;
3065 let value = storage_trie
3066 .get(&hashed_key)?
3067 .map(|rlp| U256::decode(&rlp).map_err(StoreError::RLPDecode))
3068 .transpose()?
3069 .unwrap_or_default();
3070
3071 let slot_proof = StorageSlotProof {
3072 proof,
3073 key: *key,
3074 value,
3075 };
3076 storage_proof.push(slot_proof);
3077 }
3078 } else {
3079 storage_proof.extend(storage_keys.iter().map(|key| StorageSlotProof {
3080 proof: Vec::new(),
3081 key: *key,
3082 value: U256::zero(),
3083 }));
3084 }
3085 let account = account_opt.unwrap_or_default();
3086 let account_proof = AccountProof {
3087 proof,
3088 account,
3089 storage_proof,
3090 };
3091 Ok(Some(account_proof))
3092 }
3093
3094 pub fn iter_accounts_from(
3097 &self,
3098 state_root: H256,
3099 starting_address: H256,
3100 ) -> Result<impl Iterator<Item = (H256, AccountState)>, StoreError> {
3101 let mut iter = self.open_locked_state_trie(state_root)?.into_iter();
3102 iter.advance(starting_address.0.to_vec())?;
3103 Ok(iter.content().map_while(|(path, value)| {
3104 Some((H256::from_slice(&path), AccountState::decode(&value).ok()?))
3105 }))
3106 }
3107
3108 pub fn iter_accounts(
3111 &self,
3112 state_root: H256,
3113 ) -> Result<impl Iterator<Item = (H256, AccountState)>, StoreError> {
3114 self.iter_accounts_from(state_root, H256::zero())
3115 }
3116
3117 pub fn iter_storage_from(
3120 &self,
3121 state_root: H256,
3122 hashed_address: H256,
3123 starting_slot: H256,
3124 ) -> Result<Option<impl Iterator<Item = (H256, U256)>>, StoreError> {
3125 let state_trie = self.open_locked_state_trie(state_root)?;
3126 let Some(account_rlp) = state_trie.get(hashed_address.as_bytes())? else {
3127 return Ok(None);
3128 };
3129 let storage_root = AccountState::decode(&account_rlp)?.storage_root;
3130 let mut iter = self
3131 .open_locked_storage_trie(hashed_address, state_root, storage_root)?
3132 .into_iter();
3133 iter.advance(starting_slot.0.to_vec())?;
3134 Ok(Some(iter.content().map_while(|(path, value)| {
3135 Some((H256::from_slice(&path), U256::decode(&value).ok()?))
3136 })))
3137 }
3138
3139 pub fn iter_storage(
3142 &self,
3143 state_root: H256,
3144 hashed_address: H256,
3145 ) -> Result<Option<impl Iterator<Item = (H256, U256)>>, StoreError> {
3146 self.iter_storage_from(state_root, hashed_address, H256::zero())
3147 }
3148
3149 pub fn get_account_range_proof(
3150 &self,
3151 state_root: H256,
3152 starting_hash: H256,
3153 last_hash: Option<H256>,
3154 ) -> Result<Vec<Vec<u8>>, StoreError> {
3155 let state_trie = self.open_state_trie(state_root)?;
3156 let mut proof = state_trie.get_proof(starting_hash.as_bytes())?;
3157 if let Some(last_hash) = last_hash {
3158 proof.extend_from_slice(&state_trie.get_proof(last_hash.as_bytes())?);
3159 }
3160 Ok(proof)
3161 }
3162
3163 pub fn get_storage_range_proof(
3164 &self,
3165 state_root: H256,
3166 hashed_address: H256,
3167 starting_hash: H256,
3168 last_hash: Option<H256>,
3169 ) -> Result<Option<Vec<Vec<u8>>>, StoreError> {
3170 let state_trie = self.open_state_trie(state_root)?;
3171 let Some(account_rlp) = state_trie.get(hashed_address.as_bytes())? else {
3172 return Ok(None);
3173 };
3174 let storage_root = AccountState::decode(&account_rlp)?.storage_root;
3175 let storage_trie = self.open_storage_trie(hashed_address, state_root, storage_root)?;
3176 let mut proof = storage_trie.get_proof(starting_hash.as_bytes())?;
3177 if let Some(last_hash) = last_hash {
3178 proof.extend_from_slice(&storage_trie.get_proof(last_hash.as_bytes())?);
3179 }
3180 Ok(Some(proof))
3181 }
3182
3183 pub fn get_trie_nodes(
3190 &self,
3191 state_root: H256,
3192 paths: Vec<Vec<u8>>,
3193 byte_limit: u64,
3194 ) -> Result<Vec<Vec<u8>>, StoreError> {
3195 let Some(account_path) = paths.first() else {
3196 return Ok(vec![]);
3197 };
3198 let state_trie = self.open_state_trie(state_root)?;
3199 if paths.len() == 1 {
3201 let node = state_trie.get_node(account_path)?;
3203 return Ok(vec![node]);
3204 }
3205 let Some(account_state) = state_trie
3207 .get(account_path)?
3208 .map(|ref rlp| AccountState::decode(rlp))
3209 .transpose()?
3210 else {
3211 return Ok(vec![]);
3212 };
3213 let Ok(hashed_address) = account_path.clone().try_into().map(H256) else {
3215 return Ok(vec![]);
3216 };
3217 let storage_trie =
3218 self.open_storage_trie(hashed_address, state_root, account_state.storage_root)?;
3219 let mut nodes = vec![];
3221 let mut bytes_used = 0;
3222 for path in paths.iter().skip(1) {
3226 if bytes_used >= byte_limit {
3227 break;
3228 }
3229 let node = storage_trie.get_node(path)?;
3230 bytes_used += node.len() as u64;
3231 nodes.push(node);
3232 }
3233 Ok(nodes)
3234 }
3235
3236 fn gated_snapshot(&self, state_root: H256) -> Result<Arc<TrieLayerCache>, StoreError> {
3245 self.pending_trie_roots.wait_until_ready(state_root)?;
3246 Ok(self
3247 .trie_cache
3248 .read()
3249 .map_err(|_| StoreError::LockError)?
3250 .clone())
3251 }
3252
3253 pub fn open_state_trie(&self, state_root: H256) -> Result<Trie, StoreError> {
3257 let trie_db = TrieWrapper::new(
3258 state_root,
3259 self.gated_snapshot(state_root)?,
3260 Box::new(BackendTrieDB::new_for_accounts(
3261 self.backend.clone(),
3262 self.last_written()?,
3263 )?),
3264 None,
3265 );
3266 Ok(Trie::open(Box::new(trie_db), state_root))
3267 }
3268
3269 pub fn open_direct_state_trie(&self, state_root: H256) -> Result<Trie, StoreError> {
3273 Ok(Trie::open(
3274 Box::new(BackendTrieDB::new_for_accounts(
3275 self.backend.clone(),
3276 self.last_written()?,
3277 )?),
3278 state_root,
3279 ))
3280 }
3281
3282 pub fn open_locked_state_trie(&self, state_root: H256) -> Result<Trie, StoreError> {
3286 let trie_db = TrieWrapper::new(
3287 state_root,
3288 self.gated_snapshot(state_root)?,
3289 Box::new(state_trie_locked_backend(
3290 self.backend.as_ref(),
3291 self.last_written()?,
3292 )?),
3293 None,
3294 );
3295 Ok(Trie::open(Box::new(trie_db), state_root))
3296 }
3297
3298 pub fn open_storage_trie(
3301 &self,
3302 account_hash: H256,
3303 state_root: H256,
3304 storage_root: H256,
3305 ) -> Result<Trie, StoreError> {
3306 let trie_db = TrieWrapper::new(
3307 state_root,
3308 self.gated_snapshot(state_root)?,
3309 Box::new(BackendTrieDB::new_for_storages(
3310 self.backend.clone(),
3311 self.last_written()?,
3312 )?),
3313 Some(account_hash),
3314 );
3315 Ok(Trie::open(Box::new(trie_db), storage_root))
3316 }
3317
3318 fn open_state_trie_shared(
3322 &self,
3323 state_root: H256,
3324 read_view: Arc<dyn StorageReadView>,
3325 cache: Arc<TrieLayerCache>,
3326 last_written: Vec<u8>,
3327 ) -> Result<Trie, StoreError> {
3328 let trie_db = TrieWrapper::new(
3329 state_root,
3330 cache,
3331 Box::new(BackendTrieDB::new_for_accounts_with_view(
3332 self.backend.clone(),
3333 read_view,
3334 last_written,
3335 )?),
3336 None,
3337 );
3338 Ok(Trie::open(Box::new(trie_db), state_root))
3339 }
3340
3341 fn open_storage_trie_shared(
3343 &self,
3344 account_hash: H256,
3345 state_root: H256,
3346 storage_root: H256,
3347 read_view: Arc<dyn StorageReadView>,
3348 cache: Arc<TrieLayerCache>,
3349 last_written: Vec<u8>,
3350 ) -> Result<Trie, StoreError> {
3351 let trie_db = TrieWrapper::new(
3352 state_root,
3353 cache,
3354 Box::new(BackendTrieDB::new_for_storages_with_view(
3355 self.backend.clone(),
3356 read_view,
3357 last_written,
3358 )?),
3359 Some(account_hash),
3360 );
3361 Ok(Trie::open(Box::new(trie_db), storage_root))
3362 }
3363
3364 pub fn open_direct_storage_trie(
3367 &self,
3368 account_hash: H256,
3369 storage_root: H256,
3370 ) -> Result<Trie, StoreError> {
3371 Ok(Trie::open(
3372 Box::new(BackendTrieDB::new_for_account_storage(
3373 self.backend.clone(),
3374 account_hash,
3375 self.last_written()?,
3376 )?),
3377 storage_root,
3378 ))
3379 }
3380
3381 pub fn open_locked_storage_trie(
3384 &self,
3385 account_hash: H256,
3386 state_root: H256,
3387 storage_root: H256,
3388 ) -> Result<Trie, StoreError> {
3389 let trie_db = TrieWrapper::new(
3390 state_root,
3391 self.gated_snapshot(state_root)?,
3392 Box::new(state_trie_locked_backend(
3393 self.backend.as_ref(),
3394 self.last_written()?,
3395 )?),
3396 Some(account_hash),
3397 );
3398 Ok(Trie::open(Box::new(trie_db), storage_root))
3399 }
3400
3401 pub fn has_state_root(&self, state_root: H256) -> Result<bool, StoreError> {
3402 if state_root == *EMPTY_TRIE_HASH {
3404 return Ok(true);
3405 }
3406 let trie = self.open_state_trie(state_root)?;
3407 let Some(root) = trie.db().get(Nibbles::default())? else {
3409 return Ok(false);
3410 };
3411 let root_hash = ethrex_trie::Node::decode(&root)?
3412 .compute_hash(&NativeCrypto)
3413 .finalize(&NativeCrypto);
3414 Ok(state_root == root_hash)
3415 }
3416
3417 pub fn ancestors(&self, block_hash: BlockHash) -> AncestorIterator {
3420 AncestorIterator {
3421 store: self.clone(),
3422 next_hash: block_hash,
3423 }
3424 }
3425
3426 pub fn is_canonical_sync(&self, block_hash: BlockHash) -> Result<bool, StoreError> {
3428 let Some(block_number) = self.get_block_number_sync(block_hash)? else {
3429 return Ok(false);
3430 };
3431 Ok(self
3432 .get_canonical_block_hash_sync(block_number)?
3433 .is_some_and(|h| h == block_hash))
3434 }
3435
3436 pub fn generate_flatkeyvalue(&self) -> Result<(), StoreError> {
3437 self.flatkeyvalue_control_tx
3438 .send(FKVGeneratorControlMessage::Continue)
3439 .map_err(|_| StoreError::Custom("FlatKeyValue thread disconnected.".to_string()))
3440 }
3441
3442 pub fn create_checkpoint(&self, path: impl AsRef<Path>) -> Result<(), StoreError> {
3443 self.backend.create_checkpoint(path.as_ref())?;
3444 init_metadata_file(path.as_ref())?;
3445 Ok(())
3446 }
3447
3448 pub fn get_store_directory(&self) -> Result<PathBuf, StoreError> {
3449 Ok(self.db_path.clone())
3450 }
3451
3452 async fn load_latest_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
3454 let key = chain_data_key(ChainDataIndex::LatestBlockNumber);
3455 self.read_async(CHAIN_DATA, key)
3456 .await?
3457 .map(|bytes| -> Result<BlockNumber, StoreError> {
3458 let array: [u8; 8] = bytes
3459 .try_into()
3460 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
3461 Ok(BlockNumber::from_le_bytes(array))
3462 })
3463 .transpose()
3464 }
3465
3466 fn load_canonical_block_hash(
3467 &self,
3468 block_number: BlockNumber,
3469 ) -> Result<Option<BlockHash>, StoreError> {
3470 let txn = self.backend.begin_read()?;
3471 txn.get(
3472 CANONICAL_BLOCK_HASHES,
3473 block_number.to_le_bytes().as_slice(),
3474 )?
3475 .map(|bytes| H256::decode(bytes.as_slice()))
3476 .transpose()
3477 .map_err(StoreError::from)
3478 }
3479
3480 fn load_block_header(
3481 &self,
3482 block_number: BlockNumber,
3483 ) -> Result<Option<BlockHeader>, StoreError> {
3484 let Some(block_hash) = self.load_canonical_block_hash(block_number)? else {
3485 return Ok(None);
3486 };
3487 self.load_block_header_by_hash(block_hash)
3488 }
3489
3490 fn load_block_header_by_hash(
3492 &self,
3493 block_hash: BlockHash,
3494 ) -> Result<Option<BlockHeader>, StoreError> {
3495 let txn = self.backend.begin_read()?;
3496 let hash_key = block_hash.encode_to_vec();
3497 let header_value = txn.get(HEADERS, hash_key.as_slice())?;
3498 let mut header = header_value
3499 .map(|bytes| BlockHeaderRLP::from_bytes(bytes).to())
3500 .transpose()
3501 .map_err(StoreError::from)?;
3502 header.as_mut().inspect(|h| {
3503 let _ = h.hash.set(block_hash);
3505 });
3506 Ok(header)
3507 }
3508
3509 pub fn last_written(&self) -> Result<Vec<u8>, StoreError> {
3510 let last_computed_flatkeyvalue = self
3511 .last_computed_flatkeyvalue
3512 .read()
3513 .map_err(|_| StoreError::LockError)?;
3514 Ok(last_computed_flatkeyvalue.clone())
3515 }
3516
3517 fn flatkeyvalue_computed_with_last_written(account: H256, last_written: &[u8]) -> bool {
3518 let account_nibbles = Nibbles::from_bytes(account.as_bytes());
3519 &last_written[0..64] > account_nibbles.as_ref()
3520 }
3521
3522 pub fn read_flushed_upto(&self) -> Result<BlockNumber, StoreError> {
3527 Ok(self.read_flushed_upto_opt()?.unwrap_or(0))
3528 }
3529
3530 fn read_flushed_upto_opt(&self) -> Result<Option<BlockNumber>, StoreError> {
3533 let tx = self.backend.begin_read()?;
3534 match tx.get(MISC_VALUES, FLUSHED_UPTO_KEY)? {
3535 Some(bytes) => Ok(Some(decode_flushed_upto(&bytes)?)),
3536 None => Ok(None),
3537 }
3538 }
3539
3540 #[cfg(any(test, feature = "testing"))]
3543 pub fn buffer_block_for_test(&self, block: &Block) {
3544 mutate_block_buffer(&self.block_data_buffer, |b| {
3545 b.insert(block.clone(), vec![], vec![])
3546 })
3547 .expect("block_data_buffer lock poisoned");
3548 }
3549
3550 #[cfg(any(test, feature = "testing"))]
3553 pub fn flush_block_data_for_test(&self) -> Result<(), StoreError> {
3554 flush_block_data(self.backend.as_ref(), &self.block_data_buffer)
3555 }
3556
3557 #[cfg(any(test, feature = "testing"))]
3561 pub fn get_trie_node_for_test(
3562 &self,
3563 is_account: bool,
3564 key: &[u8],
3565 ) -> Result<Option<Vec<u8>>, StoreError> {
3566 let table = if is_account {
3567 ACCOUNT_TRIE_NODES
3568 } else {
3569 STORAGE_TRIE_NODES
3570 };
3571 self.backend.begin_read()?.get(table, key)
3572 }
3573
3574 #[cfg(any(test, feature = "testing"))]
3578 pub fn buffer_block_with_codes_for_test(&self, block: &Block, codes: Vec<(H256, Code)>) {
3579 mutate_block_buffer(&self.block_data_buffer, |b| {
3580 b.insert(block.clone(), vec![], codes)
3581 })
3582 .expect("block_data_buffer lock poisoned");
3583 }
3584
3585 #[cfg(any(test, feature = "testing"))]
3590 pub fn register_pending_root_for_test(&self, root: H256) -> Result<(), StoreError> {
3591 self.pending_trie_roots.register(root)
3592 }
3593
3594 #[cfg(any(test, feature = "testing"))]
3597 pub fn clear_pending_root_for_test(&self, root: H256) {
3598 self.pending_trie_roots.clear(root)
3599 }
3600
3601 async fn anchor_to_durable_head(&self, latest: BlockNumber) -> Result<(), StoreError> {
3620 let marker = self.read_flushed_upto_opt()?;
3621 let start = match marker {
3622 Some(flushed) => flushed.min(latest),
3623 None => latest,
3624 };
3625
3626 let mut head = start;
3627 let latest_block_header = loop {
3628 match self.load_block_header(head)? {
3629 Some(header) => break header,
3630 None if marker.is_none() => return Err(StoreError::MissingLatestBlockNumber),
3633 None if head == 0 => return Err(StoreError::MissingLatestBlockNumber),
3634 None => {
3635 warn!(
3636 "durable head {head}: canonical hash has no on-disk header \
3637 (reorg inside flush window); rewinding"
3638 );
3639 head -= 1;
3640 }
3641 }
3642 };
3643 self.latest_block_header.update(latest_block_header);
3644
3645 let reanchor = head != latest;
3650 let rewrite_marker = marker != Some(head);
3651 if reanchor || rewrite_marker {
3652 let mut tx = self.backend.begin_write()?;
3653 if reanchor {
3654 let latest_key = chain_data_key(ChainDataIndex::LatestBlockNumber);
3657 tx.put(CHAIN_DATA, &latest_key, &head.to_le_bytes())?;
3658 }
3659 if rewrite_marker {
3660 write_flushed_upto(tx.as_mut(), head)?;
3661 }
3662 tx.commit()?;
3663 }
3664 Ok(())
3665 }
3666}
3667
3668pub fn write_flushed_upto(
3672 tx: &mut dyn StorageWriteBatch,
3673 n: BlockNumber,
3674) -> Result<(), StoreError> {
3675 tx.put(MISC_VALUES, FLUSHED_UPTO_KEY, &n.to_le_bytes())
3676}
3677
3678fn decode_flushed_upto(bytes: &[u8]) -> Result<BlockNumber, StoreError> {
3684 let arr: [u8; 8] = bytes
3685 .try_into()
3686 .map_err(|_| StoreError::Custom("Invalid flushed_upto bytes".to_string()))?;
3687 Ok(BlockNumber::from_le_bytes(arr))
3688}
3689
3690fn mutate_block_buffer(
3693 buffer: &Arc<RwLock<Arc<BlockDataBuffer>>>,
3694 f: impl FnOnce(&mut BlockDataBuffer),
3695) -> Result<(), StoreError> {
3696 let mut new_buf = (*buffer.read().map_err(|_| StoreError::LockError)?.clone()).clone();
3697 f(&mut new_buf);
3698 *buffer.write().map_err(|_| StoreError::LockError)? = Arc::new(new_buf);
3699 Ok(())
3700}
3701
3702const DEFAULT_PERSIST_CHANNEL_CAPACITY: usize = 2;
3704
3705struct BlockPersist {
3710 blocks: Vec<(Block, Vec<Receipt>)>,
3711 codes: Vec<(H256, Code)>,
3712 parent_state_root: H256,
3713 child_state_root: H256,
3714 account_updates: TrieNodesUpdate,
3715 storage_updates: Vec<(H256, TrieNodesUpdate)>,
3716 wait_for_flush: bool,
3717 ack: std::sync::mpsc::SyncSender<Result<(), StoreError>>,
3718}
3719
3720enum PersistMessage {
3724 Block(BlockPersist),
3725 Commit(H256),
3731 Ping(std::sync::mpsc::SyncSender<Result<(), StoreError>>),
3732 Shutdown {
3737 ack: std::sync::mpsc::SyncSender<Result<(), StoreError>>,
3738 },
3739}
3740
3741fn write_block_data(
3746 tx: &mut dyn StorageWriteBatch,
3747 number: BlockNumber,
3748 hash: BlockHash,
3749 header: &BlockHeader,
3750 body: &BlockBody,
3751) -> Result<(), StoreError> {
3752 let hash_key = hash.encode_to_vec();
3753 tx.put(
3754 HEADERS,
3755 &hash_key,
3756 BlockHeaderRLP::from(header.clone()).bytes(),
3757 )?;
3758 tx.put(
3759 BODIES,
3760 &hash_key,
3761 BlockBodyRLP::from_bytes(body.encode_to_vec()).bytes(),
3762 )?;
3763 tx.put(BLOCK_NUMBERS, &hash_key, &number.to_le_bytes())?;
3764 for (index, transaction) in body.transactions.iter().enumerate() {
3765 tx.merge(
3766 TRANSACTION_LOCATIONS,
3767 transaction.hash(&NativeCrypto).as_bytes(),
3768 &encode_tx_location_operand(number, hash, index as u64),
3769 )?;
3770 }
3771 Ok(())
3772}
3773
3774fn flush_block_data(
3777 backend: &dyn StorageBackend,
3778 buffer: &Arc<RwLock<Arc<BlockDataBuffer>>>,
3779) -> Result<(), StoreError> {
3780 let snapshot = buffer.read().map_err(|_| StoreError::LockError)?.clone();
3781 let to_flush = snapshot.flushable();
3782 if to_flush.is_empty() {
3783 return Ok(());
3784 }
3785 let hashes: Vec<_> = to_flush.iter().map(|b| b.header.hash()).collect();
3786 let codes = snapshot.codes_for(&hashes);
3787 let mut max_number = snapshot.flushed_upto();
3788
3789 let mut tx = backend.begin_write()?;
3790 for b in &to_flush {
3791 let hash = b.header.hash();
3792 write_block_data(tx.as_mut(), b.number, hash, &b.header, &b.body)?;
3793 for (index, receipt) in b.receipts.iter().enumerate() {
3794 tx.put(
3795 RECEIPTS_V2,
3796 &receipt_key(&hash, index as u64),
3797 &receipt.encode_to_vec(),
3798 )?;
3799 }
3800 max_number = max_number.max(b.number);
3801 }
3802 for (code_hash, code) in codes {
3803 let buf = encode_code(&code);
3804 tx.put(ACCOUNT_CODES, code_hash.as_ref(), &buf)?;
3805 tx.put(
3806 ACCOUNT_CODE_METADATA,
3807 code_hash.as_ref(),
3808 &(code.len() as u64).to_be_bytes(),
3809 )?;
3810 }
3811 write_flushed_upto(tx.as_mut(), max_number)?;
3812 tx.commit()?;
3813
3814 mutate_block_buffer(buffer, |b| b.evict_flushed(max_number))
3816}
3817
3818type TrieNodesUpdate = Vec<(Nibbles, Vec<u8>)>;
3819
3820#[derive(Debug, Default)]
3826struct PendingTrieRoots {
3827 count: AtomicUsize,
3829 roots: Mutex<HashSet<H256>>,
3830 ready: Condvar,
3831}
3832
3833impl PendingTrieRoots {
3834 fn register(&self, root: H256) -> Result<(), StoreError> {
3838 let mut roots = self.roots.lock().map_err(|_| StoreError::LockError)?;
3839 if roots.insert(root) {
3840 self.count.fetch_add(1, Ordering::Release);
3841 }
3842 Ok(())
3843 }
3844
3845 fn clear(&self, root: H256) {
3850 let Ok(mut roots) = self.roots.lock() else {
3851 return;
3852 };
3853 if roots.remove(&root) {
3854 self.count.fetch_sub(1, Ordering::Release);
3855 self.ready.notify_all();
3856 }
3857 }
3858
3859 fn wait_until_ready(&self, root: H256) -> Result<(), StoreError> {
3862 if self.count.load(Ordering::Acquire) == 0 {
3863 return Ok(());
3864 }
3865 let mut roots = self.roots.lock().map_err(|_| StoreError::LockError)?;
3866 while roots.contains(&root) {
3867 roots = self.ready.wait(roots).map_err(|_| StoreError::LockError)?;
3868 }
3869 Ok(())
3870 }
3871}
3872
3873fn apply_trie_phase1(
3877 trie_cache: &Arc<RwLock<Arc<TrieLayerCache>>>,
3878 pending_roots: &PendingTrieRoots,
3879 parent_state_root: H256,
3880 child_state_root: H256,
3881 account_updates: TrieNodesUpdate,
3882 storage_updates: Vec<(H256, TrieNodesUpdate)>,
3883) -> Result<(), StoreError> {
3884 let build: Result<(), StoreError> = (|| {
3885 let new_layer = storage_updates
3886 .into_iter()
3887 .flat_map(|(account_hash, nodes)| {
3888 nodes
3889 .into_iter()
3890 .map(move |(path, node)| (apply_prefix(Some(account_hash), path), node))
3891 })
3892 .chain(account_updates)
3893 .collect();
3894 let trie = trie_cache
3895 .read()
3896 .map_err(|_| StoreError::LockError)?
3897 .clone();
3898 let mut trie_mut = (*trie).clone();
3899 trie_mut.put_batch(parent_state_root, child_state_root, new_layer);
3900 *trie_cache.write().map_err(|_| StoreError::LockError)? = Arc::new(trie_mut);
3901 Ok(())
3902 })();
3903 pending_roots.clear(child_state_root);
3908 build
3909}
3910
3911fn commit_trie_if_due(
3918 backend: &dyn StorageBackend,
3919 trie_cache: &Arc<RwLock<Arc<TrieLayerCache>>>,
3920 fkv_ctl: &SyncSender<FKVGeneratorControlMessage>,
3921 parent_state_root: H256,
3922 is_batch: bool,
3923) -> Result<(), StoreError> {
3924 let trie = trie_cache
3925 .read()
3926 .map_err(|_| StoreError::LockError)?
3927 .clone();
3928 let commitable = if is_batch {
3930 trie.get_commitable_by_depth(parent_state_root, BATCH_COMMIT_THRESHOLD)
3931 } else {
3932 trie.get_commitable(parent_state_root)
3933 };
3934 let Some(root) = commitable else {
3935 return Ok(());
3937 };
3938 commit_to_disk(backend, fkv_ctl, trie_cache, &trie, root)
3939}
3940
3941fn commit_to_disk(
3951 backend: &dyn StorageBackend,
3952 fkv_ctl: &SyncSender<FKVGeneratorControlMessage>,
3953 trie_cache: &Arc<RwLock<Arc<TrieLayerCache>>>,
3954 trie: &Arc<TrieLayerCache>,
3955 root: H256,
3956) -> Result<(), StoreError> {
3957 let _ = fkv_ctl.send(FKVGeneratorControlMessage::Stop);
3960
3961 let mut trie_mut = (**trie).clone();
3963
3964 let last_written = backend
3965 .begin_read()?
3966 .get(MISC_VALUES, "last_written".as_bytes())?
3967 .unwrap_or_default();
3968
3969 let mut write_tx = backend.begin_write()?;
3970
3971 let nodes = trie_mut.commit(root).unwrap_or_default();
3976 let mut result = Ok(());
3977 for (key, value) in nodes {
3978 let is_leaf = key.len() == 65 || key.len() == 131;
3979 let is_account = key.len() <= 65;
3980
3981 if is_leaf && key > last_written {
3982 continue;
3983 }
3984 let table = if is_leaf {
3985 if is_account {
3986 &ACCOUNT_FLATKEYVALUE
3987 } else {
3988 &STORAGE_FLATKEYVALUE
3989 }
3990 } else if is_account {
3991 &ACCOUNT_TRIE_NODES
3992 } else {
3993 &STORAGE_TRIE_NODES
3994 };
3995 if value.is_empty() {
3996 result = write_tx.delete(table, &key);
3997 } else {
3998 result = write_tx.put(table, &key, &value);
3999 }
4000 if result.is_err() {
4001 break;
4002 }
4003 }
4004 if result.is_ok() {
4005 result = write_tx.commit();
4006 }
4007 let _ = fkv_ctl.send(FKVGeneratorControlMessage::Continue);
4009 result?;
4010 *trie_cache.write().map_err(|_| StoreError::LockError)? = Arc::new(trie_mut);
4012 Ok(())
4013}
4014
4015fn flatkeyvalue_generator(
4018 backend: &Arc<dyn StorageBackend>,
4019 last_computed_fkv: &RwLock<Vec<u8>>,
4020 control_rx: &std::sync::mpsc::Receiver<FKVGeneratorControlMessage>,
4021) -> Result<(), StoreError> {
4022 info!("Generation of FlatKeyValue started.");
4023 let initial_last_written = backend
4024 .begin_read()?
4025 .get(MISC_VALUES, "last_written".as_bytes())?
4026 .unwrap_or_default();
4027
4028 if initial_last_written.is_empty() {
4029 backend.clear_table(ACCOUNT_FLATKEYVALUE)?;
4031 backend.clear_table(STORAGE_FLATKEYVALUE)?;
4032 } else if initial_last_written == [0xff] {
4033 info!("FlatKeyValue already generated. Skipping.");
4035 return Ok(());
4036 }
4037
4038 loop {
4039 let read_tx = backend.begin_read()?;
4042 let root = read_tx
4043 .get(ACCOUNT_TRIE_NODES, &[])?
4044 .ok_or(StoreError::MissingLatestBlockNumber)?;
4045 let root: Node = ethrex_trie::Node::decode(&root)?;
4046 let state_root = root.compute_hash(&NativeCrypto).finalize(&NativeCrypto);
4047
4048 let last_written = read_tx
4049 .get(MISC_VALUES, "last_written".as_bytes())?
4050 .unwrap_or_default();
4051 let last_written_account = last_written
4052 .get(0..64)
4053 .map(|v| Nibbles::from_hex(v.to_vec()))
4054 .unwrap_or_default();
4055 let mut last_written_storage = last_written
4056 .get(66..130)
4057 .map(|v| Nibbles::from_hex(v.to_vec()))
4058 .unwrap_or_default();
4059
4060 debug!("Starting FlatKeyValue loop pivot={last_written:?} SR={state_root:x}");
4061
4062 let mut ctr = 0;
4063 let mut write_txn = backend.begin_write()?;
4064 let mut iter = Trie::open(
4065 Box::new(BackendTrieDB::new_for_accounts_with_view(
4066 backend.clone(),
4067 read_tx.clone(),
4068 last_written.clone(),
4069 )?),
4070 state_root,
4071 )
4072 .into_iter();
4073 if last_written_account > Nibbles::default() {
4074 iter.advance(last_written_account.to_bytes())?;
4075 }
4076 let res = iter.try_for_each(|(path, node)| -> Result<(), StoreError> {
4077 let Node::Leaf(node) = node else {
4078 return Ok(());
4079 };
4080 let account_state = AccountState::decode(&node.value)?;
4081 let account_hash = H256::from_slice(&path.to_bytes());
4082 write_txn.put(MISC_VALUES, "last_written".as_bytes(), path.as_ref())?;
4083 write_txn.put(ACCOUNT_FLATKEYVALUE, path.as_ref(), &node.value)?;
4084 ctr += 1;
4085 if ctr > 10_000 {
4086 write_txn.commit()?;
4087 write_txn = backend.begin_write()?;
4088 *last_computed_fkv
4089 .write()
4090 .map_err(|_| StoreError::LockError)? = path.as_ref().to_vec();
4091 ctr = 0;
4092 }
4093
4094 let mut iter_inner = Trie::open(
4095 Box::new(BackendTrieDB::new_for_account_storage_with_view(
4096 backend.clone(),
4097 read_tx.clone(),
4098 account_hash,
4099 path.as_ref().to_vec(),
4100 )?),
4101 account_state.storage_root,
4102 )
4103 .into_iter();
4104 if last_written_storage > Nibbles::default() {
4105 iter_inner.advance(last_written_storage.to_bytes())?;
4106 last_written_storage = Nibbles::default();
4107 }
4108 iter_inner.try_for_each(|(path, node)| -> Result<(), StoreError> {
4109 let Node::Leaf(node) = node else {
4110 return Ok(());
4111 };
4112 let key = apply_prefix(Some(account_hash), path);
4113 write_txn.put(MISC_VALUES, "last_written".as_bytes(), key.as_ref())?;
4114 write_txn.put(STORAGE_FLATKEYVALUE, key.as_ref(), &node.value)?;
4115 ctr += 1;
4116 if ctr > 10_000 {
4117 write_txn.commit()?;
4118 write_txn = backend.begin_write()?;
4119 *last_computed_fkv
4120 .write()
4121 .map_err(|_| StoreError::LockError)? = key.into_vec();
4122 ctr = 0;
4123 }
4124 fkv_check_for_stop_msg(control_rx)?;
4125 Ok(())
4126 })?;
4127 fkv_check_for_stop_msg(control_rx)?;
4128 Ok(())
4129 });
4130 match res {
4131 Err(StoreError::PivotChanged) => {
4132 match control_rx.recv() {
4133 Ok(FKVGeneratorControlMessage::Continue) => {}
4134 Ok(FKVGeneratorControlMessage::Stop) => {
4135 return Err(StoreError::Custom("Unexpected Stop message".to_string()));
4136 }
4137 Err(std::sync::mpsc::RecvError) => {
4139 info!("Store closed, stopping FlatKeyValue generation.");
4140 return Ok(());
4141 }
4142 }
4143 }
4144 Err(err) => return Err(err),
4145 Ok(()) => {
4146 write_txn.put(MISC_VALUES, "last_written".as_bytes(), &[0xff])?;
4147 write_txn.commit()?;
4148 *last_computed_fkv
4149 .write()
4150 .map_err(|_| StoreError::LockError)? = vec![0xff; 131];
4151 info!("FlatKeyValue generation finished.");
4152 return Ok(());
4153 }
4154 };
4155 }
4156}
4157
4158fn fkv_check_for_stop_msg(
4159 control_rx: &std::sync::mpsc::Receiver<FKVGeneratorControlMessage>,
4160) -> Result<(), StoreError> {
4161 match control_rx.try_recv() {
4162 Ok(FKVGeneratorControlMessage::Stop) | Err(TryRecvError::Disconnected) => {
4163 return Err(StoreError::PivotChanged);
4164 }
4165 Ok(FKVGeneratorControlMessage::Continue) => {
4166 return Err(StoreError::Custom(
4167 "Unexpected Continue message".to_string(),
4168 ));
4169 }
4170 Err(TryRecvError::Empty) => {}
4171 }
4172 Ok(())
4173}
4174
4175fn state_trie_locked_backend(
4176 backend: &dyn StorageBackend,
4177 last_written: Vec<u8>,
4178) -> Result<BackendTrieDBLocked, StoreError> {
4179 BackendTrieDBLocked::new(backend, last_written)
4181}
4182
4183pub struct AccountProof {
4184 pub proof: Vec<NodeRLP>,
4185 pub account: AccountState,
4186 pub storage_proof: Vec<StorageSlotProof>,
4187}
4188
4189pub struct StorageSlotProof {
4190 pub proof: Vec<NodeRLP>,
4191 pub key: H256,
4192 pub value: U256,
4193}
4194
4195pub struct AncestorIterator {
4196 store: Store,
4197 next_hash: BlockHash,
4198}
4199
4200impl Iterator for AncestorIterator {
4201 type Item = Result<(BlockHash, BlockHeader), StoreError>;
4202
4203 fn next(&mut self) -> Option<Self::Item> {
4204 let next_hash = self.next_hash;
4205 match self.store.get_block_header_by_hash(next_hash) {
4209 Ok(Some(header)) => {
4210 let ret_hash = self.next_hash;
4211 self.next_hash = header.parent_hash;
4212 Some(Ok((ret_hash, header)))
4213 }
4214 Ok(None) => None,
4215 Err(e) => Some(Err(e)),
4216 }
4217 }
4218}
4219
4220pub fn hash_address(address: &Address) -> Vec<u8> {
4221 keccak_hash(address.to_fixed_bytes()).to_vec()
4222}
4223
4224fn hash_address_fixed(address: &Address) -> H256 {
4225 keccak(address.to_fixed_bytes())
4226}
4227
4228pub fn hash_key(key: &H256) -> Vec<u8> {
4229 keccak_hash(key.to_fixed_bytes()).to_vec()
4230}
4231
4232pub fn hash_key_fixed(key: &H256) -> [u8; 32] {
4233 keccak_hash(key.to_fixed_bytes())
4234}
4235
4236fn chain_data_key(index: ChainDataIndex) -> Vec<u8> {
4237 (index as u8).encode_to_vec()
4238}
4239
4240fn snap_state_key(index: SnapStateIndex) -> Vec<u8> {
4241 (index as u8).encode_to_vec()
4242}
4243
4244pub fn receipt_key(block_hash: &BlockHash, index: u64) -> Vec<u8> {
4246 let mut key = Vec::with_capacity(40);
4247 key.extend_from_slice(block_hash.as_bytes());
4248 key.extend_from_slice(&index.to_be_bytes());
4249 key
4250}
4251
4252fn encode_code(code: &Code) -> Vec<u8> {
4253 let mut buf =
4254 Vec::with_capacity(6 + code.len() + std::mem::size_of_val::<[u32]>(&code.jump_targets));
4255 code.code().encode(&mut buf);
4256 code.jump_targets.to_vec().encode(&mut buf);
4259 buf
4260}
4261
4262#[derive(Debug, Default, Clone)]
4263struct LatestBlockHeaderCache {
4264 current: Arc<Mutex<Arc<BlockHeader>>>,
4265}
4266
4267impl LatestBlockHeaderCache {
4268 pub fn get(&self) -> Arc<BlockHeader> {
4269 self.current.lock().expect("poisoned mutex").clone()
4270 }
4271
4272 pub fn update(&self, header: BlockHeader) {
4273 let new = Arc::new(header);
4274 *self.current.lock().expect("poisoned mutex") = new;
4275 }
4276}
4277
4278#[derive(Debug, Serialize, Deserialize)]
4279pub struct StoreMetadata {
4280 pub schema_version: u64,
4281}
4282
4283impl StoreMetadata {
4284 pub fn new(schema_version: u64) -> Self {
4285 Self { schema_version }
4286 }
4287}
4288
4289fn read_store_schema_version(path: &Path) -> Result<Option<u64>, StoreError> {
4294 let metadata_path = path.join(STORE_METADATA_FILENAME);
4295 if !metadata_path.exists() {
4296 return Ok(None);
4297 }
4298 if !metadata_path.is_file() {
4299 return Err(StoreError::Custom(
4300 "store schema path exists but is not a file".to_string(),
4301 ));
4302 }
4303 let file_contents = std::fs::read_to_string(metadata_path)?;
4304 let metadata: StoreMetadata = serde_json::from_str(&file_contents)?;
4305 Ok(Some(metadata.schema_version))
4306}
4307
4308fn init_metadata_file(parent_path: &Path) -> Result<(), StoreError> {
4309 std::fs::create_dir_all(parent_path)?;
4310
4311 let metadata_path = parent_path.join(STORE_METADATA_FILENAME);
4312 let metadata = StoreMetadata::new(STORE_SCHEMA_VERSION);
4313 let serialized_metadata = serde_json::to_string_pretty(&metadata)?;
4314 let mut new_file = std::fs::File::create_new(metadata_path)?;
4315 new_file.write_all(serialized_metadata.as_bytes())?;
4316 Ok(())
4317}
4318
4319fn dir_contains_legacy_db(path: &Path) -> Result<bool, StoreError> {
4331 if path.join("CURRENT").is_file() {
4335 return Ok(true);
4336 }
4337 for entry in std::fs::read_dir(path)? {
4341 let entry = entry?;
4342 if !entry.file_type()?.is_file() {
4343 continue;
4344 }
4345 if entry.file_name().to_string_lossy().starts_with("MANIFEST-") {
4346 return Ok(true);
4347 }
4348 }
4349 Ok(false)
4350}
4351
4352pub fn has_valid_db(path: &Path) -> bool {
4356 let metadata_path = path.join(STORE_METADATA_FILENAME);
4357 if !metadata_path.is_file() {
4358 return false;
4359 }
4360 let Ok(contents) = std::fs::read_to_string(&metadata_path) else {
4361 return false;
4362 };
4363 let Ok(metadata) = serde_json::from_str::<StoreMetadata>(&contents) else {
4364 return false;
4365 };
4366 metadata.schema_version >= 1 && metadata.schema_version <= STORE_SCHEMA_VERSION
4367}
4368
4369pub fn read_chain_id_from_db(path: &Path) -> Option<u64> {
4378 if !has_valid_db(path) {
4379 return None;
4380 }
4381 #[cfg(feature = "rocksdb")]
4382 {
4383 let backend = match RocksDBBackend::open(path, DEFAULT_ROCKSDB_BLOCK_CACHE_SIZE_BYTES) {
4386 Ok(backend) => backend,
4387 Err(e) => {
4388 warn!("Failed to open RocksDB at {path:?} to read chain ID: {e}");
4389 return None;
4390 }
4391 };
4392 let read = match backend.begin_read() {
4393 Ok(read) => read,
4394 Err(e) => {
4395 warn!("Failed to begin read transaction at {path:?}: {e}");
4396 return None;
4397 }
4398 };
4399 let key = chain_data_key(ChainDataIndex::ChainConfig);
4400 let bytes = match read.get(CHAIN_DATA, &key) {
4401 Ok(Some(bytes)) => bytes,
4402 Ok(None) => {
4403 warn!("Chain config entry not found in database at {path:?}");
4404 return None;
4405 }
4406 Err(e) => {
4407 warn!("Failed to read chain config from database at {path:?}: {e}");
4408 return None;
4409 }
4410 };
4411 #[derive(serde::Deserialize)]
4416 #[serde(rename_all = "camelCase")]
4417 struct ChainIdOnly {
4418 chain_id: u64,
4419 }
4420 match serde_json::from_slice::<ChainIdOnly>(&bytes) {
4421 Ok(partial) => Some(partial.chain_id),
4422 Err(e) => {
4423 warn!("Failed to deserialize chain ID from database at {path:?}: {e}");
4424 None
4425 }
4426 }
4427 }
4428 #[cfg(not(feature = "rocksdb"))]
4429 {
4430 let _ = path;
4431 None
4432 }
4433}
4434
4435#[cfg(test)]
4436mod merge_tests {
4437 use super::*;
4438
4439 fn h256(b: u8) -> H256 {
4440 H256::from_low_u64_be(b as u64)
4441 }
4442
4443 fn op(bn: BlockNumber, bh: H256, idx: Index) -> Vec<u8> {
4444 encode_tx_location_operand(bn, bh, idx)
4445 }
4446
4447 fn decode(v: &[u8]) -> Vec<(BlockNumber, BlockHash, Index)> {
4448 <Vec<(BlockNumber, BlockHash, Index)>>::decode(v).unwrap()
4449 }
4450
4451 #[test]
4452 fn single_operand_on_empty_base() {
4453 let out = tx_locations_merge(None, vec![op(100, h256(0x10), 0)]).unwrap();
4454 assert_eq!(decode(&out), vec![(100, h256(0x10), 0)]);
4455 }
4456
4457 #[test]
4458 fn operand_appended_to_existing_base() {
4459 let base = vec![(100u64, h256(0x10), 0u64)].encode_to_vec();
4460 let out = tx_locations_merge(Some(&base), vec![op(101, h256(0x11), 5)]).unwrap();
4461 let mut got = decode(&out);
4462 got.sort();
4463 let mut want = vec![(100, h256(0x10), 0), (101, h256(0x11), 5)];
4464 want.sort();
4465 assert_eq!(got, want);
4466 }
4467
4468 #[test]
4469 fn multiple_operands_combined() {
4470 let out = tx_locations_merge(
4471 None,
4472 vec![
4473 op(100, h256(0x10), 0),
4474 op(100, h256(0x11), 1),
4475 op(101, h256(0x12), 2),
4476 ],
4477 )
4478 .unwrap();
4479 assert_eq!(decode(&out).len(), 3);
4480 }
4481
4482 #[test]
4483 fn same_block_hash_is_deduped() {
4484 let out =
4486 tx_locations_merge(None, vec![op(100, h256(0x10), 0), op(100, h256(0x10), 7)]).unwrap();
4487 assert_eq!(decode(&out), vec![(100, h256(0x10), 7)]);
4488 }
4489
4490 #[test]
4491 fn malformed_operand_aborts_merge() {
4492 let out = tx_locations_merge(None, vec![vec![0xff, 0xff], op(100, h256(0x10), 0)]);
4495 assert!(out.is_none(), "merge must abort on a malformed operand");
4496 }
4497
4498 #[test]
4499 fn malformed_base_value_aborts_merge() {
4500 let out = tx_locations_merge(Some(&[0xff, 0xff]), vec![op(100, h256(0x10), 0)]);
4501 assert!(out.is_none(), "merge must abort on a corrupt base value");
4502 }
4503
4504 #[test]
4511 fn partial_merge_result_is_a_valid_operand() {
4512 let partial =
4514 tx_locations_merge(None, vec![op(100, h256(0x10), 0), op(101, h256(0x11), 1)]).unwrap();
4515
4516 let base = vec![(99u64, h256(0x09), 9u64)].encode_to_vec();
4520 let out = tx_locations_merge(Some(&base), vec![partial]).unwrap();
4521
4522 let mut got = decode(&out);
4523 got.sort();
4524 let mut want = vec![
4525 (99, h256(0x09), 9),
4526 (100, h256(0x10), 0),
4527 (101, h256(0x11), 1),
4528 ];
4529 want.sort();
4530 assert_eq!(
4531 got, want,
4532 "no entries may be lost when re-merging a partial result"
4533 );
4534 }
4535
4536 #[test]
4539 fn operand_encoding_matches_value_encoding() {
4540 let operand = op(100, h256(0x10), 3);
4541 assert_eq!(decode(&operand), vec![(100, h256(0x10), 3)]);
4543 }
4544
4545 #[test]
4547 fn chained_partial_merges() {
4548 let p1 = tx_locations_merge(None, vec![op(1, h256(0x01), 0)]).unwrap();
4549 let p2 = tx_locations_merge(None, vec![p1, op(2, h256(0x02), 0)]).unwrap();
4550 let p3 = tx_locations_merge(None, vec![p2, op(3, h256(0x03), 0)]).unwrap();
4551 let out = tx_locations_merge(None, vec![p3]).unwrap();
4552 assert_eq!(decode(&out).len(), 3);
4553 }
4554}
4555
4556#[cfg(test)]
4557mod datadir_tests {
4558 use super::*;
4559 use std::fs;
4560
4561 #[test]
4562 fn empty_dir_has_no_existing_db() {
4563 let dir = tempfile::tempdir().unwrap();
4564 assert!(!dir_contains_legacy_db(dir.path()).unwrap());
4565 }
4566
4567 #[test]
4568 fn dir_with_only_unrelated_files_has_no_existing_db() {
4569 let dir = tempfile::tempdir().unwrap();
4572 fs::write(dir.path().join("jwt.hex"), "0xdeadbeef").unwrap();
4573 fs::write(dir.path().join("LOG"), "noise").unwrap();
4574 assert!(!dir_contains_legacy_db(dir.path()).unwrap());
4575 }
4576
4577 #[test]
4578 fn dir_with_rocksdb_markers_has_existing_db() {
4579 let dir = tempfile::tempdir().unwrap();
4581 fs::write(dir.path().join("CURRENT"), "MANIFEST-000001\n").unwrap();
4582 assert!(dir_contains_legacy_db(dir.path()).unwrap());
4583
4584 let dir2 = tempfile::tempdir().unwrap();
4585 fs::write(dir2.path().join("MANIFEST-000007"), "x").unwrap();
4586 assert!(dir_contains_legacy_db(dir2.path()).unwrap());
4587 }
4588
4589 #[test]
4590 fn dir_with_marker_named_subdirectories_has_no_existing_db() {
4591 let dir = tempfile::tempdir().unwrap();
4594 fs::create_dir(dir.path().join("CURRENT")).unwrap();
4595 fs::create_dir(dir.path().join("MANIFEST-000001")).unwrap();
4596 assert!(!dir_contains_legacy_db(dir.path()).unwrap());
4597 }
4598}