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 BLOCK_ACCESS_LISTS, BLOCK_NUMBERS, BODIES, CANONICAL_BLOCK_HASHES, CHAIN_DATA,
10 EXECUTION_WITNESSES, FULLSYNC_HEADERS, HEADERS, INVALID_CHAINS, MISC_VALUES,
11 PENDING_BLOCKS, RECEIPTS_V2, SNAP_STATE, STORAGE_FLATKEYVALUE, STORAGE_TRIE_NODES,
12 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
64#[allow(unused)]
68const DB_COMMIT_THRESHOLD: usize = 128;
69const IN_MEMORY_COMMIT_THRESHOLD: usize = 10000;
70
71const BATCH_COMMIT_THRESHOLD: usize = 4;
74
75pub const DEFAULT_ROCKSDB_BLOCK_CACHE_SIZE_BYTES: usize = 12 * 1024 * 1024 * 1024;
85
86#[derive(Debug, Clone, Copy)]
91pub struct StoreConfig {
92 pub rocksdb_block_cache_size: usize,
97 pub persist_channel_capacity: usize,
102}
103
104impl Default for StoreConfig {
105 fn default() -> Self {
106 Self {
107 rocksdb_block_cache_size: DEFAULT_ROCKSDB_BLOCK_CACHE_SIZE_BYTES,
108 persist_channel_capacity: DEFAULT_PERSIST_CHANNEL_CAPACITY,
109 }
110 }
111}
112
113#[derive(Debug, PartialEq)]
115enum FKVGeneratorControlMessage {
116 Stop,
117 Continue,
118}
119
120const CODE_CACHE_MAX_SIZE: u64 = 64 * 1024 * 1024;
122
123const FLUSHED_UPTO_KEY: &[u8] = b"bodies_flushed_upto";
125
126#[derive(Debug)]
127struct CodeCache {
128 inner_cache: LruCache<H256, Code, FxBuildHasher>,
129 cache_size: u64,
130}
131
132impl Default for CodeCache {
133 fn default() -> Self {
134 Self {
135 inner_cache: LruCache::unbounded_with_hasher(FxBuildHasher),
136 cache_size: 0,
137 }
138 }
139}
140
141impl CodeCache {
142 fn get(&mut self, code_hash: &H256) -> Result<Option<Code>, StoreError> {
143 Ok(self.inner_cache.get(code_hash).cloned())
144 }
145
146 fn insert(&mut self, code: &Code) -> Result<(), StoreError> {
147 let code_size = code.size();
148 let cache_len = self.inner_cache.len() + 1;
149 self.cache_size += code_size as u64;
150 let current_size = self.cache_size;
151 debug!(
152 "[ACCOUNT CODE CACHE] cache elements (): {cache_len}, total size: {current_size} bytes"
153 );
154
155 while self.cache_size > CODE_CACHE_MAX_SIZE {
156 if let Some((_, code)) = self.inner_cache.pop_lru() {
157 self.cache_size -= code.size() as u64;
158 } else {
159 break;
160 }
161 }
162
163 self.inner_cache.get_or_insert(code.hash, || code.clone());
164 Ok(())
165 }
166}
167
168#[derive(Debug, Clone)]
174pub struct Store {
175 db_path: PathBuf,
177 backend: Arc<dyn StorageBackend>,
179 chain_config: ChainConfig,
181 trie_cache: Arc<RwLock<Arc<TrieLayerCache>>>,
183 flatkeyvalue_control_tx: std::sync::mpsc::SyncSender<FKVGeneratorControlMessage>,
185 block_data_buffer: Arc<RwLock<Arc<BlockDataBuffer>>>,
187 persist_tx: std::sync::mpsc::SyncSender<PersistMessage>,
191 pending_trie_roots: Arc<PendingTrieRoots>,
195 latest_block_header: LatestBlockHeaderCache,
198 last_computed_flatkeyvalue: Arc<RwLock<Vec<u8>>>,
200
201 account_code_cache: Arc<Mutex<CodeCache>>,
206
207 code_metadata_cache: Arc<Mutex<rustc_hash::FxHashMap<H256, CodeMetadata>>>,
210
211 fcu_lock: Arc<tokio::sync::Mutex<()>>,
214
215 background_threads: Arc<ThreadList>,
216}
217
218#[derive(Debug, Default)]
219struct ThreadList {
220 list: Vec<JoinHandle<()>>,
221}
222
223impl Drop for ThreadList {
224 fn drop(&mut self) {
225 for handle in self.list.drain(..) {
226 let _ = handle.join();
227 }
228 }
229}
230
231pub type StorageTrieNodes = Vec<(H256, Vec<(Nibbles, Vec<u8>)>)>;
236type StorageTries = HashMap<Address, (TrieWitness, Trie)>;
237
238#[derive(Debug, Clone, Copy, PartialEq, Eq)]
242pub enum EngineType {
243 InMemory,
245 #[cfg(feature = "rocksdb")]
247 RocksDB,
248}
249
250pub struct UpdateBatch {
255 pub account_updates: Vec<TrieNode>,
257 pub storage_updates: Vec<(H256, Vec<TrieNode>)>,
259 pub blocks: Vec<Block>,
261 pub receipts: Vec<(H256, Vec<Receipt>)>,
263 pub code_updates: Vec<(H256, Code)>,
265 pub batch_mode: bool,
269}
270
271pub type StorageUpdates = Vec<(H256, Vec<(Nibbles, Vec<u8>)>)>;
273
274pub struct AccountUpdatesList {
279 pub state_trie_hash: H256,
281 pub state_updates: Vec<(Nibbles, Vec<u8>)>,
283 pub storage_updates: StorageUpdates,
285 pub code_updates: Vec<(H256, Code)>,
287}
288
289pub(crate) fn encode_tx_location_operand(
300 block_number: BlockNumber,
301 block_hash: BlockHash,
302 index: Index,
303) -> Vec<u8> {
304 vec![(block_number, block_hash, index)].encode_to_vec()
305}
306
307pub fn tx_locations_merge(
325 existing: Option<&[u8]>,
326 operands: impl IntoIterator<Item = impl AsRef<[u8]>>,
327) -> Option<Vec<u8>> {
328 fn fold_chunk(
332 list: &mut Vec<(BlockNumber, BlockHash, Index)>,
333 bytes: &[u8],
334 what: &str,
335 ) -> bool {
336 match <Vec<(BlockNumber, BlockHash, Index)>>::decode(bytes) {
337 Ok(entries) => {
338 for (bn, bh, idx) in entries {
339 list.retain(|(_, existing_bh, _)| *existing_bh != bh);
340 list.push((bn, bh, idx));
341 }
342 true
343 }
344 Err(e) => {
345 error!(
346 "tx_locations_merge: failed to decode {what} ({} bytes): {e}; \
347 aborting merge to avoid silent data loss",
348 bytes.len()
349 );
350 false
351 }
352 }
353 }
354
355 let mut list: Vec<(BlockNumber, BlockHash, Index)> = Vec::new();
356
357 if let Some(bytes) = existing
359 && !fold_chunk(&mut list, bytes, "existing value")
360 {
361 return None;
362 }
363 for op in operands {
364 if !fold_chunk(&mut list, op.as_ref(), "operand") {
365 return None;
366 }
367 }
368 Some(list.encode_to_vec())
369}
370
371impl Store {
372 pub async fn wait_for_persistence_idle(&self) -> Result<(), StoreError> {
383 let tx = self.persist_tx.clone();
384 tokio::task::spawn_blocking(move || {
385 let (ack_tx, ack_rx) = sync_channel::<Result<(), StoreError>>(1);
386 tx.send(PersistMessage::Ping(ack_tx))
387 .map_err(|e| StoreError::Custom(format!("wait_for_persistence_idle send: {e}")))?;
388 ack_rx
389 .recv()
390 .map_err(|e| StoreError::Custom(format!("wait_for_persistence_idle ack: {e}")))?
391 })
392 .await
393 .map_err(|e| StoreError::Custom(format!("wait_for_persistence_idle join: {e}")))?
394 }
395
396 pub async fn shutdown(&self) -> Result<(), StoreError> {
415 let tx = self.persist_tx.clone();
416 let backend = self.backend.clone();
417 tokio::task::spawn_blocking(move || {
418 let (ack_tx, ack_rx) = sync_channel::<Result<(), StoreError>>(1);
419 tx.send(PersistMessage::Shutdown { ack: ack_tx })
420 .map_err(|e| StoreError::Custom(format!("shutdown send: {e}")))?;
421 ack_rx
422 .recv()
423 .map_err(|e| StoreError::Custom(format!("shutdown ack: {e}")))??;
424 backend.flush()
427 })
428 .await
429 .map_err(|e| StoreError::Custom(format!("shutdown join: {e}")))?
430 }
431
432 pub async fn add_block(&self, block: Block) -> Result<(), StoreError> {
435 self.add_blocks(vec![block]).await
436 }
437
438 pub async fn add_blocks(&self, blocks: Vec<Block>) -> Result<(), StoreError> {
441 let db = self.backend.clone();
442 tokio::task::spawn_blocking(move || {
443 let mut tx = db.begin_write()?;
444
445 for block in blocks {
446 write_block_data(
447 tx.as_mut(),
448 block.header.number,
449 block.hash(),
450 &block.header,
451 &block.body,
452 )?;
453 }
454
455 tx.commit()
456 })
457 .await
458 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
459 }
460
461 pub async fn add_block_header(
463 &self,
464 block_hash: BlockHash,
465 block_header: BlockHeader,
466 ) -> Result<(), StoreError> {
467 let hash_key = block_hash.encode_to_vec();
468 let header_value = BlockHeaderRLP::from(block_header).into_vec();
469 self.write_async(HEADERS, hash_key, header_value).await
470 }
471
472 pub async fn add_block_headers(
474 &self,
475 block_headers: Vec<BlockHeader>,
476 ) -> Result<(), StoreError> {
477 let mut txn = self.backend.begin_write()?;
478
479 for header in block_headers {
480 let block_hash = header.hash();
481 let block_number = header.number;
482 let hash_key = block_hash.encode_to_vec();
483 let header_value = BlockHeaderRLP::from(header).into_vec();
484
485 txn.put(HEADERS, &hash_key, &header_value)?;
486
487 let number_key = block_number.to_le_bytes().to_vec();
488 txn.put(BLOCK_NUMBERS, &hash_key, &number_key)?;
489 }
490 txn.commit()?;
491 Ok(())
492 }
493
494 pub fn get_block_header(
496 &self,
497 block_number: BlockNumber,
498 ) -> Result<Option<BlockHeader>, StoreError> {
499 let latest = self.latest_block_header.get();
500 if block_number == latest.number {
501 return Ok(Some((*latest).clone()));
502 }
503 let Some(block_hash) = self.get_canonical_block_hash_sync(block_number)? else {
508 return Ok(None);
509 };
510 self.get_block_header_by_hash(block_hash)
511 }
512
513 pub async fn add_block_body(
515 &self,
516 block_hash: BlockHash,
517 block_body: BlockBody,
518 ) -> Result<(), StoreError> {
519 let hash_key = block_hash.encode_to_vec();
520 let body_value = BlockBodyRLP::from(block_body).into_vec();
521 self.write_async(BODIES, hash_key, body_value).await
522 }
523
524 pub async fn get_block_body(
526 &self,
527 block_number: BlockNumber,
528 ) -> Result<Option<BlockBody>, StoreError> {
529 let Some(block_hash) = self.get_canonical_block_hash_sync(block_number)? else {
530 return Ok(None);
531 };
532
533 self.get_block_body_by_hash(block_hash).await
534 }
535
536 pub async fn remove_block(&self, block_number: BlockNumber) -> Result<(), StoreError> {
538 let Some(hash) = self.get_canonical_block_hash_sync(block_number)? else {
539 return Ok(());
540 };
541
542 let backend = self.backend.clone();
543 tokio::task::spawn_blocking(move || {
544 let hash_key = hash.encode_to_vec();
545
546 let mut txn = backend.begin_write()?;
547 txn.delete(
548 CANONICAL_BLOCK_HASHES,
549 block_number.to_le_bytes().as_slice(),
550 )?;
551 txn.delete(BODIES, &hash_key)?;
552 txn.delete(HEADERS, &hash_key)?;
553 txn.delete(BLOCK_NUMBERS, &hash_key)?;
554 txn.commit()
555 })
556 .await
557 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
558 }
559
560 pub async fn get_block_bodies(
562 &self,
563 from: BlockNumber,
564 to: BlockNumber,
565 ) -> Result<Vec<Option<BlockBody>>, StoreError> {
566 let buffer = self.buffer()?;
568 let backend = self.backend.clone();
569 tokio::task::spawn_blocking(move || {
570 let numbers: Vec<BlockNumber> = (from..=to).collect();
571 let mut block_bodies = Vec::new();
572
573 let txn = backend.begin_read()?;
574 for number in numbers {
575 let Some(hash) = txn
576 .get(CANONICAL_BLOCK_HASHES, number.to_le_bytes().as_slice())?
577 .map(|bytes| H256::decode(bytes.as_slice()))
578 .transpose()?
579 else {
580 block_bodies.push(None);
581 continue;
582 };
583 if let Some(body) = buffer.get_body(&hash) {
586 block_bodies.push(Some(body));
587 continue;
588 }
589 let hash_key = hash.encode_to_vec();
590 let block_body_opt = txn
591 .get(BODIES, &hash_key)?
592 .map(|bytes| BlockBodyRLP::from_bytes(bytes).to())
593 .transpose()
594 .map_err(StoreError::from)?;
595
596 block_bodies.push(block_body_opt);
597 }
598
599 Ok(block_bodies)
600 })
601 .await
602 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
603 }
604
605 pub async fn get_block_bodies_by_hash(
607 &self,
608 hashes: Vec<BlockHash>,
609 ) -> Result<Vec<BlockBody>, StoreError> {
610 let buffer = self.buffer()?;
611 let backend = self.backend.clone();
612 tokio::task::spawn_blocking(move || {
614 let txn = backend.begin_read()?;
615 let mut block_bodies = Vec::new();
616 for hash in hashes {
617 if let Some(body) = buffer.get_body(&hash) {
620 block_bodies.push(body);
621 continue;
622 }
623 let hash_key = hash.encode_to_vec();
624
625 let Some(block_body) = txn
626 .get(BODIES, &hash_key)?
627 .map(|bytes| BlockBodyRLP::from_bytes(bytes).to())
628 .transpose()
629 .map_err(StoreError::from)?
630 else {
631 return Err(StoreError::Custom(format!(
632 "Block body not found for hash: {hash}"
633 )));
634 };
635 block_bodies.push(block_body);
636 }
637 Ok(block_bodies)
638 })
639 .await
640 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
641 }
642
643 pub async fn get_block_body_by_hash(
645 &self,
646 block_hash: BlockHash,
647 ) -> Result<Option<BlockBody>, StoreError> {
648 if let Some(b) = self.buffer()?.get_body(&block_hash) {
649 return Ok(Some(b));
650 }
651 self.read_async(BODIES, block_hash.encode_to_vec())
652 .await?
653 .map(|bytes| BlockBodyRLP::from_bytes(bytes).to())
654 .transpose()
655 .map_err(StoreError::from)
656 }
657
658 pub fn get_block_header_by_hash(
659 &self,
660 block_hash: BlockHash,
661 ) -> Result<Option<BlockHeader>, StoreError> {
662 let latest = self.latest_block_header.get();
663 if block_hash == latest.hash() {
664 return Ok(Some((*latest).clone()));
665 }
666 if let Some(h) = self.buffer()?.get_header(&block_hash) {
667 return Ok(Some(h));
668 }
669 self.load_block_header_by_hash(block_hash)
670 }
671
672 pub fn add_pending_block(&self, block: Block) -> Result<(), StoreError> {
673 let block_hash = block.hash();
674 let block_value = BlockRLP::from(block).into_vec();
675 self.write(PENDING_BLOCKS, block_hash.as_bytes().to_vec(), block_value)
676 }
677
678 pub async fn get_pending_block(
679 &self,
680 block_hash: BlockHash,
681 ) -> Result<Option<Block>, StoreError> {
682 self.read_async(PENDING_BLOCKS, block_hash.as_bytes().to_vec())
683 .await?
684 .map(|bytes| BlockRLP::from_bytes(bytes).to())
685 .transpose()
686 .map_err(StoreError::from)
687 }
688
689 pub async fn add_block_number(
691 &self,
692 block_hash: BlockHash,
693 block_number: BlockNumber,
694 ) -> Result<(), StoreError> {
695 let number_value = block_number.to_le_bytes().to_vec();
696 self.write_async(BLOCK_NUMBERS, block_hash.encode_to_vec(), number_value)
697 .await
698 }
699
700 pub async fn get_block_number(
702 &self,
703 block_hash: BlockHash,
704 ) -> Result<Option<BlockNumber>, StoreError> {
705 if let Some(n) = self.buffer()?.get_number(&block_hash) {
706 return Ok(Some(n));
707 }
708 self.read_async(BLOCK_NUMBERS, block_hash.encode_to_vec())
709 .await?
710 .map(|bytes| -> Result<BlockNumber, StoreError> {
711 let array: [u8; 8] = bytes
712 .try_into()
713 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
714 Ok(BlockNumber::from_le_bytes(array))
715 })
716 .transpose()
717 }
718
719 pub async fn add_transaction_location(
721 &self,
722 transaction_hash: H256,
723 block_number: BlockNumber,
724 block_hash: BlockHash,
725 index: Index,
726 ) -> Result<(), StoreError> {
727 self.add_transaction_locations(vec![(transaction_hash, block_number, block_hash, index)])
728 .await
729 }
730
731 pub async fn add_transaction_locations(
733 &self,
734 locations: Vec<(H256, BlockNumber, BlockHash, Index)>,
735 ) -> Result<(), StoreError> {
736 let db = self.backend.clone();
737 tokio::task::spawn_blocking(move || {
738 let mut tx = db.begin_write()?;
739 for (tx_hash, block_number, block_hash, index) in locations {
740 tx.merge(
741 TRANSACTION_LOCATIONS,
742 tx_hash.as_bytes(),
743 &encode_tx_location_operand(block_number, block_hash, index),
744 )?;
745 }
746 tx.commit()
747 })
748 .await
749 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
750 }
751
752 pub async fn get_transaction_location(
754 &self,
755 transaction_hash: H256,
756 ) -> Result<Option<(BlockNumber, BlockHash, Index)>, StoreError> {
757 let buffered = self.buffer()?.get_tx_locations(&transaction_hash);
758 let db = self.backend.clone();
759 tokio::task::spawn_blocking(move || {
760 let tx = db.begin_read()?;
761 let mut locations = buffered;
762 if let Some(bytes) = tx.get(TRANSACTION_LOCATIONS, transaction_hash.as_bytes())? {
763 locations.extend(<Vec<(BlockNumber, BlockHash, Index)>>::decode(&bytes)?);
764 }
765 for (block_number, block_hash, index) in locations {
766 let canonical_hash = tx
767 .get(
768 CANONICAL_BLOCK_HASHES,
769 block_number.to_le_bytes().as_slice(),
770 )?
771 .map(|bytes| H256::decode(bytes.as_slice()))
772 .transpose()?;
773 if canonical_hash == Some(block_hash) {
774 return Ok(Some((block_number, block_hash, index)));
775 }
776 }
777 Ok(None)
778 })
779 .await
780 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
781 }
782
783 pub async fn add_receipt(
785 &self,
786 block_hash: BlockHash,
787 index: Index,
788 receipt: Receipt,
789 ) -> Result<(), StoreError> {
790 let key = receipt_key(&block_hash, index);
791 let value = receipt.encode_storage();
795 self.write_async(RECEIPTS_V2, key, value).await
796 }
797
798 pub async fn add_receipts(
800 &self,
801 block_hash: BlockHash,
802 receipts: Vec<Receipt>,
803 ) -> Result<(), StoreError> {
804 let batch_items: Vec<_> = receipts
805 .into_iter()
806 .enumerate()
807 .map(|(index, receipt)| {
808 let key = receipt_key(&block_hash, index as u64);
809 let value = receipt.encode_storage();
810 (key, value)
811 })
812 .collect();
813 self.write_batch_async(RECEIPTS_V2, batch_items).await
814 }
815
816 pub async fn get_receipt(
818 &self,
819 block_number: BlockNumber,
820 index: Index,
821 ) -> Result<Option<Receipt>, StoreError> {
822 let Some(block_hash) = self.get_canonical_block_hash(block_number).await? else {
824 return Ok(None);
825 };
826 self.get_receipt_by_block_hash(block_hash, index).await
827 }
828
829 async fn get_receipt_by_block_hash(
831 &self,
832 block_hash: BlockHash,
833 index: Index,
834 ) -> Result<Option<Receipt>, StoreError> {
835 if let Some(r) = self.buffer()?.get_receipt(&block_hash, index) {
836 return Ok(Some(r));
837 }
838 let key = receipt_key(&block_hash, index);
839 self.read_async(RECEIPTS_V2, key)
840 .await?
841 .map(|bytes| Receipt::decode_storage(bytes.as_slice()))
842 .transpose()
843 .map_err(StoreError::from)
844 }
845
846 pub fn get_account_code(&self, code_hash: H256) -> Result<Option<Code>, StoreError> {
853 if let Some(code) = self.buffer()?.get_code(&code_hash) {
854 return Ok(Some(code));
855 }
856 if let Some(code) = self
858 .account_code_cache
859 .lock()
860 .map_err(|_| StoreError::LockError)?
861 .get(&code_hash)?
862 {
863 return Ok(Some(code));
864 }
865
866 let Some(bytes) = self
867 .backend
868 .begin_read()?
869 .get(ACCOUNT_CODES, code_hash.as_bytes())?
870 else {
871 return Ok(None);
872 };
873 let (bytecode_slice, targets) = decode_bytes(&bytes)?;
874 let code = Code::from_parts_unchecked(
875 code_hash,
876 bytecode_slice,
877 <Vec<u32>>::decode(targets)?.into(),
878 );
879
880 self.account_code_cache
882 .lock()
883 .map_err(|_| StoreError::LockError)?
884 .insert(&code)?;
885
886 Ok(Some(code))
887 }
888
889 pub fn code_exists(&self, code_hash: H256) -> Result<bool, StoreError> {
894 if self.buffer()?.get_code(&code_hash).is_some() {
898 return Ok(true);
899 }
900 if self
902 .account_code_cache
903 .lock()
904 .map_err(|_| StoreError::LockError)?
905 .get(&code_hash)?
906 .is_some()
907 {
908 return Ok(true);
909 }
910 Ok(self
912 .backend
913 .begin_read()?
914 .get(ACCOUNT_CODES, code_hash.as_bytes())?
915 .is_some())
916 }
917
918 pub fn get_code_metadata(&self, code_hash: H256) -> Result<Option<CodeMetadata>, StoreError> {
923 use ethrex_common::constants::EMPTY_KECCAK_HASH;
924
925 if code_hash == *EMPTY_KECCAK_HASH {
927 return Ok(Some(CodeMetadata { length: 0 }));
928 }
929
930 if let Some(metadata) = self
932 .code_metadata_cache
933 .lock()
934 .map_err(|_| StoreError::LockError)?
935 .get(&code_hash)
936 .copied()
937 {
938 return Ok(Some(metadata));
939 }
940
941 let metadata = if let Some(bytes) = self
943 .backend
944 .begin_read()?
945 .get(ACCOUNT_CODE_METADATA, code_hash.as_bytes())?
946 {
947 let length =
948 u64::from_be_bytes(bytes.try_into().map_err(|_| {
949 StoreError::Custom("Invalid metadata length encoding".to_string())
950 })?);
951 CodeMetadata { length }
952 } else {
953 let Some(code) = self.get_account_code(code_hash)? else {
955 return Ok(None);
956 };
957 let metadata = CodeMetadata {
958 length: code.len() as u64,
959 };
960
961 let metadata_buf = metadata.length.to_be_bytes().to_vec();
963 let hash_key = code_hash.0.to_vec();
964 let backend = self.backend.clone();
965 tokio::task::spawn(async move {
966 if let Err(e) = async {
967 let mut tx = backend.begin_write()?;
968 tx.put(ACCOUNT_CODE_METADATA, &hash_key, &metadata_buf)?;
969 tx.commit()
970 }
971 .await
972 {
973 tracing::warn!("Failed to write code metadata during auto-migration: {}", e);
974 }
975 });
976
977 metadata
978 };
979
980 self.code_metadata_cache
982 .lock()
983 .map_err(|_| StoreError::LockError)?
984 .insert(code_hash, metadata);
985
986 Ok(Some(metadata))
987 }
988
989 pub async fn add_account_code(&self, code: Code) -> Result<(), StoreError> {
991 let hash_key = code.hash.0.to_vec();
992 let buf = encode_code(&code);
993 let metadata_buf = (code.len() as u64).to_be_bytes();
994
995 let backend = self.backend.clone();
997 tokio::task::spawn_blocking(move || {
998 let mut tx = backend.begin_write()?;
999 tx.put(ACCOUNT_CODES, &hash_key, &buf)?;
1000 tx.put(ACCOUNT_CODE_METADATA, &hash_key, &metadata_buf)?;
1001 tx.commit()
1002 })
1003 .await
1004 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1005 }
1006
1007 pub async fn clear_snap_state(&self) -> Result<(), StoreError> {
1009 let db = self.backend.clone();
1010 tokio::task::spawn_blocking(move || db.clear_table(SNAP_STATE))
1011 .await
1012 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1013 }
1014
1015 pub async fn get_transaction_by_hash(
1016 &self,
1017 transaction_hash: H256,
1018 ) -> Result<Option<Transaction>, StoreError> {
1019 let (_block_number, block_hash, index) =
1020 match self.get_transaction_location(transaction_hash).await? {
1021 Some(location) => location,
1022 None => return Ok(None),
1023 };
1024 self.get_transaction_by_location(block_hash, index).await
1025 }
1026
1027 pub async fn get_transaction_by_location(
1028 &self,
1029 block_hash: H256,
1030 index: u64,
1031 ) -> Result<Option<Transaction>, StoreError> {
1032 let block_body = match self.get_block_body_by_hash(block_hash).await? {
1033 Some(body) => body,
1034 None => return Ok(None),
1035 };
1036 let index: usize = index.try_into()?;
1037 Ok(block_body.transactions.get(index).cloned())
1038 }
1039
1040 pub async fn get_block_by_hash(
1041 &self,
1042 block_hash: BlockHash,
1043 ) -> Result<Option<Block>, StoreError> {
1044 let header = match self.get_block_header_by_hash(block_hash)? {
1045 Some(header) => header,
1046 None => return Ok(None),
1047 };
1048 let body = match self.get_block_body_by_hash(block_hash).await? {
1049 Some(body) => body,
1050 None => return Ok(None),
1051 };
1052 Ok(Some(Block::new(header, body)))
1053 }
1054
1055 pub async fn get_block_by_number(
1056 &self,
1057 block_number: BlockNumber,
1058 ) -> Result<Option<Block>, StoreError> {
1059 let Some(block_hash) = self.get_canonical_block_hash(block_number).await? else {
1060 return Ok(None);
1061 };
1062 self.get_block_by_hash(block_hash).await
1063 }
1064
1065 pub async fn get_canonical_block_hash(
1067 &self,
1068 block_number: BlockNumber,
1069 ) -> Result<Option<BlockHash>, StoreError> {
1070 let last = self.latest_block_header.get();
1071 if last.number == block_number {
1072 return Ok(Some(last.hash()));
1073 }
1074 let backend = self.backend.clone();
1075 tokio::task::spawn_blocking(move || {
1076 backend
1077 .begin_read()?
1078 .get(
1079 CANONICAL_BLOCK_HASHES,
1080 block_number.to_le_bytes().as_slice(),
1081 )?
1082 .map(|bytes| H256::decode(bytes.as_slice()))
1083 .transpose()
1084 .map_err(StoreError::from)
1085 })
1086 .await
1087 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1088 }
1089
1090 pub async fn set_chain_config(&mut self, chain_config: &ChainConfig) -> Result<(), StoreError> {
1093 self.chain_config = *chain_config;
1094 let key = chain_data_key(ChainDataIndex::ChainConfig);
1095 let value = serde_json::to_string(chain_config)
1096 .map_err(|_| StoreError::Custom("Failed to serialize chain config".to_string()))?
1097 .into_bytes();
1098 self.write_async(CHAIN_DATA, key, value).await
1099 }
1100
1101 pub async fn update_earliest_block_number(
1103 &self,
1104 block_number: BlockNumber,
1105 ) -> Result<(), StoreError> {
1106 let key = chain_data_key(ChainDataIndex::EarliestBlockNumber);
1107 let value = block_number.to_le_bytes().to_vec();
1108 self.write_async(CHAIN_DATA, key, value).await
1109 }
1110
1111 pub async fn get_earliest_block_number(&self) -> Result<BlockNumber, StoreError> {
1113 let key = chain_data_key(ChainDataIndex::EarliestBlockNumber);
1114 self.read_async(CHAIN_DATA, key)
1115 .await?
1116 .map(|bytes| -> Result<BlockNumber, StoreError> {
1117 let array: [u8; 8] = bytes
1118 .try_into()
1119 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
1120 Ok(BlockNumber::from_le_bytes(array))
1121 })
1122 .ok_or(StoreError::MissingEarliestBlockNumber)?
1123 }
1124
1125 pub async fn get_finalized_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
1127 let key = chain_data_key(ChainDataIndex::FinalizedBlockNumber);
1128 self.read_async(CHAIN_DATA, key)
1129 .await?
1130 .map(|bytes| -> Result<BlockNumber, StoreError> {
1131 let array: [u8; 8] = bytes
1132 .try_into()
1133 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
1134 Ok(BlockNumber::from_le_bytes(array))
1135 })
1136 .transpose()
1137 }
1138
1139 pub async fn get_safe_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
1141 let key = chain_data_key(ChainDataIndex::SafeBlockNumber);
1142 self.read_async(CHAIN_DATA, key)
1143 .await?
1144 .map(|bytes| -> Result<BlockNumber, StoreError> {
1145 let array: [u8; 8] = bytes
1146 .try_into()
1147 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
1148 Ok(BlockNumber::from_le_bytes(array))
1149 })
1150 .transpose()
1151 }
1152
1153 pub async fn get_latest_block_number(&self) -> Result<BlockNumber, StoreError> {
1155 Ok(self.latest_block_header.get().number)
1156 }
1157
1158 pub async fn update_pending_block_number(
1160 &self,
1161 block_number: BlockNumber,
1162 ) -> Result<(), StoreError> {
1163 let key = chain_data_key(ChainDataIndex::PendingBlockNumber);
1164 let value = block_number.to_le_bytes().to_vec();
1165 self.write_async(CHAIN_DATA, key, value).await
1166 }
1167
1168 pub async fn get_pending_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
1170 let key = chain_data_key(ChainDataIndex::PendingBlockNumber);
1171 self.read_async(CHAIN_DATA, key)
1172 .await?
1173 .map(|bytes| -> Result<BlockNumber, StoreError> {
1174 let array: [u8; 8] = bytes
1175 .try_into()
1176 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
1177 Ok(BlockNumber::from_le_bytes(array))
1178 })
1179 .transpose()
1180 }
1181
1182 async fn forkchoice_update_inner(
1188 &self,
1189 new_canonical_blocks: Vec<(BlockNumber, BlockHash)>,
1190 head_number: BlockNumber,
1191 head_hash: BlockHash,
1192 safe: Option<BlockNumber>,
1193 finalized: Option<BlockNumber>,
1194 ) -> Result<(), StoreError> {
1195 let latest = self.load_latest_block_number().await?.unwrap_or(0);
1196 let db = self.backend.clone();
1197 tokio::task::spawn_blocking(move || {
1198 let mut txn = db.begin_write()?;
1199
1200 for (block_number, block_hash) in new_canonical_blocks {
1201 let head_key = block_number.to_le_bytes();
1202 let head_value = block_hash.encode_to_vec();
1203 txn.put(CANONICAL_BLOCK_HASHES, &head_key, &head_value)?;
1204 }
1205
1206 for number in (head_number + 1)..=(latest) {
1213 txn.delete(CANONICAL_BLOCK_HASHES, number.to_le_bytes().as_slice())?;
1214 }
1215
1216 let head_key = head_number.to_le_bytes();
1218 let head_value = head_hash.encode_to_vec();
1219 txn.put(CANONICAL_BLOCK_HASHES, &head_key, &head_value)?;
1220
1221 let latest_key = chain_data_key(ChainDataIndex::LatestBlockNumber);
1223 txn.put(CHAIN_DATA, &latest_key, &head_number.to_le_bytes())?;
1224
1225 if let Some(safe) = safe {
1226 let safe_key = chain_data_key(ChainDataIndex::SafeBlockNumber);
1227 txn.put(CHAIN_DATA, &safe_key, &safe.to_le_bytes())?;
1228 }
1229
1230 if let Some(finalized) = finalized {
1231 let finalized_key = chain_data_key(ChainDataIndex::FinalizedBlockNumber);
1232 txn.put(CHAIN_DATA, &finalized_key, &finalized.to_le_bytes())?;
1233 }
1234
1235 txn.commit()
1236 })
1237 .await
1238 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1239 }
1240
1241 pub async fn get_receipts_for_block(
1242 &self,
1243 block_hash: &BlockHash,
1244 ) -> Result<Vec<Receipt>, StoreError> {
1245 self.get_receipts_for_block_from_index(block_hash, 0, None)
1246 .await
1247 }
1248
1249 pub async fn get_receipts_for_block_from_index(
1258 &self,
1259 block_hash: &BlockHash,
1260 start_index: u64,
1261 max_count: Option<usize>,
1262 ) -> Result<Vec<Receipt>, StoreError> {
1263 if let Some(all) = self.buffer()?.get_receipts(block_hash) {
1264 let start = start_index as usize;
1265 let slice = all.into_iter().skip(start);
1266 return Ok(match max_count {
1267 Some(max) => slice.take(max).collect(),
1268 None => slice.collect(),
1269 });
1270 }
1271 let backend = self.backend.clone();
1272 let block_hash = *block_hash;
1273
1274 tokio::task::spawn_blocking(move || {
1275 let txn = backend.begin_read()?;
1276 let prefix = block_hash.as_bytes().to_vec();
1277 let mut seek_key = prefix.clone();
1280 seek_key.extend_from_slice(&start_index.to_be_bytes());
1281 let iter = txn.prefix_iterator(RECEIPTS_V2, &seek_key)?;
1282 let mut receipts = Vec::new();
1283 for result in iter {
1284 let (k, v) = result?;
1285 if !k.starts_with(&prefix) {
1286 break;
1287 }
1288 if k.len() != 40 {
1289 continue;
1290 }
1291 receipts.push(Receipt::decode_storage(v.as_ref())?);
1292 if let Some(max) = max_count
1293 && receipts.len() >= max
1294 {
1295 break;
1296 }
1297 }
1298 Ok(receipts)
1299 })
1300 .await
1301 .map_err(|e| StoreError::Custom(format!("Task panicked: {e}")))?
1302 }
1303
1304 pub async fn set_header_download_checkpoint(
1308 &self,
1309 block_hash: BlockHash,
1310 ) -> Result<(), StoreError> {
1311 let key = snap_state_key(SnapStateIndex::HeaderDownloadCheckpoint);
1312 let value = block_hash.encode_to_vec();
1313 self.write_async(SNAP_STATE, key, value).await
1314 }
1315
1316 pub async fn get_header_download_checkpoint(&self) -> Result<Option<BlockHash>, StoreError> {
1318 let key = snap_state_key(SnapStateIndex::HeaderDownloadCheckpoint);
1319 self.backend
1320 .begin_read()?
1321 .get(SNAP_STATE, &key)?
1322 .map(|bytes| H256::decode(bytes.as_slice()))
1323 .transpose()
1324 .map_err(StoreError::from)
1325 }
1326
1327 pub async fn set_latest_valid_ancestor(
1333 &self,
1334 bad_block: BlockHash,
1335 latest_valid: BlockHash,
1336 ) -> Result<(), StoreError> {
1337 let value = latest_valid.encode_to_vec();
1338 self.write_async(INVALID_CHAINS, bad_block.as_bytes().to_vec(), value)
1339 .await
1340 }
1341
1342 pub async fn get_latest_valid_ancestor(
1345 &self,
1346 block: BlockHash,
1347 ) -> Result<Option<BlockHash>, StoreError> {
1348 self.read_async(INVALID_CHAINS, block.as_bytes().to_vec())
1349 .await?
1350 .map(|bytes| H256::decode(bytes.as_slice()))
1351 .transpose()
1352 .map_err(StoreError::from)
1353 }
1354
1355 pub fn get_block_number_sync(
1357 &self,
1358 block_hash: BlockHash,
1359 ) -> Result<Option<BlockNumber>, StoreError> {
1360 if let Some(n) = self.buffer()?.get_number(&block_hash) {
1361 return Ok(Some(n));
1362 }
1363 let txn = self.backend.begin_read()?;
1364 txn.get(BLOCK_NUMBERS, &block_hash.encode_to_vec())?
1365 .map(|bytes| -> Result<BlockNumber, StoreError> {
1366 let array: [u8; 8] = bytes
1367 .try_into()
1368 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
1369 Ok(BlockNumber::from_le_bytes(array))
1370 })
1371 .transpose()
1372 }
1373
1374 pub fn get_canonical_block_hash_sync(
1376 &self,
1377 block_number: BlockNumber,
1378 ) -> Result<Option<BlockHash>, StoreError> {
1379 let last = self.latest_block_header.get();
1380 if last.number == block_number {
1381 return Ok(Some(last.hash()));
1382 }
1383 let txn = self.backend.begin_read()?;
1384 txn.get(
1385 CANONICAL_BLOCK_HASHES,
1386 block_number.to_le_bytes().as_slice(),
1387 )?
1388 .map(|bytes| H256::decode(bytes.as_slice()))
1389 .transpose()
1390 .map_err(StoreError::from)
1391 }
1392
1393 pub async fn write_storage_trie_nodes_batch(
1396 &self,
1397 storage_trie_nodes: StorageUpdates,
1398 ) -> Result<(), StoreError> {
1399 let mut txn = self.backend.begin_write()?;
1400 tokio::task::spawn_blocking(move || {
1401 for (address_hash, nodes) in storage_trie_nodes {
1402 for (node_path, node_data) in nodes {
1403 let key = apply_prefix(Some(address_hash), node_path);
1404 if node_data.is_empty() {
1405 txn.delete(STORAGE_TRIE_NODES, key.as_ref())?;
1406 } else {
1407 txn.put(STORAGE_TRIE_NODES, key.as_ref(), &node_data)?;
1408 }
1409 }
1410 }
1411 txn.commit()
1412 })
1413 .await
1414 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1415 }
1416
1417 pub async fn write_account_code_batch(
1420 &self,
1421 account_codes: Vec<(H256, Code)>,
1422 ) -> Result<(), StoreError> {
1423 let mut code_batch_items = Vec::new();
1424 let mut metadata_batch_items = Vec::new();
1425
1426 for (code_hash, code) in account_codes {
1427 let buf = encode_code(&code);
1428 let metadata_buf = (code.len() as u64).to_be_bytes().to_vec();
1429 code_batch_items.push((code_hash.as_bytes().to_vec(), buf));
1430 metadata_batch_items.push((code_hash.as_bytes().to_vec(), metadata_buf));
1431 }
1432
1433 self.write_batch_async(ACCOUNT_CODES, code_batch_items)
1435 .await?;
1436 self.write_batch_async(ACCOUNT_CODE_METADATA, metadata_batch_items)
1437 .await
1438 }
1439
1440 fn buffer(&self) -> Result<Arc<BlockDataBuffer>, StoreError> {
1442 Ok(self
1443 .block_data_buffer
1444 .read()
1445 .map_err(|_| StoreError::LockError)?
1446 .clone())
1447 }
1448
1449 pub fn write(
1455 &self,
1456 table: &'static str,
1457 key: Vec<u8>,
1458 value: Vec<u8>,
1459 ) -> Result<(), StoreError> {
1460 let backend = self.backend.clone();
1461 let mut txn = backend.begin_write()?;
1462 txn.put(table, &key, &value)?;
1463 txn.commit()
1464 }
1465
1466 async fn write_async(
1469 &self,
1470 table: &'static str,
1471 key: Vec<u8>,
1472 value: Vec<u8>,
1473 ) -> Result<(), StoreError> {
1474 let backend = self.backend.clone();
1475
1476 tokio::task::spawn_blocking(move || {
1477 let mut txn = backend.begin_write()?;
1478 txn.put(table, &key, &value)?;
1479 txn.commit()
1480 })
1481 .await
1482 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1483 }
1484
1485 pub async fn read_async(
1488 &self,
1489 table: &'static str,
1490 key: Vec<u8>,
1491 ) -> Result<Option<Vec<u8>>, StoreError> {
1492 let backend = self.backend.clone();
1493
1494 tokio::task::spawn_blocking(move || {
1495 let txn = backend.begin_read()?;
1496 txn.get(table, &key)
1497 })
1498 .await
1499 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1500 }
1501
1502 pub fn read(&self, table: &'static str, key: Vec<u8>) -> Result<Option<Vec<u8>>, StoreError> {
1505 let backend = self.backend.clone();
1506 let txn = backend.begin_read()?;
1507 txn.get(table, &key)
1508 }
1509
1510 pub async fn write_batch_async(
1514 &self,
1515 table: &'static str,
1516 batch_ops: Vec<(Vec<u8>, Vec<u8>)>,
1517 ) -> Result<(), StoreError> {
1518 let backend = self.backend.clone();
1519
1520 tokio::task::spawn_blocking(move || {
1521 let mut txn = backend.begin_write()?;
1522 txn.put_batch(table, batch_ops)?;
1523 txn.commit()
1524 })
1525 .await
1526 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1527 }
1528
1529 pub fn write_batch(
1531 &self,
1532 table: &'static str,
1533 batch_ops: Vec<(Vec<u8>, Vec<u8>)>,
1534 ) -> Result<(), StoreError> {
1535 let backend = self.backend.clone();
1536 let mut txn = backend.begin_write()?;
1537 txn.put_batch(table, batch_ops)?;
1538 txn.commit()
1539 }
1540
1541 pub async fn add_fullsync_batch(&self, headers: Vec<BlockHeader>) -> Result<(), StoreError> {
1542 self.write_batch_async(
1543 FULLSYNC_HEADERS,
1544 headers
1545 .into_iter()
1546 .map(|header| (header.number.to_le_bytes().to_vec(), header.encode_to_vec()))
1547 .collect(),
1548 )
1549 .await
1550 }
1551
1552 pub async fn read_fullsync_batch(
1553 &self,
1554 start: BlockNumber,
1555 limit: u64,
1556 ) -> Result<Vec<Option<BlockHeader>>, StoreError> {
1557 let mut res = vec![];
1558 let read_tx = self.backend.begin_read()?;
1559 for key in start..start + limit {
1561 let header_opt = read_tx
1562 .get(FULLSYNC_HEADERS, &key.to_le_bytes())?
1563 .map(|header| BlockHeader::decode(&header))
1564 .transpose()?;
1565 res.push(header_opt);
1566 }
1567 Ok(res)
1568 }
1569
1570 pub async fn clear_fullsync_headers(&self) -> Result<(), StoreError> {
1571 self.backend.clear_table(FULLSYNC_HEADERS)
1572 }
1573
1574 pub fn delete(&self, table: &'static str, key: Vec<u8>) -> Result<(), StoreError> {
1576 let mut txn = self.backend.begin_write()?;
1577 txn.delete(table, &key)?;
1578 txn.commit()
1579 }
1580
1581 pub fn store_block_updates(&self, update_batch: UpdateBatch) -> Result<(), StoreError> {
1582 self.apply_updates(update_batch)
1583 }
1584
1585 fn batch_state_roots(&self, update_batch: &UpdateBatch) -> Result<(H256, H256), StoreError> {
1590 let parent_state_root = self
1591 .get_block_header_by_hash(
1592 update_batch
1593 .blocks
1594 .first()
1595 .ok_or(StoreError::UpdateBatchNoBlocks)?
1596 .header
1597 .parent_hash,
1598 )?
1599 .map(|header| header.state_root)
1600 .unwrap_or_default();
1601 let last_state_root = update_batch
1602 .blocks
1603 .last()
1604 .ok_or(StoreError::UpdateBatchNoBlocks)?
1605 .header
1606 .state_root;
1607 Ok((parent_state_root, last_state_root))
1608 }
1609
1610 fn apply_updates(&self, update_batch: UpdateBatch) -> Result<(), StoreError> {
1615 let (parent_state_root, last_state_root) = self.batch_state_roots(&update_batch)?;
1616
1617 let UpdateBatch {
1618 account_updates,
1619 storage_updates,
1620 blocks,
1621 receipts,
1622 code_updates,
1623 batch_mode,
1624 } = update_batch;
1625
1626 self.pending_trie_roots.register(last_state_root)?;
1630
1631 let blocks_with_receipts: Vec<(Block, Vec<Receipt>)> = if blocks.len() == 1 {
1634 let block = blocks.into_iter().next().expect("len == 1");
1635 let hash = block.hash();
1636 let r = receipts
1637 .into_iter()
1638 .find(|(h, _)| *h == hash)
1639 .map(|(_, r)| r)
1640 .unwrap_or_default();
1641 vec![(block, r)]
1642 } else {
1643 let mut receipts_by_hash: std::collections::HashMap<BlockHash, Vec<Receipt>> =
1644 receipts.into_iter().collect();
1645 blocks
1646 .into_iter()
1647 .map(|b| {
1648 let r = receipts_by_hash.remove(&b.hash()).unwrap_or_default();
1649 (b, r)
1650 })
1651 .collect()
1652 };
1653
1654 let (ack_tx, ack_rx) = sync_channel(1);
1660 self.persist_tx
1661 .send(PersistMessage::Block(BlockPersist {
1662 blocks: blocks_with_receipts,
1663 codes: code_updates,
1664 parent_state_root,
1665 child_state_root: last_state_root,
1666 account_updates,
1667 storage_updates,
1668 wait_for_flush: batch_mode,
1669 ack: ack_tx,
1670 }))
1671 .map_err(|e| StoreError::Custom(format!("failed to send block persist: {e}")))?;
1672 ack_rx
1673 .recv()
1674 .map_err(|e| StoreError::Custom(format!("block persist ack failed: {e}")))??;
1675
1676 Ok(())
1677 }
1678
1679 pub fn new(path: impl AsRef<Path>, engine_type: EngineType) -> Result<Self, StoreError> {
1684 Self::new_with_config(path, engine_type, StoreConfig::default())
1685 }
1686
1687 pub fn new_with_config(
1689 path: impl AsRef<Path>,
1690 engine_type: EngineType,
1691 #[cfg_attr(not(feature = "rocksdb"), allow(unused_variables))] config: StoreConfig,
1693 ) -> Result<Self, StoreError> {
1694 let db_path = path.as_ref().to_path_buf();
1695
1696 if engine_type != EngineType::InMemory {
1697 let version = read_store_schema_version(&db_path)?;
1698
1699 match version {
1700 None if db_path.exists() && dir_contains_legacy_db(&db_path)? => {
1701 return Err(StoreError::NotFoundDBVersion);
1703 }
1704 None => {
1705 init_metadata_file(&db_path)?;
1711 }
1712 Some(v) if v < 1 => {
1713 return Err(StoreError::MigrationFailed {
1714 from: v,
1715 to: STORE_SCHEMA_VERSION,
1716 reason: format!("DB version v{v} is invalid (predates migrations)"),
1717 });
1718 }
1719 Some(v) if v > STORE_SCHEMA_VERSION => {
1720 return Err(StoreError::MigrationFailed {
1721 from: v,
1722 to: STORE_SCHEMA_VERSION,
1723 reason: format!(
1724 "DB version v{v} is more recent than the client expects (v{STORE_SCHEMA_VERSION}). Rolling back is not supported"
1725 ),
1726 });
1727 }
1728 #[cfg(feature = "rocksdb")]
1729 Some(v) if v < STORE_SCHEMA_VERSION => {
1730 let rocksdb = Arc::new(RocksDBBackend::open(
1734 &path,
1735 config.rocksdb_block_cache_size,
1736 )?);
1737 crate::migrations::run_pending_migrations(rocksdb.as_ref(), &db_path, v)?;
1738 rocksdb.drop_obsolete_cfs(&path);
1739 let backend: Arc<dyn crate::api::StorageBackend> = rocksdb;
1740 return Self::from_backend(
1741 backend,
1742 db_path,
1743 DB_COMMIT_THRESHOLD,
1744 config.persist_channel_capacity,
1745 );
1746 }
1747 Some(_) => {
1748 }
1753 }
1754 }
1755
1756 match engine_type {
1757 #[cfg(feature = "rocksdb")]
1758 EngineType::RocksDB => {
1759 let rocksdb = RocksDBBackend::open(&path, config.rocksdb_block_cache_size)?;
1760 rocksdb.drop_obsolete_cfs(&path);
1761 let backend: Arc<dyn StorageBackend> = Arc::new(rocksdb);
1762 Self::from_backend(
1763 backend,
1764 db_path,
1765 DB_COMMIT_THRESHOLD,
1766 config.persist_channel_capacity,
1767 )
1768 }
1769 EngineType::InMemory => {
1770 let backend = Arc::new(InMemoryBackend::open()?);
1771 Self::from_backend(
1772 backend,
1773 db_path,
1774 IN_MEMORY_COMMIT_THRESHOLD,
1775 config.persist_channel_capacity,
1776 )
1777 }
1778 }
1779 }
1780
1781 fn from_backend(
1782 backend: Arc<dyn StorageBackend>,
1783 db_path: PathBuf,
1784 commit_threshold: usize,
1785 persist_channel_capacity: usize,
1786 ) -> Result<Self, StoreError> {
1787 debug!("Initializing Store with {commit_threshold} in-memory diff-layers");
1788 let (fkv_tx, fkv_rx) = std::sync::mpsc::sync_channel(0);
1789 let persist_cap = persist_channel_capacity.max(1); let (persist_tx, persist_rx) = std::sync::mpsc::sync_channel(persist_cap);
1791
1792 let (last_written, initial_flushed_upto) = {
1793 let tx = backend.begin_read()?;
1794 let last_written = tx
1795 .get(MISC_VALUES, "last_written".as_bytes())?
1796 .unwrap_or_else(|| vec![0u8; 64]);
1797 let last_written = if last_written == [0xff] {
1798 vec![0xff; 64]
1799 } else {
1800 last_written
1801 };
1802 let initial_flushed_upto = match tx.get(MISC_VALUES, FLUSHED_UPTO_KEY)? {
1803 Some(bytes) => decode_flushed_upto(&bytes)?,
1804 None => 0,
1805 };
1806 (last_written, initial_flushed_upto)
1807 };
1808 let mut initial_buffer = BlockDataBuffer::new();
1809 initial_buffer.set_flushed_upto(initial_flushed_upto);
1810
1811 let mut background_threads = Vec::new();
1812 let mut store = Self {
1813 db_path,
1814 backend,
1815 chain_config: Default::default(),
1816 latest_block_header: Default::default(),
1817 trie_cache: Arc::new(RwLock::new(Arc::new(TrieLayerCache::new(commit_threshold)))),
1818 flatkeyvalue_control_tx: fkv_tx,
1819 block_data_buffer: Arc::new(RwLock::new(Arc::new(initial_buffer))),
1820 persist_tx,
1821 pending_trie_roots: Arc::new(PendingTrieRoots::default()),
1822 last_computed_flatkeyvalue: Arc::new(RwLock::new(last_written)),
1823 account_code_cache: Arc::new(Mutex::new(CodeCache::default())),
1824 code_metadata_cache: Arc::new(Mutex::new(rustc_hash::FxHashMap::default())),
1825 fcu_lock: Arc::new(tokio::sync::Mutex::new(())),
1826 background_threads: Default::default(),
1827 };
1828 let backend_clone = store.backend.clone();
1829 let last_computed_fkv = store.last_computed_flatkeyvalue.clone();
1830 background_threads.push(std::thread::spawn(move || {
1831 let rx = fkv_rx;
1832 loop {
1834 match rx.recv() {
1835 Ok(FKVGeneratorControlMessage::Continue) => break,
1836 Ok(FKVGeneratorControlMessage::Stop) => {}
1837 Err(std::sync::mpsc::RecvError) => {
1838 debug!("Closing FlatKeyValue generator.");
1839 return;
1840 }
1841 }
1842 }
1843
1844 let _ = flatkeyvalue_generator(&backend_clone, &last_computed_fkv, &rx)
1845 .inspect_err(|err| error!("Error while generating FlatKeyValue: {err}"));
1846 }));
1847 let persist_backend = store.backend.clone();
1850 let persist_buffer = store.block_data_buffer.clone();
1851 let persist_trie_cache = store.trie_cache.clone();
1852 let persist_pending_roots = store.pending_trie_roots.clone();
1853 let persist_fkv_ctl = store.flatkeyvalue_control_tx.clone();
1854 background_threads.push(std::thread::spawn(move || {
1855 let rx = persist_rx;
1856 let mut last_flush_result: Result<(), StoreError> = Ok(());
1859 loop {
1860 match rx.recv() {
1861 Ok(PersistMessage::Block(bp)) => {
1862 let staged = mutate_block_buffer(&persist_buffer, move |b| {
1865 let mut codes = Some(bp.codes);
1866 for (block, receipts) in bp.blocks {
1867 b.insert(block, receipts, codes.take().unwrap_or_default());
1868 }
1869 });
1870 if let Err(e) = staged {
1871 persist_pending_roots.clear(bp.child_state_root);
1876 let _ = bp.ack.send(Err(e));
1877 continue;
1878 }
1879 if !bp.wait_for_flush {
1888 let _ = bp
1889 .ack
1890 .send(std::mem::replace(&mut last_flush_result, Ok(())));
1891 }
1892 if let Err(err) = apply_trie_phase1(
1894 &persist_trie_cache,
1895 &persist_pending_roots,
1896 bp.parent_state_root,
1897 bp.child_state_root,
1898 bp.account_updates,
1899 bp.storage_updates,
1900 ) {
1901 error!("persist worker trie phase-1 failed: {err}");
1902 if bp.wait_for_flush {
1903 let _ = bp.ack.send(Err(err));
1904 } else {
1905 last_flush_result = Err(err);
1906 }
1907 continue;
1908 }
1909 let flushed = flush_block_data(persist_backend.as_ref(), &persist_buffer)
1911 .inspect_err(|err| error!("flush_block_data failed: {err}"))
1912 .and_then(|_| {
1913 commit_trie_if_due(
1914 persist_backend.as_ref(),
1915 &persist_trie_cache,
1916 &persist_fkv_ctl,
1917 bp.parent_state_root,
1918 bp.wait_for_flush,
1919 )
1920 });
1921 if bp.wait_for_flush {
1924 let prior = std::mem::replace(&mut last_flush_result, Ok(()));
1925 let _ = bp.ack.send(prior.and(flushed));
1926 } else {
1927 last_flush_result = flushed;
1928 }
1929 }
1930 Ok(PersistMessage::Ping(ack)) => {
1931 let _ = ack.send(std::mem::replace(&mut last_flush_result, Ok(())));
1935 }
1936 Ok(PersistMessage::Shutdown { ack }) => {
1937 let result = flush_block_data(persist_backend.as_ref(), &persist_buffer);
1944 let prior = std::mem::replace(&mut last_flush_result, Ok(()));
1945 let _ = ack.send(prior.and(result));
1946 return;
1948 }
1949 Err(_) => return,
1950 }
1951 }
1952 }));
1953 store.background_threads = Arc::new(ThreadList {
1954 list: background_threads,
1955 });
1956 Ok(store)
1957 }
1958
1959 pub async fn new_from_genesis(
1962 store_path: &Path,
1963 engine_type: EngineType,
1964 genesis_path: &str,
1965 ) -> Result<Self, StoreError> {
1966 Self::new_from_genesis_with_config(
1967 store_path,
1968 engine_type,
1969 genesis_path,
1970 StoreConfig::default(),
1971 )
1972 .await
1973 }
1974
1975 pub async fn new_from_genesis_with_config(
1978 store_path: &Path,
1979 engine_type: EngineType,
1980 genesis_path: &str,
1981 config: StoreConfig,
1982 ) -> Result<Self, StoreError> {
1983 let file = std::fs::File::open(genesis_path)
1984 .map_err(|error| StoreError::Custom(format!("Failed to open genesis file: {error}")))?;
1985 let reader = std::io::BufReader::new(file);
1986 let genesis: Genesis = serde_json::from_reader(reader)
1987 .map_err(|e| StoreError::Custom(format!("Failed to deserialize genesis file: {e}")))?;
1988 let mut store = Self::new_with_config(store_path, engine_type, config)?;
1989 store.add_initial_state(genesis).await?;
1990 Ok(store)
1991 }
1992
1993 pub async fn get_account_info(
1994 &self,
1995 block_number: BlockNumber,
1996 address: Address,
1997 ) -> Result<Option<AccountInfo>, StoreError> {
1998 match self.get_canonical_block_hash(block_number).await? {
1999 Some(block_hash) => self.get_account_info_by_hash(block_hash, address),
2000 None => Ok(None),
2001 }
2002 }
2003
2004 pub fn get_account_info_by_hash(
2005 &self,
2006 block_hash: BlockHash,
2007 address: Address,
2008 ) -> Result<Option<AccountInfo>, StoreError> {
2009 let Some(state_trie) = self.state_trie(block_hash)? else {
2010 return Ok(None);
2011 };
2012 let hashed_address = hash_address_fixed(&address);
2013
2014 let Some(encoded_state) = state_trie.get(hashed_address.as_bytes())? else {
2015 return Ok(None);
2016 };
2017
2018 let account_state = AccountState::decode(&encoded_state)?;
2019 Ok(Some(AccountInfo {
2020 code_hash: account_state.code_hash,
2021 balance: account_state.balance,
2022 nonce: account_state.nonce,
2023 }))
2024 }
2025
2026 pub fn get_account_state_by_acc_hash(
2027 &self,
2028 block_hash: BlockHash,
2029 account_hash: H256,
2030 ) -> Result<Option<AccountState>, StoreError> {
2031 let Some(state_trie) = self.state_trie(block_hash)? else {
2032 return Ok(None);
2033 };
2034 let Some(encoded_state) = state_trie.get(account_hash.as_bytes())? else {
2035 return Ok(None);
2036 };
2037 let account_state = AccountState::decode(&encoded_state)?;
2038 Ok(Some(account_state))
2039 }
2040
2041 pub async fn get_fork_id(&self) -> Result<ForkId, StoreError> {
2042 let chain_config = self.get_chain_config();
2043 let genesis_header = self
2044 .load_block_header(0)?
2045 .ok_or(StoreError::MissingEarliestBlockNumber)?;
2046 let block_header = self.latest_block_header.get();
2047
2048 Ok(ForkId::new(
2049 chain_config,
2050 genesis_header,
2051 block_header.timestamp,
2052 block_header.number,
2053 ))
2054 }
2055
2056 pub async fn get_code_by_account_address(
2057 &self,
2058 block_number: BlockNumber,
2059 address: Address,
2060 ) -> Result<Option<Code>, StoreError> {
2061 let Some(block_hash) = self.get_canonical_block_hash(block_number).await? else {
2062 return Ok(None);
2063 };
2064 let Some(state_trie) = self.state_trie(block_hash)? else {
2065 return Ok(None);
2066 };
2067 let hashed_address = hash_address_fixed(&address);
2068 let Some(encoded_state) = state_trie.get(hashed_address.as_bytes())? else {
2069 return Ok(None);
2070 };
2071 let account_state = AccountState::decode(&encoded_state)?;
2072 self.get_account_code(account_state.code_hash)
2073 }
2074
2075 pub async fn get_nonce_by_account_address(
2076 &self,
2077 block_number: BlockNumber,
2078 address: Address,
2079 ) -> Result<Option<u64>, StoreError> {
2080 let Some(block_hash) = self.get_canonical_block_hash(block_number).await? else {
2081 return Ok(None);
2082 };
2083 let Some(state_trie) = self.state_trie(block_hash)? else {
2084 return Ok(None);
2085 };
2086 let hashed_address = hash_address_fixed(&address);
2087 let Some(encoded_state) = state_trie.get(hashed_address.as_bytes())? else {
2088 return Ok(None);
2089 };
2090 let account_state = AccountState::decode(&encoded_state)?;
2091 Ok(Some(account_state.nonce))
2092 }
2093
2094 pub fn apply_account_updates_batch(
2097 &self,
2098 block_hash: BlockHash,
2099 account_updates: &[AccountUpdate],
2100 ) -> Result<Option<AccountUpdatesList>, StoreError> {
2101 let Some(mut state_trie) = self.state_trie(block_hash)? else {
2102 return Ok(None);
2103 };
2104
2105 Ok(Some(self.apply_account_updates_from_trie_batch(
2106 &mut state_trie,
2107 account_updates,
2108 )?))
2109 }
2110
2111 pub fn apply_account_updates_from_trie_batch<'a>(
2112 &self,
2113 state_trie: &mut Trie,
2114 account_updates: impl IntoIterator<Item = &'a AccountUpdate>,
2115 ) -> Result<AccountUpdatesList, StoreError> {
2116 let mut ret_storage_updates = Vec::new();
2117 let mut code_updates = Vec::new();
2118 let state_root = state_trie.hash_no_commit(&NativeCrypto);
2119 for update in account_updates {
2120 let hashed_address = hash_address_fixed(&update.address);
2121 if update.removed {
2122 state_trie.remove(hashed_address.as_bytes())?;
2124 continue;
2125 }
2126 let mut account_state = match state_trie.get(hashed_address.as_bytes())? {
2129 Some(encoded_state) => AccountState::decode(&encoded_state)?,
2130 None => AccountState::default(),
2131 };
2132 if update.removed_storage {
2133 account_state.storage_root = *EMPTY_TRIE_HASH;
2134 }
2135 if let Some(info) = &update.info {
2136 account_state.nonce = info.nonce;
2137 account_state.balance = info.balance;
2138 account_state.code_hash = info.code_hash;
2139 if let Some(code) = &update.code {
2141 code_updates.push((info.code_hash, code.clone()));
2142 }
2143 }
2144 if !update.added_storage.is_empty() {
2146 let mut storage_trie =
2147 self.open_storage_trie(hashed_address, state_root, account_state.storage_root)?;
2148 for (storage_key, storage_value) in &update.added_storage {
2149 let hashed_key = hash_key(storage_key);
2150 if storage_value.is_zero() {
2151 storage_trie.remove(&hashed_key)?;
2152 } else {
2153 storage_trie.insert(hashed_key, storage_value.encode_to_vec())?;
2154 }
2155 }
2156 let (storage_hash, storage_updates) =
2157 storage_trie.collect_changes_since_last_hash(&NativeCrypto);
2158 account_state.storage_root = storage_hash;
2159 ret_storage_updates.push((hashed_address, storage_updates));
2160 }
2161 state_trie.insert(
2162 hashed_address.as_bytes().to_vec(),
2163 account_state.encode_to_vec(),
2164 )?;
2165 }
2166 let (state_trie_hash, state_updates) =
2167 state_trie.collect_changes_since_last_hash(&NativeCrypto);
2168
2169 Ok(AccountUpdatesList {
2170 state_trie_hash,
2171 state_updates,
2172 storage_updates: ret_storage_updates,
2173 code_updates,
2174 })
2175 }
2176
2177 pub fn apply_account_updates_from_trie_with_witness(
2180 &self,
2181 mut state_trie: Trie,
2182 account_updates: &[AccountUpdate],
2183 mut storage_tries: StorageTries,
2184 ) -> Result<(StorageTries, AccountUpdatesList), StoreError> {
2185 let mut ret_storage_updates = Vec::new();
2186
2187 let mut code_updates = Vec::new();
2188
2189 let state_root = state_trie.hash_no_commit(&NativeCrypto);
2190
2191 for update in account_updates.iter() {
2192 let hashed_address = hash_address(&update.address);
2193
2194 if update.removed {
2195 state_trie.remove(&hashed_address)?;
2197
2198 continue;
2199 }
2200
2201 let mut account_state = match state_trie.get(&hashed_address)? {
2204 Some(encoded_state) => AccountState::decode(&encoded_state)?,
2205 None => AccountState::default(),
2206 };
2207
2208 if update.removed_storage {
2209 account_state.storage_root = *EMPTY_TRIE_HASH;
2210 }
2211
2212 if let Some(info) = &update.info {
2213 account_state.nonce = info.nonce;
2214
2215 account_state.balance = info.balance;
2216
2217 account_state.code_hash = info.code_hash;
2218
2219 if let Some(code) = &update.code {
2221 code_updates.push((info.code_hash, code.clone()));
2222 }
2223 }
2224
2225 if !update.added_storage.is_empty() {
2227 let (_witness, storage_trie) = match storage_tries.entry(update.address) {
2228 Entry::Occupied(value) => value.into_mut(),
2229 Entry::Vacant(vacant) => {
2230 let trie = self.open_storage_trie(
2231 H256::from_slice(&hashed_address),
2232 state_root,
2233 account_state.storage_root,
2234 )?;
2235 vacant.insert(TrieLogger::open_trie(trie))
2236 }
2237 };
2238
2239 for (storage_key, storage_value) in &update.added_storage {
2240 let hashed_key = hash_key(storage_key);
2241
2242 if storage_value.is_zero() {
2243 storage_trie.remove(&hashed_key)?;
2244 } else {
2245 storage_trie.insert(hashed_key, storage_value.encode_to_vec())?;
2246 }
2247 }
2248
2249 let (storage_hash, storage_updates) =
2250 storage_trie.collect_changes_since_last_hash(&NativeCrypto);
2251
2252 account_state.storage_root = storage_hash;
2253
2254 ret_storage_updates.push((H256::from_slice(&hashed_address), storage_updates));
2255 }
2256
2257 state_trie.insert(hashed_address, account_state.encode_to_vec())?;
2258 }
2259
2260 let (state_trie_hash, state_updates) =
2261 state_trie.collect_changes_since_last_hash(&NativeCrypto);
2262
2263 let account_updates_list = AccountUpdatesList {
2264 state_trie_hash,
2265 state_updates,
2266 storage_updates: ret_storage_updates,
2267 code_updates,
2268 };
2269
2270 Ok((storage_tries, account_updates_list))
2271 }
2272
2273 pub async fn setup_genesis_state_trie(
2275 &self,
2276 genesis_accounts: BTreeMap<Address, GenesisAccount>,
2277 ) -> Result<H256, StoreError> {
2278 let mut storage_trie_nodes = vec![];
2279 let mut genesis_state_trie = self.open_direct_state_trie(*EMPTY_TRIE_HASH)?;
2280 for (address, account) in genesis_accounts {
2281 let hashed_address = hash_address(&address);
2282 let h256_hashed_address = H256::from_slice(&hashed_address);
2283
2284 let code = Code::from_bytecode(account.code, &NativeCrypto);
2286 let code_hash = code.hash;
2287 self.add_account_code(code).await?;
2288
2289 let mut storage_trie =
2291 self.open_direct_storage_trie(h256_hashed_address, *EMPTY_TRIE_HASH)?;
2292 for (storage_key, storage_value) in account.storage {
2293 if !storage_value.is_zero() {
2294 let hashed_key = hash_key(&H256(storage_key.to_big_endian()));
2295 storage_trie.insert(hashed_key, storage_value.encode_to_vec())?;
2296 }
2297 }
2298
2299 let (storage_root, storage_nodes) =
2300 storage_trie.collect_changes_since_last_hash(&NativeCrypto);
2301
2302 storage_trie_nodes.extend(
2303 storage_nodes
2304 .into_iter()
2305 .map(|(path, n)| (apply_prefix(Some(h256_hashed_address), path).into_vec(), n)),
2306 );
2307
2308 let account_state = AccountState {
2310 nonce: account.nonce,
2311 balance: account.balance,
2312 storage_root,
2313 code_hash,
2314 };
2315 genesis_state_trie.insert(hashed_address, account_state.encode_to_vec())?;
2316 }
2317
2318 let (state_root, account_trie_nodes) =
2319 genesis_state_trie.collect_changes_since_last_hash(&NativeCrypto);
2320 let account_trie_nodes = account_trie_nodes
2321 .into_iter()
2322 .map(|(path, n)| (apply_prefix(None, path).into_vec(), n))
2323 .collect::<Vec<_>>();
2324
2325 let mut tx = self.backend.begin_write()?;
2326 tx.put_batch(ACCOUNT_TRIE_NODES, account_trie_nodes)?;
2327 tx.put_batch(STORAGE_TRIE_NODES, storage_trie_nodes)?;
2328 tx.commit()?;
2329
2330 Ok(state_root)
2331 }
2332
2333 fn make_witness_key(block_number: u64, block_hash: &BlockHash) -> Vec<u8> {
2335 let mut composite_key = Vec::with_capacity(8 + 32);
2336 composite_key.extend_from_slice(&block_number.to_be_bytes());
2337 composite_key.extend_from_slice(block_hash.as_bytes());
2338 composite_key
2339 }
2340
2341 pub fn store_witness(
2347 &self,
2348 block_hash: BlockHash,
2349 block_number: u64,
2350 witness: ExecutionWitness,
2351 ) -> Result<(), StoreError> {
2352 let rpc_witness = RpcExecutionWitness::try_from(witness)?;
2354 let key = Self::make_witness_key(block_number, &block_hash);
2355 let value = serde_json::to_vec(&rpc_witness)?;
2356 self.write(EXECUTION_WITNESSES, key, value)?;
2357 self.cleanup_old_witnesses(block_number)
2359 }
2360
2361 fn cleanup_old_witnesses(&self, latest_block_number: u64) -> Result<(), StoreError> {
2362 if latest_block_number <= MAX_WITNESSES {
2364 return Ok(());
2365 }
2366
2367 let threshold = latest_block_number - MAX_WITNESSES;
2368
2369 if let Some(oldest_block_number) = self.get_oldest_witness_number()? {
2370 let prefix = oldest_block_number.to_be_bytes();
2371 let mut to_delete = Vec::new();
2372
2373 {
2374 let read_txn = self.backend.begin_read()?;
2375 let iter = read_txn.prefix_iterator(EXECUTION_WITNESSES, &prefix)?;
2376
2377 for item in iter {
2379 let (key, _value) = item?;
2380 let mut block_number_bytes = [0u8; 8];
2381 block_number_bytes.copy_from_slice(&key[0..8]);
2382 let block_number = u64::from_be_bytes(block_number_bytes);
2383 if block_number > threshold {
2384 break;
2385 }
2386 to_delete.push(key.to_vec());
2387 }
2388 }
2389
2390 for key in to_delete {
2391 self.delete(EXECUTION_WITNESSES, key)?;
2392 }
2393 };
2394
2395 self.update_oldest_witness_number(threshold + 1)?;
2396
2397 Ok(())
2398 }
2399
2400 fn update_oldest_witness_number(&self, oldest_block_number: u64) -> Result<(), StoreError> {
2401 self.write(
2402 MISC_VALUES,
2403 b"oldest_witness_block_number".to_vec(),
2404 oldest_block_number.to_le_bytes().to_vec(),
2405 )?;
2406 Ok(())
2407 }
2408
2409 fn get_oldest_witness_number(&self) -> Result<Option<u64>, StoreError> {
2410 let Some(value) = self.read(MISC_VALUES, b"oldest_witness_block_number".to_vec())? else {
2411 return Ok(None);
2412 };
2413
2414 let array: [u8; 8] = value.as_slice().try_into().map_err(|_| {
2415 StoreError::Custom("Invalid oldest witness block number bytes".to_string())
2416 })?;
2417 Ok(Some(u64::from_le_bytes(array)))
2418 }
2419
2420 pub fn get_witness_json_bytes(
2426 &self,
2427 block_number: u64,
2428 block_hash: BlockHash,
2429 ) -> Result<Option<Vec<u8>>, StoreError> {
2430 let key = Self::make_witness_key(block_number, &block_hash);
2431 self.read(EXECUTION_WITNESSES, key)
2432 }
2433
2434 pub fn get_witness_by_number_and_hash(
2439 &self,
2440 block_number: u64,
2441 block_hash: BlockHash,
2442 ) -> Result<Option<RpcExecutionWitness>, StoreError> {
2443 let key = Self::make_witness_key(block_number, &block_hash);
2444 match self.read(EXECUTION_WITNESSES, key)? {
2445 Some(value) => {
2446 let witness: RpcExecutionWitness = serde_json::from_slice(&value)?;
2447 Ok(Some(witness))
2448 }
2449 None => Ok(None),
2450 }
2451 }
2452
2453 pub fn store_block_access_list(
2455 &self,
2456 block_hash: BlockHash,
2457 bal: &BlockAccessList,
2458 ) -> Result<(), StoreError> {
2459 let key = block_hash.as_bytes().to_vec();
2460 let mut value = vec![];
2461 bal.encode(&mut value);
2462 self.write(BLOCK_ACCESS_LISTS, key, value)
2463 }
2464
2465 pub fn get_block_access_list(
2467 &self,
2468 block_hash: BlockHash,
2469 ) -> Result<Option<BlockAccessList>, StoreError> {
2470 let key = block_hash.as_bytes().to_vec();
2471 match self.read(BLOCK_ACCESS_LISTS, key)? {
2472 Some(value) => {
2473 let bal = BlockAccessList::decode(&value)
2474 .map_err(|e| StoreError::Custom(format!("Failed to decode BAL: {e}")))?;
2475 Ok(Some(bal))
2476 }
2477 None => Ok(None),
2478 }
2479 }
2480
2481 pub async fn add_initial_state(&mut self, genesis: Genesis) -> Result<(), StoreError> {
2482 self.add_initial_state_inner(genesis, false).await
2483 }
2484
2485 pub async fn add_initial_state_skip_validation(
2496 &mut self,
2497 genesis: Genesis,
2498 ) -> Result<(), StoreError> {
2499 self.add_initial_state_inner(genesis, true).await
2500 }
2501
2502 async fn add_initial_state_inner(
2503 &mut self,
2504 genesis: Genesis,
2505 skip_genesis_validation: bool,
2506 ) -> Result<(), StoreError> {
2507 debug!("Storing initial state from genesis");
2508
2509 let genesis_block = genesis.get_block();
2511 let genesis_block_number = genesis_block.header.number;
2512
2513 let genesis_hash = genesis_block.hash();
2514
2515 let stored_genesis_header = self.load_block_header(genesis_block_number)?;
2516
2517 self.set_chain_config(&genesis.config).await?;
2524
2525 if let Some(latest) = self.load_latest_block_number().await? {
2530 self.anchor_to_durable_head(latest).await?;
2531 }
2532
2533 match stored_genesis_header {
2534 Some(header) if skip_genesis_validation => {
2535 info!(
2536 stored_genesis = %header.hash(),
2537 "Skipping genesis state validation; trusting the genesis header and state already stored in the datadir"
2538 );
2539 return Ok(());
2540 }
2541 Some(header) if header.hash() == genesis_hash => {
2542 info!("Received genesis file matching a previously stored one, nothing to do");
2543 return Ok(());
2544 }
2545 Some(_) => {
2546 error!(
2547 "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."
2548 );
2549 return Err(StoreError::IncompatibleChainConfig);
2550 }
2551 None => {
2552 self.add_block_header(genesis_hash, genesis_block.header.clone())
2553 .await?
2554 }
2555 }
2556 let genesis_state_root = self.setup_genesis_state_trie(genesis.alloc).await?;
2559 debug_assert_eq!(genesis_state_root, genesis_block.header.state_root);
2560
2561 info!(hash = %genesis_hash, "Storing genesis block");
2563
2564 self.add_block(genesis_block).await?;
2565 self.update_earliest_block_number(genesis_block_number)
2566 .await?;
2567 self.forkchoice_update(vec![], genesis_block_number, genesis_hash, None, None)
2568 .await?;
2569 Ok(())
2570 }
2571
2572 pub async fn load_initial_state(&self) -> Result<(), StoreError> {
2573 info!("Loading initial state from DB");
2574 let Some(latest) = self.load_latest_block_number().await? else {
2575 return Err(StoreError::MissingLatestBlockNumber);
2576 };
2577 self.anchor_to_durable_head(latest).await?;
2581 Ok(())
2582 }
2583
2584 pub fn get_storage_at(
2585 &self,
2586 block_number: BlockNumber,
2587 address: Address,
2588 storage_key: H256,
2589 ) -> Result<Option<U256>, StoreError> {
2590 match self.get_block_header(block_number)? {
2591 Some(header) => self.get_storage_at_root(header.state_root, address, storage_key),
2592 None => Ok(None),
2593 }
2594 }
2595
2596 pub fn get_storage_at_root(
2597 &self,
2598 state_root: H256,
2599 address: Address,
2600 storage_key: H256,
2601 ) -> Result<Option<U256>, StoreError> {
2602 let account_hash = hash_address_fixed(&address);
2603
2604 let read_view = self.backend.begin_read()?;
2606 let cache = self.gated_snapshot(state_root)?;
2607 let last_written = self.last_written()?;
2608 let use_fkv = Self::flatkeyvalue_computed_with_last_written(account_hash, &last_written);
2609
2610 let storage_root = if use_fkv {
2611 *EMPTY_TRIE_HASH
2613 } else {
2614 let state_trie = self.open_state_trie_shared(
2615 state_root,
2616 read_view.clone(),
2617 cache.clone(),
2618 last_written.clone(),
2619 )?;
2620 let Some(encoded_account) = state_trie.get(account_hash.as_bytes())? else {
2621 return Ok(None);
2622 };
2623 let account = AccountState::decode(&encoded_account)?;
2624 account.storage_root
2625 };
2626 let storage_trie = self.open_storage_trie_shared(
2627 account_hash,
2628 state_root,
2629 storage_root,
2630 read_view,
2631 cache,
2632 last_written,
2633 )?;
2634
2635 let hashed_key = hash_key_fixed(&storage_key);
2636 storage_trie
2637 .get(&hashed_key)?
2638 .map(|rlp| U256::decode(&rlp).map_err(StoreError::RLPDecode))
2639 .transpose()
2640 }
2641
2642 pub fn get_storage_at_root_with_known_storage_root(
2647 &self,
2648 state_root: H256,
2649 account_hash: H256,
2650 storage_root: H256,
2651 storage_key: H256,
2652 ) -> Result<Option<U256>, StoreError> {
2653 let read_view = self.backend.begin_read()?;
2654 let cache = self.gated_snapshot(state_root)?;
2655 let last_written = self.last_written()?;
2656 let storage_root =
2660 if Self::flatkeyvalue_computed_with_last_written(account_hash, &last_written) {
2661 *EMPTY_TRIE_HASH
2662 } else {
2663 storage_root
2664 };
2665 let storage_trie = self.open_storage_trie_shared(
2666 account_hash,
2667 state_root,
2668 storage_root,
2669 read_view,
2670 cache,
2671 last_written,
2672 )?;
2673
2674 let hashed_key = hash_key_fixed(&storage_key);
2675 storage_trie
2676 .get(&hashed_key)?
2677 .map(|rlp| U256::decode(&rlp).map_err(StoreError::RLPDecode))
2678 .transpose()
2679 }
2680
2681 pub fn get_chain_config(&self) -> ChainConfig {
2682 self.chain_config
2683 }
2684
2685 pub async fn get_latest_canonical_block_hash(&self) -> Result<Option<BlockHash>, StoreError> {
2686 Ok(Some(self.latest_block_header.get().hash()))
2687 }
2688
2689 pub async fn forkchoice_update(
2694 &self,
2695 new_canonical_blocks: Vec<(BlockNumber, BlockHash)>,
2696 head_number: BlockNumber,
2697 head_hash: BlockHash,
2698 safe: Option<BlockNumber>,
2699 finalized: Option<BlockNumber>,
2700 ) -> Result<(), StoreError> {
2701 let _guard = self.fcu_lock.lock().await;
2707
2708 let previous_head = self.latest_block_header.get();
2713 let new_head = self
2714 .get_block_header_by_hash(head_hash)?
2715 .ok_or_else(|| StoreError::MissingLatestBlockNumber)?;
2716 self.latest_block_header.update(new_head);
2717 if let Err(err) = self
2718 .forkchoice_update_inner(
2719 new_canonical_blocks,
2720 head_number,
2721 head_hash,
2722 safe,
2723 finalized,
2724 )
2725 .await
2726 {
2727 self.latest_block_header.update((*previous_head).clone());
2728 return Err(err);
2729 }
2730
2731 Ok(())
2732 }
2733
2734 pub fn state_trie(&self, block_hash: BlockHash) -> Result<Option<Trie>, StoreError> {
2736 let Some(header) = self.get_block_header_by_hash(block_hash)? else {
2737 return Ok(None);
2738 };
2739 Ok(Some(self.open_state_trie(header.state_root)?))
2740 }
2741
2742 pub fn storage_trie(
2744 &self,
2745 block_hash: BlockHash,
2746 address: Address,
2747 ) -> Result<Option<Trie>, StoreError> {
2748 let Some(header) = self.get_block_header_by_hash(block_hash)? else {
2749 return Ok(None);
2750 };
2751 let Some(state_trie) = self.state_trie(block_hash)? else {
2753 return Ok(None);
2754 };
2755 let hashed_address = hash_address_fixed(&address);
2756 let Some(encoded_account) = state_trie.get(hashed_address.as_bytes())? else {
2757 return Ok(None);
2758 };
2759 let account = AccountState::decode(&encoded_account)?;
2760 let storage_root = account.storage_root;
2762 Ok(Some(self.open_storage_trie(
2763 hashed_address,
2764 header.state_root,
2765 storage_root,
2766 )?))
2767 }
2768
2769 pub async fn get_account_state(
2770 &self,
2771 block_number: BlockNumber,
2772 address: Address,
2773 ) -> Result<Option<AccountState>, StoreError> {
2774 let Some(block_hash) = self.get_canonical_block_hash(block_number).await? else {
2775 return Ok(None);
2776 };
2777 let Some(state_trie) = self.state_trie(block_hash)? else {
2778 return Ok(None);
2779 };
2780 self.get_account_state_from_trie(&state_trie, address)
2781 }
2782
2783 pub fn get_account_state_by_root(
2784 &self,
2785 state_root: H256,
2786 address: Address,
2787 ) -> Result<Option<AccountState>, StoreError> {
2788 let state_trie = self.open_state_trie(state_root)?;
2789 self.get_account_state_from_trie(&state_trie, address)
2790 }
2791
2792 pub fn get_account_state_from_trie(
2793 &self,
2794 state_trie: &Trie,
2795 address: Address,
2796 ) -> Result<Option<AccountState>, StoreError> {
2797 let hashed_address = hash_address_fixed(&address);
2798 let Some(encoded_state) = state_trie.get(hashed_address.as_bytes())? else {
2799 return Ok(None);
2800 };
2801 Ok(Some(AccountState::decode(&encoded_state)?))
2802 }
2803
2804 pub fn get_account_states_batch_by_root(
2813 &self,
2814 state_root: H256,
2815 addresses: &[Address],
2816 ) -> Result<Vec<Option<AccountState>>, StoreError> {
2817 if addresses.is_empty() {
2818 return Ok(Vec::new());
2819 }
2820
2821 let last_written = self.last_written()?;
2822 let trie_cache = self
2823 .trie_cache
2824 .read()
2825 .map_err(|_| StoreError::LockError)?
2826 .clone();
2827
2828 let mut results: Vec<Option<AccountState>> = vec![None; addresses.len()];
2829 let leaf_paths: Vec<Vec<u8>> = addresses
2831 .iter()
2832 .map(|addr| {
2833 let hashed = hash_address_fixed(addr);
2834 Nibbles::from_bytes(hashed.as_bytes()).into_vec()
2835 })
2836 .collect();
2837
2838 let mut fkv_indices: Vec<usize> = Vec::new();
2839 let mut trie_indices: Vec<usize> = Vec::new();
2840
2841 let fkv_cursor: &[u8] = last_written.as_slice();
2850 for (i, path) in leaf_paths.iter().enumerate() {
2851 if let Some(value) = trie_cache.get(state_root, path.as_slice()) {
2852 if !value.is_empty() {
2853 results[i] = Some(AccountState::decode(&value)?);
2854 }
2855 continue;
2856 }
2857 if fkv_cursor >= path.as_slice() {
2858 fkv_indices.push(i);
2859 } else {
2860 trie_indices.push(i);
2861 }
2862 }
2863
2864 if !fkv_indices.is_empty() {
2865 let read_view = self.backend.begin_read()?;
2866 let keys: Vec<&[u8]> = fkv_indices
2867 .iter()
2868 .map(|&i| leaf_paths[i].as_slice())
2869 .collect();
2870 let raw = read_view.multi_get(ACCOUNT_FLATKEYVALUE, &keys);
2871 for (slot, res) in fkv_indices.iter().zip(raw.into_iter()) {
2872 let Some(encoded) = res? else { continue };
2873 if encoded.is_empty() {
2874 continue;
2875 }
2876 results[*slot] = Some(AccountState::decode(&encoded)?);
2877 }
2878 }
2879
2880 if !trie_indices.is_empty() {
2881 let state_trie = self.open_state_trie(state_root)?;
2887 let fetched: Result<Vec<(usize, Option<AccountState>)>, StoreError> = trie_indices
2888 .par_iter()
2889 .map(|&i| {
2890 self.get_account_state_from_trie(&state_trie, addresses[i])
2891 .map(|s| (i, s))
2892 })
2893 .collect();
2894 for (i, s) in fetched? {
2895 results[i] = s;
2896 }
2897 }
2898
2899 Ok(results)
2900 }
2901
2902 pub async fn get_account_proof(
2907 &self,
2908 state_root: H256,
2909 address: Address,
2910 storage_keys: &[H256],
2911 ) -> Result<Option<AccountProof>, StoreError> {
2912 let state_trie = self.open_state_trie(state_root)?;
2917 let address_path = hash_address_fixed(&address);
2918 let proof = state_trie.get_proof(address_path.as_bytes())?;
2919 let account_opt = state_trie
2920 .get(address_path.as_bytes())?
2921 .map(|encoded_state| AccountState::decode(&encoded_state))
2922 .transpose()?;
2923
2924 let mut storage_proof = Vec::with_capacity(storage_keys.len());
2925
2926 if let Some(account) = &account_opt {
2927 let storage_trie =
2928 self.open_storage_trie(address_path, state_root, account.storage_root)?;
2929
2930 for key in storage_keys {
2931 let hashed_key = hash_key(key);
2932 let proof = storage_trie.get_proof(&hashed_key)?;
2933 let value = storage_trie
2934 .get(&hashed_key)?
2935 .map(|rlp| U256::decode(&rlp).map_err(StoreError::RLPDecode))
2936 .transpose()?
2937 .unwrap_or_default();
2938
2939 let slot_proof = StorageSlotProof {
2940 proof,
2941 key: *key,
2942 value,
2943 };
2944 storage_proof.push(slot_proof);
2945 }
2946 } else {
2947 storage_proof.extend(storage_keys.iter().map(|key| StorageSlotProof {
2948 proof: Vec::new(),
2949 key: *key,
2950 value: U256::zero(),
2951 }));
2952 }
2953 let account = account_opt.unwrap_or_default();
2954 let account_proof = AccountProof {
2955 proof,
2956 account,
2957 storage_proof,
2958 };
2959 Ok(Some(account_proof))
2960 }
2961
2962 pub fn iter_accounts_from(
2965 &self,
2966 state_root: H256,
2967 starting_address: H256,
2968 ) -> Result<impl Iterator<Item = (H256, AccountState)>, StoreError> {
2969 let mut iter = self.open_locked_state_trie(state_root)?.into_iter();
2970 iter.advance(starting_address.0.to_vec())?;
2971 Ok(iter.content().map_while(|(path, value)| {
2972 Some((H256::from_slice(&path), AccountState::decode(&value).ok()?))
2973 }))
2974 }
2975
2976 pub fn iter_accounts(
2979 &self,
2980 state_root: H256,
2981 ) -> Result<impl Iterator<Item = (H256, AccountState)>, StoreError> {
2982 self.iter_accounts_from(state_root, H256::zero())
2983 }
2984
2985 pub fn iter_storage_from(
2988 &self,
2989 state_root: H256,
2990 hashed_address: H256,
2991 starting_slot: H256,
2992 ) -> Result<Option<impl Iterator<Item = (H256, U256)>>, StoreError> {
2993 let state_trie = self.open_locked_state_trie(state_root)?;
2994 let Some(account_rlp) = state_trie.get(hashed_address.as_bytes())? else {
2995 return Ok(None);
2996 };
2997 let storage_root = AccountState::decode(&account_rlp)?.storage_root;
2998 let mut iter = self
2999 .open_locked_storage_trie(hashed_address, state_root, storage_root)?
3000 .into_iter();
3001 iter.advance(starting_slot.0.to_vec())?;
3002 Ok(Some(iter.content().map_while(|(path, value)| {
3003 Some((H256::from_slice(&path), U256::decode(&value).ok()?))
3004 })))
3005 }
3006
3007 pub fn iter_storage(
3010 &self,
3011 state_root: H256,
3012 hashed_address: H256,
3013 ) -> Result<Option<impl Iterator<Item = (H256, U256)>>, StoreError> {
3014 self.iter_storage_from(state_root, hashed_address, H256::zero())
3015 }
3016
3017 pub fn get_account_range_proof(
3018 &self,
3019 state_root: H256,
3020 starting_hash: H256,
3021 last_hash: Option<H256>,
3022 ) -> Result<Vec<Vec<u8>>, StoreError> {
3023 let state_trie = self.open_state_trie(state_root)?;
3024 let mut proof = state_trie.get_proof(starting_hash.as_bytes())?;
3025 if let Some(last_hash) = last_hash {
3026 proof.extend_from_slice(&state_trie.get_proof(last_hash.as_bytes())?);
3027 }
3028 Ok(proof)
3029 }
3030
3031 pub fn get_storage_range_proof(
3032 &self,
3033 state_root: H256,
3034 hashed_address: H256,
3035 starting_hash: H256,
3036 last_hash: Option<H256>,
3037 ) -> Result<Option<Vec<Vec<u8>>>, StoreError> {
3038 let state_trie = self.open_state_trie(state_root)?;
3039 let Some(account_rlp) = state_trie.get(hashed_address.as_bytes())? else {
3040 return Ok(None);
3041 };
3042 let storage_root = AccountState::decode(&account_rlp)?.storage_root;
3043 let storage_trie = self.open_storage_trie(hashed_address, state_root, storage_root)?;
3044 let mut proof = storage_trie.get_proof(starting_hash.as_bytes())?;
3045 if let Some(last_hash) = last_hash {
3046 proof.extend_from_slice(&storage_trie.get_proof(last_hash.as_bytes())?);
3047 }
3048 Ok(Some(proof))
3049 }
3050
3051 pub fn get_trie_nodes(
3058 &self,
3059 state_root: H256,
3060 paths: Vec<Vec<u8>>,
3061 byte_limit: u64,
3062 ) -> Result<Vec<Vec<u8>>, StoreError> {
3063 let Some(account_path) = paths.first() else {
3064 return Ok(vec![]);
3065 };
3066 let state_trie = self.open_state_trie(state_root)?;
3067 if paths.len() == 1 {
3069 let node = state_trie.get_node(account_path)?;
3071 return Ok(vec![node]);
3072 }
3073 let Some(account_state) = state_trie
3075 .get(account_path)?
3076 .map(|ref rlp| AccountState::decode(rlp))
3077 .transpose()?
3078 else {
3079 return Ok(vec![]);
3080 };
3081 let Ok(hashed_address) = account_path.clone().try_into().map(H256) else {
3083 return Ok(vec![]);
3084 };
3085 let storage_trie =
3086 self.open_storage_trie(hashed_address, state_root, account_state.storage_root)?;
3087 let mut nodes = vec![];
3089 let mut bytes_used = 0;
3090 for path in paths.iter().skip(1) {
3094 if bytes_used >= byte_limit {
3095 break;
3096 }
3097 let node = storage_trie.get_node(path)?;
3098 bytes_used += node.len() as u64;
3099 nodes.push(node);
3100 }
3101 Ok(nodes)
3102 }
3103
3104 fn gated_snapshot(&self, state_root: H256) -> Result<Arc<TrieLayerCache>, StoreError> {
3113 self.pending_trie_roots.wait_until_ready(state_root)?;
3114 Ok(self
3115 .trie_cache
3116 .read()
3117 .map_err(|_| StoreError::LockError)?
3118 .clone())
3119 }
3120
3121 pub fn open_state_trie(&self, state_root: H256) -> Result<Trie, StoreError> {
3125 let trie_db = TrieWrapper::new(
3126 state_root,
3127 self.gated_snapshot(state_root)?,
3128 Box::new(BackendTrieDB::new_for_accounts(
3129 self.backend.clone(),
3130 self.last_written()?,
3131 )?),
3132 None,
3133 );
3134 Ok(Trie::open(Box::new(trie_db), state_root))
3135 }
3136
3137 pub fn open_direct_state_trie(&self, state_root: H256) -> Result<Trie, StoreError> {
3141 Ok(Trie::open(
3142 Box::new(BackendTrieDB::new_for_accounts(
3143 self.backend.clone(),
3144 self.last_written()?,
3145 )?),
3146 state_root,
3147 ))
3148 }
3149
3150 pub fn open_locked_state_trie(&self, state_root: H256) -> Result<Trie, StoreError> {
3154 let trie_db = TrieWrapper::new(
3155 state_root,
3156 self.gated_snapshot(state_root)?,
3157 Box::new(state_trie_locked_backend(
3158 self.backend.as_ref(),
3159 self.last_written()?,
3160 )?),
3161 None,
3162 );
3163 Ok(Trie::open(Box::new(trie_db), state_root))
3164 }
3165
3166 pub fn open_storage_trie(
3169 &self,
3170 account_hash: H256,
3171 state_root: H256,
3172 storage_root: H256,
3173 ) -> Result<Trie, StoreError> {
3174 let trie_db = TrieWrapper::new(
3175 state_root,
3176 self.gated_snapshot(state_root)?,
3177 Box::new(BackendTrieDB::new_for_storages(
3178 self.backend.clone(),
3179 self.last_written()?,
3180 )?),
3181 Some(account_hash),
3182 );
3183 Ok(Trie::open(Box::new(trie_db), storage_root))
3184 }
3185
3186 fn open_state_trie_shared(
3190 &self,
3191 state_root: H256,
3192 read_view: Arc<dyn StorageReadView>,
3193 cache: Arc<TrieLayerCache>,
3194 last_written: Vec<u8>,
3195 ) -> Result<Trie, StoreError> {
3196 let trie_db = TrieWrapper::new(
3197 state_root,
3198 cache,
3199 Box::new(BackendTrieDB::new_for_accounts_with_view(
3200 self.backend.clone(),
3201 read_view,
3202 last_written,
3203 )?),
3204 None,
3205 );
3206 Ok(Trie::open(Box::new(trie_db), state_root))
3207 }
3208
3209 fn open_storage_trie_shared(
3211 &self,
3212 account_hash: H256,
3213 state_root: H256,
3214 storage_root: H256,
3215 read_view: Arc<dyn StorageReadView>,
3216 cache: Arc<TrieLayerCache>,
3217 last_written: Vec<u8>,
3218 ) -> Result<Trie, StoreError> {
3219 let trie_db = TrieWrapper::new(
3220 state_root,
3221 cache,
3222 Box::new(BackendTrieDB::new_for_storages_with_view(
3223 self.backend.clone(),
3224 read_view,
3225 last_written,
3226 )?),
3227 Some(account_hash),
3228 );
3229 Ok(Trie::open(Box::new(trie_db), storage_root))
3230 }
3231
3232 pub fn open_direct_storage_trie(
3235 &self,
3236 account_hash: H256,
3237 storage_root: H256,
3238 ) -> Result<Trie, StoreError> {
3239 Ok(Trie::open(
3240 Box::new(BackendTrieDB::new_for_account_storage(
3241 self.backend.clone(),
3242 account_hash,
3243 self.last_written()?,
3244 )?),
3245 storage_root,
3246 ))
3247 }
3248
3249 pub fn open_locked_storage_trie(
3252 &self,
3253 account_hash: H256,
3254 state_root: H256,
3255 storage_root: H256,
3256 ) -> Result<Trie, StoreError> {
3257 let trie_db = TrieWrapper::new(
3258 state_root,
3259 self.gated_snapshot(state_root)?,
3260 Box::new(state_trie_locked_backend(
3261 self.backend.as_ref(),
3262 self.last_written()?,
3263 )?),
3264 Some(account_hash),
3265 );
3266 Ok(Trie::open(Box::new(trie_db), storage_root))
3267 }
3268
3269 pub fn has_state_root(&self, state_root: H256) -> Result<bool, StoreError> {
3270 if state_root == *EMPTY_TRIE_HASH {
3272 return Ok(true);
3273 }
3274 let trie = self.open_state_trie(state_root)?;
3275 let Some(root) = trie.db().get(Nibbles::default())? else {
3277 return Ok(false);
3278 };
3279 let root_hash = ethrex_trie::Node::decode(&root)?
3280 .compute_hash(&NativeCrypto)
3281 .finalize(&NativeCrypto);
3282 Ok(state_root == root_hash)
3283 }
3284
3285 pub fn ancestors(&self, block_hash: BlockHash) -> AncestorIterator {
3288 AncestorIterator {
3289 store: self.clone(),
3290 next_hash: block_hash,
3291 }
3292 }
3293
3294 pub fn is_canonical_sync(&self, block_hash: BlockHash) -> Result<bool, StoreError> {
3296 let Some(block_number) = self.get_block_number_sync(block_hash)? else {
3297 return Ok(false);
3298 };
3299 Ok(self
3300 .get_canonical_block_hash_sync(block_number)?
3301 .is_some_and(|h| h == block_hash))
3302 }
3303
3304 pub fn generate_flatkeyvalue(&self) -> Result<(), StoreError> {
3305 self.flatkeyvalue_control_tx
3306 .send(FKVGeneratorControlMessage::Continue)
3307 .map_err(|_| StoreError::Custom("FlatKeyValue thread disconnected.".to_string()))
3308 }
3309
3310 pub fn create_checkpoint(&self, path: impl AsRef<Path>) -> Result<(), StoreError> {
3311 self.backend.create_checkpoint(path.as_ref())?;
3312 init_metadata_file(path.as_ref())?;
3313 Ok(())
3314 }
3315
3316 pub fn get_store_directory(&self) -> Result<PathBuf, StoreError> {
3317 Ok(self.db_path.clone())
3318 }
3319
3320 async fn load_latest_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
3322 let key = chain_data_key(ChainDataIndex::LatestBlockNumber);
3323 self.read_async(CHAIN_DATA, key)
3324 .await?
3325 .map(|bytes| -> Result<BlockNumber, StoreError> {
3326 let array: [u8; 8] = bytes
3327 .try_into()
3328 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
3329 Ok(BlockNumber::from_le_bytes(array))
3330 })
3331 .transpose()
3332 }
3333
3334 fn load_canonical_block_hash(
3335 &self,
3336 block_number: BlockNumber,
3337 ) -> Result<Option<BlockHash>, StoreError> {
3338 let txn = self.backend.begin_read()?;
3339 txn.get(
3340 CANONICAL_BLOCK_HASHES,
3341 block_number.to_le_bytes().as_slice(),
3342 )?
3343 .map(|bytes| H256::decode(bytes.as_slice()))
3344 .transpose()
3345 .map_err(StoreError::from)
3346 }
3347
3348 fn load_block_header(
3349 &self,
3350 block_number: BlockNumber,
3351 ) -> Result<Option<BlockHeader>, StoreError> {
3352 let Some(block_hash) = self.load_canonical_block_hash(block_number)? else {
3353 return Ok(None);
3354 };
3355 self.load_block_header_by_hash(block_hash)
3356 }
3357
3358 fn load_block_header_by_hash(
3360 &self,
3361 block_hash: BlockHash,
3362 ) -> Result<Option<BlockHeader>, StoreError> {
3363 let txn = self.backend.begin_read()?;
3364 let hash_key = block_hash.encode_to_vec();
3365 let header_value = txn.get(HEADERS, hash_key.as_slice())?;
3366 let mut header = header_value
3367 .map(|bytes| BlockHeaderRLP::from_bytes(bytes).to())
3368 .transpose()
3369 .map_err(StoreError::from)?;
3370 header.as_mut().inspect(|h| {
3371 let _ = h.hash.set(block_hash);
3373 });
3374 Ok(header)
3375 }
3376
3377 pub fn last_written(&self) -> Result<Vec<u8>, StoreError> {
3378 let last_computed_flatkeyvalue = self
3379 .last_computed_flatkeyvalue
3380 .read()
3381 .map_err(|_| StoreError::LockError)?;
3382 Ok(last_computed_flatkeyvalue.clone())
3383 }
3384
3385 fn flatkeyvalue_computed_with_last_written(account: H256, last_written: &[u8]) -> bool {
3386 let account_nibbles = Nibbles::from_bytes(account.as_bytes());
3387 &last_written[0..64] > account_nibbles.as_ref()
3388 }
3389
3390 pub fn read_flushed_upto(&self) -> Result<BlockNumber, StoreError> {
3395 Ok(self.read_flushed_upto_opt()?.unwrap_or(0))
3396 }
3397
3398 fn read_flushed_upto_opt(&self) -> Result<Option<BlockNumber>, StoreError> {
3401 let tx = self.backend.begin_read()?;
3402 match tx.get(MISC_VALUES, FLUSHED_UPTO_KEY)? {
3403 Some(bytes) => Ok(Some(decode_flushed_upto(&bytes)?)),
3404 None => Ok(None),
3405 }
3406 }
3407
3408 #[cfg(any(test, feature = "testing"))]
3411 pub fn buffer_block_for_test(&self, block: &Block) {
3412 mutate_block_buffer(&self.block_data_buffer, |b| {
3413 b.insert(block.clone(), vec![], vec![])
3414 })
3415 .expect("block_data_buffer lock poisoned");
3416 }
3417
3418 #[cfg(any(test, feature = "testing"))]
3421 pub fn flush_block_data_for_test(&self) -> Result<(), StoreError> {
3422 flush_block_data(self.backend.as_ref(), &self.block_data_buffer)
3423 }
3424
3425 #[cfg(any(test, feature = "testing"))]
3429 pub fn get_trie_node_for_test(
3430 &self,
3431 is_account: bool,
3432 key: &[u8],
3433 ) -> Result<Option<Vec<u8>>, StoreError> {
3434 let table = if is_account {
3435 ACCOUNT_TRIE_NODES
3436 } else {
3437 STORAGE_TRIE_NODES
3438 };
3439 self.backend.begin_read()?.get(table, key)
3440 }
3441
3442 #[cfg(any(test, feature = "testing"))]
3446 pub fn buffer_block_with_codes_for_test(&self, block: &Block, codes: Vec<(H256, Code)>) {
3447 mutate_block_buffer(&self.block_data_buffer, |b| {
3448 b.insert(block.clone(), vec![], codes)
3449 })
3450 .expect("block_data_buffer lock poisoned");
3451 }
3452
3453 #[cfg(any(test, feature = "testing"))]
3458 pub fn register_pending_root_for_test(&self, root: H256) -> Result<(), StoreError> {
3459 self.pending_trie_roots.register(root)
3460 }
3461
3462 #[cfg(any(test, feature = "testing"))]
3465 pub fn clear_pending_root_for_test(&self, root: H256) {
3466 self.pending_trie_roots.clear(root)
3467 }
3468
3469 async fn anchor_to_durable_head(&self, latest: BlockNumber) -> Result<(), StoreError> {
3488 let marker = self.read_flushed_upto_opt()?;
3489 let start = match marker {
3490 Some(flushed) => flushed.min(latest),
3491 None => latest,
3492 };
3493
3494 let mut head = start;
3495 let latest_block_header = loop {
3496 match self.load_block_header(head)? {
3497 Some(header) => break header,
3498 None if marker.is_none() => return Err(StoreError::MissingLatestBlockNumber),
3501 None if head == 0 => return Err(StoreError::MissingLatestBlockNumber),
3502 None => {
3503 warn!(
3504 "durable head {head}: canonical hash has no on-disk header \
3505 (reorg inside flush window); rewinding"
3506 );
3507 head -= 1;
3508 }
3509 }
3510 };
3511 self.latest_block_header.update(latest_block_header);
3512
3513 let reanchor = head != latest;
3518 let rewrite_marker = marker != Some(head);
3519 if reanchor || rewrite_marker {
3520 let mut tx = self.backend.begin_write()?;
3521 if reanchor {
3522 let latest_key = chain_data_key(ChainDataIndex::LatestBlockNumber);
3525 tx.put(CHAIN_DATA, &latest_key, &head.to_le_bytes())?;
3526 }
3527 if rewrite_marker {
3528 write_flushed_upto(tx.as_mut(), head)?;
3529 }
3530 tx.commit()?;
3531 }
3532 Ok(())
3533 }
3534}
3535
3536pub fn write_flushed_upto(
3540 tx: &mut dyn StorageWriteBatch,
3541 n: BlockNumber,
3542) -> Result<(), StoreError> {
3543 tx.put(MISC_VALUES, FLUSHED_UPTO_KEY, &n.to_le_bytes())
3544}
3545
3546fn decode_flushed_upto(bytes: &[u8]) -> Result<BlockNumber, StoreError> {
3552 let arr: [u8; 8] = bytes
3553 .try_into()
3554 .map_err(|_| StoreError::Custom("Invalid flushed_upto bytes".to_string()))?;
3555 Ok(BlockNumber::from_le_bytes(arr))
3556}
3557
3558fn mutate_block_buffer(
3561 buffer: &Arc<RwLock<Arc<BlockDataBuffer>>>,
3562 f: impl FnOnce(&mut BlockDataBuffer),
3563) -> Result<(), StoreError> {
3564 let mut new_buf = (*buffer.read().map_err(|_| StoreError::LockError)?.clone()).clone();
3565 f(&mut new_buf);
3566 *buffer.write().map_err(|_| StoreError::LockError)? = Arc::new(new_buf);
3567 Ok(())
3568}
3569
3570const DEFAULT_PERSIST_CHANNEL_CAPACITY: usize = 2;
3572
3573struct BlockPersist {
3578 blocks: Vec<(Block, Vec<Receipt>)>,
3579 codes: Vec<(H256, Code)>,
3580 parent_state_root: H256,
3581 child_state_root: H256,
3582 account_updates: TrieNodesUpdate,
3583 storage_updates: Vec<(H256, TrieNodesUpdate)>,
3584 wait_for_flush: bool,
3585 ack: std::sync::mpsc::SyncSender<Result<(), StoreError>>,
3586}
3587
3588enum PersistMessage {
3592 Block(BlockPersist),
3593 Ping(std::sync::mpsc::SyncSender<Result<(), StoreError>>),
3594 Shutdown {
3599 ack: std::sync::mpsc::SyncSender<Result<(), StoreError>>,
3600 },
3601}
3602
3603fn write_block_data(
3608 tx: &mut dyn StorageWriteBatch,
3609 number: BlockNumber,
3610 hash: BlockHash,
3611 header: &BlockHeader,
3612 body: &BlockBody,
3613) -> Result<(), StoreError> {
3614 let hash_key = hash.encode_to_vec();
3615 tx.put(
3616 HEADERS,
3617 &hash_key,
3618 BlockHeaderRLP::from(header.clone()).bytes(),
3619 )?;
3620 tx.put(
3621 BODIES,
3622 &hash_key,
3623 BlockBodyRLP::from_bytes(body.encode_to_vec()).bytes(),
3624 )?;
3625 tx.put(BLOCK_NUMBERS, &hash_key, &number.to_le_bytes())?;
3626 for (index, transaction) in body.transactions.iter().enumerate() {
3627 tx.merge(
3628 TRANSACTION_LOCATIONS,
3629 transaction.hash(&NativeCrypto).as_bytes(),
3630 &encode_tx_location_operand(number, hash, index as u64),
3631 )?;
3632 }
3633 Ok(())
3634}
3635
3636fn flush_block_data(
3639 backend: &dyn StorageBackend,
3640 buffer: &Arc<RwLock<Arc<BlockDataBuffer>>>,
3641) -> Result<(), StoreError> {
3642 let snapshot = buffer.read().map_err(|_| StoreError::LockError)?.clone();
3643 let to_flush = snapshot.flushable();
3644 if to_flush.is_empty() {
3645 return Ok(());
3646 }
3647 let hashes: Vec<_> = to_flush.iter().map(|b| b.header.hash()).collect();
3648 let codes = snapshot.codes_for(&hashes);
3649 let mut max_number = snapshot.flushed_upto();
3650
3651 let mut tx = backend.begin_write()?;
3652 for b in &to_flush {
3653 let hash = b.header.hash();
3654 write_block_data(tx.as_mut(), b.number, hash, &b.header, &b.body)?;
3655 for (index, receipt) in b.receipts.iter().enumerate() {
3656 tx.put(
3657 RECEIPTS_V2,
3658 &receipt_key(&hash, index as u64),
3659 &receipt.encode_to_vec(),
3660 )?;
3661 }
3662 max_number = max_number.max(b.number);
3663 }
3664 for (code_hash, code) in codes {
3665 let buf = encode_code(&code);
3666 tx.put(ACCOUNT_CODES, code_hash.as_ref(), &buf)?;
3667 tx.put(
3668 ACCOUNT_CODE_METADATA,
3669 code_hash.as_ref(),
3670 &(code.len() as u64).to_be_bytes(),
3671 )?;
3672 }
3673 write_flushed_upto(tx.as_mut(), max_number)?;
3674 tx.commit()?;
3675
3676 mutate_block_buffer(buffer, |b| b.evict_flushed(max_number))
3678}
3679
3680type TrieNodesUpdate = Vec<(Nibbles, Vec<u8>)>;
3681
3682#[derive(Debug, Default)]
3688struct PendingTrieRoots {
3689 count: AtomicUsize,
3691 roots: Mutex<HashSet<H256>>,
3692 ready: Condvar,
3693}
3694
3695impl PendingTrieRoots {
3696 fn register(&self, root: H256) -> Result<(), StoreError> {
3700 let mut roots = self.roots.lock().map_err(|_| StoreError::LockError)?;
3701 if roots.insert(root) {
3702 self.count.fetch_add(1, Ordering::Release);
3703 }
3704 Ok(())
3705 }
3706
3707 fn clear(&self, root: H256) {
3712 let Ok(mut roots) = self.roots.lock() else {
3713 return;
3714 };
3715 if roots.remove(&root) {
3716 self.count.fetch_sub(1, Ordering::Release);
3717 self.ready.notify_all();
3718 }
3719 }
3720
3721 fn wait_until_ready(&self, root: H256) -> Result<(), StoreError> {
3724 if self.count.load(Ordering::Acquire) == 0 {
3725 return Ok(());
3726 }
3727 let mut roots = self.roots.lock().map_err(|_| StoreError::LockError)?;
3728 while roots.contains(&root) {
3729 roots = self.ready.wait(roots).map_err(|_| StoreError::LockError)?;
3730 }
3731 Ok(())
3732 }
3733}
3734
3735fn apply_trie_phase1(
3739 trie_cache: &Arc<RwLock<Arc<TrieLayerCache>>>,
3740 pending_roots: &PendingTrieRoots,
3741 parent_state_root: H256,
3742 child_state_root: H256,
3743 account_updates: TrieNodesUpdate,
3744 storage_updates: Vec<(H256, TrieNodesUpdate)>,
3745) -> Result<(), StoreError> {
3746 let build: Result<(), StoreError> = (|| {
3747 let new_layer = storage_updates
3748 .into_iter()
3749 .flat_map(|(account_hash, nodes)| {
3750 nodes
3751 .into_iter()
3752 .map(move |(path, node)| (apply_prefix(Some(account_hash), path), node))
3753 })
3754 .chain(account_updates)
3755 .collect();
3756 let trie = trie_cache
3757 .read()
3758 .map_err(|_| StoreError::LockError)?
3759 .clone();
3760 let mut trie_mut = (*trie).clone();
3761 trie_mut.put_batch(parent_state_root, child_state_root, new_layer);
3762 *trie_cache.write().map_err(|_| StoreError::LockError)? = Arc::new(trie_mut);
3763 Ok(())
3764 })();
3765 pending_roots.clear(child_state_root);
3770 build
3771}
3772
3773fn commit_trie_if_due(
3777 backend: &dyn StorageBackend,
3778 trie_cache: &Arc<RwLock<Arc<TrieLayerCache>>>,
3779 fkv_ctl: &SyncSender<FKVGeneratorControlMessage>,
3780 parent_state_root: H256,
3781 is_batch: bool,
3782) -> Result<(), StoreError> {
3783 let trie = trie_cache
3784 .read()
3785 .map_err(|_| StoreError::LockError)?
3786 .clone();
3787 let commitable = if is_batch {
3789 trie.get_commitable_with_threshold(parent_state_root, BATCH_COMMIT_THRESHOLD)
3790 } else {
3791 trie.get_commitable(parent_state_root)
3792 };
3793 let Some(root) = commitable else {
3794 return Ok(());
3796 };
3797 commit_trie_layers(backend, trie_cache, fkv_ctl, &trie, root)
3798}
3799
3800fn commit_trie_layers(
3805 backend: &dyn StorageBackend,
3806 trie_cache: &Arc<RwLock<Arc<TrieLayerCache>>>,
3807 fkv_ctl: &SyncSender<FKVGeneratorControlMessage>,
3808 trie: &Arc<TrieLayerCache>,
3809 root: H256,
3810) -> Result<(), StoreError> {
3811 let _ = fkv_ctl.send(FKVGeneratorControlMessage::Stop);
3814
3815 let mut trie_mut = (**trie).clone();
3817
3818 let last_written = backend
3819 .begin_read()?
3820 .get(MISC_VALUES, "last_written".as_bytes())?
3821 .unwrap_or_default();
3822
3823 let mut write_tx = backend.begin_write()?;
3824
3825 let nodes = trie_mut.commit(root).unwrap_or_default();
3830 let mut result = Ok(());
3831 for (key, value) in nodes {
3832 let is_leaf = key.len() == 65 || key.len() == 131;
3833 let is_account = key.len() <= 65;
3834
3835 if is_leaf && key > last_written {
3836 continue;
3837 }
3838 let table = if is_leaf {
3839 if is_account {
3840 &ACCOUNT_FLATKEYVALUE
3841 } else {
3842 &STORAGE_FLATKEYVALUE
3843 }
3844 } else if is_account {
3845 &ACCOUNT_TRIE_NODES
3846 } else {
3847 &STORAGE_TRIE_NODES
3848 };
3849 if value.is_empty() {
3850 result = write_tx.delete(table, &key);
3851 } else {
3852 result = write_tx.put(table, &key, &value);
3853 }
3854 if result.is_err() {
3855 break;
3856 }
3857 }
3858 if result.is_ok() {
3859 result = write_tx.commit();
3860 }
3861 let _ = fkv_ctl.send(FKVGeneratorControlMessage::Continue);
3863 result?;
3864 *trie_cache.write().map_err(|_| StoreError::LockError)? = Arc::new(trie_mut);
3866 Ok(())
3867}
3868
3869fn flatkeyvalue_generator(
3872 backend: &Arc<dyn StorageBackend>,
3873 last_computed_fkv: &RwLock<Vec<u8>>,
3874 control_rx: &std::sync::mpsc::Receiver<FKVGeneratorControlMessage>,
3875) -> Result<(), StoreError> {
3876 info!("Generation of FlatKeyValue started.");
3877 let initial_last_written = backend
3878 .begin_read()?
3879 .get(MISC_VALUES, "last_written".as_bytes())?
3880 .unwrap_or_default();
3881
3882 if initial_last_written.is_empty() {
3883 backend.clear_table(ACCOUNT_FLATKEYVALUE)?;
3885 backend.clear_table(STORAGE_FLATKEYVALUE)?;
3886 } else if initial_last_written == [0xff] {
3887 info!("FlatKeyValue already generated. Skipping.");
3889 return Ok(());
3890 }
3891
3892 loop {
3893 let read_tx = backend.begin_read()?;
3896 let root = read_tx
3897 .get(ACCOUNT_TRIE_NODES, &[])?
3898 .ok_or(StoreError::MissingLatestBlockNumber)?;
3899 let root: Node = ethrex_trie::Node::decode(&root)?;
3900 let state_root = root.compute_hash(&NativeCrypto).finalize(&NativeCrypto);
3901
3902 let last_written = read_tx
3903 .get(MISC_VALUES, "last_written".as_bytes())?
3904 .unwrap_or_default();
3905 let last_written_account = last_written
3906 .get(0..64)
3907 .map(|v| Nibbles::from_hex(v.to_vec()))
3908 .unwrap_or_default();
3909 let mut last_written_storage = last_written
3910 .get(66..130)
3911 .map(|v| Nibbles::from_hex(v.to_vec()))
3912 .unwrap_or_default();
3913
3914 debug!("Starting FlatKeyValue loop pivot={last_written:?} SR={state_root:x}");
3915
3916 let mut ctr = 0;
3917 let mut write_txn = backend.begin_write()?;
3918 let mut iter = Trie::open(
3919 Box::new(BackendTrieDB::new_for_accounts_with_view(
3920 backend.clone(),
3921 read_tx.clone(),
3922 last_written.clone(),
3923 )?),
3924 state_root,
3925 )
3926 .into_iter();
3927 if last_written_account > Nibbles::default() {
3928 iter.advance(last_written_account.to_bytes())?;
3929 }
3930 let res = iter.try_for_each(|(path, node)| -> Result<(), StoreError> {
3931 let Node::Leaf(node) = node else {
3932 return Ok(());
3933 };
3934 let account_state = AccountState::decode(&node.value)?;
3935 let account_hash = H256::from_slice(&path.to_bytes());
3936 write_txn.put(MISC_VALUES, "last_written".as_bytes(), path.as_ref())?;
3937 write_txn.put(ACCOUNT_FLATKEYVALUE, path.as_ref(), &node.value)?;
3938 ctr += 1;
3939 if ctr > 10_000 {
3940 write_txn.commit()?;
3941 write_txn = backend.begin_write()?;
3942 *last_computed_fkv
3943 .write()
3944 .map_err(|_| StoreError::LockError)? = path.as_ref().to_vec();
3945 ctr = 0;
3946 }
3947
3948 let mut iter_inner = Trie::open(
3949 Box::new(BackendTrieDB::new_for_account_storage_with_view(
3950 backend.clone(),
3951 read_tx.clone(),
3952 account_hash,
3953 path.as_ref().to_vec(),
3954 )?),
3955 account_state.storage_root,
3956 )
3957 .into_iter();
3958 if last_written_storage > Nibbles::default() {
3959 iter_inner.advance(last_written_storage.to_bytes())?;
3960 last_written_storage = Nibbles::default();
3961 }
3962 iter_inner.try_for_each(|(path, node)| -> Result<(), StoreError> {
3963 let Node::Leaf(node) = node else {
3964 return Ok(());
3965 };
3966 let key = apply_prefix(Some(account_hash), path);
3967 write_txn.put(MISC_VALUES, "last_written".as_bytes(), key.as_ref())?;
3968 write_txn.put(STORAGE_FLATKEYVALUE, key.as_ref(), &node.value)?;
3969 ctr += 1;
3970 if ctr > 10_000 {
3971 write_txn.commit()?;
3972 write_txn = backend.begin_write()?;
3973 *last_computed_fkv
3974 .write()
3975 .map_err(|_| StoreError::LockError)? = key.into_vec();
3976 ctr = 0;
3977 }
3978 fkv_check_for_stop_msg(control_rx)?;
3979 Ok(())
3980 })?;
3981 fkv_check_for_stop_msg(control_rx)?;
3982 Ok(())
3983 });
3984 match res {
3985 Err(StoreError::PivotChanged) => {
3986 match control_rx.recv() {
3987 Ok(FKVGeneratorControlMessage::Continue) => {}
3988 Ok(FKVGeneratorControlMessage::Stop) => {
3989 return Err(StoreError::Custom("Unexpected Stop message".to_string()));
3990 }
3991 Err(std::sync::mpsc::RecvError) => {
3993 info!("Store closed, stopping FlatKeyValue generation.");
3994 return Ok(());
3995 }
3996 }
3997 }
3998 Err(err) => return Err(err),
3999 Ok(()) => {
4000 write_txn.put(MISC_VALUES, "last_written".as_bytes(), &[0xff])?;
4001 write_txn.commit()?;
4002 *last_computed_fkv
4003 .write()
4004 .map_err(|_| StoreError::LockError)? = vec![0xff; 131];
4005 info!("FlatKeyValue generation finished.");
4006 return Ok(());
4007 }
4008 };
4009 }
4010}
4011
4012fn fkv_check_for_stop_msg(
4013 control_rx: &std::sync::mpsc::Receiver<FKVGeneratorControlMessage>,
4014) -> Result<(), StoreError> {
4015 match control_rx.try_recv() {
4016 Ok(FKVGeneratorControlMessage::Stop) | Err(TryRecvError::Disconnected) => {
4017 return Err(StoreError::PivotChanged);
4018 }
4019 Ok(FKVGeneratorControlMessage::Continue) => {
4020 return Err(StoreError::Custom(
4021 "Unexpected Continue message".to_string(),
4022 ));
4023 }
4024 Err(TryRecvError::Empty) => {}
4025 }
4026 Ok(())
4027}
4028
4029fn state_trie_locked_backend(
4030 backend: &dyn StorageBackend,
4031 last_written: Vec<u8>,
4032) -> Result<BackendTrieDBLocked, StoreError> {
4033 BackendTrieDBLocked::new(backend, last_written)
4035}
4036
4037pub struct AccountProof {
4038 pub proof: Vec<NodeRLP>,
4039 pub account: AccountState,
4040 pub storage_proof: Vec<StorageSlotProof>,
4041}
4042
4043pub struct StorageSlotProof {
4044 pub proof: Vec<NodeRLP>,
4045 pub key: H256,
4046 pub value: U256,
4047}
4048
4049pub struct AncestorIterator {
4050 store: Store,
4051 next_hash: BlockHash,
4052}
4053
4054impl Iterator for AncestorIterator {
4055 type Item = Result<(BlockHash, BlockHeader), StoreError>;
4056
4057 fn next(&mut self) -> Option<Self::Item> {
4058 let next_hash = self.next_hash;
4059 match self.store.get_block_header_by_hash(next_hash) {
4063 Ok(Some(header)) => {
4064 let ret_hash = self.next_hash;
4065 self.next_hash = header.parent_hash;
4066 Some(Ok((ret_hash, header)))
4067 }
4068 Ok(None) => None,
4069 Err(e) => Some(Err(e)),
4070 }
4071 }
4072}
4073
4074pub fn hash_address(address: &Address) -> Vec<u8> {
4075 keccak_hash(address.to_fixed_bytes()).to_vec()
4076}
4077
4078fn hash_address_fixed(address: &Address) -> H256 {
4079 keccak(address.to_fixed_bytes())
4080}
4081
4082pub fn hash_key(key: &H256) -> Vec<u8> {
4083 keccak_hash(key.to_fixed_bytes()).to_vec()
4084}
4085
4086pub fn hash_key_fixed(key: &H256) -> [u8; 32] {
4087 keccak_hash(key.to_fixed_bytes())
4088}
4089
4090fn chain_data_key(index: ChainDataIndex) -> Vec<u8> {
4091 (index as u8).encode_to_vec()
4092}
4093
4094fn snap_state_key(index: SnapStateIndex) -> Vec<u8> {
4095 (index as u8).encode_to_vec()
4096}
4097
4098pub fn receipt_key(block_hash: &BlockHash, index: u64) -> Vec<u8> {
4100 let mut key = Vec::with_capacity(40);
4101 key.extend_from_slice(block_hash.as_bytes());
4102 key.extend_from_slice(&index.to_be_bytes());
4103 key
4104}
4105
4106fn encode_code(code: &Code) -> Vec<u8> {
4107 let mut buf =
4108 Vec::with_capacity(6 + code.len() + std::mem::size_of_val::<[u32]>(&code.jump_targets));
4109 code.code().encode(&mut buf);
4110 code.jump_targets.to_vec().encode(&mut buf);
4113 buf
4114}
4115
4116#[derive(Debug, Default, Clone)]
4117struct LatestBlockHeaderCache {
4118 current: Arc<Mutex<Arc<BlockHeader>>>,
4119}
4120
4121impl LatestBlockHeaderCache {
4122 pub fn get(&self) -> Arc<BlockHeader> {
4123 self.current.lock().expect("poisoned mutex").clone()
4124 }
4125
4126 pub fn update(&self, header: BlockHeader) {
4127 let new = Arc::new(header);
4128 *self.current.lock().expect("poisoned mutex") = new;
4129 }
4130}
4131
4132#[derive(Debug, Serialize, Deserialize)]
4133pub struct StoreMetadata {
4134 pub schema_version: u64,
4135}
4136
4137impl StoreMetadata {
4138 pub fn new(schema_version: u64) -> Self {
4139 Self { schema_version }
4140 }
4141}
4142
4143fn read_store_schema_version(path: &Path) -> Result<Option<u64>, StoreError> {
4148 let metadata_path = path.join(STORE_METADATA_FILENAME);
4149 if !metadata_path.exists() {
4150 return Ok(None);
4151 }
4152 if !metadata_path.is_file() {
4153 return Err(StoreError::Custom(
4154 "store schema path exists but is not a file".to_string(),
4155 ));
4156 }
4157 let file_contents = std::fs::read_to_string(metadata_path)?;
4158 let metadata: StoreMetadata = serde_json::from_str(&file_contents)?;
4159 Ok(Some(metadata.schema_version))
4160}
4161
4162fn init_metadata_file(parent_path: &Path) -> Result<(), StoreError> {
4163 std::fs::create_dir_all(parent_path)?;
4164
4165 let metadata_path = parent_path.join(STORE_METADATA_FILENAME);
4166 let metadata = StoreMetadata::new(STORE_SCHEMA_VERSION);
4167 let serialized_metadata = serde_json::to_string_pretty(&metadata)?;
4168 let mut new_file = std::fs::File::create_new(metadata_path)?;
4169 new_file.write_all(serialized_metadata.as_bytes())?;
4170 Ok(())
4171}
4172
4173fn dir_contains_legacy_db(path: &Path) -> Result<bool, StoreError> {
4185 if path.join("CURRENT").is_file() {
4189 return Ok(true);
4190 }
4191 for entry in std::fs::read_dir(path)? {
4195 let entry = entry?;
4196 if !entry.file_type()?.is_file() {
4197 continue;
4198 }
4199 if entry.file_name().to_string_lossy().starts_with("MANIFEST-") {
4200 return Ok(true);
4201 }
4202 }
4203 Ok(false)
4204}
4205
4206pub fn has_valid_db(path: &Path) -> bool {
4210 let metadata_path = path.join(STORE_METADATA_FILENAME);
4211 if !metadata_path.is_file() {
4212 return false;
4213 }
4214 let Ok(contents) = std::fs::read_to_string(&metadata_path) else {
4215 return false;
4216 };
4217 let Ok(metadata) = serde_json::from_str::<StoreMetadata>(&contents) else {
4218 return false;
4219 };
4220 metadata.schema_version >= 1 && metadata.schema_version <= STORE_SCHEMA_VERSION
4221}
4222
4223pub fn read_chain_id_from_db(path: &Path) -> Option<u64> {
4232 if !has_valid_db(path) {
4233 return None;
4234 }
4235 #[cfg(feature = "rocksdb")]
4236 {
4237 let backend = match RocksDBBackend::open(path, DEFAULT_ROCKSDB_BLOCK_CACHE_SIZE_BYTES) {
4240 Ok(backend) => backend,
4241 Err(e) => {
4242 warn!("Failed to open RocksDB at {path:?} to read chain ID: {e}");
4243 return None;
4244 }
4245 };
4246 let read = match backend.begin_read() {
4247 Ok(read) => read,
4248 Err(e) => {
4249 warn!("Failed to begin read transaction at {path:?}: {e}");
4250 return None;
4251 }
4252 };
4253 let key = chain_data_key(ChainDataIndex::ChainConfig);
4254 let bytes = match read.get(CHAIN_DATA, &key) {
4255 Ok(Some(bytes)) => bytes,
4256 Ok(None) => {
4257 warn!("Chain config entry not found in database at {path:?}");
4258 return None;
4259 }
4260 Err(e) => {
4261 warn!("Failed to read chain config from database at {path:?}: {e}");
4262 return None;
4263 }
4264 };
4265 #[derive(serde::Deserialize)]
4270 #[serde(rename_all = "camelCase")]
4271 struct ChainIdOnly {
4272 chain_id: u64,
4273 }
4274 match serde_json::from_slice::<ChainIdOnly>(&bytes) {
4275 Ok(partial) => Some(partial.chain_id),
4276 Err(e) => {
4277 warn!("Failed to deserialize chain ID from database at {path:?}: {e}");
4278 None
4279 }
4280 }
4281 }
4282 #[cfg(not(feature = "rocksdb"))]
4283 {
4284 let _ = path;
4285 None
4286 }
4287}
4288
4289#[cfg(test)]
4290mod merge_tests {
4291 use super::*;
4292
4293 fn h256(b: u8) -> H256 {
4294 H256::from_low_u64_be(b as u64)
4295 }
4296
4297 fn op(bn: BlockNumber, bh: H256, idx: Index) -> Vec<u8> {
4298 encode_tx_location_operand(bn, bh, idx)
4299 }
4300
4301 fn decode(v: &[u8]) -> Vec<(BlockNumber, BlockHash, Index)> {
4302 <Vec<(BlockNumber, BlockHash, Index)>>::decode(v).unwrap()
4303 }
4304
4305 #[test]
4306 fn single_operand_on_empty_base() {
4307 let out = tx_locations_merge(None, vec![op(100, h256(0x10), 0)]).unwrap();
4308 assert_eq!(decode(&out), vec![(100, h256(0x10), 0)]);
4309 }
4310
4311 #[test]
4312 fn operand_appended_to_existing_base() {
4313 let base = vec![(100u64, h256(0x10), 0u64)].encode_to_vec();
4314 let out = tx_locations_merge(Some(&base), vec![op(101, h256(0x11), 5)]).unwrap();
4315 let mut got = decode(&out);
4316 got.sort();
4317 let mut want = vec![(100, h256(0x10), 0), (101, h256(0x11), 5)];
4318 want.sort();
4319 assert_eq!(got, want);
4320 }
4321
4322 #[test]
4323 fn multiple_operands_combined() {
4324 let out = tx_locations_merge(
4325 None,
4326 vec![
4327 op(100, h256(0x10), 0),
4328 op(100, h256(0x11), 1),
4329 op(101, h256(0x12), 2),
4330 ],
4331 )
4332 .unwrap();
4333 assert_eq!(decode(&out).len(), 3);
4334 }
4335
4336 #[test]
4337 fn same_block_hash_is_deduped() {
4338 let out =
4340 tx_locations_merge(None, vec![op(100, h256(0x10), 0), op(100, h256(0x10), 7)]).unwrap();
4341 assert_eq!(decode(&out), vec![(100, h256(0x10), 7)]);
4342 }
4343
4344 #[test]
4345 fn malformed_operand_aborts_merge() {
4346 let out = tx_locations_merge(None, vec![vec![0xff, 0xff], op(100, h256(0x10), 0)]);
4349 assert!(out.is_none(), "merge must abort on a malformed operand");
4350 }
4351
4352 #[test]
4353 fn malformed_base_value_aborts_merge() {
4354 let out = tx_locations_merge(Some(&[0xff, 0xff]), vec![op(100, h256(0x10), 0)]);
4355 assert!(out.is_none(), "merge must abort on a corrupt base value");
4356 }
4357
4358 #[test]
4365 fn partial_merge_result_is_a_valid_operand() {
4366 let partial =
4368 tx_locations_merge(None, vec![op(100, h256(0x10), 0), op(101, h256(0x11), 1)]).unwrap();
4369
4370 let base = vec![(99u64, h256(0x09), 9u64)].encode_to_vec();
4374 let out = tx_locations_merge(Some(&base), vec![partial]).unwrap();
4375
4376 let mut got = decode(&out);
4377 got.sort();
4378 let mut want = vec![
4379 (99, h256(0x09), 9),
4380 (100, h256(0x10), 0),
4381 (101, h256(0x11), 1),
4382 ];
4383 want.sort();
4384 assert_eq!(
4385 got, want,
4386 "no entries may be lost when re-merging a partial result"
4387 );
4388 }
4389
4390 #[test]
4393 fn operand_encoding_matches_value_encoding() {
4394 let operand = op(100, h256(0x10), 3);
4395 assert_eq!(decode(&operand), vec![(100, h256(0x10), 3)]);
4397 }
4398
4399 #[test]
4401 fn chained_partial_merges() {
4402 let p1 = tx_locations_merge(None, vec![op(1, h256(0x01), 0)]).unwrap();
4403 let p2 = tx_locations_merge(None, vec![p1, op(2, h256(0x02), 0)]).unwrap();
4404 let p3 = tx_locations_merge(None, vec![p2, op(3, h256(0x03), 0)]).unwrap();
4405 let out = tx_locations_merge(None, vec![p3]).unwrap();
4406 assert_eq!(decode(&out).len(), 3);
4407 }
4408}
4409
4410#[cfg(test)]
4411mod datadir_tests {
4412 use super::*;
4413 use std::fs;
4414
4415 #[test]
4416 fn empty_dir_has_no_existing_db() {
4417 let dir = tempfile::tempdir().unwrap();
4418 assert!(!dir_contains_legacy_db(dir.path()).unwrap());
4419 }
4420
4421 #[test]
4422 fn dir_with_only_unrelated_files_has_no_existing_db() {
4423 let dir = tempfile::tempdir().unwrap();
4426 fs::write(dir.path().join("jwt.hex"), "0xdeadbeef").unwrap();
4427 fs::write(dir.path().join("LOG"), "noise").unwrap();
4428 assert!(!dir_contains_legacy_db(dir.path()).unwrap());
4429 }
4430
4431 #[test]
4432 fn dir_with_rocksdb_markers_has_existing_db() {
4433 let dir = tempfile::tempdir().unwrap();
4435 fs::write(dir.path().join("CURRENT"), "MANIFEST-000001\n").unwrap();
4436 assert!(dir_contains_legacy_db(dir.path()).unwrap());
4437
4438 let dir2 = tempfile::tempdir().unwrap();
4439 fs::write(dir2.path().join("MANIFEST-000007"), "x").unwrap();
4440 assert!(dir_contains_legacy_db(dir2.path()).unwrap());
4441 }
4442
4443 #[test]
4444 fn dir_with_marker_named_subdirectories_has_no_existing_db() {
4445 let dir = tempfile::tempdir().unwrap();
4448 fs::create_dir(dir.path().join("CURRENT")).unwrap();
4449 fs::create_dir(dir.path().join("MANIFEST-000001")).unwrap();
4450 assert!(!dir_contains_legacy_db(dir.path()).unwrap());
4451 }
4452}