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 rustc_hash::FxBuildHasher;
45use serde::{Deserialize, Serialize};
46use std::{
47 collections::{BTreeMap, HashMap, HashSet, hash_map::Entry},
48 fmt::Debug,
49 io::Write,
50 path::{Path, PathBuf},
51 sync::{
52 Arc, Condvar, Mutex, RwLock,
53 atomic::{AtomicUsize, Ordering},
54 mpsc::{SyncSender, TryRecvError, sync_channel},
55 },
56 thread::JoinHandle,
57};
58use tracing::{debug, error, info, warn};
59
60pub const MAX_WITNESSES: u64 = 128;
62
63#[allow(unused)]
67const DB_COMMIT_THRESHOLD: usize = 128;
68const IN_MEMORY_COMMIT_THRESHOLD: usize = 10000;
69
70const BATCH_COMMIT_THRESHOLD: usize = 4;
73
74pub const DEFAULT_ROCKSDB_BLOCK_CACHE_SIZE_BYTES: usize = 12 * 1024 * 1024 * 1024;
84
85#[derive(Debug, Clone, Copy)]
90pub struct StoreConfig {
91 pub rocksdb_block_cache_size: usize,
96 pub persist_channel_capacity: usize,
101}
102
103impl Default for StoreConfig {
104 fn default() -> Self {
105 Self {
106 rocksdb_block_cache_size: DEFAULT_ROCKSDB_BLOCK_CACHE_SIZE_BYTES,
107 persist_channel_capacity: DEFAULT_PERSIST_CHANNEL_CAPACITY,
108 }
109 }
110}
111
112#[derive(Debug, PartialEq)]
114enum FKVGeneratorControlMessage {
115 Stop,
116 Continue,
117}
118
119const CODE_CACHE_MAX_SIZE: u64 = 64 * 1024 * 1024;
121
122const FLUSHED_UPTO_KEY: &[u8] = b"bodies_flushed_upto";
124
125#[derive(Debug)]
126struct CodeCache {
127 inner_cache: LruCache<H256, Code, FxBuildHasher>,
128 cache_size: u64,
129}
130
131impl Default for CodeCache {
132 fn default() -> Self {
133 Self {
134 inner_cache: LruCache::unbounded_with_hasher(FxBuildHasher),
135 cache_size: 0,
136 }
137 }
138}
139
140impl CodeCache {
141 fn get(&mut self, code_hash: &H256) -> Result<Option<Code>, StoreError> {
142 Ok(self.inner_cache.get(code_hash).cloned())
143 }
144
145 fn insert(&mut self, code: &Code) -> Result<(), StoreError> {
146 let code_size = code.size();
147 let cache_len = self.inner_cache.len() + 1;
148 self.cache_size += code_size as u64;
149 let current_size = self.cache_size;
150 debug!(
151 "[ACCOUNT CODE CACHE] cache elements (): {cache_len}, total size: {current_size} bytes"
152 );
153
154 while self.cache_size > CODE_CACHE_MAX_SIZE {
155 if let Some((_, code)) = self.inner_cache.pop_lru() {
156 self.cache_size -= code.size() as u64;
157 } else {
158 break;
159 }
160 }
161
162 self.inner_cache.get_or_insert(code.hash, || code.clone());
163 Ok(())
164 }
165}
166
167#[derive(Debug, Clone)]
173pub struct Store {
174 db_path: PathBuf,
176 backend: Arc<dyn StorageBackend>,
178 chain_config: ChainConfig,
180 trie_cache: Arc<RwLock<Arc<TrieLayerCache>>>,
182 flatkeyvalue_control_tx: std::sync::mpsc::SyncSender<FKVGeneratorControlMessage>,
184 block_data_buffer: Arc<RwLock<Arc<BlockDataBuffer>>>,
186 persist_tx: std::sync::mpsc::SyncSender<PersistMessage>,
190 pending_trie_roots: Arc<PendingTrieRoots>,
194 latest_block_header: LatestBlockHeaderCache,
197 last_computed_flatkeyvalue: Arc<RwLock<Vec<u8>>>,
199
200 account_code_cache: Arc<Mutex<CodeCache>>,
205
206 code_metadata_cache: Arc<Mutex<rustc_hash::FxHashMap<H256, CodeMetadata>>>,
209
210 fcu_lock: Arc<tokio::sync::Mutex<()>>,
213
214 background_threads: Arc<ThreadList>,
215}
216
217#[derive(Debug, Default)]
218struct ThreadList {
219 list: Vec<JoinHandle<()>>,
220}
221
222impl Drop for ThreadList {
223 fn drop(&mut self) {
224 for handle in self.list.drain(..) {
225 let _ = handle.join();
226 }
227 }
228}
229
230pub type StorageTrieNodes = Vec<(H256, Vec<(Nibbles, Vec<u8>)>)>;
235type StorageTries = HashMap<Address, (TrieWitness, Trie)>;
236
237#[derive(Debug, Clone, Copy, PartialEq, Eq)]
241pub enum EngineType {
242 InMemory,
244 #[cfg(feature = "rocksdb")]
246 RocksDB,
247}
248
249pub struct UpdateBatch {
254 pub account_updates: Vec<TrieNode>,
256 pub storage_updates: Vec<(H256, Vec<TrieNode>)>,
258 pub blocks: Vec<Block>,
260 pub receipts: Vec<(H256, Vec<Receipt>)>,
262 pub code_updates: Vec<(H256, Code)>,
264 pub batch_mode: bool,
268}
269
270pub type StorageUpdates = Vec<(H256, Vec<(Nibbles, Vec<u8>)>)>;
272
273pub struct AccountUpdatesList {
278 pub state_trie_hash: H256,
280 pub state_updates: Vec<(Nibbles, Vec<u8>)>,
282 pub storage_updates: StorageUpdates,
284 pub code_updates: Vec<(H256, Code)>,
286}
287
288pub(crate) fn encode_tx_location_operand(
299 block_number: BlockNumber,
300 block_hash: BlockHash,
301 index: Index,
302) -> Vec<u8> {
303 vec![(block_number, block_hash, index)].encode_to_vec()
304}
305
306pub fn tx_locations_merge(
324 existing: Option<&[u8]>,
325 operands: impl IntoIterator<Item = impl AsRef<[u8]>>,
326) -> Option<Vec<u8>> {
327 fn fold_chunk(
331 list: &mut Vec<(BlockNumber, BlockHash, Index)>,
332 bytes: &[u8],
333 what: &str,
334 ) -> bool {
335 match <Vec<(BlockNumber, BlockHash, Index)>>::decode(bytes) {
336 Ok(entries) => {
337 for (bn, bh, idx) in entries {
338 list.retain(|(_, existing_bh, _)| *existing_bh != bh);
339 list.push((bn, bh, idx));
340 }
341 true
342 }
343 Err(e) => {
344 error!(
345 "tx_locations_merge: failed to decode {what} ({} bytes): {e}; \
346 aborting merge to avoid silent data loss",
347 bytes.len()
348 );
349 false
350 }
351 }
352 }
353
354 let mut list: Vec<(BlockNumber, BlockHash, Index)> = Vec::new();
355
356 if let Some(bytes) = existing
358 && !fold_chunk(&mut list, bytes, "existing value")
359 {
360 return None;
361 }
362 for op in operands {
363 if !fold_chunk(&mut list, op.as_ref(), "operand") {
364 return None;
365 }
366 }
367 Some(list.encode_to_vec())
368}
369
370impl Store {
371 pub async fn wait_for_persistence_idle(&self) -> Result<(), StoreError> {
382 let tx = self.persist_tx.clone();
383 tokio::task::spawn_blocking(move || {
384 let (ack_tx, ack_rx) = sync_channel::<Result<(), StoreError>>(1);
385 tx.send(PersistMessage::Ping(ack_tx))
386 .map_err(|e| StoreError::Custom(format!("wait_for_persistence_idle send: {e}")))?;
387 ack_rx
388 .recv()
389 .map_err(|e| StoreError::Custom(format!("wait_for_persistence_idle ack: {e}")))?
390 })
391 .await
392 .map_err(|e| StoreError::Custom(format!("wait_for_persistence_idle join: {e}")))?
393 }
394
395 pub async fn add_block(&self, block: Block) -> Result<(), StoreError> {
398 self.add_blocks(vec![block]).await
399 }
400
401 pub async fn add_blocks(&self, blocks: Vec<Block>) -> Result<(), StoreError> {
404 let db = self.backend.clone();
405 tokio::task::spawn_blocking(move || {
406 let mut tx = db.begin_write()?;
407
408 for block in blocks {
409 write_block_data(
410 tx.as_mut(),
411 block.header.number,
412 block.hash(),
413 &block.header,
414 &block.body,
415 )?;
416 }
417
418 tx.commit()
419 })
420 .await
421 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
422 }
423
424 pub async fn add_block_header(
426 &self,
427 block_hash: BlockHash,
428 block_header: BlockHeader,
429 ) -> Result<(), StoreError> {
430 let hash_key = block_hash.encode_to_vec();
431 let header_value = BlockHeaderRLP::from(block_header).into_vec();
432 self.write_async(HEADERS, hash_key, header_value).await
433 }
434
435 pub async fn add_block_headers(
437 &self,
438 block_headers: Vec<BlockHeader>,
439 ) -> Result<(), StoreError> {
440 let mut txn = self.backend.begin_write()?;
441
442 for header in block_headers {
443 let block_hash = header.hash();
444 let block_number = header.number;
445 let hash_key = block_hash.encode_to_vec();
446 let header_value = BlockHeaderRLP::from(header).into_vec();
447
448 txn.put(HEADERS, &hash_key, &header_value)?;
449
450 let number_key = block_number.to_le_bytes().to_vec();
451 txn.put(BLOCK_NUMBERS, &hash_key, &number_key)?;
452 }
453 txn.commit()?;
454 Ok(())
455 }
456
457 pub fn get_block_header(
459 &self,
460 block_number: BlockNumber,
461 ) -> Result<Option<BlockHeader>, StoreError> {
462 let latest = self.latest_block_header.get();
463 if block_number == latest.number {
464 return Ok(Some((*latest).clone()));
465 }
466 let Some(block_hash) = self.get_canonical_block_hash_sync(block_number)? else {
471 return Ok(None);
472 };
473 self.get_block_header_by_hash(block_hash)
474 }
475
476 pub async fn add_block_body(
478 &self,
479 block_hash: BlockHash,
480 block_body: BlockBody,
481 ) -> Result<(), StoreError> {
482 let hash_key = block_hash.encode_to_vec();
483 let body_value = BlockBodyRLP::from(block_body).into_vec();
484 self.write_async(BODIES, hash_key, body_value).await
485 }
486
487 pub async fn get_block_body(
489 &self,
490 block_number: BlockNumber,
491 ) -> Result<Option<BlockBody>, StoreError> {
492 let Some(block_hash) = self.get_canonical_block_hash_sync(block_number)? else {
493 return Ok(None);
494 };
495
496 self.get_block_body_by_hash(block_hash).await
497 }
498
499 pub async fn remove_block(&self, block_number: BlockNumber) -> Result<(), StoreError> {
501 let Some(hash) = self.get_canonical_block_hash_sync(block_number)? else {
502 return Ok(());
503 };
504
505 let backend = self.backend.clone();
506 tokio::task::spawn_blocking(move || {
507 let hash_key = hash.encode_to_vec();
508
509 let mut txn = backend.begin_write()?;
510 txn.delete(
511 CANONICAL_BLOCK_HASHES,
512 block_number.to_le_bytes().as_slice(),
513 )?;
514 txn.delete(BODIES, &hash_key)?;
515 txn.delete(HEADERS, &hash_key)?;
516 txn.delete(BLOCK_NUMBERS, &hash_key)?;
517 txn.commit()
518 })
519 .await
520 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
521 }
522
523 pub async fn get_block_bodies(
525 &self,
526 from: BlockNumber,
527 to: BlockNumber,
528 ) -> Result<Vec<Option<BlockBody>>, StoreError> {
529 let buffer = self.buffer()?;
531 let backend = self.backend.clone();
532 tokio::task::spawn_blocking(move || {
533 let numbers: Vec<BlockNumber> = (from..=to).collect();
534 let mut block_bodies = Vec::new();
535
536 let txn = backend.begin_read()?;
537 for number in numbers {
538 let Some(hash) = txn
539 .get(CANONICAL_BLOCK_HASHES, number.to_le_bytes().as_slice())?
540 .map(|bytes| H256::decode(bytes.as_slice()))
541 .transpose()?
542 else {
543 block_bodies.push(None);
544 continue;
545 };
546 if let Some(body) = buffer.get_body(&hash) {
549 block_bodies.push(Some(body));
550 continue;
551 }
552 let hash_key = hash.encode_to_vec();
553 let block_body_opt = txn
554 .get(BODIES, &hash_key)?
555 .map(|bytes| BlockBodyRLP::from_bytes(bytes).to())
556 .transpose()
557 .map_err(StoreError::from)?;
558
559 block_bodies.push(block_body_opt);
560 }
561
562 Ok(block_bodies)
563 })
564 .await
565 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
566 }
567
568 pub async fn get_block_bodies_by_hash(
570 &self,
571 hashes: Vec<BlockHash>,
572 ) -> Result<Vec<BlockBody>, StoreError> {
573 let buffer = self.buffer()?;
574 let backend = self.backend.clone();
575 tokio::task::spawn_blocking(move || {
577 let txn = backend.begin_read()?;
578 let mut block_bodies = Vec::new();
579 for hash in hashes {
580 if let Some(body) = buffer.get_body(&hash) {
583 block_bodies.push(body);
584 continue;
585 }
586 let hash_key = hash.encode_to_vec();
587
588 let Some(block_body) = txn
589 .get(BODIES, &hash_key)?
590 .map(|bytes| BlockBodyRLP::from_bytes(bytes).to())
591 .transpose()
592 .map_err(StoreError::from)?
593 else {
594 return Err(StoreError::Custom(format!(
595 "Block body not found for hash: {hash}"
596 )));
597 };
598 block_bodies.push(block_body);
599 }
600 Ok(block_bodies)
601 })
602 .await
603 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
604 }
605
606 pub async fn get_block_body_by_hash(
608 &self,
609 block_hash: BlockHash,
610 ) -> Result<Option<BlockBody>, StoreError> {
611 if let Some(b) = self.buffer()?.get_body(&block_hash) {
612 return Ok(Some(b));
613 }
614 self.read_async(BODIES, block_hash.encode_to_vec())
615 .await?
616 .map(|bytes| BlockBodyRLP::from_bytes(bytes).to())
617 .transpose()
618 .map_err(StoreError::from)
619 }
620
621 pub fn get_block_header_by_hash(
622 &self,
623 block_hash: BlockHash,
624 ) -> Result<Option<BlockHeader>, StoreError> {
625 let latest = self.latest_block_header.get();
626 if block_hash == latest.hash() {
627 return Ok(Some((*latest).clone()));
628 }
629 if let Some(h) = self.buffer()?.get_header(&block_hash) {
630 return Ok(Some(h));
631 }
632 self.load_block_header_by_hash(block_hash)
633 }
634
635 pub fn add_pending_block(&self, block: Block) -> Result<(), StoreError> {
636 let block_hash = block.hash();
637 let block_value = BlockRLP::from(block).into_vec();
638 self.write(PENDING_BLOCKS, block_hash.as_bytes().to_vec(), block_value)
639 }
640
641 pub async fn get_pending_block(
642 &self,
643 block_hash: BlockHash,
644 ) -> Result<Option<Block>, StoreError> {
645 self.read_async(PENDING_BLOCKS, block_hash.as_bytes().to_vec())
646 .await?
647 .map(|bytes| BlockRLP::from_bytes(bytes).to())
648 .transpose()
649 .map_err(StoreError::from)
650 }
651
652 pub async fn add_block_number(
654 &self,
655 block_hash: BlockHash,
656 block_number: BlockNumber,
657 ) -> Result<(), StoreError> {
658 let number_value = block_number.to_le_bytes().to_vec();
659 self.write_async(BLOCK_NUMBERS, block_hash.encode_to_vec(), number_value)
660 .await
661 }
662
663 pub async fn get_block_number(
665 &self,
666 block_hash: BlockHash,
667 ) -> Result<Option<BlockNumber>, StoreError> {
668 if let Some(n) = self.buffer()?.get_number(&block_hash) {
669 return Ok(Some(n));
670 }
671 self.read_async(BLOCK_NUMBERS, block_hash.encode_to_vec())
672 .await?
673 .map(|bytes| -> Result<BlockNumber, StoreError> {
674 let array: [u8; 8] = bytes
675 .try_into()
676 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
677 Ok(BlockNumber::from_le_bytes(array))
678 })
679 .transpose()
680 }
681
682 pub async fn add_transaction_location(
684 &self,
685 transaction_hash: H256,
686 block_number: BlockNumber,
687 block_hash: BlockHash,
688 index: Index,
689 ) -> Result<(), StoreError> {
690 self.add_transaction_locations(vec![(transaction_hash, block_number, block_hash, index)])
691 .await
692 }
693
694 pub async fn add_transaction_locations(
696 &self,
697 locations: Vec<(H256, BlockNumber, BlockHash, Index)>,
698 ) -> Result<(), StoreError> {
699 let db = self.backend.clone();
700 tokio::task::spawn_blocking(move || {
701 let mut tx = db.begin_write()?;
702 for (tx_hash, block_number, block_hash, index) in locations {
703 tx.merge(
704 TRANSACTION_LOCATIONS,
705 tx_hash.as_bytes(),
706 &encode_tx_location_operand(block_number, block_hash, index),
707 )?;
708 }
709 tx.commit()
710 })
711 .await
712 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
713 }
714
715 pub async fn get_transaction_location(
717 &self,
718 transaction_hash: H256,
719 ) -> Result<Option<(BlockNumber, BlockHash, Index)>, StoreError> {
720 let buffered = self.buffer()?.get_tx_locations(&transaction_hash);
721 let db = self.backend.clone();
722 tokio::task::spawn_blocking(move || {
723 let tx = db.begin_read()?;
724 let mut locations = buffered;
725 if let Some(bytes) = tx.get(TRANSACTION_LOCATIONS, transaction_hash.as_bytes())? {
726 locations.extend(<Vec<(BlockNumber, BlockHash, Index)>>::decode(&bytes)?);
727 }
728 for (block_number, block_hash, index) in locations {
729 let canonical_hash = tx
730 .get(
731 CANONICAL_BLOCK_HASHES,
732 block_number.to_le_bytes().as_slice(),
733 )?
734 .map(|bytes| H256::decode(bytes.as_slice()))
735 .transpose()?;
736 if canonical_hash == Some(block_hash) {
737 return Ok(Some((block_number, block_hash, index)));
738 }
739 }
740 Ok(None)
741 })
742 .await
743 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
744 }
745
746 pub async fn add_receipt(
748 &self,
749 block_hash: BlockHash,
750 index: Index,
751 receipt: Receipt,
752 ) -> Result<(), StoreError> {
753 let key = receipt_key(&block_hash, index);
754 let value = receipt.encode_to_vec();
755 self.write_async(RECEIPTS_V2, key, value).await
756 }
757
758 pub async fn add_receipts(
760 &self,
761 block_hash: BlockHash,
762 receipts: Vec<Receipt>,
763 ) -> Result<(), StoreError> {
764 let batch_items: Vec<_> = receipts
765 .into_iter()
766 .enumerate()
767 .map(|(index, receipt)| {
768 let key = receipt_key(&block_hash, index as u64);
769 let value = receipt.encode_to_vec();
770 (key, value)
771 })
772 .collect();
773 self.write_batch_async(RECEIPTS_V2, batch_items).await
774 }
775
776 pub async fn get_receipt(
778 &self,
779 block_number: BlockNumber,
780 index: Index,
781 ) -> Result<Option<Receipt>, StoreError> {
782 let Some(block_hash) = self.get_canonical_block_hash(block_number).await? else {
784 return Ok(None);
785 };
786 self.get_receipt_by_block_hash(block_hash, index).await
787 }
788
789 async fn get_receipt_by_block_hash(
791 &self,
792 block_hash: BlockHash,
793 index: Index,
794 ) -> Result<Option<Receipt>, StoreError> {
795 if let Some(r) = self.buffer()?.get_receipt(&block_hash, index) {
796 return Ok(Some(r));
797 }
798 let key = receipt_key(&block_hash, index);
799 self.read_async(RECEIPTS_V2, key)
800 .await?
801 .map(|bytes| Receipt::decode(bytes.as_slice()))
802 .transpose()
803 .map_err(StoreError::from)
804 }
805
806 pub fn get_account_code(&self, code_hash: H256) -> Result<Option<Code>, StoreError> {
813 if let Some(code) = self.buffer()?.get_code(&code_hash) {
814 return Ok(Some(code));
815 }
816 if let Some(code) = self
818 .account_code_cache
819 .lock()
820 .map_err(|_| StoreError::LockError)?
821 .get(&code_hash)?
822 {
823 return Ok(Some(code));
824 }
825
826 let Some(bytes) = self
827 .backend
828 .begin_read()?
829 .get(ACCOUNT_CODES, code_hash.as_bytes())?
830 else {
831 return Ok(None);
832 };
833 let (bytecode_slice, targets) = decode_bytes(&bytes)?;
834 let code = Code::from_parts_unchecked(
835 code_hash,
836 bytecode_slice,
837 <Vec<u32>>::decode(targets)?.into(),
838 );
839
840 self.account_code_cache
842 .lock()
843 .map_err(|_| StoreError::LockError)?
844 .insert(&code)?;
845
846 Ok(Some(code))
847 }
848
849 pub fn code_exists(&self, code_hash: H256) -> Result<bool, StoreError> {
854 if self.buffer()?.get_code(&code_hash).is_some() {
858 return Ok(true);
859 }
860 if self
862 .account_code_cache
863 .lock()
864 .map_err(|_| StoreError::LockError)?
865 .get(&code_hash)?
866 .is_some()
867 {
868 return Ok(true);
869 }
870 Ok(self
872 .backend
873 .begin_read()?
874 .get(ACCOUNT_CODES, code_hash.as_bytes())?
875 .is_some())
876 }
877
878 pub fn get_code_metadata(&self, code_hash: H256) -> Result<Option<CodeMetadata>, StoreError> {
883 use ethrex_common::constants::EMPTY_KECCAK_HASH;
884
885 if code_hash == *EMPTY_KECCAK_HASH {
887 return Ok(Some(CodeMetadata { length: 0 }));
888 }
889
890 if let Some(metadata) = self
892 .code_metadata_cache
893 .lock()
894 .map_err(|_| StoreError::LockError)?
895 .get(&code_hash)
896 .copied()
897 {
898 return Ok(Some(metadata));
899 }
900
901 let metadata = if let Some(bytes) = self
903 .backend
904 .begin_read()?
905 .get(ACCOUNT_CODE_METADATA, code_hash.as_bytes())?
906 {
907 let length =
908 u64::from_be_bytes(bytes.try_into().map_err(|_| {
909 StoreError::Custom("Invalid metadata length encoding".to_string())
910 })?);
911 CodeMetadata { length }
912 } else {
913 let Some(code) = self.get_account_code(code_hash)? else {
915 return Ok(None);
916 };
917 let metadata = CodeMetadata {
918 length: code.len() as u64,
919 };
920
921 let metadata_buf = metadata.length.to_be_bytes().to_vec();
923 let hash_key = code_hash.0.to_vec();
924 let backend = self.backend.clone();
925 tokio::task::spawn(async move {
926 if let Err(e) = async {
927 let mut tx = backend.begin_write()?;
928 tx.put(ACCOUNT_CODE_METADATA, &hash_key, &metadata_buf)?;
929 tx.commit()
930 }
931 .await
932 {
933 tracing::warn!("Failed to write code metadata during auto-migration: {}", e);
934 }
935 });
936
937 metadata
938 };
939
940 self.code_metadata_cache
942 .lock()
943 .map_err(|_| StoreError::LockError)?
944 .insert(code_hash, metadata);
945
946 Ok(Some(metadata))
947 }
948
949 pub async fn add_account_code(&self, code: Code) -> Result<(), StoreError> {
951 let hash_key = code.hash.0.to_vec();
952 let buf = encode_code(&code);
953 let metadata_buf = (code.len() as u64).to_be_bytes();
954
955 let backend = self.backend.clone();
957 tokio::task::spawn_blocking(move || {
958 let mut tx = backend.begin_write()?;
959 tx.put(ACCOUNT_CODES, &hash_key, &buf)?;
960 tx.put(ACCOUNT_CODE_METADATA, &hash_key, &metadata_buf)?;
961 tx.commit()
962 })
963 .await
964 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
965 }
966
967 pub async fn clear_snap_state(&self) -> Result<(), StoreError> {
969 let db = self.backend.clone();
970 tokio::task::spawn_blocking(move || db.clear_table(SNAP_STATE))
971 .await
972 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
973 }
974
975 pub async fn get_transaction_by_hash(
976 &self,
977 transaction_hash: H256,
978 ) -> Result<Option<Transaction>, StoreError> {
979 let (_block_number, block_hash, index) =
980 match self.get_transaction_location(transaction_hash).await? {
981 Some(location) => location,
982 None => return Ok(None),
983 };
984 self.get_transaction_by_location(block_hash, index).await
985 }
986
987 pub async fn get_transaction_by_location(
988 &self,
989 block_hash: H256,
990 index: u64,
991 ) -> Result<Option<Transaction>, StoreError> {
992 let block_body = match self.get_block_body_by_hash(block_hash).await? {
993 Some(body) => body,
994 None => return Ok(None),
995 };
996 let index: usize = index.try_into()?;
997 Ok(block_body.transactions.get(index).cloned())
998 }
999
1000 pub async fn get_block_by_hash(
1001 &self,
1002 block_hash: BlockHash,
1003 ) -> Result<Option<Block>, StoreError> {
1004 let header = match self.get_block_header_by_hash(block_hash)? {
1005 Some(header) => header,
1006 None => return Ok(None),
1007 };
1008 let body = match self.get_block_body_by_hash(block_hash).await? {
1009 Some(body) => body,
1010 None => return Ok(None),
1011 };
1012 Ok(Some(Block::new(header, body)))
1013 }
1014
1015 pub async fn get_block_by_number(
1016 &self,
1017 block_number: BlockNumber,
1018 ) -> Result<Option<Block>, StoreError> {
1019 let Some(block_hash) = self.get_canonical_block_hash(block_number).await? else {
1020 return Ok(None);
1021 };
1022 self.get_block_by_hash(block_hash).await
1023 }
1024
1025 pub async fn get_canonical_block_hash(
1027 &self,
1028 block_number: BlockNumber,
1029 ) -> Result<Option<BlockHash>, StoreError> {
1030 let last = self.latest_block_header.get();
1031 if last.number == block_number {
1032 return Ok(Some(last.hash()));
1033 }
1034 let backend = self.backend.clone();
1035 tokio::task::spawn_blocking(move || {
1036 backend
1037 .begin_read()?
1038 .get(
1039 CANONICAL_BLOCK_HASHES,
1040 block_number.to_le_bytes().as_slice(),
1041 )?
1042 .map(|bytes| H256::decode(bytes.as_slice()))
1043 .transpose()
1044 .map_err(StoreError::from)
1045 })
1046 .await
1047 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1048 }
1049
1050 pub async fn set_chain_config(&mut self, chain_config: &ChainConfig) -> Result<(), StoreError> {
1053 self.chain_config = *chain_config;
1054 let key = chain_data_key(ChainDataIndex::ChainConfig);
1055 let value = serde_json::to_string(chain_config)
1056 .map_err(|_| StoreError::Custom("Failed to serialize chain config".to_string()))?
1057 .into_bytes();
1058 self.write_async(CHAIN_DATA, key, value).await
1059 }
1060
1061 pub async fn update_earliest_block_number(
1063 &self,
1064 block_number: BlockNumber,
1065 ) -> Result<(), StoreError> {
1066 let key = chain_data_key(ChainDataIndex::EarliestBlockNumber);
1067 let value = block_number.to_le_bytes().to_vec();
1068 self.write_async(CHAIN_DATA, key, value).await
1069 }
1070
1071 pub async fn get_earliest_block_number(&self) -> Result<BlockNumber, StoreError> {
1073 let key = chain_data_key(ChainDataIndex::EarliestBlockNumber);
1074 self.read_async(CHAIN_DATA, key)
1075 .await?
1076 .map(|bytes| -> Result<BlockNumber, StoreError> {
1077 let array: [u8; 8] = bytes
1078 .try_into()
1079 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
1080 Ok(BlockNumber::from_le_bytes(array))
1081 })
1082 .ok_or(StoreError::MissingEarliestBlockNumber)?
1083 }
1084
1085 pub async fn get_finalized_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
1087 let key = chain_data_key(ChainDataIndex::FinalizedBlockNumber);
1088 self.read_async(CHAIN_DATA, key)
1089 .await?
1090 .map(|bytes| -> Result<BlockNumber, StoreError> {
1091 let array: [u8; 8] = bytes
1092 .try_into()
1093 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
1094 Ok(BlockNumber::from_le_bytes(array))
1095 })
1096 .transpose()
1097 }
1098
1099 pub async fn get_safe_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
1101 let key = chain_data_key(ChainDataIndex::SafeBlockNumber);
1102 self.read_async(CHAIN_DATA, key)
1103 .await?
1104 .map(|bytes| -> Result<BlockNumber, StoreError> {
1105 let array: [u8; 8] = bytes
1106 .try_into()
1107 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
1108 Ok(BlockNumber::from_le_bytes(array))
1109 })
1110 .transpose()
1111 }
1112
1113 pub async fn get_latest_block_number(&self) -> Result<BlockNumber, StoreError> {
1115 Ok(self.latest_block_header.get().number)
1116 }
1117
1118 pub async fn update_pending_block_number(
1120 &self,
1121 block_number: BlockNumber,
1122 ) -> Result<(), StoreError> {
1123 let key = chain_data_key(ChainDataIndex::PendingBlockNumber);
1124 let value = block_number.to_le_bytes().to_vec();
1125 self.write_async(CHAIN_DATA, key, value).await
1126 }
1127
1128 pub async fn get_pending_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
1130 let key = chain_data_key(ChainDataIndex::PendingBlockNumber);
1131 self.read_async(CHAIN_DATA, key)
1132 .await?
1133 .map(|bytes| -> Result<BlockNumber, StoreError> {
1134 let array: [u8; 8] = bytes
1135 .try_into()
1136 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
1137 Ok(BlockNumber::from_le_bytes(array))
1138 })
1139 .transpose()
1140 }
1141
1142 async fn forkchoice_update_inner(
1148 &self,
1149 new_canonical_blocks: Vec<(BlockNumber, BlockHash)>,
1150 head_number: BlockNumber,
1151 head_hash: BlockHash,
1152 safe: Option<BlockNumber>,
1153 finalized: Option<BlockNumber>,
1154 ) -> Result<(), StoreError> {
1155 let latest = self.load_latest_block_number().await?.unwrap_or(0);
1156 let db = self.backend.clone();
1157 tokio::task::spawn_blocking(move || {
1158 let mut txn = db.begin_write()?;
1159
1160 for (block_number, block_hash) in new_canonical_blocks {
1161 let head_key = block_number.to_le_bytes();
1162 let head_value = block_hash.encode_to_vec();
1163 txn.put(CANONICAL_BLOCK_HASHES, &head_key, &head_value)?;
1164 }
1165
1166 for number in (head_number + 1)..=(latest) {
1173 txn.delete(CANONICAL_BLOCK_HASHES, number.to_le_bytes().as_slice())?;
1174 }
1175
1176 let head_key = head_number.to_le_bytes();
1178 let head_value = head_hash.encode_to_vec();
1179 txn.put(CANONICAL_BLOCK_HASHES, &head_key, &head_value)?;
1180
1181 let latest_key = chain_data_key(ChainDataIndex::LatestBlockNumber);
1183 txn.put(CHAIN_DATA, &latest_key, &head_number.to_le_bytes())?;
1184
1185 if let Some(safe) = safe {
1186 let safe_key = chain_data_key(ChainDataIndex::SafeBlockNumber);
1187 txn.put(CHAIN_DATA, &safe_key, &safe.to_le_bytes())?;
1188 }
1189
1190 if let Some(finalized) = finalized {
1191 let finalized_key = chain_data_key(ChainDataIndex::FinalizedBlockNumber);
1192 txn.put(CHAIN_DATA, &finalized_key, &finalized.to_le_bytes())?;
1193 }
1194
1195 txn.commit()
1196 })
1197 .await
1198 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1199 }
1200
1201 pub async fn get_receipts_for_block(
1202 &self,
1203 block_hash: &BlockHash,
1204 ) -> Result<Vec<Receipt>, StoreError> {
1205 self.get_receipts_for_block_from_index(block_hash, 0, None)
1206 .await
1207 }
1208
1209 pub async fn get_receipts_for_block_from_index(
1218 &self,
1219 block_hash: &BlockHash,
1220 start_index: u64,
1221 max_count: Option<usize>,
1222 ) -> Result<Vec<Receipt>, StoreError> {
1223 if let Some(all) = self.buffer()?.get_receipts(block_hash) {
1224 let start = start_index as usize;
1225 let slice = all.into_iter().skip(start);
1226 return Ok(match max_count {
1227 Some(max) => slice.take(max).collect(),
1228 None => slice.collect(),
1229 });
1230 }
1231 let backend = self.backend.clone();
1232 let block_hash = *block_hash;
1233
1234 tokio::task::spawn_blocking(move || {
1235 let txn = backend.begin_read()?;
1236 let prefix = block_hash.as_bytes().to_vec();
1237 let mut seek_key = prefix.clone();
1240 seek_key.extend_from_slice(&start_index.to_be_bytes());
1241 let iter = txn.prefix_iterator(RECEIPTS_V2, &seek_key)?;
1242 let mut receipts = Vec::new();
1243 for result in iter {
1244 let (k, v) = result?;
1245 if !k.starts_with(&prefix) {
1246 break;
1247 }
1248 if k.len() != 40 {
1249 continue;
1250 }
1251 receipts.push(Receipt::decode(v.as_ref())?);
1252 if let Some(max) = max_count
1253 && receipts.len() >= max
1254 {
1255 break;
1256 }
1257 }
1258 Ok(receipts)
1259 })
1260 .await
1261 .map_err(|e| StoreError::Custom(format!("Task panicked: {e}")))?
1262 }
1263
1264 pub async fn set_header_download_checkpoint(
1268 &self,
1269 block_hash: BlockHash,
1270 ) -> Result<(), StoreError> {
1271 let key = snap_state_key(SnapStateIndex::HeaderDownloadCheckpoint);
1272 let value = block_hash.encode_to_vec();
1273 self.write_async(SNAP_STATE, key, value).await
1274 }
1275
1276 pub async fn get_header_download_checkpoint(&self) -> Result<Option<BlockHash>, StoreError> {
1278 let key = snap_state_key(SnapStateIndex::HeaderDownloadCheckpoint);
1279 self.backend
1280 .begin_read()?
1281 .get(SNAP_STATE, &key)?
1282 .map(|bytes| H256::decode(bytes.as_slice()))
1283 .transpose()
1284 .map_err(StoreError::from)
1285 }
1286
1287 pub async fn set_latest_valid_ancestor(
1293 &self,
1294 bad_block: BlockHash,
1295 latest_valid: BlockHash,
1296 ) -> Result<(), StoreError> {
1297 let value = latest_valid.encode_to_vec();
1298 self.write_async(INVALID_CHAINS, bad_block.as_bytes().to_vec(), value)
1299 .await
1300 }
1301
1302 pub async fn get_latest_valid_ancestor(
1305 &self,
1306 block: BlockHash,
1307 ) -> Result<Option<BlockHash>, StoreError> {
1308 self.read_async(INVALID_CHAINS, block.as_bytes().to_vec())
1309 .await?
1310 .map(|bytes| H256::decode(bytes.as_slice()))
1311 .transpose()
1312 .map_err(StoreError::from)
1313 }
1314
1315 pub fn get_block_number_sync(
1317 &self,
1318 block_hash: BlockHash,
1319 ) -> Result<Option<BlockNumber>, StoreError> {
1320 if let Some(n) = self.buffer()?.get_number(&block_hash) {
1321 return Ok(Some(n));
1322 }
1323 let txn = self.backend.begin_read()?;
1324 txn.get(BLOCK_NUMBERS, &block_hash.encode_to_vec())?
1325 .map(|bytes| -> Result<BlockNumber, StoreError> {
1326 let array: [u8; 8] = bytes
1327 .try_into()
1328 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
1329 Ok(BlockNumber::from_le_bytes(array))
1330 })
1331 .transpose()
1332 }
1333
1334 pub fn get_canonical_block_hash_sync(
1336 &self,
1337 block_number: BlockNumber,
1338 ) -> Result<Option<BlockHash>, StoreError> {
1339 let last = self.latest_block_header.get();
1340 if last.number == block_number {
1341 return Ok(Some(last.hash()));
1342 }
1343 let txn = self.backend.begin_read()?;
1344 txn.get(
1345 CANONICAL_BLOCK_HASHES,
1346 block_number.to_le_bytes().as_slice(),
1347 )?
1348 .map(|bytes| H256::decode(bytes.as_slice()))
1349 .transpose()
1350 .map_err(StoreError::from)
1351 }
1352
1353 pub async fn write_storage_trie_nodes_batch(
1356 &self,
1357 storage_trie_nodes: StorageUpdates,
1358 ) -> Result<(), StoreError> {
1359 let mut txn = self.backend.begin_write()?;
1360 tokio::task::spawn_blocking(move || {
1361 for (address_hash, nodes) in storage_trie_nodes {
1362 for (node_path, node_data) in nodes {
1363 let key = apply_prefix(Some(address_hash), node_path);
1364 if node_data.is_empty() {
1365 txn.delete(STORAGE_TRIE_NODES, key.as_ref())?;
1366 } else {
1367 txn.put(STORAGE_TRIE_NODES, key.as_ref(), &node_data)?;
1368 }
1369 }
1370 }
1371 txn.commit()
1372 })
1373 .await
1374 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1375 }
1376
1377 pub async fn write_account_code_batch(
1380 &self,
1381 account_codes: Vec<(H256, Code)>,
1382 ) -> Result<(), StoreError> {
1383 let mut code_batch_items = Vec::new();
1384 let mut metadata_batch_items = Vec::new();
1385
1386 for (code_hash, code) in account_codes {
1387 let buf = encode_code(&code);
1388 let metadata_buf = (code.len() as u64).to_be_bytes().to_vec();
1389 code_batch_items.push((code_hash.as_bytes().to_vec(), buf));
1390 metadata_batch_items.push((code_hash.as_bytes().to_vec(), metadata_buf));
1391 }
1392
1393 self.write_batch_async(ACCOUNT_CODES, code_batch_items)
1395 .await?;
1396 self.write_batch_async(ACCOUNT_CODE_METADATA, metadata_batch_items)
1397 .await
1398 }
1399
1400 fn buffer(&self) -> Result<Arc<BlockDataBuffer>, StoreError> {
1402 Ok(self
1403 .block_data_buffer
1404 .read()
1405 .map_err(|_| StoreError::LockError)?
1406 .clone())
1407 }
1408
1409 pub fn write(
1415 &self,
1416 table: &'static str,
1417 key: Vec<u8>,
1418 value: Vec<u8>,
1419 ) -> Result<(), StoreError> {
1420 let backend = self.backend.clone();
1421 let mut txn = backend.begin_write()?;
1422 txn.put(table, &key, &value)?;
1423 txn.commit()
1424 }
1425
1426 async fn write_async(
1429 &self,
1430 table: &'static str,
1431 key: Vec<u8>,
1432 value: Vec<u8>,
1433 ) -> Result<(), StoreError> {
1434 let backend = self.backend.clone();
1435
1436 tokio::task::spawn_blocking(move || {
1437 let mut txn = backend.begin_write()?;
1438 txn.put(table, &key, &value)?;
1439 txn.commit()
1440 })
1441 .await
1442 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1443 }
1444
1445 pub async fn read_async(
1448 &self,
1449 table: &'static str,
1450 key: Vec<u8>,
1451 ) -> Result<Option<Vec<u8>>, StoreError> {
1452 let backend = self.backend.clone();
1453
1454 tokio::task::spawn_blocking(move || {
1455 let txn = backend.begin_read()?;
1456 txn.get(table, &key)
1457 })
1458 .await
1459 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1460 }
1461
1462 pub fn read(&self, table: &'static str, key: Vec<u8>) -> Result<Option<Vec<u8>>, StoreError> {
1465 let backend = self.backend.clone();
1466 let txn = backend.begin_read()?;
1467 txn.get(table, &key)
1468 }
1469
1470 pub async fn write_batch_async(
1474 &self,
1475 table: &'static str,
1476 batch_ops: Vec<(Vec<u8>, Vec<u8>)>,
1477 ) -> Result<(), StoreError> {
1478 let backend = self.backend.clone();
1479
1480 tokio::task::spawn_blocking(move || {
1481 let mut txn = backend.begin_write()?;
1482 txn.put_batch(table, batch_ops)?;
1483 txn.commit()
1484 })
1485 .await
1486 .map_err(|e| StoreError::Custom(format!("Task panicked: {}", e)))?
1487 }
1488
1489 pub fn write_batch(
1491 &self,
1492 table: &'static str,
1493 batch_ops: Vec<(Vec<u8>, Vec<u8>)>,
1494 ) -> Result<(), StoreError> {
1495 let backend = self.backend.clone();
1496 let mut txn = backend.begin_write()?;
1497 txn.put_batch(table, batch_ops)?;
1498 txn.commit()
1499 }
1500
1501 pub async fn add_fullsync_batch(&self, headers: Vec<BlockHeader>) -> Result<(), StoreError> {
1502 self.write_batch_async(
1503 FULLSYNC_HEADERS,
1504 headers
1505 .into_iter()
1506 .map(|header| (header.number.to_le_bytes().to_vec(), header.encode_to_vec()))
1507 .collect(),
1508 )
1509 .await
1510 }
1511
1512 pub async fn read_fullsync_batch(
1513 &self,
1514 start: BlockNumber,
1515 limit: u64,
1516 ) -> Result<Vec<Option<BlockHeader>>, StoreError> {
1517 let mut res = vec![];
1518 let read_tx = self.backend.begin_read()?;
1519 for key in start..start + limit {
1521 let header_opt = read_tx
1522 .get(FULLSYNC_HEADERS, &key.to_le_bytes())?
1523 .map(|header| BlockHeader::decode(&header))
1524 .transpose()?;
1525 res.push(header_opt);
1526 }
1527 Ok(res)
1528 }
1529
1530 pub async fn clear_fullsync_headers(&self) -> Result<(), StoreError> {
1531 self.backend.clear_table(FULLSYNC_HEADERS)
1532 }
1533
1534 pub fn delete(&self, table: &'static str, key: Vec<u8>) -> Result<(), StoreError> {
1536 let mut txn = self.backend.begin_write()?;
1537 txn.delete(table, &key)?;
1538 txn.commit()
1539 }
1540
1541 pub fn store_block_updates(&self, update_batch: UpdateBatch) -> Result<(), StoreError> {
1542 self.apply_updates(update_batch)
1543 }
1544
1545 fn batch_state_roots(&self, update_batch: &UpdateBatch) -> Result<(H256, H256), StoreError> {
1550 let parent_state_root = self
1551 .get_block_header_by_hash(
1552 update_batch
1553 .blocks
1554 .first()
1555 .ok_or(StoreError::UpdateBatchNoBlocks)?
1556 .header
1557 .parent_hash,
1558 )?
1559 .map(|header| header.state_root)
1560 .unwrap_or_default();
1561 let last_state_root = update_batch
1562 .blocks
1563 .last()
1564 .ok_or(StoreError::UpdateBatchNoBlocks)?
1565 .header
1566 .state_root;
1567 Ok((parent_state_root, last_state_root))
1568 }
1569
1570 fn apply_updates(&self, update_batch: UpdateBatch) -> Result<(), StoreError> {
1575 let (parent_state_root, last_state_root) = self.batch_state_roots(&update_batch)?;
1576
1577 let UpdateBatch {
1578 account_updates,
1579 storage_updates,
1580 blocks,
1581 receipts,
1582 code_updates,
1583 batch_mode,
1584 } = update_batch;
1585
1586 self.pending_trie_roots.register(last_state_root)?;
1590
1591 let blocks_with_receipts: Vec<(Block, Vec<Receipt>)> = if blocks.len() == 1 {
1594 let block = blocks.into_iter().next().expect("len == 1");
1595 let hash = block.hash();
1596 let r = receipts
1597 .into_iter()
1598 .find(|(h, _)| *h == hash)
1599 .map(|(_, r)| r)
1600 .unwrap_or_default();
1601 vec![(block, r)]
1602 } else {
1603 let mut receipts_by_hash: std::collections::HashMap<BlockHash, Vec<Receipt>> =
1604 receipts.into_iter().collect();
1605 blocks
1606 .into_iter()
1607 .map(|b| {
1608 let r = receipts_by_hash.remove(&b.hash()).unwrap_or_default();
1609 (b, r)
1610 })
1611 .collect()
1612 };
1613
1614 let (ack_tx, ack_rx) = sync_channel(1);
1620 self.persist_tx
1621 .send(PersistMessage::Block(BlockPersist {
1622 blocks: blocks_with_receipts,
1623 codes: code_updates,
1624 parent_state_root,
1625 child_state_root: last_state_root,
1626 account_updates,
1627 storage_updates,
1628 wait_for_flush: batch_mode,
1629 ack: ack_tx,
1630 }))
1631 .map_err(|e| StoreError::Custom(format!("failed to send block persist: {e}")))?;
1632 ack_rx
1633 .recv()
1634 .map_err(|e| StoreError::Custom(format!("block persist ack failed: {e}")))??;
1635
1636 Ok(())
1637 }
1638
1639 pub fn new(path: impl AsRef<Path>, engine_type: EngineType) -> Result<Self, StoreError> {
1644 Self::new_with_config(path, engine_type, StoreConfig::default())
1645 }
1646
1647 pub fn new_with_config(
1649 path: impl AsRef<Path>,
1650 engine_type: EngineType,
1651 #[cfg_attr(not(feature = "rocksdb"), allow(unused_variables))] config: StoreConfig,
1653 ) -> Result<Self, StoreError> {
1654 let db_path = path.as_ref().to_path_buf();
1655
1656 if engine_type != EngineType::InMemory {
1657 let version = read_store_schema_version(&db_path)?;
1658
1659 match version {
1660 None if db_path.exists() && dir_contains_legacy_db(&db_path)? => {
1661 return Err(StoreError::NotFoundDBVersion);
1663 }
1664 None => {
1665 init_metadata_file(&db_path)?;
1671 }
1672 Some(v) if v < 1 => {
1673 return Err(StoreError::MigrationFailed {
1674 from: v,
1675 to: STORE_SCHEMA_VERSION,
1676 reason: format!("DB version v{v} is invalid (predates migrations)"),
1677 });
1678 }
1679 Some(v) if v > STORE_SCHEMA_VERSION => {
1680 return Err(StoreError::MigrationFailed {
1681 from: v,
1682 to: STORE_SCHEMA_VERSION,
1683 reason: format!(
1684 "DB version v{v} is more recent than the client expects (v{STORE_SCHEMA_VERSION}). Rolling back is not supported"
1685 ),
1686 });
1687 }
1688 #[cfg(feature = "rocksdb")]
1689 Some(v) if v < STORE_SCHEMA_VERSION => {
1690 let rocksdb = Arc::new(RocksDBBackend::open(
1694 &path,
1695 config.rocksdb_block_cache_size,
1696 )?);
1697 crate::migrations::run_pending_migrations(rocksdb.as_ref(), &db_path, v)?;
1698 rocksdb.drop_obsolete_cfs(&path);
1699 let backend: Arc<dyn crate::api::StorageBackend> = rocksdb;
1700 return Self::from_backend(
1701 backend,
1702 db_path,
1703 DB_COMMIT_THRESHOLD,
1704 config.persist_channel_capacity,
1705 );
1706 }
1707 Some(_) => {
1708 }
1713 }
1714 }
1715
1716 match engine_type {
1717 #[cfg(feature = "rocksdb")]
1718 EngineType::RocksDB => {
1719 let rocksdb = RocksDBBackend::open(&path, config.rocksdb_block_cache_size)?;
1720 rocksdb.drop_obsolete_cfs(&path);
1721 let backend: Arc<dyn StorageBackend> = Arc::new(rocksdb);
1722 Self::from_backend(
1723 backend,
1724 db_path,
1725 DB_COMMIT_THRESHOLD,
1726 config.persist_channel_capacity,
1727 )
1728 }
1729 EngineType::InMemory => {
1730 let backend = Arc::new(InMemoryBackend::open()?);
1731 Self::from_backend(
1732 backend,
1733 db_path,
1734 IN_MEMORY_COMMIT_THRESHOLD,
1735 config.persist_channel_capacity,
1736 )
1737 }
1738 }
1739 }
1740
1741 fn from_backend(
1742 backend: Arc<dyn StorageBackend>,
1743 db_path: PathBuf,
1744 commit_threshold: usize,
1745 persist_channel_capacity: usize,
1746 ) -> Result<Self, StoreError> {
1747 debug!("Initializing Store with {commit_threshold} in-memory diff-layers");
1748 let (fkv_tx, fkv_rx) = std::sync::mpsc::sync_channel(0);
1749 let persist_cap = persist_channel_capacity.max(1); let (persist_tx, persist_rx) = std::sync::mpsc::sync_channel(persist_cap);
1751
1752 let (last_written, initial_flushed_upto) = {
1753 let tx = backend.begin_read()?;
1754 let last_written = tx
1755 .get(MISC_VALUES, "last_written".as_bytes())?
1756 .unwrap_or_else(|| vec![0u8; 64]);
1757 let last_written = if last_written == [0xff] {
1758 vec![0xff; 64]
1759 } else {
1760 last_written
1761 };
1762 let initial_flushed_upto = match tx.get(MISC_VALUES, FLUSHED_UPTO_KEY)? {
1763 Some(bytes) => decode_flushed_upto(&bytes)?,
1764 None => 0,
1765 };
1766 (last_written, initial_flushed_upto)
1767 };
1768 let mut initial_buffer = BlockDataBuffer::new();
1769 initial_buffer.set_flushed_upto(initial_flushed_upto);
1770
1771 let mut background_threads = Vec::new();
1772 let mut store = Self {
1773 db_path,
1774 backend,
1775 chain_config: Default::default(),
1776 latest_block_header: Default::default(),
1777 trie_cache: Arc::new(RwLock::new(Arc::new(TrieLayerCache::new(commit_threshold)))),
1778 flatkeyvalue_control_tx: fkv_tx,
1779 block_data_buffer: Arc::new(RwLock::new(Arc::new(initial_buffer))),
1780 persist_tx,
1781 pending_trie_roots: Arc::new(PendingTrieRoots::default()),
1782 last_computed_flatkeyvalue: Arc::new(RwLock::new(last_written)),
1783 account_code_cache: Arc::new(Mutex::new(CodeCache::default())),
1784 code_metadata_cache: Arc::new(Mutex::new(rustc_hash::FxHashMap::default())),
1785 fcu_lock: Arc::new(tokio::sync::Mutex::new(())),
1786 background_threads: Default::default(),
1787 };
1788 let backend_clone = store.backend.clone();
1789 let last_computed_fkv = store.last_computed_flatkeyvalue.clone();
1790 background_threads.push(std::thread::spawn(move || {
1791 let rx = fkv_rx;
1792 loop {
1794 match rx.recv() {
1795 Ok(FKVGeneratorControlMessage::Continue) => break,
1796 Ok(FKVGeneratorControlMessage::Stop) => {}
1797 Err(std::sync::mpsc::RecvError) => {
1798 debug!("Closing FlatKeyValue generator.");
1799 return;
1800 }
1801 }
1802 }
1803
1804 let _ = flatkeyvalue_generator(&backend_clone, &last_computed_fkv, &rx)
1805 .inspect_err(|err| error!("Error while generating FlatKeyValue: {err}"));
1806 }));
1807 let persist_backend = store.backend.clone();
1810 let persist_buffer = store.block_data_buffer.clone();
1811 let persist_trie_cache = store.trie_cache.clone();
1812 let persist_pending_roots = store.pending_trie_roots.clone();
1813 let persist_fkv_ctl = store.flatkeyvalue_control_tx.clone();
1814 background_threads.push(std::thread::spawn(move || {
1815 let rx = persist_rx;
1816 let mut last_flush_result: Result<(), StoreError> = Ok(());
1819 loop {
1820 match rx.recv() {
1821 Ok(PersistMessage::Block(bp)) => {
1822 let staged = mutate_block_buffer(&persist_buffer, move |b| {
1825 let mut codes = Some(bp.codes);
1826 for (block, receipts) in bp.blocks {
1827 b.insert(block, receipts, codes.take().unwrap_or_default());
1828 }
1829 });
1830 if let Err(e) = staged {
1831 persist_pending_roots.clear(bp.child_state_root);
1836 let _ = bp.ack.send(Err(e));
1837 continue;
1838 }
1839 if !bp.wait_for_flush {
1848 let _ = bp
1849 .ack
1850 .send(std::mem::replace(&mut last_flush_result, Ok(())));
1851 }
1852 if let Err(err) = apply_trie_phase1(
1854 &persist_trie_cache,
1855 &persist_pending_roots,
1856 bp.parent_state_root,
1857 bp.child_state_root,
1858 bp.account_updates,
1859 bp.storage_updates,
1860 ) {
1861 error!("persist worker trie phase-1 failed: {err}");
1862 if bp.wait_for_flush {
1863 let _ = bp.ack.send(Err(err));
1864 } else {
1865 last_flush_result = Err(err);
1866 }
1867 continue;
1868 }
1869 let flushed = flush_block_data(persist_backend.as_ref(), &persist_buffer)
1871 .inspect_err(|err| error!("flush_block_data failed: {err}"))
1872 .and_then(|_| {
1873 commit_trie_if_due(
1874 persist_backend.as_ref(),
1875 &persist_trie_cache,
1876 &persist_fkv_ctl,
1877 bp.parent_state_root,
1878 bp.wait_for_flush,
1879 )
1880 });
1881 if bp.wait_for_flush {
1884 let prior = std::mem::replace(&mut last_flush_result, Ok(()));
1885 let _ = bp.ack.send(prior.and(flushed));
1886 } else {
1887 last_flush_result = flushed;
1888 }
1889 }
1890 Ok(PersistMessage::Ping(ack)) => {
1891 let _ = ack.send(std::mem::replace(&mut last_flush_result, Ok(())));
1895 }
1896 Err(_) => return,
1897 }
1898 }
1899 }));
1900 store.background_threads = Arc::new(ThreadList {
1901 list: background_threads,
1902 });
1903 Ok(store)
1904 }
1905
1906 pub async fn new_from_genesis(
1909 store_path: &Path,
1910 engine_type: EngineType,
1911 genesis_path: &str,
1912 ) -> Result<Self, StoreError> {
1913 Self::new_from_genesis_with_config(
1914 store_path,
1915 engine_type,
1916 genesis_path,
1917 StoreConfig::default(),
1918 )
1919 .await
1920 }
1921
1922 pub async fn new_from_genesis_with_config(
1925 store_path: &Path,
1926 engine_type: EngineType,
1927 genesis_path: &str,
1928 config: StoreConfig,
1929 ) -> Result<Self, StoreError> {
1930 let file = std::fs::File::open(genesis_path)
1931 .map_err(|error| StoreError::Custom(format!("Failed to open genesis file: {error}")))?;
1932 let reader = std::io::BufReader::new(file);
1933 let genesis: Genesis = serde_json::from_reader(reader)
1934 .map_err(|e| StoreError::Custom(format!("Failed to deserialize genesis file: {e}")))?;
1935 let mut store = Self::new_with_config(store_path, engine_type, config)?;
1936 store.add_initial_state(genesis).await?;
1937 Ok(store)
1938 }
1939
1940 pub async fn get_account_info(
1941 &self,
1942 block_number: BlockNumber,
1943 address: Address,
1944 ) -> Result<Option<AccountInfo>, StoreError> {
1945 match self.get_canonical_block_hash(block_number).await? {
1946 Some(block_hash) => self.get_account_info_by_hash(block_hash, address),
1947 None => Ok(None),
1948 }
1949 }
1950
1951 pub fn get_account_info_by_hash(
1952 &self,
1953 block_hash: BlockHash,
1954 address: Address,
1955 ) -> Result<Option<AccountInfo>, StoreError> {
1956 let Some(state_trie) = self.state_trie(block_hash)? else {
1957 return Ok(None);
1958 };
1959 let hashed_address = hash_address_fixed(&address);
1960
1961 let Some(encoded_state) = state_trie.get(hashed_address.as_bytes())? else {
1962 return Ok(None);
1963 };
1964
1965 let account_state = AccountState::decode(&encoded_state)?;
1966 Ok(Some(AccountInfo {
1967 code_hash: account_state.code_hash,
1968 balance: account_state.balance,
1969 nonce: account_state.nonce,
1970 }))
1971 }
1972
1973 pub fn get_account_state_by_acc_hash(
1974 &self,
1975 block_hash: BlockHash,
1976 account_hash: H256,
1977 ) -> Result<Option<AccountState>, StoreError> {
1978 let Some(state_trie) = self.state_trie(block_hash)? else {
1979 return Ok(None);
1980 };
1981 let Some(encoded_state) = state_trie.get(account_hash.as_bytes())? else {
1982 return Ok(None);
1983 };
1984 let account_state = AccountState::decode(&encoded_state)?;
1985 Ok(Some(account_state))
1986 }
1987
1988 pub async fn get_fork_id(&self) -> Result<ForkId, StoreError> {
1989 let chain_config = self.get_chain_config();
1990 let genesis_header = self
1991 .load_block_header(0)?
1992 .ok_or(StoreError::MissingEarliestBlockNumber)?;
1993 let block_header = self.latest_block_header.get();
1994
1995 Ok(ForkId::new(
1996 chain_config,
1997 genesis_header,
1998 block_header.timestamp,
1999 block_header.number,
2000 ))
2001 }
2002
2003 pub async fn get_code_by_account_address(
2004 &self,
2005 block_number: BlockNumber,
2006 address: Address,
2007 ) -> Result<Option<Code>, StoreError> {
2008 let Some(block_hash) = self.get_canonical_block_hash(block_number).await? else {
2009 return Ok(None);
2010 };
2011 let Some(state_trie) = self.state_trie(block_hash)? else {
2012 return Ok(None);
2013 };
2014 let hashed_address = hash_address_fixed(&address);
2015 let Some(encoded_state) = state_trie.get(hashed_address.as_bytes())? else {
2016 return Ok(None);
2017 };
2018 let account_state = AccountState::decode(&encoded_state)?;
2019 self.get_account_code(account_state.code_hash)
2020 }
2021
2022 pub async fn get_nonce_by_account_address(
2023 &self,
2024 block_number: BlockNumber,
2025 address: Address,
2026 ) -> Result<Option<u64>, StoreError> {
2027 let Some(block_hash) = self.get_canonical_block_hash(block_number).await? else {
2028 return Ok(None);
2029 };
2030 let Some(state_trie) = self.state_trie(block_hash)? else {
2031 return Ok(None);
2032 };
2033 let hashed_address = hash_address_fixed(&address);
2034 let Some(encoded_state) = state_trie.get(hashed_address.as_bytes())? else {
2035 return Ok(None);
2036 };
2037 let account_state = AccountState::decode(&encoded_state)?;
2038 Ok(Some(account_state.nonce))
2039 }
2040
2041 pub fn apply_account_updates_batch(
2044 &self,
2045 block_hash: BlockHash,
2046 account_updates: &[AccountUpdate],
2047 ) -> Result<Option<AccountUpdatesList>, StoreError> {
2048 let Some(mut state_trie) = self.state_trie(block_hash)? else {
2049 return Ok(None);
2050 };
2051
2052 Ok(Some(self.apply_account_updates_from_trie_batch(
2053 &mut state_trie,
2054 account_updates,
2055 )?))
2056 }
2057
2058 pub fn apply_account_updates_from_trie_batch<'a>(
2059 &self,
2060 state_trie: &mut Trie,
2061 account_updates: impl IntoIterator<Item = &'a AccountUpdate>,
2062 ) -> Result<AccountUpdatesList, StoreError> {
2063 let mut ret_storage_updates = Vec::new();
2064 let mut code_updates = Vec::new();
2065 let state_root = state_trie.hash_no_commit(&NativeCrypto);
2066 for update in account_updates {
2067 let hashed_address = hash_address_fixed(&update.address);
2068 if update.removed {
2069 state_trie.remove(hashed_address.as_bytes())?;
2071 continue;
2072 }
2073 let mut account_state = match state_trie.get(hashed_address.as_bytes())? {
2076 Some(encoded_state) => AccountState::decode(&encoded_state)?,
2077 None => AccountState::default(),
2078 };
2079 if update.removed_storage {
2080 account_state.storage_root = *EMPTY_TRIE_HASH;
2081 }
2082 if let Some(info) = &update.info {
2083 account_state.nonce = info.nonce;
2084 account_state.balance = info.balance;
2085 account_state.code_hash = info.code_hash;
2086 if let Some(code) = &update.code {
2088 code_updates.push((info.code_hash, code.clone()));
2089 }
2090 }
2091 if !update.added_storage.is_empty() {
2093 let mut storage_trie =
2094 self.open_storage_trie(hashed_address, state_root, account_state.storage_root)?;
2095 for (storage_key, storage_value) in &update.added_storage {
2096 let hashed_key = hash_key(storage_key);
2097 if storage_value.is_zero() {
2098 storage_trie.remove(&hashed_key)?;
2099 } else {
2100 storage_trie.insert(hashed_key, storage_value.encode_to_vec())?;
2101 }
2102 }
2103 let (storage_hash, storage_updates) =
2104 storage_trie.collect_changes_since_last_hash(&NativeCrypto);
2105 account_state.storage_root = storage_hash;
2106 ret_storage_updates.push((hashed_address, storage_updates));
2107 }
2108 state_trie.insert(
2109 hashed_address.as_bytes().to_vec(),
2110 account_state.encode_to_vec(),
2111 )?;
2112 }
2113 let (state_trie_hash, state_updates) =
2114 state_trie.collect_changes_since_last_hash(&NativeCrypto);
2115
2116 Ok(AccountUpdatesList {
2117 state_trie_hash,
2118 state_updates,
2119 storage_updates: ret_storage_updates,
2120 code_updates,
2121 })
2122 }
2123
2124 pub fn apply_account_updates_from_trie_with_witness(
2127 &self,
2128 mut state_trie: Trie,
2129 account_updates: &[AccountUpdate],
2130 mut storage_tries: StorageTries,
2131 ) -> Result<(StorageTries, AccountUpdatesList), StoreError> {
2132 let mut ret_storage_updates = Vec::new();
2133
2134 let mut code_updates = Vec::new();
2135
2136 let state_root = state_trie.hash_no_commit(&NativeCrypto);
2137
2138 for update in account_updates.iter() {
2139 let hashed_address = hash_address(&update.address);
2140
2141 if update.removed {
2142 state_trie.remove(&hashed_address)?;
2144
2145 continue;
2146 }
2147
2148 let mut account_state = match state_trie.get(&hashed_address)? {
2151 Some(encoded_state) => AccountState::decode(&encoded_state)?,
2152 None => AccountState::default(),
2153 };
2154
2155 if update.removed_storage {
2156 account_state.storage_root = *EMPTY_TRIE_HASH;
2157 }
2158
2159 if let Some(info) = &update.info {
2160 account_state.nonce = info.nonce;
2161
2162 account_state.balance = info.balance;
2163
2164 account_state.code_hash = info.code_hash;
2165
2166 if let Some(code) = &update.code {
2168 code_updates.push((info.code_hash, code.clone()));
2169 }
2170 }
2171
2172 if !update.added_storage.is_empty() {
2174 let (_witness, storage_trie) = match storage_tries.entry(update.address) {
2175 Entry::Occupied(value) => value.into_mut(),
2176 Entry::Vacant(vacant) => {
2177 let trie = self.open_storage_trie(
2178 H256::from_slice(&hashed_address),
2179 state_root,
2180 account_state.storage_root,
2181 )?;
2182 vacant.insert(TrieLogger::open_trie(trie))
2183 }
2184 };
2185
2186 for (storage_key, storage_value) in &update.added_storage {
2187 let hashed_key = hash_key(storage_key);
2188
2189 if storage_value.is_zero() {
2190 storage_trie.remove(&hashed_key)?;
2191 } else {
2192 storage_trie.insert(hashed_key, storage_value.encode_to_vec())?;
2193 }
2194 }
2195
2196 let (storage_hash, storage_updates) =
2197 storage_trie.collect_changes_since_last_hash(&NativeCrypto);
2198
2199 account_state.storage_root = storage_hash;
2200
2201 ret_storage_updates.push((H256::from_slice(&hashed_address), storage_updates));
2202 }
2203
2204 state_trie.insert(hashed_address, account_state.encode_to_vec())?;
2205 }
2206
2207 let (state_trie_hash, state_updates) =
2208 state_trie.collect_changes_since_last_hash(&NativeCrypto);
2209
2210 let account_updates_list = AccountUpdatesList {
2211 state_trie_hash,
2212 state_updates,
2213 storage_updates: ret_storage_updates,
2214 code_updates,
2215 };
2216
2217 Ok((storage_tries, account_updates_list))
2218 }
2219
2220 pub async fn setup_genesis_state_trie(
2222 &self,
2223 genesis_accounts: BTreeMap<Address, GenesisAccount>,
2224 ) -> Result<H256, StoreError> {
2225 let mut storage_trie_nodes = vec![];
2226 let mut genesis_state_trie = self.open_direct_state_trie(*EMPTY_TRIE_HASH)?;
2227 for (address, account) in genesis_accounts {
2228 let hashed_address = hash_address(&address);
2229 let h256_hashed_address = H256::from_slice(&hashed_address);
2230
2231 let code = Code::from_bytecode(account.code, &NativeCrypto);
2233 let code_hash = code.hash;
2234 self.add_account_code(code).await?;
2235
2236 let mut storage_trie =
2238 self.open_direct_storage_trie(h256_hashed_address, *EMPTY_TRIE_HASH)?;
2239 for (storage_key, storage_value) in account.storage {
2240 if !storage_value.is_zero() {
2241 let hashed_key = hash_key(&H256(storage_key.to_big_endian()));
2242 storage_trie.insert(hashed_key, storage_value.encode_to_vec())?;
2243 }
2244 }
2245
2246 let (storage_root, storage_nodes) =
2247 storage_trie.collect_changes_since_last_hash(&NativeCrypto);
2248
2249 storage_trie_nodes.extend(
2250 storage_nodes
2251 .into_iter()
2252 .map(|(path, n)| (apply_prefix(Some(h256_hashed_address), path).into_vec(), n)),
2253 );
2254
2255 let account_state = AccountState {
2257 nonce: account.nonce,
2258 balance: account.balance,
2259 storage_root,
2260 code_hash,
2261 };
2262 genesis_state_trie.insert(hashed_address, account_state.encode_to_vec())?;
2263 }
2264
2265 let (state_root, account_trie_nodes) =
2266 genesis_state_trie.collect_changes_since_last_hash(&NativeCrypto);
2267 let account_trie_nodes = account_trie_nodes
2268 .into_iter()
2269 .map(|(path, n)| (apply_prefix(None, path).into_vec(), n))
2270 .collect::<Vec<_>>();
2271
2272 let mut tx = self.backend.begin_write()?;
2273 tx.put_batch(ACCOUNT_TRIE_NODES, account_trie_nodes)?;
2274 tx.put_batch(STORAGE_TRIE_NODES, storage_trie_nodes)?;
2275 tx.commit()?;
2276
2277 Ok(state_root)
2278 }
2279
2280 fn make_witness_key(block_number: u64, block_hash: &BlockHash) -> Vec<u8> {
2282 let mut composite_key = Vec::with_capacity(8 + 32);
2283 composite_key.extend_from_slice(&block_number.to_be_bytes());
2284 composite_key.extend_from_slice(block_hash.as_bytes());
2285 composite_key
2286 }
2287
2288 pub fn store_witness(
2294 &self,
2295 block_hash: BlockHash,
2296 block_number: u64,
2297 witness: ExecutionWitness,
2298 ) -> Result<(), StoreError> {
2299 let rpc_witness = RpcExecutionWitness::try_from(witness)?;
2301 let key = Self::make_witness_key(block_number, &block_hash);
2302 let value = serde_json::to_vec(&rpc_witness)?;
2303 self.write(EXECUTION_WITNESSES, key, value)?;
2304 self.cleanup_old_witnesses(block_number)
2306 }
2307
2308 fn cleanup_old_witnesses(&self, latest_block_number: u64) -> Result<(), StoreError> {
2309 if latest_block_number <= MAX_WITNESSES {
2311 return Ok(());
2312 }
2313
2314 let threshold = latest_block_number - MAX_WITNESSES;
2315
2316 if let Some(oldest_block_number) = self.get_oldest_witness_number()? {
2317 let prefix = oldest_block_number.to_be_bytes();
2318 let mut to_delete = Vec::new();
2319
2320 {
2321 let read_txn = self.backend.begin_read()?;
2322 let iter = read_txn.prefix_iterator(EXECUTION_WITNESSES, &prefix)?;
2323
2324 for item in iter {
2326 let (key, _value) = item?;
2327 let mut block_number_bytes = [0u8; 8];
2328 block_number_bytes.copy_from_slice(&key[0..8]);
2329 let block_number = u64::from_be_bytes(block_number_bytes);
2330 if block_number > threshold {
2331 break;
2332 }
2333 to_delete.push(key.to_vec());
2334 }
2335 }
2336
2337 for key in to_delete {
2338 self.delete(EXECUTION_WITNESSES, key)?;
2339 }
2340 };
2341
2342 self.update_oldest_witness_number(threshold + 1)?;
2343
2344 Ok(())
2345 }
2346
2347 fn update_oldest_witness_number(&self, oldest_block_number: u64) -> Result<(), StoreError> {
2348 self.write(
2349 MISC_VALUES,
2350 b"oldest_witness_block_number".to_vec(),
2351 oldest_block_number.to_le_bytes().to_vec(),
2352 )?;
2353 Ok(())
2354 }
2355
2356 fn get_oldest_witness_number(&self) -> Result<Option<u64>, StoreError> {
2357 let Some(value) = self.read(MISC_VALUES, b"oldest_witness_block_number".to_vec())? else {
2358 return Ok(None);
2359 };
2360
2361 let array: [u8; 8] = value.as_slice().try_into().map_err(|_| {
2362 StoreError::Custom("Invalid oldest witness block number bytes".to_string())
2363 })?;
2364 Ok(Some(u64::from_le_bytes(array)))
2365 }
2366
2367 pub fn get_witness_json_bytes(
2373 &self,
2374 block_number: u64,
2375 block_hash: BlockHash,
2376 ) -> Result<Option<Vec<u8>>, StoreError> {
2377 let key = Self::make_witness_key(block_number, &block_hash);
2378 self.read(EXECUTION_WITNESSES, key)
2379 }
2380
2381 pub fn get_witness_by_number_and_hash(
2386 &self,
2387 block_number: u64,
2388 block_hash: BlockHash,
2389 ) -> Result<Option<RpcExecutionWitness>, StoreError> {
2390 let key = Self::make_witness_key(block_number, &block_hash);
2391 match self.read(EXECUTION_WITNESSES, key)? {
2392 Some(value) => {
2393 let witness: RpcExecutionWitness = serde_json::from_slice(&value)?;
2394 Ok(Some(witness))
2395 }
2396 None => Ok(None),
2397 }
2398 }
2399
2400 pub fn store_block_access_list(
2402 &self,
2403 block_hash: BlockHash,
2404 bal: &BlockAccessList,
2405 ) -> Result<(), StoreError> {
2406 let key = block_hash.as_bytes().to_vec();
2407 let mut value = vec![];
2408 bal.encode(&mut value);
2409 self.write(BLOCK_ACCESS_LISTS, key, value)
2410 }
2411
2412 pub fn get_block_access_list(
2414 &self,
2415 block_hash: BlockHash,
2416 ) -> Result<Option<BlockAccessList>, StoreError> {
2417 let key = block_hash.as_bytes().to_vec();
2418 match self.read(BLOCK_ACCESS_LISTS, key)? {
2419 Some(value) => {
2420 let bal = BlockAccessList::decode(&value)
2421 .map_err(|e| StoreError::Custom(format!("Failed to decode BAL: {e}")))?;
2422 Ok(Some(bal))
2423 }
2424 None => Ok(None),
2425 }
2426 }
2427
2428 pub async fn add_initial_state(&mut self, genesis: Genesis) -> Result<(), StoreError> {
2429 self.add_initial_state_inner(genesis, false).await
2430 }
2431
2432 pub async fn add_initial_state_skip_validation(
2443 &mut self,
2444 genesis: Genesis,
2445 ) -> Result<(), StoreError> {
2446 self.add_initial_state_inner(genesis, true).await
2447 }
2448
2449 async fn add_initial_state_inner(
2450 &mut self,
2451 genesis: Genesis,
2452 skip_genesis_validation: bool,
2453 ) -> Result<(), StoreError> {
2454 debug!("Storing initial state from genesis");
2455
2456 let genesis_block = genesis.get_block();
2458 let genesis_block_number = genesis_block.header.number;
2459
2460 let genesis_hash = genesis_block.hash();
2461
2462 let stored_genesis_header = self.load_block_header(genesis_block_number)?;
2463
2464 self.set_chain_config(&genesis.config).await?;
2471
2472 if let Some(latest) = self.load_latest_block_number().await? {
2477 self.anchor_to_durable_head(latest).await?;
2478 }
2479
2480 match stored_genesis_header {
2481 Some(header) if skip_genesis_validation => {
2482 info!(
2483 stored_genesis = %header.hash(),
2484 "Skipping genesis state validation; trusting the genesis header and state already stored in the datadir"
2485 );
2486 return Ok(());
2487 }
2488 Some(header) if header.hash() == genesis_hash => {
2489 info!("Received genesis file matching a previously stored one, nothing to do");
2490 return Ok(());
2491 }
2492 Some(_) => {
2493 error!(
2494 "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."
2495 );
2496 return Err(StoreError::IncompatibleChainConfig);
2497 }
2498 None => {
2499 self.add_block_header(genesis_hash, genesis_block.header.clone())
2500 .await?
2501 }
2502 }
2503 let genesis_state_root = self.setup_genesis_state_trie(genesis.alloc).await?;
2506 debug_assert_eq!(genesis_state_root, genesis_block.header.state_root);
2507
2508 info!(hash = %genesis_hash, "Storing genesis block");
2510
2511 self.add_block(genesis_block).await?;
2512 self.update_earliest_block_number(genesis_block_number)
2513 .await?;
2514 self.forkchoice_update(vec![], genesis_block_number, genesis_hash, None, None)
2515 .await?;
2516 Ok(())
2517 }
2518
2519 pub async fn load_initial_state(&self) -> Result<(), StoreError> {
2520 info!("Loading initial state from DB");
2521 let Some(latest) = self.load_latest_block_number().await? else {
2522 return Err(StoreError::MissingLatestBlockNumber);
2523 };
2524 self.anchor_to_durable_head(latest).await?;
2528 Ok(())
2529 }
2530
2531 pub fn get_storage_at(
2532 &self,
2533 block_number: BlockNumber,
2534 address: Address,
2535 storage_key: H256,
2536 ) -> Result<Option<U256>, StoreError> {
2537 match self.get_block_header(block_number)? {
2538 Some(header) => self.get_storage_at_root(header.state_root, address, storage_key),
2539 None => Ok(None),
2540 }
2541 }
2542
2543 pub fn get_storage_at_root(
2544 &self,
2545 state_root: H256,
2546 address: Address,
2547 storage_key: H256,
2548 ) -> Result<Option<U256>, StoreError> {
2549 let account_hash = hash_address_fixed(&address);
2550
2551 let read_view = self.backend.begin_read()?;
2553 let cache = self.gated_snapshot(state_root)?;
2554 let last_written = self.last_written()?;
2555 let use_fkv = Self::flatkeyvalue_computed_with_last_written(account_hash, &last_written);
2556
2557 let storage_root = if use_fkv {
2558 *EMPTY_TRIE_HASH
2560 } else {
2561 let state_trie = self.open_state_trie_shared(
2562 state_root,
2563 read_view.clone(),
2564 cache.clone(),
2565 last_written.clone(),
2566 )?;
2567 let Some(encoded_account) = state_trie.get(account_hash.as_bytes())? else {
2568 return Ok(None);
2569 };
2570 let account = AccountState::decode(&encoded_account)?;
2571 account.storage_root
2572 };
2573 let storage_trie = self.open_storage_trie_shared(
2574 account_hash,
2575 state_root,
2576 storage_root,
2577 read_view,
2578 cache,
2579 last_written,
2580 )?;
2581
2582 let hashed_key = hash_key_fixed(&storage_key);
2583 storage_trie
2584 .get(&hashed_key)?
2585 .map(|rlp| U256::decode(&rlp).map_err(StoreError::RLPDecode))
2586 .transpose()
2587 }
2588
2589 pub fn get_storage_at_root_with_known_storage_root(
2594 &self,
2595 state_root: H256,
2596 account_hash: H256,
2597 storage_root: H256,
2598 storage_key: H256,
2599 ) -> Result<Option<U256>, StoreError> {
2600 let read_view = self.backend.begin_read()?;
2601 let cache = self.gated_snapshot(state_root)?;
2602 let last_written = self.last_written()?;
2603 let storage_root =
2607 if Self::flatkeyvalue_computed_with_last_written(account_hash, &last_written) {
2608 *EMPTY_TRIE_HASH
2609 } else {
2610 storage_root
2611 };
2612 let storage_trie = self.open_storage_trie_shared(
2613 account_hash,
2614 state_root,
2615 storage_root,
2616 read_view,
2617 cache,
2618 last_written,
2619 )?;
2620
2621 let hashed_key = hash_key_fixed(&storage_key);
2622 storage_trie
2623 .get(&hashed_key)?
2624 .map(|rlp| U256::decode(&rlp).map_err(StoreError::RLPDecode))
2625 .transpose()
2626 }
2627
2628 pub fn get_chain_config(&self) -> ChainConfig {
2629 self.chain_config
2630 }
2631
2632 pub async fn get_latest_canonical_block_hash(&self) -> Result<Option<BlockHash>, StoreError> {
2633 Ok(Some(self.latest_block_header.get().hash()))
2634 }
2635
2636 pub async fn forkchoice_update(
2641 &self,
2642 new_canonical_blocks: Vec<(BlockNumber, BlockHash)>,
2643 head_number: BlockNumber,
2644 head_hash: BlockHash,
2645 safe: Option<BlockNumber>,
2646 finalized: Option<BlockNumber>,
2647 ) -> Result<(), StoreError> {
2648 let _guard = self.fcu_lock.lock().await;
2654
2655 let previous_head = self.latest_block_header.get();
2660 let new_head = self
2661 .get_block_header_by_hash(head_hash)?
2662 .ok_or_else(|| StoreError::MissingLatestBlockNumber)?;
2663 self.latest_block_header.update(new_head);
2664 if let Err(err) = self
2665 .forkchoice_update_inner(
2666 new_canonical_blocks,
2667 head_number,
2668 head_hash,
2669 safe,
2670 finalized,
2671 )
2672 .await
2673 {
2674 self.latest_block_header.update((*previous_head).clone());
2675 return Err(err);
2676 }
2677
2678 Ok(())
2679 }
2680
2681 pub fn state_trie(&self, block_hash: BlockHash) -> Result<Option<Trie>, StoreError> {
2683 let Some(header) = self.get_block_header_by_hash(block_hash)? else {
2684 return Ok(None);
2685 };
2686 Ok(Some(self.open_state_trie(header.state_root)?))
2687 }
2688
2689 pub fn storage_trie(
2691 &self,
2692 block_hash: BlockHash,
2693 address: Address,
2694 ) -> Result<Option<Trie>, StoreError> {
2695 let Some(header) = self.get_block_header_by_hash(block_hash)? else {
2696 return Ok(None);
2697 };
2698 let Some(state_trie) = self.state_trie(block_hash)? else {
2700 return Ok(None);
2701 };
2702 let hashed_address = hash_address_fixed(&address);
2703 let Some(encoded_account) = state_trie.get(hashed_address.as_bytes())? else {
2704 return Ok(None);
2705 };
2706 let account = AccountState::decode(&encoded_account)?;
2707 let storage_root = account.storage_root;
2709 Ok(Some(self.open_storage_trie(
2710 hashed_address,
2711 header.state_root,
2712 storage_root,
2713 )?))
2714 }
2715
2716 pub async fn get_account_state(
2717 &self,
2718 block_number: BlockNumber,
2719 address: Address,
2720 ) -> Result<Option<AccountState>, StoreError> {
2721 let Some(block_hash) = self.get_canonical_block_hash(block_number).await? else {
2722 return Ok(None);
2723 };
2724 let Some(state_trie) = self.state_trie(block_hash)? else {
2725 return Ok(None);
2726 };
2727 self.get_account_state_from_trie(&state_trie, address)
2728 }
2729
2730 pub fn get_account_state_by_root(
2731 &self,
2732 state_root: H256,
2733 address: Address,
2734 ) -> Result<Option<AccountState>, StoreError> {
2735 let state_trie = self.open_state_trie(state_root)?;
2736 self.get_account_state_from_trie(&state_trie, address)
2737 }
2738
2739 pub fn get_account_state_from_trie(
2740 &self,
2741 state_trie: &Trie,
2742 address: Address,
2743 ) -> Result<Option<AccountState>, StoreError> {
2744 let hashed_address = hash_address_fixed(&address);
2745 let Some(encoded_state) = state_trie.get(hashed_address.as_bytes())? else {
2746 return Ok(None);
2747 };
2748 Ok(Some(AccountState::decode(&encoded_state)?))
2749 }
2750
2751 pub async fn get_account_proof(
2756 &self,
2757 state_root: H256,
2758 address: Address,
2759 storage_keys: &[H256],
2760 ) -> Result<Option<AccountProof>, StoreError> {
2761 let state_trie = self.open_state_trie(state_root)?;
2766 let address_path = hash_address_fixed(&address);
2767 let proof = state_trie.get_proof(address_path.as_bytes())?;
2768 let account_opt = state_trie
2769 .get(address_path.as_bytes())?
2770 .map(|encoded_state| AccountState::decode(&encoded_state))
2771 .transpose()?;
2772
2773 let mut storage_proof = Vec::with_capacity(storage_keys.len());
2774
2775 if let Some(account) = &account_opt {
2776 let storage_trie =
2777 self.open_storage_trie(address_path, state_root, account.storage_root)?;
2778
2779 for key in storage_keys {
2780 let hashed_key = hash_key(key);
2781 let proof = storage_trie.get_proof(&hashed_key)?;
2782 let value = storage_trie
2783 .get(&hashed_key)?
2784 .map(|rlp| U256::decode(&rlp).map_err(StoreError::RLPDecode))
2785 .transpose()?
2786 .unwrap_or_default();
2787
2788 let slot_proof = StorageSlotProof {
2789 proof,
2790 key: *key,
2791 value,
2792 };
2793 storage_proof.push(slot_proof);
2794 }
2795 } else {
2796 storage_proof.extend(storage_keys.iter().map(|key| StorageSlotProof {
2797 proof: Vec::new(),
2798 key: *key,
2799 value: U256::zero(),
2800 }));
2801 }
2802 let account = account_opt.unwrap_or_default();
2803 let account_proof = AccountProof {
2804 proof,
2805 account,
2806 storage_proof,
2807 };
2808 Ok(Some(account_proof))
2809 }
2810
2811 pub fn iter_accounts_from(
2814 &self,
2815 state_root: H256,
2816 starting_address: H256,
2817 ) -> Result<impl Iterator<Item = (H256, AccountState)>, StoreError> {
2818 let mut iter = self.open_locked_state_trie(state_root)?.into_iter();
2819 iter.advance(starting_address.0.to_vec())?;
2820 Ok(iter.content().map_while(|(path, value)| {
2821 Some((H256::from_slice(&path), AccountState::decode(&value).ok()?))
2822 }))
2823 }
2824
2825 pub fn iter_accounts(
2828 &self,
2829 state_root: H256,
2830 ) -> Result<impl Iterator<Item = (H256, AccountState)>, StoreError> {
2831 self.iter_accounts_from(state_root, H256::zero())
2832 }
2833
2834 pub fn iter_storage_from(
2837 &self,
2838 state_root: H256,
2839 hashed_address: H256,
2840 starting_slot: H256,
2841 ) -> Result<Option<impl Iterator<Item = (H256, U256)>>, StoreError> {
2842 let state_trie = self.open_locked_state_trie(state_root)?;
2843 let Some(account_rlp) = state_trie.get(hashed_address.as_bytes())? else {
2844 return Ok(None);
2845 };
2846 let storage_root = AccountState::decode(&account_rlp)?.storage_root;
2847 let mut iter = self
2848 .open_locked_storage_trie(hashed_address, state_root, storage_root)?
2849 .into_iter();
2850 iter.advance(starting_slot.0.to_vec())?;
2851 Ok(Some(iter.content().map_while(|(path, value)| {
2852 Some((H256::from_slice(&path), U256::decode(&value).ok()?))
2853 })))
2854 }
2855
2856 pub fn iter_storage(
2859 &self,
2860 state_root: H256,
2861 hashed_address: H256,
2862 ) -> Result<Option<impl Iterator<Item = (H256, U256)>>, StoreError> {
2863 self.iter_storage_from(state_root, hashed_address, H256::zero())
2864 }
2865
2866 pub fn get_account_range_proof(
2867 &self,
2868 state_root: H256,
2869 starting_hash: H256,
2870 last_hash: Option<H256>,
2871 ) -> Result<Vec<Vec<u8>>, StoreError> {
2872 let state_trie = self.open_state_trie(state_root)?;
2873 let mut proof = state_trie.get_proof(starting_hash.as_bytes())?;
2874 if let Some(last_hash) = last_hash {
2875 proof.extend_from_slice(&state_trie.get_proof(last_hash.as_bytes())?);
2876 }
2877 Ok(proof)
2878 }
2879
2880 pub fn get_storage_range_proof(
2881 &self,
2882 state_root: H256,
2883 hashed_address: H256,
2884 starting_hash: H256,
2885 last_hash: Option<H256>,
2886 ) -> Result<Option<Vec<Vec<u8>>>, StoreError> {
2887 let state_trie = self.open_state_trie(state_root)?;
2888 let Some(account_rlp) = state_trie.get(hashed_address.as_bytes())? else {
2889 return Ok(None);
2890 };
2891 let storage_root = AccountState::decode(&account_rlp)?.storage_root;
2892 let storage_trie = self.open_storage_trie(hashed_address, state_root, storage_root)?;
2893 let mut proof = storage_trie.get_proof(starting_hash.as_bytes())?;
2894 if let Some(last_hash) = last_hash {
2895 proof.extend_from_slice(&storage_trie.get_proof(last_hash.as_bytes())?);
2896 }
2897 Ok(Some(proof))
2898 }
2899
2900 pub fn get_trie_nodes(
2907 &self,
2908 state_root: H256,
2909 paths: Vec<Vec<u8>>,
2910 byte_limit: u64,
2911 ) -> Result<Vec<Vec<u8>>, StoreError> {
2912 let Some(account_path) = paths.first() else {
2913 return Ok(vec![]);
2914 };
2915 let state_trie = self.open_state_trie(state_root)?;
2916 if paths.len() == 1 {
2918 let node = state_trie.get_node(account_path)?;
2920 return Ok(vec![node]);
2921 }
2922 let Some(account_state) = state_trie
2924 .get(account_path)?
2925 .map(|ref rlp| AccountState::decode(rlp))
2926 .transpose()?
2927 else {
2928 return Ok(vec![]);
2929 };
2930 let Ok(hashed_address) = account_path.clone().try_into().map(H256) else {
2932 return Ok(vec![]);
2933 };
2934 let storage_trie =
2935 self.open_storage_trie(hashed_address, state_root, account_state.storage_root)?;
2936 let mut nodes = vec![];
2938 let mut bytes_used = 0;
2939 for path in paths.iter().skip(1) {
2940 if bytes_used >= byte_limit {
2941 break;
2942 }
2943 let node = storage_trie.get_node(path)?;
2944 bytes_used += node.len() as u64;
2945 nodes.push(node);
2946 }
2947 Ok(nodes)
2948 }
2949
2950 fn gated_snapshot(&self, state_root: H256) -> Result<Arc<TrieLayerCache>, StoreError> {
2959 self.pending_trie_roots.wait_until_ready(state_root)?;
2960 Ok(self
2961 .trie_cache
2962 .read()
2963 .map_err(|_| StoreError::LockError)?
2964 .clone())
2965 }
2966
2967 pub fn open_state_trie(&self, state_root: H256) -> Result<Trie, StoreError> {
2971 let trie_db = TrieWrapper::new(
2972 state_root,
2973 self.gated_snapshot(state_root)?,
2974 Box::new(BackendTrieDB::new_for_accounts(
2975 self.backend.clone(),
2976 self.last_written()?,
2977 )?),
2978 None,
2979 );
2980 Ok(Trie::open(Box::new(trie_db), state_root))
2981 }
2982
2983 pub fn open_direct_state_trie(&self, state_root: H256) -> Result<Trie, StoreError> {
2987 Ok(Trie::open(
2988 Box::new(BackendTrieDB::new_for_accounts(
2989 self.backend.clone(),
2990 self.last_written()?,
2991 )?),
2992 state_root,
2993 ))
2994 }
2995
2996 pub fn open_locked_state_trie(&self, state_root: H256) -> Result<Trie, StoreError> {
3000 let trie_db = TrieWrapper::new(
3001 state_root,
3002 self.gated_snapshot(state_root)?,
3003 Box::new(state_trie_locked_backend(
3004 self.backend.as_ref(),
3005 self.last_written()?,
3006 )?),
3007 None,
3008 );
3009 Ok(Trie::open(Box::new(trie_db), state_root))
3010 }
3011
3012 pub fn open_storage_trie(
3015 &self,
3016 account_hash: H256,
3017 state_root: H256,
3018 storage_root: H256,
3019 ) -> Result<Trie, StoreError> {
3020 let trie_db = TrieWrapper::new(
3021 state_root,
3022 self.gated_snapshot(state_root)?,
3023 Box::new(BackendTrieDB::new_for_storages(
3024 self.backend.clone(),
3025 self.last_written()?,
3026 )?),
3027 Some(account_hash),
3028 );
3029 Ok(Trie::open(Box::new(trie_db), storage_root))
3030 }
3031
3032 fn open_state_trie_shared(
3036 &self,
3037 state_root: H256,
3038 read_view: Arc<dyn StorageReadView>,
3039 cache: Arc<TrieLayerCache>,
3040 last_written: Vec<u8>,
3041 ) -> Result<Trie, StoreError> {
3042 let trie_db = TrieWrapper::new(
3043 state_root,
3044 cache,
3045 Box::new(BackendTrieDB::new_for_accounts_with_view(
3046 self.backend.clone(),
3047 read_view,
3048 last_written,
3049 )?),
3050 None,
3051 );
3052 Ok(Trie::open(Box::new(trie_db), state_root))
3053 }
3054
3055 fn open_storage_trie_shared(
3057 &self,
3058 account_hash: H256,
3059 state_root: H256,
3060 storage_root: H256,
3061 read_view: Arc<dyn StorageReadView>,
3062 cache: Arc<TrieLayerCache>,
3063 last_written: Vec<u8>,
3064 ) -> Result<Trie, StoreError> {
3065 let trie_db = TrieWrapper::new(
3066 state_root,
3067 cache,
3068 Box::new(BackendTrieDB::new_for_storages_with_view(
3069 self.backend.clone(),
3070 read_view,
3071 last_written,
3072 )?),
3073 Some(account_hash),
3074 );
3075 Ok(Trie::open(Box::new(trie_db), storage_root))
3076 }
3077
3078 pub fn open_direct_storage_trie(
3081 &self,
3082 account_hash: H256,
3083 storage_root: H256,
3084 ) -> Result<Trie, StoreError> {
3085 Ok(Trie::open(
3086 Box::new(BackendTrieDB::new_for_account_storage(
3087 self.backend.clone(),
3088 account_hash,
3089 self.last_written()?,
3090 )?),
3091 storage_root,
3092 ))
3093 }
3094
3095 pub fn open_locked_storage_trie(
3098 &self,
3099 account_hash: H256,
3100 state_root: H256,
3101 storage_root: H256,
3102 ) -> Result<Trie, StoreError> {
3103 let trie_db = TrieWrapper::new(
3104 state_root,
3105 self.gated_snapshot(state_root)?,
3106 Box::new(state_trie_locked_backend(
3107 self.backend.as_ref(),
3108 self.last_written()?,
3109 )?),
3110 Some(account_hash),
3111 );
3112 Ok(Trie::open(Box::new(trie_db), storage_root))
3113 }
3114
3115 pub fn has_state_root(&self, state_root: H256) -> Result<bool, StoreError> {
3116 if state_root == *EMPTY_TRIE_HASH {
3118 return Ok(true);
3119 }
3120 let trie = self.open_state_trie(state_root)?;
3121 let Some(root) = trie.db().get(Nibbles::default())? else {
3123 return Ok(false);
3124 };
3125 let root_hash = ethrex_trie::Node::decode(&root)?
3126 .compute_hash(&NativeCrypto)
3127 .finalize(&NativeCrypto);
3128 Ok(state_root == root_hash)
3129 }
3130
3131 pub fn ancestors(&self, block_hash: BlockHash) -> AncestorIterator {
3134 AncestorIterator {
3135 store: self.clone(),
3136 next_hash: block_hash,
3137 }
3138 }
3139
3140 pub fn is_canonical_sync(&self, block_hash: BlockHash) -> Result<bool, StoreError> {
3142 let Some(block_number) = self.get_block_number_sync(block_hash)? else {
3143 return Ok(false);
3144 };
3145 Ok(self
3146 .get_canonical_block_hash_sync(block_number)?
3147 .is_some_and(|h| h == block_hash))
3148 }
3149
3150 pub fn generate_flatkeyvalue(&self) -> Result<(), StoreError> {
3151 self.flatkeyvalue_control_tx
3152 .send(FKVGeneratorControlMessage::Continue)
3153 .map_err(|_| StoreError::Custom("FlatKeyValue thread disconnected.".to_string()))
3154 }
3155
3156 pub fn create_checkpoint(&self, path: impl AsRef<Path>) -> Result<(), StoreError> {
3157 self.backend.create_checkpoint(path.as_ref())?;
3158 init_metadata_file(path.as_ref())?;
3159 Ok(())
3160 }
3161
3162 pub fn get_store_directory(&self) -> Result<PathBuf, StoreError> {
3163 Ok(self.db_path.clone())
3164 }
3165
3166 async fn load_latest_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
3168 let key = chain_data_key(ChainDataIndex::LatestBlockNumber);
3169 self.read_async(CHAIN_DATA, key)
3170 .await?
3171 .map(|bytes| -> Result<BlockNumber, StoreError> {
3172 let array: [u8; 8] = bytes
3173 .try_into()
3174 .map_err(|_| StoreError::Custom("Invalid BlockNumber bytes".to_string()))?;
3175 Ok(BlockNumber::from_le_bytes(array))
3176 })
3177 .transpose()
3178 }
3179
3180 fn load_canonical_block_hash(
3181 &self,
3182 block_number: BlockNumber,
3183 ) -> Result<Option<BlockHash>, StoreError> {
3184 let txn = self.backend.begin_read()?;
3185 txn.get(
3186 CANONICAL_BLOCK_HASHES,
3187 block_number.to_le_bytes().as_slice(),
3188 )?
3189 .map(|bytes| H256::decode(bytes.as_slice()))
3190 .transpose()
3191 .map_err(StoreError::from)
3192 }
3193
3194 fn load_block_header(
3195 &self,
3196 block_number: BlockNumber,
3197 ) -> Result<Option<BlockHeader>, StoreError> {
3198 let Some(block_hash) = self.load_canonical_block_hash(block_number)? else {
3199 return Ok(None);
3200 };
3201 self.load_block_header_by_hash(block_hash)
3202 }
3203
3204 fn load_block_header_by_hash(
3206 &self,
3207 block_hash: BlockHash,
3208 ) -> Result<Option<BlockHeader>, StoreError> {
3209 let txn = self.backend.begin_read()?;
3210 let hash_key = block_hash.encode_to_vec();
3211 let header_value = txn.get(HEADERS, hash_key.as_slice())?;
3212 let mut header = header_value
3213 .map(|bytes| BlockHeaderRLP::from_bytes(bytes).to())
3214 .transpose()
3215 .map_err(StoreError::from)?;
3216 header.as_mut().inspect(|h| {
3217 let _ = h.hash.set(block_hash);
3219 });
3220 Ok(header)
3221 }
3222
3223 pub fn last_written(&self) -> Result<Vec<u8>, StoreError> {
3224 let last_computed_flatkeyvalue = self
3225 .last_computed_flatkeyvalue
3226 .read()
3227 .map_err(|_| StoreError::LockError)?;
3228 Ok(last_computed_flatkeyvalue.clone())
3229 }
3230
3231 fn flatkeyvalue_computed_with_last_written(account: H256, last_written: &[u8]) -> bool {
3232 let account_nibbles = Nibbles::from_bytes(account.as_bytes());
3233 &last_written[0..64] > account_nibbles.as_ref()
3234 }
3235
3236 pub fn read_flushed_upto(&self) -> Result<BlockNumber, StoreError> {
3241 Ok(self.read_flushed_upto_opt()?.unwrap_or(0))
3242 }
3243
3244 fn read_flushed_upto_opt(&self) -> Result<Option<BlockNumber>, StoreError> {
3247 let tx = self.backend.begin_read()?;
3248 match tx.get(MISC_VALUES, FLUSHED_UPTO_KEY)? {
3249 Some(bytes) => Ok(Some(decode_flushed_upto(&bytes)?)),
3250 None => Ok(None),
3251 }
3252 }
3253
3254 #[cfg(any(test, feature = "testing"))]
3257 pub fn buffer_block_for_test(&self, block: &Block) {
3258 mutate_block_buffer(&self.block_data_buffer, |b| {
3259 b.insert(block.clone(), vec![], vec![])
3260 })
3261 .expect("block_data_buffer lock poisoned");
3262 }
3263
3264 #[cfg(any(test, feature = "testing"))]
3267 pub fn flush_block_data_for_test(&self) -> Result<(), StoreError> {
3268 flush_block_data(self.backend.as_ref(), &self.block_data_buffer)
3269 }
3270
3271 #[cfg(any(test, feature = "testing"))]
3275 pub fn buffer_block_with_codes_for_test(&self, block: &Block, codes: Vec<(H256, Code)>) {
3276 mutate_block_buffer(&self.block_data_buffer, |b| {
3277 b.insert(block.clone(), vec![], codes)
3278 })
3279 .expect("block_data_buffer lock poisoned");
3280 }
3281
3282 #[cfg(any(test, feature = "testing"))]
3287 pub fn register_pending_root_for_test(&self, root: H256) -> Result<(), StoreError> {
3288 self.pending_trie_roots.register(root)
3289 }
3290
3291 #[cfg(any(test, feature = "testing"))]
3294 pub fn clear_pending_root_for_test(&self, root: H256) {
3295 self.pending_trie_roots.clear(root)
3296 }
3297
3298 async fn anchor_to_durable_head(&self, latest: BlockNumber) -> Result<(), StoreError> {
3317 let marker = self.read_flushed_upto_opt()?;
3318 let start = match marker {
3319 Some(flushed) => flushed.min(latest),
3320 None => latest,
3321 };
3322
3323 let mut head = start;
3324 let latest_block_header = loop {
3325 match self.load_block_header(head)? {
3326 Some(header) => break header,
3327 None if marker.is_none() => return Err(StoreError::MissingLatestBlockNumber),
3330 None if head == 0 => return Err(StoreError::MissingLatestBlockNumber),
3331 None => {
3332 warn!(
3333 "durable head {head}: canonical hash has no on-disk header \
3334 (reorg inside flush window); rewinding"
3335 );
3336 head -= 1;
3337 }
3338 }
3339 };
3340 self.latest_block_header.update(latest_block_header);
3341
3342 let reanchor = head != latest;
3347 let rewrite_marker = marker != Some(head);
3348 if reanchor || rewrite_marker {
3349 let mut tx = self.backend.begin_write()?;
3350 if reanchor {
3351 let latest_key = chain_data_key(ChainDataIndex::LatestBlockNumber);
3354 tx.put(CHAIN_DATA, &latest_key, &head.to_le_bytes())?;
3355 }
3356 if rewrite_marker {
3357 write_flushed_upto(tx.as_mut(), head)?;
3358 }
3359 tx.commit()?;
3360 }
3361 Ok(())
3362 }
3363}
3364
3365pub fn write_flushed_upto(
3369 tx: &mut dyn StorageWriteBatch,
3370 n: BlockNumber,
3371) -> Result<(), StoreError> {
3372 tx.put(MISC_VALUES, FLUSHED_UPTO_KEY, &n.to_le_bytes())
3373}
3374
3375fn decode_flushed_upto(bytes: &[u8]) -> Result<BlockNumber, StoreError> {
3381 let arr: [u8; 8] = bytes
3382 .try_into()
3383 .map_err(|_| StoreError::Custom("Invalid flushed_upto bytes".to_string()))?;
3384 Ok(BlockNumber::from_le_bytes(arr))
3385}
3386
3387fn mutate_block_buffer(
3390 buffer: &Arc<RwLock<Arc<BlockDataBuffer>>>,
3391 f: impl FnOnce(&mut BlockDataBuffer),
3392) -> Result<(), StoreError> {
3393 let mut new_buf = (*buffer.read().map_err(|_| StoreError::LockError)?.clone()).clone();
3394 f(&mut new_buf);
3395 *buffer.write().map_err(|_| StoreError::LockError)? = Arc::new(new_buf);
3396 Ok(())
3397}
3398
3399const DEFAULT_PERSIST_CHANNEL_CAPACITY: usize = 2;
3401
3402struct BlockPersist {
3407 blocks: Vec<(Block, Vec<Receipt>)>,
3408 codes: Vec<(H256, Code)>,
3409 parent_state_root: H256,
3410 child_state_root: H256,
3411 account_updates: TrieNodesUpdate,
3412 storage_updates: Vec<(H256, TrieNodesUpdate)>,
3413 wait_for_flush: bool,
3414 ack: std::sync::mpsc::SyncSender<Result<(), StoreError>>,
3415}
3416
3417enum PersistMessage {
3421 Block(BlockPersist),
3422 Ping(std::sync::mpsc::SyncSender<Result<(), StoreError>>),
3423}
3424
3425fn write_block_data(
3430 tx: &mut dyn StorageWriteBatch,
3431 number: BlockNumber,
3432 hash: BlockHash,
3433 header: &BlockHeader,
3434 body: &BlockBody,
3435) -> Result<(), StoreError> {
3436 let hash_key = hash.encode_to_vec();
3437 tx.put(
3438 HEADERS,
3439 &hash_key,
3440 BlockHeaderRLP::from(header.clone()).bytes(),
3441 )?;
3442 tx.put(
3443 BODIES,
3444 &hash_key,
3445 BlockBodyRLP::from_bytes(body.encode_to_vec()).bytes(),
3446 )?;
3447 tx.put(BLOCK_NUMBERS, &hash_key, &number.to_le_bytes())?;
3448 for (index, transaction) in body.transactions.iter().enumerate() {
3449 tx.merge(
3450 TRANSACTION_LOCATIONS,
3451 transaction.hash(&NativeCrypto).as_bytes(),
3452 &encode_tx_location_operand(number, hash, index as u64),
3453 )?;
3454 }
3455 Ok(())
3456}
3457
3458fn flush_block_data(
3461 backend: &dyn StorageBackend,
3462 buffer: &Arc<RwLock<Arc<BlockDataBuffer>>>,
3463) -> Result<(), StoreError> {
3464 let snapshot = buffer.read().map_err(|_| StoreError::LockError)?.clone();
3465 let to_flush = snapshot.flushable();
3466 if to_flush.is_empty() {
3467 return Ok(());
3468 }
3469 let hashes: Vec<_> = to_flush.iter().map(|b| b.header.hash()).collect();
3470 let codes = snapshot.codes_for(&hashes);
3471 let mut max_number = snapshot.flushed_upto();
3472
3473 let mut tx = backend.begin_write()?;
3474 for b in &to_flush {
3475 let hash = b.header.hash();
3476 write_block_data(tx.as_mut(), b.number, hash, &b.header, &b.body)?;
3477 for (index, receipt) in b.receipts.iter().enumerate() {
3478 tx.put(
3479 RECEIPTS_V2,
3480 &receipt_key(&hash, index as u64),
3481 &receipt.encode_to_vec(),
3482 )?;
3483 }
3484 max_number = max_number.max(b.number);
3485 }
3486 for (code_hash, code) in codes {
3487 let buf = encode_code(&code);
3488 tx.put(ACCOUNT_CODES, code_hash.as_ref(), &buf)?;
3489 tx.put(
3490 ACCOUNT_CODE_METADATA,
3491 code_hash.as_ref(),
3492 &(code.len() as u64).to_be_bytes(),
3493 )?;
3494 }
3495 write_flushed_upto(tx.as_mut(), max_number)?;
3496 tx.commit()?;
3497
3498 mutate_block_buffer(buffer, |b| b.evict_flushed(max_number))
3500}
3501
3502type TrieNodesUpdate = Vec<(Nibbles, Vec<u8>)>;
3503
3504#[derive(Debug, Default)]
3510struct PendingTrieRoots {
3511 count: AtomicUsize,
3513 roots: Mutex<HashSet<H256>>,
3514 ready: Condvar,
3515}
3516
3517impl PendingTrieRoots {
3518 fn register(&self, root: H256) -> Result<(), StoreError> {
3522 let mut roots = self.roots.lock().map_err(|_| StoreError::LockError)?;
3523 if roots.insert(root) {
3524 self.count.fetch_add(1, Ordering::Release);
3525 }
3526 Ok(())
3527 }
3528
3529 fn clear(&self, root: H256) {
3534 let Ok(mut roots) = self.roots.lock() else {
3535 return;
3536 };
3537 if roots.remove(&root) {
3538 self.count.fetch_sub(1, Ordering::Release);
3539 self.ready.notify_all();
3540 }
3541 }
3542
3543 fn wait_until_ready(&self, root: H256) -> Result<(), StoreError> {
3546 if self.count.load(Ordering::Acquire) == 0 {
3547 return Ok(());
3548 }
3549 let mut roots = self.roots.lock().map_err(|_| StoreError::LockError)?;
3550 while roots.contains(&root) {
3551 roots = self.ready.wait(roots).map_err(|_| StoreError::LockError)?;
3552 }
3553 Ok(())
3554 }
3555}
3556
3557fn apply_trie_phase1(
3561 trie_cache: &Arc<RwLock<Arc<TrieLayerCache>>>,
3562 pending_roots: &PendingTrieRoots,
3563 parent_state_root: H256,
3564 child_state_root: H256,
3565 account_updates: TrieNodesUpdate,
3566 storage_updates: Vec<(H256, TrieNodesUpdate)>,
3567) -> Result<(), StoreError> {
3568 let build: Result<(), StoreError> = (|| {
3569 let new_layer = storage_updates
3570 .into_iter()
3571 .flat_map(|(account_hash, nodes)| {
3572 nodes
3573 .into_iter()
3574 .map(move |(path, node)| (apply_prefix(Some(account_hash), path), node))
3575 })
3576 .chain(account_updates)
3577 .collect();
3578 let trie = trie_cache
3579 .read()
3580 .map_err(|_| StoreError::LockError)?
3581 .clone();
3582 let mut trie_mut = (*trie).clone();
3583 trie_mut.put_batch(parent_state_root, child_state_root, new_layer);
3584 *trie_cache.write().map_err(|_| StoreError::LockError)? = Arc::new(trie_mut);
3585 Ok(())
3586 })();
3587 pending_roots.clear(child_state_root);
3592 build
3593}
3594
3595fn commit_trie_if_due(
3599 backend: &dyn StorageBackend,
3600 trie_cache: &Arc<RwLock<Arc<TrieLayerCache>>>,
3601 fkv_ctl: &SyncSender<FKVGeneratorControlMessage>,
3602 parent_state_root: H256,
3603 is_batch: bool,
3604) -> Result<(), StoreError> {
3605 let trie = trie_cache
3606 .read()
3607 .map_err(|_| StoreError::LockError)?
3608 .clone();
3609 let commitable = if is_batch {
3611 trie.get_commitable_with_threshold(parent_state_root, BATCH_COMMIT_THRESHOLD)
3612 } else {
3613 trie.get_commitable(parent_state_root)
3614 };
3615 let Some(root) = commitable else {
3616 return Ok(());
3618 };
3619 let _ = fkv_ctl.send(FKVGeneratorControlMessage::Stop);
3622
3623 let mut trie_mut = (*trie).clone();
3625
3626 let last_written = backend
3627 .begin_read()?
3628 .get(MISC_VALUES, "last_written".as_bytes())?
3629 .unwrap_or_default();
3630
3631 let mut write_tx = backend.begin_write()?;
3632
3633 let nodes = trie_mut.commit(root).unwrap_or_default();
3638 let mut result = Ok(());
3639 for (key, value) in nodes {
3640 let is_leaf = key.len() == 65 || key.len() == 131;
3641 let is_account = key.len() <= 65;
3642
3643 if is_leaf && key > last_written {
3644 continue;
3645 }
3646 let table = if is_leaf {
3647 if is_account {
3648 &ACCOUNT_FLATKEYVALUE
3649 } else {
3650 &STORAGE_FLATKEYVALUE
3651 }
3652 } else if is_account {
3653 &ACCOUNT_TRIE_NODES
3654 } else {
3655 &STORAGE_TRIE_NODES
3656 };
3657 if value.is_empty() {
3658 result = write_tx.delete(table, &key);
3659 } else {
3660 result = write_tx.put(table, &key, &value);
3661 }
3662 if result.is_err() {
3663 break;
3664 }
3665 }
3666 if result.is_ok() {
3667 result = write_tx.commit();
3668 }
3669 let _ = fkv_ctl.send(FKVGeneratorControlMessage::Continue);
3671 result?;
3672 *trie_cache.write().map_err(|_| StoreError::LockError)? = Arc::new(trie_mut);
3674 Ok(())
3675}
3676
3677fn flatkeyvalue_generator(
3680 backend: &Arc<dyn StorageBackend>,
3681 last_computed_fkv: &RwLock<Vec<u8>>,
3682 control_rx: &std::sync::mpsc::Receiver<FKVGeneratorControlMessage>,
3683) -> Result<(), StoreError> {
3684 info!("Generation of FlatKeyValue started.");
3685 let initial_last_written = backend
3686 .begin_read()?
3687 .get(MISC_VALUES, "last_written".as_bytes())?
3688 .unwrap_or_default();
3689
3690 if initial_last_written.is_empty() {
3691 backend.clear_table(ACCOUNT_FLATKEYVALUE)?;
3693 backend.clear_table(STORAGE_FLATKEYVALUE)?;
3694 } else if initial_last_written == [0xff] {
3695 info!("FlatKeyValue already generated. Skipping.");
3697 return Ok(());
3698 }
3699
3700 loop {
3701 let read_tx = backend.begin_read()?;
3704 let root = read_tx
3705 .get(ACCOUNT_TRIE_NODES, &[])?
3706 .ok_or(StoreError::MissingLatestBlockNumber)?;
3707 let root: Node = ethrex_trie::Node::decode(&root)?;
3708 let state_root = root.compute_hash(&NativeCrypto).finalize(&NativeCrypto);
3709
3710 let last_written = read_tx
3711 .get(MISC_VALUES, "last_written".as_bytes())?
3712 .unwrap_or_default();
3713 let last_written_account = last_written
3714 .get(0..64)
3715 .map(|v| Nibbles::from_hex(v.to_vec()))
3716 .unwrap_or_default();
3717 let mut last_written_storage = last_written
3718 .get(66..130)
3719 .map(|v| Nibbles::from_hex(v.to_vec()))
3720 .unwrap_or_default();
3721
3722 debug!("Starting FlatKeyValue loop pivot={last_written:?} SR={state_root:x}");
3723
3724 let mut ctr = 0;
3725 let mut write_txn = backend.begin_write()?;
3726 let mut iter = Trie::open(
3727 Box::new(BackendTrieDB::new_for_accounts_with_view(
3728 backend.clone(),
3729 read_tx.clone(),
3730 last_written.clone(),
3731 )?),
3732 state_root,
3733 )
3734 .into_iter();
3735 if last_written_account > Nibbles::default() {
3736 iter.advance(last_written_account.to_bytes())?;
3737 }
3738 let res = iter.try_for_each(|(path, node)| -> Result<(), StoreError> {
3739 let Node::Leaf(node) = node else {
3740 return Ok(());
3741 };
3742 let account_state = AccountState::decode(&node.value)?;
3743 let account_hash = H256::from_slice(&path.to_bytes());
3744 write_txn.put(MISC_VALUES, "last_written".as_bytes(), path.as_ref())?;
3745 write_txn.put(ACCOUNT_FLATKEYVALUE, path.as_ref(), &node.value)?;
3746 ctr += 1;
3747 if ctr > 10_000 {
3748 write_txn.commit()?;
3749 write_txn = backend.begin_write()?;
3750 *last_computed_fkv
3751 .write()
3752 .map_err(|_| StoreError::LockError)? = path.as_ref().to_vec();
3753 ctr = 0;
3754 }
3755
3756 let mut iter_inner = Trie::open(
3757 Box::new(BackendTrieDB::new_for_account_storage_with_view(
3758 backend.clone(),
3759 read_tx.clone(),
3760 account_hash,
3761 path.as_ref().to_vec(),
3762 )?),
3763 account_state.storage_root,
3764 )
3765 .into_iter();
3766 if last_written_storage > Nibbles::default() {
3767 iter_inner.advance(last_written_storage.to_bytes())?;
3768 last_written_storage = Nibbles::default();
3769 }
3770 iter_inner.try_for_each(|(path, node)| -> Result<(), StoreError> {
3771 let Node::Leaf(node) = node else {
3772 return Ok(());
3773 };
3774 let key = apply_prefix(Some(account_hash), path);
3775 write_txn.put(MISC_VALUES, "last_written".as_bytes(), key.as_ref())?;
3776 write_txn.put(STORAGE_FLATKEYVALUE, key.as_ref(), &node.value)?;
3777 ctr += 1;
3778 if ctr > 10_000 {
3779 write_txn.commit()?;
3780 write_txn = backend.begin_write()?;
3781 *last_computed_fkv
3782 .write()
3783 .map_err(|_| StoreError::LockError)? = key.into_vec();
3784 ctr = 0;
3785 }
3786 fkv_check_for_stop_msg(control_rx)?;
3787 Ok(())
3788 })?;
3789 fkv_check_for_stop_msg(control_rx)?;
3790 Ok(())
3791 });
3792 match res {
3793 Err(StoreError::PivotChanged) => {
3794 match control_rx.recv() {
3795 Ok(FKVGeneratorControlMessage::Continue) => {}
3796 Ok(FKVGeneratorControlMessage::Stop) => {
3797 return Err(StoreError::Custom("Unexpected Stop message".to_string()));
3798 }
3799 Err(std::sync::mpsc::RecvError) => {
3801 info!("Store closed, stopping FlatKeyValue generation.");
3802 return Ok(());
3803 }
3804 }
3805 }
3806 Err(err) => return Err(err),
3807 Ok(()) => {
3808 write_txn.put(MISC_VALUES, "last_written".as_bytes(), &[0xff])?;
3809 write_txn.commit()?;
3810 *last_computed_fkv
3811 .write()
3812 .map_err(|_| StoreError::LockError)? = vec![0xff; 131];
3813 info!("FlatKeyValue generation finished.");
3814 return Ok(());
3815 }
3816 };
3817 }
3818}
3819
3820fn fkv_check_for_stop_msg(
3821 control_rx: &std::sync::mpsc::Receiver<FKVGeneratorControlMessage>,
3822) -> Result<(), StoreError> {
3823 match control_rx.try_recv() {
3824 Ok(FKVGeneratorControlMessage::Stop) | Err(TryRecvError::Disconnected) => {
3825 return Err(StoreError::PivotChanged);
3826 }
3827 Ok(FKVGeneratorControlMessage::Continue) => {
3828 return Err(StoreError::Custom(
3829 "Unexpected Continue message".to_string(),
3830 ));
3831 }
3832 Err(TryRecvError::Empty) => {}
3833 }
3834 Ok(())
3835}
3836
3837fn state_trie_locked_backend(
3838 backend: &dyn StorageBackend,
3839 last_written: Vec<u8>,
3840) -> Result<BackendTrieDBLocked, StoreError> {
3841 BackendTrieDBLocked::new(backend, last_written)
3843}
3844
3845pub struct AccountProof {
3846 pub proof: Vec<NodeRLP>,
3847 pub account: AccountState,
3848 pub storage_proof: Vec<StorageSlotProof>,
3849}
3850
3851pub struct StorageSlotProof {
3852 pub proof: Vec<NodeRLP>,
3853 pub key: H256,
3854 pub value: U256,
3855}
3856
3857pub struct AncestorIterator {
3858 store: Store,
3859 next_hash: BlockHash,
3860}
3861
3862impl Iterator for AncestorIterator {
3863 type Item = Result<(BlockHash, BlockHeader), StoreError>;
3864
3865 fn next(&mut self) -> Option<Self::Item> {
3866 let next_hash = self.next_hash;
3867 match self.store.get_block_header_by_hash(next_hash) {
3871 Ok(Some(header)) => {
3872 let ret_hash = self.next_hash;
3873 self.next_hash = header.parent_hash;
3874 Some(Ok((ret_hash, header)))
3875 }
3876 Ok(None) => None,
3877 Err(e) => Some(Err(e)),
3878 }
3879 }
3880}
3881
3882pub fn hash_address(address: &Address) -> Vec<u8> {
3883 keccak_hash(address.to_fixed_bytes()).to_vec()
3884}
3885
3886fn hash_address_fixed(address: &Address) -> H256 {
3887 keccak(address.to_fixed_bytes())
3888}
3889
3890pub fn hash_key(key: &H256) -> Vec<u8> {
3891 keccak_hash(key.to_fixed_bytes()).to_vec()
3892}
3893
3894pub fn hash_key_fixed(key: &H256) -> [u8; 32] {
3895 keccak_hash(key.to_fixed_bytes())
3896}
3897
3898fn chain_data_key(index: ChainDataIndex) -> Vec<u8> {
3899 (index as u8).encode_to_vec()
3900}
3901
3902fn snap_state_key(index: SnapStateIndex) -> Vec<u8> {
3903 (index as u8).encode_to_vec()
3904}
3905
3906pub fn receipt_key(block_hash: &BlockHash, index: u64) -> Vec<u8> {
3908 let mut key = Vec::with_capacity(40);
3909 key.extend_from_slice(block_hash.as_bytes());
3910 key.extend_from_slice(&index.to_be_bytes());
3911 key
3912}
3913
3914fn encode_code(code: &Code) -> Vec<u8> {
3915 let mut buf =
3916 Vec::with_capacity(6 + code.len() + std::mem::size_of_val::<[u32]>(&code.jump_targets));
3917 code.code().encode(&mut buf);
3918 code.jump_targets.to_vec().encode(&mut buf);
3921 buf
3922}
3923
3924#[derive(Debug, Default, Clone)]
3925struct LatestBlockHeaderCache {
3926 current: Arc<Mutex<Arc<BlockHeader>>>,
3927}
3928
3929impl LatestBlockHeaderCache {
3930 pub fn get(&self) -> Arc<BlockHeader> {
3931 self.current.lock().expect("poisoned mutex").clone()
3932 }
3933
3934 pub fn update(&self, header: BlockHeader) {
3935 let new = Arc::new(header);
3936 *self.current.lock().expect("poisoned mutex") = new;
3937 }
3938}
3939
3940#[derive(Debug, Serialize, Deserialize)]
3941pub struct StoreMetadata {
3942 pub schema_version: u64,
3943}
3944
3945impl StoreMetadata {
3946 pub fn new(schema_version: u64) -> Self {
3947 Self { schema_version }
3948 }
3949}
3950
3951fn read_store_schema_version(path: &Path) -> Result<Option<u64>, StoreError> {
3956 let metadata_path = path.join(STORE_METADATA_FILENAME);
3957 if !metadata_path.exists() {
3958 return Ok(None);
3959 }
3960 if !metadata_path.is_file() {
3961 return Err(StoreError::Custom(
3962 "store schema path exists but is not a file".to_string(),
3963 ));
3964 }
3965 let file_contents = std::fs::read_to_string(metadata_path)?;
3966 let metadata: StoreMetadata = serde_json::from_str(&file_contents)?;
3967 Ok(Some(metadata.schema_version))
3968}
3969
3970fn init_metadata_file(parent_path: &Path) -> Result<(), StoreError> {
3971 std::fs::create_dir_all(parent_path)?;
3972
3973 let metadata_path = parent_path.join(STORE_METADATA_FILENAME);
3974 let metadata = StoreMetadata::new(STORE_SCHEMA_VERSION);
3975 let serialized_metadata = serde_json::to_string_pretty(&metadata)?;
3976 let mut new_file = std::fs::File::create_new(metadata_path)?;
3977 new_file.write_all(serialized_metadata.as_bytes())?;
3978 Ok(())
3979}
3980
3981fn dir_contains_legacy_db(path: &Path) -> Result<bool, StoreError> {
3993 if path.join("CURRENT").is_file() {
3997 return Ok(true);
3998 }
3999 for entry in std::fs::read_dir(path)? {
4003 let entry = entry?;
4004 if !entry.file_type()?.is_file() {
4005 continue;
4006 }
4007 if entry.file_name().to_string_lossy().starts_with("MANIFEST-") {
4008 return Ok(true);
4009 }
4010 }
4011 Ok(false)
4012}
4013
4014pub fn has_valid_db(path: &Path) -> bool {
4018 let metadata_path = path.join(STORE_METADATA_FILENAME);
4019 if !metadata_path.is_file() {
4020 return false;
4021 }
4022 let Ok(contents) = std::fs::read_to_string(&metadata_path) else {
4023 return false;
4024 };
4025 let Ok(metadata) = serde_json::from_str::<StoreMetadata>(&contents) else {
4026 return false;
4027 };
4028 metadata.schema_version >= 1 && metadata.schema_version <= STORE_SCHEMA_VERSION
4029}
4030
4031pub fn read_chain_id_from_db(path: &Path) -> Option<u64> {
4040 if !has_valid_db(path) {
4041 return None;
4042 }
4043 #[cfg(feature = "rocksdb")]
4044 {
4045 let backend = match RocksDBBackend::open(path, DEFAULT_ROCKSDB_BLOCK_CACHE_SIZE_BYTES) {
4048 Ok(backend) => backend,
4049 Err(e) => {
4050 warn!("Failed to open RocksDB at {path:?} to read chain ID: {e}");
4051 return None;
4052 }
4053 };
4054 let read = match backend.begin_read() {
4055 Ok(read) => read,
4056 Err(e) => {
4057 warn!("Failed to begin read transaction at {path:?}: {e}");
4058 return None;
4059 }
4060 };
4061 let key = chain_data_key(ChainDataIndex::ChainConfig);
4062 let bytes = match read.get(CHAIN_DATA, &key) {
4063 Ok(Some(bytes)) => bytes,
4064 Ok(None) => {
4065 warn!("Chain config entry not found in database at {path:?}");
4066 return None;
4067 }
4068 Err(e) => {
4069 warn!("Failed to read chain config from database at {path:?}: {e}");
4070 return None;
4071 }
4072 };
4073 #[derive(serde::Deserialize)]
4078 #[serde(rename_all = "camelCase")]
4079 struct ChainIdOnly {
4080 chain_id: u64,
4081 }
4082 match serde_json::from_slice::<ChainIdOnly>(&bytes) {
4083 Ok(partial) => Some(partial.chain_id),
4084 Err(e) => {
4085 warn!("Failed to deserialize chain ID from database at {path:?}: {e}");
4086 None
4087 }
4088 }
4089 }
4090 #[cfg(not(feature = "rocksdb"))]
4091 {
4092 let _ = path;
4093 None
4094 }
4095}
4096
4097#[cfg(test)]
4098mod merge_tests {
4099 use super::*;
4100
4101 fn h256(b: u8) -> H256 {
4102 H256::from_low_u64_be(b as u64)
4103 }
4104
4105 fn op(bn: BlockNumber, bh: H256, idx: Index) -> Vec<u8> {
4106 encode_tx_location_operand(bn, bh, idx)
4107 }
4108
4109 fn decode(v: &[u8]) -> Vec<(BlockNumber, BlockHash, Index)> {
4110 <Vec<(BlockNumber, BlockHash, Index)>>::decode(v).unwrap()
4111 }
4112
4113 #[test]
4114 fn single_operand_on_empty_base() {
4115 let out = tx_locations_merge(None, vec![op(100, h256(0x10), 0)]).unwrap();
4116 assert_eq!(decode(&out), vec![(100, h256(0x10), 0)]);
4117 }
4118
4119 #[test]
4120 fn operand_appended_to_existing_base() {
4121 let base = vec![(100u64, h256(0x10), 0u64)].encode_to_vec();
4122 let out = tx_locations_merge(Some(&base), vec![op(101, h256(0x11), 5)]).unwrap();
4123 let mut got = decode(&out);
4124 got.sort();
4125 let mut want = vec![(100, h256(0x10), 0), (101, h256(0x11), 5)];
4126 want.sort();
4127 assert_eq!(got, want);
4128 }
4129
4130 #[test]
4131 fn multiple_operands_combined() {
4132 let out = tx_locations_merge(
4133 None,
4134 vec![
4135 op(100, h256(0x10), 0),
4136 op(100, h256(0x11), 1),
4137 op(101, h256(0x12), 2),
4138 ],
4139 )
4140 .unwrap();
4141 assert_eq!(decode(&out).len(), 3);
4142 }
4143
4144 #[test]
4145 fn same_block_hash_is_deduped() {
4146 let out =
4148 tx_locations_merge(None, vec![op(100, h256(0x10), 0), op(100, h256(0x10), 7)]).unwrap();
4149 assert_eq!(decode(&out), vec![(100, h256(0x10), 7)]);
4150 }
4151
4152 #[test]
4153 fn malformed_operand_aborts_merge() {
4154 let out = tx_locations_merge(None, vec![vec![0xff, 0xff], op(100, h256(0x10), 0)]);
4157 assert!(out.is_none(), "merge must abort on a malformed operand");
4158 }
4159
4160 #[test]
4161 fn malformed_base_value_aborts_merge() {
4162 let out = tx_locations_merge(Some(&[0xff, 0xff]), vec![op(100, h256(0x10), 0)]);
4163 assert!(out.is_none(), "merge must abort on a corrupt base value");
4164 }
4165
4166 #[test]
4173 fn partial_merge_result_is_a_valid_operand() {
4174 let partial =
4176 tx_locations_merge(None, vec![op(100, h256(0x10), 0), op(101, h256(0x11), 1)]).unwrap();
4177
4178 let base = vec![(99u64, h256(0x09), 9u64)].encode_to_vec();
4182 let out = tx_locations_merge(Some(&base), vec![partial]).unwrap();
4183
4184 let mut got = decode(&out);
4185 got.sort();
4186 let mut want = vec![
4187 (99, h256(0x09), 9),
4188 (100, h256(0x10), 0),
4189 (101, h256(0x11), 1),
4190 ];
4191 want.sort();
4192 assert_eq!(
4193 got, want,
4194 "no entries may be lost when re-merging a partial result"
4195 );
4196 }
4197
4198 #[test]
4201 fn operand_encoding_matches_value_encoding() {
4202 let operand = op(100, h256(0x10), 3);
4203 assert_eq!(decode(&operand), vec![(100, h256(0x10), 3)]);
4205 }
4206
4207 #[test]
4209 fn chained_partial_merges() {
4210 let p1 = tx_locations_merge(None, vec![op(1, h256(0x01), 0)]).unwrap();
4211 let p2 = tx_locations_merge(None, vec![p1, op(2, h256(0x02), 0)]).unwrap();
4212 let p3 = tx_locations_merge(None, vec![p2, op(3, h256(0x03), 0)]).unwrap();
4213 let out = tx_locations_merge(None, vec![p3]).unwrap();
4214 assert_eq!(decode(&out).len(), 3);
4215 }
4216}
4217
4218#[cfg(test)]
4219mod datadir_tests {
4220 use super::*;
4221 use std::fs;
4222
4223 #[test]
4224 fn empty_dir_has_no_existing_db() {
4225 let dir = tempfile::tempdir().unwrap();
4226 assert!(!dir_contains_legacy_db(dir.path()).unwrap());
4227 }
4228
4229 #[test]
4230 fn dir_with_only_unrelated_files_has_no_existing_db() {
4231 let dir = tempfile::tempdir().unwrap();
4234 fs::write(dir.path().join("jwt.hex"), "0xdeadbeef").unwrap();
4235 fs::write(dir.path().join("LOG"), "noise").unwrap();
4236 assert!(!dir_contains_legacy_db(dir.path()).unwrap());
4237 }
4238
4239 #[test]
4240 fn dir_with_rocksdb_markers_has_existing_db() {
4241 let dir = tempfile::tempdir().unwrap();
4243 fs::write(dir.path().join("CURRENT"), "MANIFEST-000001\n").unwrap();
4244 assert!(dir_contains_legacy_db(dir.path()).unwrap());
4245
4246 let dir2 = tempfile::tempdir().unwrap();
4247 fs::write(dir2.path().join("MANIFEST-000007"), "x").unwrap();
4248 assert!(dir_contains_legacy_db(dir2.path()).unwrap());
4249 }
4250
4251 #[test]
4252 fn dir_with_marker_named_subdirectories_has_no_existing_db() {
4253 let dir = tempfile::tempdir().unwrap();
4256 fs::create_dir(dir.path().join("CURRENT")).unwrap();
4257 fs::create_dir(dir.path().join("MANIFEST-000001")).unwrap();
4258 assert!(!dir_contains_legacy_db(dir.path()).unwrap());
4259 }
4260}