1#![feature(
44 const_block_items,
45 const_convert,
46 const_trait_impl,
47 default_field_values,
48 iter_collect_into,
49 maybe_uninit_as_bytes,
50 maybe_uninit_fill
51)]
52
53mod page_group;
54pub mod storage_backend;
55mod storage_backend_adapter;
56#[cfg(test)]
57mod test_utils;
58#[cfg(test)]
59mod tests;
60
61use crate::page_group::temporary::StorageItemTemporary;
62use crate::page_group::temporary::block::StorageItemTemporaryBlock;
63use crate::page_group::temporary::segment_headers::StorageItemTemporarySegmentHeaders;
64use crate::page_group::temporary::super_segment_headers::StorageItemTemporarySuperSegmentHeaders;
65use crate::storage_backend::ClientDatabaseStorageBackend;
66use crate::storage_backend_adapter::{
67 StorageBackendAdapter, StorageItemHandlerArg, StorageItemHandlers, WriteLocation,
68};
69use ab_client_api::{
70 BeaconChainInfo, BeaconChainInfoWrite, BlockDetails, ChainInfo, ChainInfoWrite,
71 ContractSlotState, PersistBlockError, PersistSegmentHeadersError,
72 PersistSuperSegmentHeadersError, ReadBlockError, ShardSegmentRoot, ShardSegmentRootsError,
73};
74use ab_core_primitives::block::body::BeaconChainBody;
75use ab_core_primitives::block::body::owned::{GenericOwnedBlockBody, OwnedBeaconChainBody};
76use ab_core_primitives::block::header::GenericBlockHeader;
77use ab_core_primitives::block::header::owned::GenericOwnedBlockHeader;
78use ab_core_primitives::block::owned::{GenericOwnedBlock, OwnedBeaconChainBlock};
79use ab_core_primitives::block::{BlockNumber, BlockRoot, GenericBlock};
80use ab_core_primitives::segments::{
81 LocalSegmentIndex, SegmentHeader, SegmentIndex, SuperSegmentHeader, SuperSegmentIndex,
82};
83use ab_core_primitives::shard::RealShardKind;
84use ab_core_primitives::trees::BlockMerkleMountainRange;
85use ab_io_type::trivial_type::TrivialType;
86use async_lock::{
87 RwLock as AsyncRwLock, RwLockUpgradableReadGuard, RwLockWriteGuard as AsyncRwLockWriteGuard,
88};
89use rand::rngs::SysError;
90use replace_with::replace_with_or_abort;
91use smallvec::{SmallVec, smallvec};
92use std::any::Any;
93use std::collections::{HashMap, VecDeque};
94use std::hash::{BuildHasherDefault, Hasher};
95use std::num::{NonZeroU32, NonZeroUsize};
96use std::ops::Deref;
97use std::{fmt, io};
98use tracing::error;
99use triomphe::Arc;
100
101#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
103#[repr(C)]
104pub struct DatabaseId([u8; 32]);
105
106impl Deref for DatabaseId {
107 type Target = [u8; 32];
108
109 #[inline(always)]
110 fn deref(&self) -> &Self::Target {
111 &self.0
112 }
113}
114
115impl AsRef<[u8]> for DatabaseId {
116 #[inline(always)]
117 fn as_ref(&self) -> &[u8] {
118 &self.0
119 }
120}
121
122impl DatabaseId {
123 #[inline(always)]
124 pub const fn new(bytes: [u8; 32]) -> Self {
125 Self(bytes)
126 }
127}
128
129#[derive(Default)]
130struct BlockRootHasher(u64);
131
132impl Hasher for BlockRootHasher {
133 #[inline(always)]
134 fn finish(&self) -> u64 {
135 self.0
136 }
137
138 #[inline(always)]
139 fn write(&mut self, bytes: &[u8]) {
140 let Some(state) = bytes.as_chunks().0.first().copied().map(u64::from_le_bytes) else {
141 return;
142 };
143
144 self.0 = state;
145 }
146}
147
148#[derive(Debug)]
149pub struct GenesisBlockBuilderResult<Block> {
150 pub block: Block,
152 pub system_contract_states: Arc<[ContractSlotState]>,
154}
155
156#[derive(Debug, Copy, Clone)]
189#[expect(unevaluated_default_field_value, reason = "Intentional")]
190pub struct ClientDatabaseOptions<GBB, StorageBackend> {
191 pub write_buffer_size: usize = 5,
199 pub block_confirmation_depth: BlockNumber,
208 pub soft_confirmation_depth: BlockNumber = BlockNumber::from(3),
225 pub max_fork_tips: NonZeroUsize = NonZeroUsize::new(3).expect("Not zero; qed"),
236 pub max_fork_tip_distance: BlockNumber = BlockNumber::from(5),
251 pub genesis_block_builder: GBB,
254 pub storage_backend: StorageBackend,
256}
257
258#[derive(Debug, Copy, Clone)]
260pub struct ClientDatabaseFormatOptions {
261 pub page_group_size: NonZeroU32,
281 pub force: bool,
285}
286
287#[derive(Debug, thiserror::Error)]
288pub enum ClientDatabaseError {
289 #[error("Invalid block confirmation depth, it must be at least 2")]
294 InvalidBlockConfirmationDepth,
295 #[error("Invalid soft confirmation depth, it must be smaller than block confirmation depth")]
297 InvalidSoftConfirmationDepth,
298 #[error("Storage backend has canceled read request")]
300 ReadRequestCancelled,
301 #[error("Storage backend read error: {error}")]
303 ReadError {
304 error: io::Error,
306 },
307 #[error("Unsupported database version: {database_version}")]
309 UnsupportedDatabaseVersion {
310 database_version: u8,
312 },
313 #[error("Page group size is too small ({page_group_size}), must be at least two pages")]
315 PageGroupSizeTooSmall {
316 page_group_size: u32,
318 },
319 #[error(
321 "Page group size is too large ({page_group_size}), storage backend only has {num_pages} \
322 pages"
323 )]
324 PageGroupSizeTooLarge {
325 page_group_size: u32,
327 num_pages: u32,
329 },
330 #[error(
332 "Unexpected sequence number {actual} at page offset {page_offset} (expected \
333 {expected})"
334 )]
335 UnexpectedSequenceNumber {
336 actual: u64,
338 expected: u64,
340 page_offset: u32,
342 },
343 #[error("Unexpected storage item at offset {page_offset}: {storage_item:?}")]
345 UnexpectedStorageItem {
346 storage_item: Box<dyn fmt::Debug + Send + Sync>,
348 page_offset: u32,
350 },
351 #[error("Invalid block at offset {page_offset}")]
353 InvalidBlock {
354 page_offset: u32,
356 },
357 #[error("Invalid segment headers at offset {page_offset}")]
359 InvalidSegmentHeaders {
360 page_offset: u32,
362 },
363 #[error("Failed to adjust ancestor block forks")]
365 FailedToAdjustAncestorBlockForks,
366 #[error("Database is not formatted yet")]
368 Unformatted,
369 #[error("Non-permanent first page group")]
371 NonPermanentFirstPageGroup,
372}
373
374#[derive(Debug, thiserror::Error)]
376pub enum ClientDatabaseFormatError {
377 #[error("Storage backend has canceled read request")]
379 ReadRequestCancelled,
380 #[error("Storage backend read error: {error}")]
382 ReadError {
383 error: io::Error,
385 },
386 #[error("Failed to generate database id")]
388 FailedToGenerateDatabaseId {
389 #[from]
391 error: SysError,
392 },
393 #[error("Page group size is too small ({page_group_size}), must be at least two pages")]
395 PageGroupSizeTooSmall {
396 page_group_size: u32,
398 },
399 #[error(
401 "Page group size is too large ({page_group_size}), storage backend only has {num_pages} \
402 pages"
403 )]
404 PageGroupSizeTooLarge {
405 page_group_size: u32,
407 num_pages: u32,
409 },
410 #[error("Database is already formatted yet")]
412 AlreadyFormatted,
413 #[error("Storage backend has canceled a writing request")]
415 WriteRequestCancelled,
416 #[error("Storage item write error")]
418 StorageItemWriteError {
419 #[from]
421 error: io::Error,
422 },
423}
424
425#[derive(Debug, Copy, Clone)]
426struct ForkTip {
427 number: BlockNumber,
428 root: BlockRoot,
429}
430
431#[derive(Debug, Copy, Clone)]
433enum AncestorBlockForksWalk {
434 UntilCanonical,
437 UpToBlockOffset { max_block_offset: usize },
440}
441
442enum FullBlock<'a, Block>
443where
444 Block: GenericOwnedBlock,
445{
446 InMemory(&'a Block),
447 Persisted {
448 header: &'a Block::Header,
449 write_location: WriteLocation,
450 },
451}
452
453#[derive(Debug)]
454struct BeaconChainBlockDetails {
455 shard_segment_roots: Arc<[ShardSegmentRoot]>,
457}
458
459impl BeaconChainBlockDetails {
460 fn from_body(body: &BeaconChainBody<'_>) -> Self {
461 let shard_segment_roots = body
462 .intermediate_shard_blocks()
463 .iter()
464 .flat_map(|intermediate_shard_block_info| {
465 let own_segments = intermediate_shard_block_info
466 .own_segments
467 .into_iter()
468 .flat_map({
469 let shard_index = intermediate_shard_block_info.header.prefix.shard_index;
470
471 move |own_segments| {
472 own_segments
473 .iter()
474 .map(move |(segment_index, &segment_root)| ShardSegmentRoot {
475 shard_index,
476 segment_index,
477 segment_root,
478 })
479 }
480 });
481 let child_shard_segment_roots = intermediate_shard_block_info
482 .leaf_shards_segments()
483 .flat_map(move |(_position, shard_index, own_segments)| {
484 own_segments
485 .iter()
486 .map(move |(segment_index, &segment_root)| ShardSegmentRoot {
487 shard_index,
488 segment_index,
489 segment_root,
490 })
491 });
492
493 own_segments.chain(child_shard_segment_roots)
494 })
495 .collect();
496
497 Self {
498 shard_segment_roots,
499 }
500 }
501}
502
503#[derive(Debug)]
511enum ClientDatabaseBlock<Block>
512where
513 Block: GenericOwnedBlock,
514{
515 InMemory {
517 block: Block,
518 block_details: BlockDetails,
519 beacon_chain_block_details: Option<BeaconChainBlockDetails>,
521 },
522 Persisted {
524 header: Block::Header,
525 block_details: BlockDetails,
526 beacon_chain_block_details: Option<BeaconChainBlockDetails>,
528 write_location: WriteLocation,
529 },
530 PersistedConfirmed {
532 header: Block::Header,
533 beacon_chain_block_details: Option<BeaconChainBlockDetails>,
535 write_location: WriteLocation,
536 },
537}
538
539impl<Block> ClientDatabaseBlock<Block>
540where
541 Block: GenericOwnedBlock,
542{
543 #[inline(always)]
544 fn header(&self) -> &Block::Header {
545 #[expect(
546 clippy::rest_pattern_accessible_field,
547 reason = "Do not need other fields"
548 )]
549 match self {
550 Self::InMemory { block, .. } => block.header(),
551 Self::Persisted { header, .. } | Self::PersistedConfirmed { header, .. } => header,
552 }
553 }
554
555 #[inline(always)]
556 fn full_block(&self) -> FullBlock<'_, Block> {
557 #[expect(
558 clippy::rest_pattern_accessible_field,
559 reason = "Do not need other fields"
560 )]
561 match self {
562 Self::InMemory { block, .. } => FullBlock::InMemory(block),
563 Self::Persisted {
564 header,
565 write_location,
566 ..
567 }
568 | Self::PersistedConfirmed {
569 header,
570 write_location,
571 ..
572 } => FullBlock::Persisted {
573 header,
574 write_location: *write_location,
575 },
576 }
577 }
578
579 #[inline(always)]
580 fn block_details(&self) -> Option<&BlockDetails> {
581 #[expect(
582 clippy::rest_pattern_accessible_field,
583 reason = "Do not need other fields"
584 )]
585 match self {
586 Self::InMemory { block_details, .. } | Self::Persisted { block_details, .. } => {
587 Some(block_details)
588 }
589 Self::PersistedConfirmed { .. } => None,
590 }
591 }
592
593 #[inline(always)]
594 fn beacon_chain_block_details(&self) -> Option<&BeaconChainBlockDetails> {
595 #[expect(
596 clippy::rest_pattern_accessible_field,
597 reason = "Do not need other fields"
598 )]
599 match self {
600 Self::InMemory {
601 beacon_chain_block_details,
602 ..
603 }
604 | Self::Persisted {
605 beacon_chain_block_details,
606 ..
607 }
608 | Self::PersistedConfirmed {
609 beacon_chain_block_details,
610 ..
611 } => beacon_chain_block_details.as_ref(),
612 }
613 }
614}
615
616#[derive(Debug)]
617struct StateData<Block>
618where
619 Block: GenericOwnedBlock,
620{
621 fork_tips: VecDeque<ForkTip>,
626 block_roots: HashMap<BlockRoot, BlockNumber, BuildHasherDefault<BlockRootHasher>>,
631 blocks: VecDeque<SmallVec<[ClientDatabaseBlock<Block>; 2]>>,
653}
654
655#[derive(Debug)]
656struct SegmentHeadersCache {
657 segment_headers_cache: Vec<SegmentHeader>,
658}
659
660impl SegmentHeadersCache {
661 #[inline(always)]
662 fn last_segment_header(&self) -> Option<SegmentHeader> {
663 self.segment_headers_cache.last().copied()
664 }
665
666 #[inline(always)]
667 fn max_local_segment_index(&self) -> Option<LocalSegmentIndex> {
668 self.segment_headers_cache
669 .last()
670 .map(|segment_header| segment_header.index.as_inner())
671 }
672
673 #[inline(always)]
674 fn get_segment_header(&self, local_segment_index: LocalSegmentIndex) -> Option<SegmentHeader> {
675 self.segment_headers_cache
676 .get(u64::from(local_segment_index) as usize)
677 .copied()
678 }
679
680 fn add_segment_headers(
682 &mut self,
683 mut segment_headers: Vec<SegmentHeader>,
684 ) -> Result<Vec<SegmentHeader>, PersistSegmentHeadersError> {
685 self.segment_headers_cache.reserve(segment_headers.len());
686
687 let mut maybe_last_local_segment_index = self.max_local_segment_index();
688
689 if let Some(last_segment_index) = maybe_last_local_segment_index {
690 segment_headers
692 .retain(|segment_header| segment_header.index.as_inner() > last_segment_index);
693 }
694
695 for segment_header in segment_headers.iter().copied() {
698 let local_segment_index = segment_header.index.as_inner();
699 if let Some(last_local_segment_index) = maybe_last_local_segment_index {
700 if local_segment_index != last_local_segment_index + LocalSegmentIndex::ONE {
701 return Err(PersistSegmentHeadersError::MustFollowLastSegmentIndex {
702 local_segment_index,
703 last_local_segment_index,
704 });
705 }
706
707 self.segment_headers_cache.push(segment_header);
708 maybe_last_local_segment_index.replace(local_segment_index);
709 } else {
710 if local_segment_index != LocalSegmentIndex::ZERO {
711 return Err(PersistSegmentHeadersError::FirstSegmentIndexZero {
712 local_segment_index,
713 });
714 }
715
716 self.segment_headers_cache.push(segment_header);
717 maybe_last_local_segment_index.replace(local_segment_index);
718 }
719 }
720
721 Ok(segment_headers)
722 }
723}
724
725#[derive(Debug)]
726struct SuperSegmentHeadersCache {
727 super_segment_headers_cache: Vec<SuperSegmentHeader>,
728}
729
730impl SuperSegmentHeadersCache {
731 #[inline(always)]
732 fn last_super_segment_header(&self) -> Option<SuperSegmentHeader> {
733 self.super_segment_headers_cache.last().copied()
734 }
735
736 #[inline]
737 fn previous_super_segment_header(
738 &self,
739 target_block_number: BlockNumber,
740 ) -> Option<SuperSegmentHeader> {
741 let block_number = target_block_number.checked_sub(BlockNumber::ONE)?;
742 let index = match self.super_segment_headers_cache.binary_search_by_key(
743 &block_number,
744 |super_segment_header| {
745 super_segment_header
746 .target_beacon_chain_block_number
747 .as_inner()
748 },
749 ) {
750 Ok(found_index) => found_index,
751 Err(insert_index) => insert_index.checked_sub(1)?,
752 };
753
754 self.super_segment_headers_cache.get(index).copied()
755 }
756
757 #[inline(always)]
758 fn get_super_segment_header(
759 &self,
760 local_segment_index: SuperSegmentIndex,
761 ) -> Option<SuperSegmentHeader> {
762 self.super_segment_headers_cache
763 .get(u64::from(local_segment_index) as usize)
764 .copied()
765 }
766
767 #[inline(always)]
768 fn get_super_segment_header_for_segment_index(
769 &self,
770 segment_index: SegmentIndex,
771 ) -> Option<SuperSegmentHeader> {
772 let index = self
773 .super_segment_headers_cache
774 .binary_search_by_key(&segment_index, |super_segment_header| {
775 super_segment_header.max_segment_index.as_inner()
776 })
777 .unwrap_or_else(|insert_index| insert_index);
778
779 let super_segment_header = self.super_segment_headers_cache.get(index).copied()?;
780
781 let max_segment_index = super_segment_header.max_segment_index.as_inner();
782 let first_segment_index = max_segment_index
783 - SegmentIndex::from(u64::from(super_segment_header.num_segments))
784 + SegmentIndex::ONE;
785
786 (first_segment_index..=max_segment_index)
787 .contains(&segment_index)
788 .then_some(super_segment_header)
789 }
790
791 fn add_super_segment_headers(
793 &mut self,
794 mut super_segment_headers: Vec<SuperSegmentHeader>,
795 ) -> Result<Vec<SuperSegmentHeader>, PersistSuperSegmentHeadersError> {
796 self.super_segment_headers_cache
797 .reserve(super_segment_headers.len());
798
799 let mut maybe_last_super_segment_index = self
800 .super_segment_headers_cache
801 .last()
802 .map(|header| header.index.as_inner());
803
804 if let Some(last_super_segment_index) = maybe_last_super_segment_index {
805 super_segment_headers.retain(|super_segment_header| {
807 super_segment_header.index.as_inner() > last_super_segment_index
808 });
809 }
810
811 for super_segment_header in super_segment_headers.iter().copied() {
814 let super_segment_index = super_segment_header.index.as_inner();
815 if let Some(last_super_segment_index) = maybe_last_super_segment_index {
816 if super_segment_index != last_super_segment_index + SuperSegmentIndex::ONE {
817 return Err(
818 PersistSuperSegmentHeadersError::MustFollowLastSegmentIndex {
819 super_segment_index,
820 last_super_segment_index,
821 },
822 );
823 }
824
825 self.super_segment_headers_cache.push(super_segment_header);
826 maybe_last_super_segment_index.replace(super_segment_index);
827 } else {
828 if super_segment_index != SuperSegmentIndex::ZERO {
829 return Err(PersistSuperSegmentHeadersError::FirstSegmentIndexZero {
830 super_segment_index,
831 });
832 }
833
834 self.super_segment_headers_cache.push(super_segment_header);
835 maybe_last_super_segment_index.replace(super_segment_index);
836 }
837 }
838
839 Ok(super_segment_headers)
840 }
841}
842
843#[derive(Debug)]
845struct State<Block, StorageBackend>
846where
847 Block: GenericOwnedBlock,
848{
849 data: StateData<Block>,
850 segment_headers_cache: SegmentHeadersCache,
851 super_segment_headers_cache: SuperSegmentHeadersCache,
852 storage_backend_adapter: AsyncRwLock<StorageBackendAdapter<StorageBackend>>,
853}
854
855impl<Block, StorageBackend> State<Block, StorageBackend>
856where
857 Block: GenericOwnedBlock,
858{
859 #[inline(always)]
860 fn best_tip(&self) -> &ForkTip {
861 self.data
862 .fork_tips
863 .front()
864 .expect("The best block is always present; qed")
865 }
866
867 #[inline(always)]
868 fn best_block(&self) -> &ClientDatabaseBlock<Block> {
869 self.data
870 .blocks
871 .front()
872 .expect("The best block is always present; qed")
873 .first()
874 .expect("The best block is always present; qed")
875 }
876}
877
878#[derive(Debug)]
879struct BlockToPersist<'a, Block>
880where
881 Block: GenericOwnedBlock,
882{
883 block_offset: usize,
884 fork_offset: usize,
885 block: &'a Block,
886 block_details: &'a BlockDetails,
887}
888
889#[derive(Debug)]
890struct PersistedBlock {
891 block_offset: usize,
892 fork_offset: usize,
893 write_location: WriteLocation,
894}
895
896#[derive(Debug)]
897struct ClientDatabaseInnerOptions {
898 block_confirmation_depth: BlockNumber,
899 soft_confirmation_depth: BlockNumber,
900 max_fork_tips: NonZeroUsize,
901 max_fork_tip_distance: BlockNumber,
902}
903
904impl ClientDatabaseInnerOptions {
905 fn new(
908 block_confirmation_depth: BlockNumber,
909 soft_confirmation_depth: BlockNumber,
910 max_fork_tips: NonZeroUsize,
911 max_fork_tip_distance: BlockNumber,
912 ) -> Result<Self, ClientDatabaseError> {
913 if block_confirmation_depth < BlockNumber::from(2) {
914 return Err(ClientDatabaseError::InvalidBlockConfirmationDepth);
915 }
916
917 if soft_confirmation_depth >= block_confirmation_depth {
918 return Err(ClientDatabaseError::InvalidSoftConfirmationDepth);
919 }
920
921 Ok(Self {
922 block_confirmation_depth,
923 soft_confirmation_depth,
924 max_fork_tips,
925 max_fork_tip_distance,
926 })
927 }
928
929 #[inline(always)]
944 fn fork_pruning_block_offset(&self) -> usize {
945 let fork_pruning_block_offset = self
946 .block_confirmation_depth
947 .checked_sub(BlockNumber::ONE)
948 .expect("Block confirmation depth is checked to be at least 2 in `Self::new()`; qed");
949
950 u64::from(fork_pruning_block_offset) as usize
951 }
952}
953
954#[derive(Debug)]
955struct Inner<Block, StorageBackend>
956where
957 Block: GenericOwnedBlock,
958{
959 state: AsyncRwLock<State<Block, StorageBackend>>,
960 options: ClientDatabaseInnerOptions,
961}
962
963#[derive(Debug)]
965pub struct ClientDatabase<Block, StorageBackend>
966where
967 Block: GenericOwnedBlock,
968{
969 inner: Arc<Inner<Block, StorageBackend>>,
970}
971
972impl<Block, StorageBackend> Clone for ClientDatabase<Block, StorageBackend>
973where
974 Block: GenericOwnedBlock,
975{
976 fn clone(&self) -> Self {
977 Self {
978 inner: self.inner.clone(),
979 }
980 }
981}
982
983#[expect(clippy::empty_drop, reason = "Not implemented yet")]
984impl<Block, StorageBackend> Drop for ClientDatabase<Block, StorageBackend>
985where
986 Block: GenericOwnedBlock,
987{
988 fn drop(&mut self) {
989 }
993}
994
995impl<Block, StorageBackend> ChainInfo<Block> for ClientDatabase<Block, StorageBackend>
996where
997 Block: GenericOwnedBlock,
998 StorageBackend: ClientDatabaseStorageBackend,
999{
1000 #[inline]
1001 fn best_root(&self) -> BlockRoot {
1002 self.inner.state.read_blocking().best_tip().root
1005 }
1006
1007 #[inline]
1008 fn best_header(&self) -> Block::Header {
1009 self.inner
1012 .state
1013 .read_blocking()
1014 .best_block()
1015 .header()
1016 .clone()
1017 }
1018
1019 #[inline]
1020 fn best_header_with_details(&self) -> (Block::Header, BlockDetails) {
1021 let state = self.inner.state.read_blocking();
1024 let best_block = state.best_block();
1025 (
1026 best_block.header().clone(),
1027 best_block
1028 .block_details()
1029 .expect("Always present for the best block; qed")
1030 .clone(),
1031 )
1032 }
1033
1034 #[inline]
1036 fn ancestor_header(
1037 &self,
1038 ancestor_block_number: BlockNumber,
1039 descendant_block_root: &BlockRoot,
1040 ) -> Option<Block::Header> {
1041 let state = self.inner.state.read_blocking();
1044 let best_number = state.best_tip().number;
1045
1046 let ancestor_block_offset =
1047 u64::from(best_number.checked_sub(ancestor_block_number)?) as usize;
1048 let ancestor_block_candidates = state.data.blocks.get(ancestor_block_offset)?;
1049
1050 let descendant_block_number = *state.data.block_roots.get(descendant_block_root)?;
1051 if ancestor_block_number > descendant_block_number {
1052 return None;
1053 }
1054 let descendant_block_offset =
1055 u64::from(best_number.checked_sub(descendant_block_number)?) as usize;
1056
1057 let mut blocks_range_iter = state
1059 .data
1060 .blocks
1061 .iter()
1062 .enumerate()
1063 .skip(descendant_block_offset);
1064
1065 let (_offset, descendant_block_candidates) = blocks_range_iter.next()?;
1066 let descendant_header = descendant_block_candidates
1067 .iter()
1068 .find(|block| &*block.header().header().root() == descendant_block_root)?
1069 .header();
1070
1071 if ancestor_block_number == descendant_block_number {
1072 return Some(descendant_header.clone());
1073 }
1074
1075 if descendant_block_candidates.len() == 1 || ancestor_block_candidates.len() == 1 {
1080 return ancestor_block_candidates
1081 .iter()
1082 .next()
1083 .map(|block| block.header().clone());
1084 }
1085
1086 let mut parent_block_root = &descendant_header.header().prefix.parent_root;
1087
1088 for (block_offset, parent_candidates) in blocks_range_iter {
1090 let parent_header = parent_candidates
1091 .iter()
1092 .find(|header| &*header.header().header().root() == parent_block_root)?
1093 .header();
1094
1095 if block_offset == ancestor_block_offset {
1097 return Some(parent_header.clone());
1098 }
1099
1100 parent_block_root = &parent_header.header().prefix.parent_root;
1101 }
1102
1103 None
1104 }
1105
1106 #[inline]
1107 fn header(&self, block_root: &BlockRoot) -> Option<Block::Header> {
1108 let state = self.inner.state.read_blocking();
1111 let best_number = state.best_tip().number;
1112
1113 let block_number = *state.data.block_roots.get(block_root)?;
1114 let block_offset = u64::from(best_number.checked_sub(block_number)?) as usize;
1115 let block_candidates = state.data.blocks.get(block_offset)?;
1116
1117 block_candidates.iter().find_map(|block| {
1118 let header = block.header();
1119
1120 if &*header.header().root() == block_root {
1121 Some(header.clone())
1122 } else {
1123 None
1124 }
1125 })
1126 }
1127
1128 #[inline]
1129 fn header_with_details(&self, block_root: &BlockRoot) -> Option<(Block::Header, BlockDetails)> {
1130 let state = self.inner.state.read_blocking();
1133 let best_number = state.best_tip().number;
1134
1135 let block_number = *state.data.block_roots.get(block_root)?;
1136 let block_offset = u64::from(best_number.checked_sub(block_number)?) as usize;
1137 let block_candidates = state.data.blocks.get(block_offset)?;
1138
1139 block_candidates.iter().find_map(|block| {
1140 let header = block.header();
1141 let block_details = block.block_details().cloned()?;
1142
1143 if &*header.header().root() == block_root {
1144 Some((header.clone(), block_details))
1145 } else {
1146 None
1147 }
1148 })
1149 }
1150
1151 #[inline]
1152 async fn block(&self, block_root: &BlockRoot) -> Result<Block, ReadBlockError> {
1153 let state = self.inner.state.read().await;
1154 let best_number = state.best_tip().number;
1155
1156 let block_number = *state
1157 .data
1158 .block_roots
1159 .get(block_root)
1160 .ok_or(ReadBlockError::UnknownBlockRoot)?;
1161 let block_offset = u64::from(
1162 best_number
1163 .checked_sub(block_number)
1164 .expect("Known block roots always have valid block offset; qed"),
1165 ) as usize;
1166 let block_candidates = state
1167 .data
1168 .blocks
1169 .get(block_offset)
1170 .expect("Valid block offsets always have block entries; qed");
1171
1172 for block_candidate in block_candidates {
1173 let header = block_candidate.header();
1174
1175 if &*header.header().root() == block_root {
1176 return match block_candidate.full_block() {
1177 FullBlock::InMemory(block) => Ok(block.clone()),
1178 FullBlock::Persisted {
1179 header,
1180 write_location,
1181 } => {
1182 let storage_backend_adapter = state.storage_backend_adapter.read().await;
1183
1184 let storage_item = storage_backend_adapter
1185 .read_storage_item::<StorageItemTemporary>(write_location)
1186 .await?;
1187
1188 let storage_item_block = match storage_item {
1189 StorageItemTemporary::Block(storage_item_block) => storage_item_block,
1190 StorageItemTemporary::SegmentHeaders(_) => {
1191 return Err(ReadBlockError::StorageItemReadError {
1192 error: io::Error::other(
1193 "Unexpected storage item: `SegmentHeaders`",
1194 ),
1195 });
1196 }
1197 StorageItemTemporary::SuperSegmentHeaders(_) => {
1198 return Err(ReadBlockError::StorageItemReadError {
1199 error: io::Error::other(
1200 "Unexpected storage item: `SuperSegmentHeaders`",
1201 ),
1202 });
1203 }
1204 };
1205
1206 let StorageItemTemporaryBlock {
1207 header: _,
1208 body,
1209 mmr_with_block: _,
1210 system_contract_states: _,
1211 } = storage_item_block;
1212
1213 Block::from_buffers(header.buffer().clone(), body)
1214 .ok_or(ReadBlockError::FailedToDecode)
1215 }
1216 };
1217 }
1218 }
1219
1220 unreachable!("Known block root always has block candidate associated with it; qed")
1221 }
1222
1223 #[inline]
1224 fn last_segment_header(&self) -> Option<SegmentHeader> {
1225 let state = self.inner.state.read_blocking();
1228 state.segment_headers_cache.last_segment_header()
1229 }
1230
1231 #[inline]
1232 fn get_segment_header(&self, segment_index: LocalSegmentIndex) -> Option<SegmentHeader> {
1233 let state = self.inner.state.read_blocking();
1236
1237 state
1238 .segment_headers_cache
1239 .get_segment_header(segment_index)
1240 }
1241
1242 fn segment_headers_for_block(&self, block_number: BlockNumber) -> Vec<SegmentHeader> {
1243 let state = self.inner.state.read_blocking();
1246
1247 let Some(last_local_segment_index) = state.segment_headers_cache.max_local_segment_index()
1248 else {
1249 return Vec::new();
1251 };
1252
1253 if Block::Block::SHARD_KIND == RealShardKind::BeaconChain
1255 && block_number == BlockNumber::ONE
1256 {
1257 return vec![
1260 state
1261 .segment_headers_cache
1262 .get_segment_header(LocalSegmentIndex::ZERO)
1263 .expect("Segment headers are stored in monotonically increasing order; qed"),
1264 ];
1265 }
1266
1267 if last_local_segment_index == LocalSegmentIndex::ZERO {
1268 return Vec::new();
1270 }
1271
1272 let mut current_local_segment_index = last_local_segment_index;
1273 loop {
1274 let current_segment_header = state
1277 .segment_headers_cache
1278 .get_segment_header(current_local_segment_index)
1279 .expect("Segment headers are stored in monotonically increasing order; qed");
1280
1281 let target_block_number = current_segment_header.last_archived_block.number()
1283 + BlockNumber::ONE
1284 + self.inner.options.block_confirmation_depth;
1285 if target_block_number == block_number {
1286 let mut headers_for_block = vec![current_segment_header];
1287
1288 let last_archived_block_number = current_segment_header.last_archived_block.number;
1290 let mut local_segment_index = current_local_segment_index - LocalSegmentIndex::ONE;
1291
1292 while let Some(segment_header) = state
1293 .segment_headers_cache
1294 .get_segment_header(local_segment_index)
1295 {
1296 if segment_header.last_archived_block.number == last_archived_block_number {
1297 headers_for_block.insert(0, segment_header);
1298 local_segment_index -= LocalSegmentIndex::ONE;
1299 } else {
1300 break;
1301 }
1302 }
1303
1304 return headers_for_block;
1305 }
1306
1307 if target_block_number > block_number {
1309 if current_local_segment_index > LocalSegmentIndex::ONE {
1311 current_local_segment_index -= LocalSegmentIndex::ONE;
1312 } else {
1313 break;
1314 }
1315 } else {
1316 return Vec::new();
1318 }
1319 }
1320
1321 Vec::new()
1323 }
1324}
1325
1326impl<Block, StorageBackend> ChainInfoWrite<Block> for ClientDatabase<Block, StorageBackend>
1327where
1328 Block: GenericOwnedBlock,
1329 StorageBackend: ClientDatabaseStorageBackend,
1330{
1331 async fn persist_block(
1332 &self,
1333 block: Block,
1334 block_details: BlockDetails,
1335 ) -> Result<(), PersistBlockError> {
1336 let mut state = self.inner.state.write().await;
1337 let best_number = state.best_tip().number;
1338
1339 let header = block.header().header();
1340
1341 let block_number = header.prefix.number;
1342 let block_root = *header.root();
1343
1344 if state.data.block_roots.contains_key(&block_root) {
1347 return Err(PersistBlockError::AlreadyKnown);
1348 }
1349
1350 if best_number == BlockNumber::ZERO && block_number != BlockNumber::ONE {
1351 Self::insert_first_block(&mut state.data, block, block_details);
1353
1354 return Ok(());
1355 }
1356
1357 if block_number == best_number + BlockNumber::ONE {
1358 return Self::insert_new_best_block(state, &self.inner, block, block_details).await;
1359 }
1360
1361 let block_offset = u64::from(
1362 best_number
1363 .checked_sub(block_number)
1364 .ok_or(PersistBlockError::MissingParent)?,
1365 ) as usize;
1366
1367 if block_offset >= self.inner.options.fork_pruning_block_offset() {
1371 return Err(PersistBlockError::OutsideAcceptableRange);
1372 }
1373
1374 if !state
1377 .data
1378 .block_roots
1379 .contains_key(&header.prefix.parent_root)
1380 {
1381 return Err(PersistBlockError::MissingParent);
1382 }
1383
1384 let state = &mut *state;
1385
1386 let block_forks = state.data.blocks.get_mut(block_offset).ok_or_else(|| {
1387 error!(
1388 %block_number,
1389 %block_offset,
1390 "Failed to store block fork, header offset is missing despite being within \
1391 acceptable range"
1392 );
1393
1394 PersistBlockError::OutsideAcceptableRange
1395 })?;
1396
1397 for (index, fork_tip) in state.data.fork_tips.iter_mut().enumerate() {
1398 if fork_tip.root == header.prefix.parent_root {
1400 state.data.fork_tips.remove(index);
1401 break;
1402 }
1403 }
1404
1405 state.data.fork_tips.insert(
1408 1,
1409 ForkTip {
1410 number: block_number,
1411 root: block_root,
1412 },
1413 );
1414 state.data.block_roots.insert(block_root, block_number);
1415 let beacon_chain_block_details = <dyn Any>::downcast_ref::<OwnedBeaconChainBlock>(&block)
1416 .map(|block| BeaconChainBlockDetails::from_body(block.body.body()));
1417 block_forks.push(ClientDatabaseBlock::InMemory {
1418 block,
1419 block_details,
1420 beacon_chain_block_details,
1421 });
1422
1423 Self::prune_outdated_fork_tips(best_number, &mut state.data, &self.inner.options);
1428
1429 Ok(())
1430 }
1431
1432 async fn persist_segment_headers(
1433 &self,
1434 segment_headers: Vec<SegmentHeader>,
1435 ) -> Result<(), PersistSegmentHeadersError> {
1436 let mut state = self.inner.state.write().await;
1437
1438 let added_segment_headers = state
1439 .segment_headers_cache
1440 .add_segment_headers(segment_headers)?;
1441
1442 if added_segment_headers.is_empty() {
1443 return Ok(());
1444 }
1445
1446 let state = AsyncRwLockWriteGuard::downgrade_to_upgradable(state);
1451
1452 let mut storage_backend_adapter = state.storage_backend_adapter.write().await;
1453
1454 storage_backend_adapter
1455 .write_storage_item(StorageItemTemporary::SegmentHeaders(
1456 StorageItemTemporarySegmentHeaders {
1457 segment_headers: added_segment_headers,
1458 },
1459 ))
1460 .await?;
1461
1462 Ok(())
1463 }
1464}
1465
1466impl<StorageBackend> BeaconChainInfo for ClientDatabase<OwnedBeaconChainBlock, StorageBackend>
1467where
1468 StorageBackend: ClientDatabaseStorageBackend,
1469{
1470 fn shard_segment_roots(
1471 &self,
1472 block_number: BlockNumber,
1473 ) -> Result<Arc<[ShardSegmentRoot]>, ShardSegmentRootsError> {
1474 let state = self.inner.state.read_blocking();
1477 let best_number = state.best_tip().number;
1478
1479 let block_offset = u64::from(
1480 best_number
1481 .checked_sub(block_number)
1482 .ok_or(ShardSegmentRootsError::BlockMissing { block_number })?,
1483 ) as usize;
1484
1485 let block = state
1486 .data
1487 .blocks
1488 .get(block_offset)
1489 .ok_or(ShardSegmentRootsError::BlockMissing { block_number })?
1490 .first()
1491 .expect("There is always at least one block candidate; qed");
1492
1493 Ok(Arc::clone(
1494 &block
1495 .beacon_chain_block_details()
1496 .as_ref()
1497 .expect("Always present in the beacon chain block; qed")
1498 .shard_segment_roots,
1499 ))
1500 }
1501
1502 #[inline]
1503 fn last_super_segment_header(&self) -> Option<SuperSegmentHeader> {
1504 let state = self.inner.state.read_blocking();
1507 state
1508 .super_segment_headers_cache
1509 .last_super_segment_header()
1510 }
1511
1512 #[inline]
1513 fn previous_super_segment_header(
1514 &self,
1515 block_number: BlockNumber,
1516 ) -> Option<SuperSegmentHeader> {
1517 let state = self.inner.state.read_blocking();
1520
1521 state
1522 .super_segment_headers_cache
1523 .previous_super_segment_header(block_number)
1524 }
1525
1526 #[inline]
1527 fn get_super_segment_header(
1528 &self,
1529 super_segment_index: SuperSegmentIndex,
1530 ) -> Option<SuperSegmentHeader> {
1531 let state = self.inner.state.read_blocking();
1534
1535 state
1536 .super_segment_headers_cache
1537 .get_super_segment_header(super_segment_index)
1538 }
1539
1540 fn get_super_segment_header_for_segment_index(
1541 &self,
1542 segment_index: SegmentIndex,
1543 ) -> Option<SuperSegmentHeader> {
1544 let state = self.inner.state.read_blocking();
1547
1548 state
1549 .super_segment_headers_cache
1550 .get_super_segment_header_for_segment_index(segment_index)
1551 }
1552}
1553
1554impl<StorageBackend> BeaconChainInfoWrite for ClientDatabase<OwnedBeaconChainBlock, StorageBackend>
1555where
1556 StorageBackend: ClientDatabaseStorageBackend,
1557{
1558 async fn persist_super_segment_header(
1559 &self,
1560 super_segment_header: SuperSegmentHeader,
1561 ) -> Result<bool, PersistSuperSegmentHeadersError> {
1562 let mut state = self.inner.state.write().await;
1563
1564 let added_super_segment_headers = state
1565 .super_segment_headers_cache
1566 .add_super_segment_headers(vec![super_segment_header])?;
1567
1568 if added_super_segment_headers.is_empty() {
1569 return Ok(false);
1570 }
1571
1572 let state = AsyncRwLockWriteGuard::downgrade_to_upgradable(state);
1577
1578 let mut storage_backend_adapter = state.storage_backend_adapter.write().await;
1579
1580 storage_backend_adapter
1581 .write_storage_item(StorageItemTemporary::SuperSegmentHeaders(
1582 StorageItemTemporarySuperSegmentHeaders {
1583 super_segment_headers: added_super_segment_headers,
1584 },
1585 ))
1586 .await?;
1587
1588 Ok(true)
1589 }
1590
1591 async fn persist_super_segment_headers(
1592 &self,
1593 super_segment_headers: Vec<SuperSegmentHeader>,
1594 ) -> Result<(), PersistSuperSegmentHeadersError> {
1595 let mut state = self.inner.state.write().await;
1596
1597 let added_super_segment_headers = state
1598 .super_segment_headers_cache
1599 .add_super_segment_headers(super_segment_headers)?;
1600
1601 if added_super_segment_headers.is_empty() {
1602 return Ok(());
1603 }
1604
1605 let state = AsyncRwLockWriteGuard::downgrade_to_upgradable(state);
1610
1611 let mut storage_backend_adapter = state.storage_backend_adapter.write().await;
1612
1613 storage_backend_adapter
1614 .write_storage_item(StorageItemTemporary::SuperSegmentHeaders(
1615 StorageItemTemporarySuperSegmentHeaders {
1616 super_segment_headers: added_super_segment_headers,
1617 },
1618 ))
1619 .await?;
1620
1621 Ok(())
1622 }
1623}
1624
1625impl<Block, StorageBackend> ClientDatabase<Block, StorageBackend>
1626where
1627 Block: GenericOwnedBlock,
1628 StorageBackend: ClientDatabaseStorageBackend,
1629{
1630 pub async fn open<GBB>(
1642 options: ClientDatabaseOptions<GBB, StorageBackend>,
1643 ) -> Result<Self, ClientDatabaseError>
1644 where
1645 GBB: FnOnce() -> GenesisBlockBuilderResult<Block>,
1646 {
1647 let ClientDatabaseOptions {
1648 write_buffer_size,
1649 block_confirmation_depth,
1650 soft_confirmation_depth,
1651 max_fork_tips,
1652 max_fork_tip_distance,
1653 genesis_block_builder,
1654 storage_backend,
1655 } = options;
1656 let options = ClientDatabaseInnerOptions::new(
1657 block_confirmation_depth,
1658 soft_confirmation_depth,
1659 max_fork_tips,
1660 max_fork_tip_distance,
1661 )?;
1662
1663 let mut state_data = StateData {
1664 fork_tips: VecDeque::new(),
1665 block_roots: HashMap::default(),
1666 blocks: VecDeque::new(),
1667 };
1668 let mut segment_headers_cache = SegmentHeadersCache {
1669 segment_headers_cache: Vec::new(),
1670 };
1671 let mut super_segment_headers_cache = SuperSegmentHeadersCache {
1672 super_segment_headers_cache: Vec::new(),
1673 };
1674
1675 let fork_pruning_block_offset = options.fork_pruning_block_offset();
1677
1678 let storage_item_handlers = StorageItemHandlers {
1679 permanent: |_arg| {
1680 Ok(())
1682 },
1683 temporary: |arg| {
1684 let StorageItemHandlerArg {
1685 storage_item,
1686 page_offset,
1687 num_pages,
1688 } = arg;
1689 let storage_item_block = match storage_item {
1690 StorageItemTemporary::Block(storage_item_block) => storage_item_block,
1691 StorageItemTemporary::SegmentHeaders(segment_headers) => {
1692 let num_segment_headers = segment_headers.segment_headers.len();
1693 return match segment_headers_cache
1694 .add_segment_headers(segment_headers.segment_headers)
1695 {
1696 Ok(_) => Ok(()),
1697 Err(error) => {
1698 error!(
1699 %page_offset,
1700 %num_segment_headers,
1701 %error,
1702 "Failed to add segment headers from storage item"
1703 );
1704
1705 Err(ClientDatabaseError::InvalidSegmentHeaders { page_offset })
1706 }
1707 };
1708 }
1709 StorageItemTemporary::SuperSegmentHeaders(super_segment_headers) => {
1710 let num_super_segment_headers =
1711 super_segment_headers.super_segment_headers.len();
1712 return match super_segment_headers_cache
1713 .add_super_segment_headers(super_segment_headers.super_segment_headers)
1714 {
1715 Ok(_) => Ok(()),
1716 Err(error) => {
1717 error!(
1718 %page_offset,
1719 %num_super_segment_headers,
1720 %error,
1721 "Failed to add segment headers from storage item"
1722 );
1723
1724 Err(ClientDatabaseError::InvalidSegmentHeaders { page_offset })
1725 }
1726 };
1727 }
1728 };
1729
1730 let StorageItemTemporaryBlock {
1733 header,
1734 body,
1735 mmr_with_block,
1736 system_contract_states,
1737 } = storage_item_block;
1738
1739 let header = Block::Header::from_buffer(header).map_err(|_buffer| {
1740 error!(%page_offset, "Failed to decode block header from bytes");
1741
1742 ClientDatabaseError::InvalidBlock { page_offset }
1743 })?;
1744 let body = Block::Body::from_buffer(body).map_err(|_buffer| {
1745 error!(%page_offset, "Failed to decode block body from bytes");
1746
1747 ClientDatabaseError::InvalidBlock { page_offset }
1748 })?;
1749
1750 let block_root = *header.header().root();
1751 let block_number = header.header().prefix.number;
1752
1753 state_data.block_roots.insert(block_root, block_number);
1754
1755 let maybe_best_number = state_data
1756 .blocks
1757 .front()
1758 .and_then(|block_forks| block_forks.first())
1759 .map(|best_block| {
1760 let header: &Block::Header = best_block.header();
1762
1763 header.header().prefix.number
1764 });
1765
1766 let block_offset = if let Some(best_number) = maybe_best_number {
1767 if block_number <= best_number {
1768 u64::from(best_number - block_number) as usize
1769 } else {
1770 if block_number - best_number != BlockNumber::ONE {
1772 error!(
1773 %page_offset,
1774 %best_number,
1775 %block_number,
1776 "Invalid new best block number, it must be only one block \
1777 higher than the best block"
1778 );
1779
1780 return Err(ClientDatabaseError::InvalidBlock { page_offset });
1781 }
1782
1783 state_data.blocks.push_front(SmallVec::new());
1784 0
1786 }
1787 } else {
1788 state_data.blocks.push_front(SmallVec::new());
1789 0
1791 };
1792
1793 let Some(block_forks) = state_data.blocks.get_mut(block_offset) else {
1794 return Ok(());
1797 };
1798
1799 let beacon_chain_block_details =
1801 <dyn Any>::downcast_ref::<OwnedBeaconChainBody>(&body)
1802 .map(|body| BeaconChainBlockDetails::from_body(body.body()));
1803 block_forks.push(ClientDatabaseBlock::Persisted {
1804 header,
1805 block_details: BlockDetails {
1806 mmr_with_block,
1807 system_contract_states,
1808 },
1809 beacon_chain_block_details,
1810 write_location: WriteLocation {
1811 page_offset,
1812 num_pages,
1813 },
1814 });
1815
1816 if block_offset == 0 && block_forks.len() == 1 {
1820 if state_data
1825 .blocks
1826 .get(fork_pruning_block_offset)
1827 .is_some_and(|block_forks| block_forks.len() > 1)
1828 {
1829 if !Self::adjust_ancestor_block_forks(
1830 &mut state_data.blocks,
1831 block_root,
1832 AncestorBlockForksWalk::UpToBlockOffset {
1833 max_block_offset: fork_pruning_block_offset,
1834 },
1835 ) {
1836 error!(
1837 %page_offset,
1838 %block_number,
1839 "Failed to find ancestors of the block read from the database"
1840 );
1841
1842 return Err(ClientDatabaseError::FailedToAdjustAncestorBlockForks);
1843 }
1844
1845 Self::prune_non_canonical_blocks(
1846 fork_pruning_block_offset,
1847 &mut state_data,
1848 );
1849 }
1850
1851 Self::confirm_canonical_block(block_number, &mut state_data, &options);
1852 }
1853
1854 Ok(())
1855 },
1856 };
1857
1858 let storage_backend_adapter =
1859 StorageBackendAdapter::open(write_buffer_size, storage_item_handlers, storage_backend)
1860 .await?;
1861
1862 if let Some(best_block) = state_data.blocks.front().and_then(|block_forks| {
1865 block_forks.last()
1868 }) {
1869 let header: &Block::Header = best_block.header();
1871 let header = header.header();
1872 let block_number = header.prefix.number;
1873 let block_root = *header.root();
1874
1875 if !Self::adjust_ancestor_block_forks(
1878 &mut state_data.blocks,
1879 block_root,
1880 AncestorBlockForksWalk::UpToBlockOffset {
1881 max_block_offset: fork_pruning_block_offset,
1882 },
1883 ) {
1884 return Err(ClientDatabaseError::FailedToAdjustAncestorBlockForks);
1885 }
1886
1887 state_data.fork_tips.push_front(ForkTip {
1889 number: block_number,
1890 root: block_root,
1891 });
1892 } else {
1893 let GenesisBlockBuilderResult {
1894 block,
1895 system_contract_states,
1896 } = genesis_block_builder();
1897
1898 let header = block.header().header();
1900 let block_number = header.prefix.number;
1901 let block_root = *header.root();
1902
1903 state_data.fork_tips.push_front(ForkTip {
1904 number: block_number,
1905 root: block_root,
1906 });
1907 state_data.block_roots.insert(block_root, block_number);
1908 let beacon_chain_block_details =
1909 <dyn Any>::downcast_ref::<OwnedBeaconChainBlock>(&block)
1910 .map(|block| BeaconChainBlockDetails::from_body(block.body.body()));
1911 state_data
1912 .blocks
1913 .push_front(smallvec![ClientDatabaseBlock::InMemory {
1914 block,
1915 block_details: BlockDetails {
1916 system_contract_states,
1917 mmr_with_block: Arc::new({
1918 let mut mmr = BlockMerkleMountainRange::new();
1919 mmr.add_leaf(&block_root);
1920 mmr
1921 })
1922 },
1923 beacon_chain_block_details,
1924 }]);
1925 }
1926
1927 let state = State {
1928 data: state_data,
1929 segment_headers_cache,
1930 super_segment_headers_cache,
1931 storage_backend_adapter: AsyncRwLock::new(storage_backend_adapter),
1932 };
1933
1934 let inner = Inner {
1935 state: AsyncRwLock::new(state),
1936 options,
1937 };
1938
1939 Ok(Self {
1940 inner: Arc::new(inner),
1941 })
1942 }
1943
1944 pub async fn format(
1946 storage_backend: &StorageBackend,
1947 options: ClientDatabaseFormatOptions,
1948 ) -> Result<(), ClientDatabaseFormatError> {
1949 StorageBackendAdapter::format(storage_backend, options).await
1950 }
1951
1952 fn insert_first_block(state: &mut StateData<Block>, block: Block, block_details: BlockDetails) {
1953 let header = block.header().header();
1955 let block_number = header.prefix.number;
1956 let block_root = *header.root();
1957
1958 state.fork_tips.clear();
1959 state.fork_tips.push_front(ForkTip {
1960 number: block_number,
1961 root: block_root,
1962 });
1963 state.block_roots.clear();
1964 state.block_roots.insert(block_root, block_number);
1965 state.blocks.clear();
1966 let beacon_chain_block_details = <dyn Any>::downcast_ref::<OwnedBeaconChainBlock>(&block)
1967 .map(|block| BeaconChainBlockDetails::from_body(block.body.body()));
1968 state
1969 .blocks
1970 .push_front(smallvec![ClientDatabaseBlock::InMemory {
1971 block,
1972 block_details,
1973 beacon_chain_block_details,
1974 }]);
1975 }
1976
1977 async fn insert_new_best_block(
1978 mut state: AsyncRwLockWriteGuard<'_, State<Block, StorageBackend>>,
1979 inner: &Inner<Block, StorageBackend>,
1980 block: Block,
1981 block_details: BlockDetails,
1982 ) -> Result<(), PersistBlockError> {
1983 let header = block.header().header();
1984 let block_number = header.prefix.number;
1985 let block_root = *header.root();
1986 let parent_root = header.prefix.parent_root;
1987
1988 if !Self::adjust_ancestor_block_forks(
1991 &mut state.data.blocks,
1992 parent_root,
1993 AncestorBlockForksWalk::UntilCanonical,
1994 ) {
1995 return Err(PersistBlockError::MissingParent);
1996 }
1997
1998 {
2000 for (index, fork_tip) in state.data.fork_tips.iter_mut().enumerate() {
2001 if fork_tip.root == parent_root {
2003 state.data.fork_tips.remove(index);
2004 break;
2005 }
2006 }
2007
2008 state.data.fork_tips.push_front(ForkTip {
2009 number: block_number,
2010 root: block_root,
2011 });
2012 state.data.block_roots.insert(block_root, block_number);
2013 let beacon_chain_block_details =
2014 <dyn Any>::downcast_ref::<OwnedBeaconChainBlock>(&block)
2015 .map(|block| BeaconChainBlockDetails::from_body(block.body.body()));
2016 state
2017 .data
2018 .blocks
2019 .push_front(smallvec![ClientDatabaseBlock::InMemory {
2020 block,
2021 block_details: block_details.clone(),
2022 beacon_chain_block_details,
2023 }]);
2024 }
2025
2026 let options = &inner.options;
2027
2028 Self::prune_non_canonical_blocks(options.fork_pruning_block_offset(), &mut state.data);
2033 Self::confirm_canonical_block(block_number, &mut state.data, options);
2034 Self::prune_outdated_fork_tips(block_number, &mut state.data, options);
2035
2036 let state = AsyncRwLockWriteGuard::downgrade_to_upgradable(state);
2041
2042 let mut blocks_to_persist = Vec::new();
2043 for block_offset in u64::from(options.soft_confirmation_depth) as usize.. {
2044 let Some(fork_blocks) = state.data.blocks.get(block_offset) else {
2045 break;
2046 };
2047
2048 let len_before = blocks_to_persist.len();
2049 fork_blocks
2050 .iter()
2051 .enumerate()
2052 .filter_map(|(fork_offset, client_database_block)| {
2053 #[expect(
2054 clippy::rest_pattern_accessible_field,
2055 reason = "Do not need other fields"
2056 )]
2057 match client_database_block {
2058 ClientDatabaseBlock::InMemory {
2059 block,
2060 block_details,
2061 beacon_chain_block_details: _,
2062 } => Some(BlockToPersist {
2063 block_offset,
2064 fork_offset,
2065 block,
2066 block_details,
2067 }),
2068 ClientDatabaseBlock::Persisted { .. }
2069 | ClientDatabaseBlock::PersistedConfirmed { .. } => {
2070 None
2072 }
2073 }
2074 })
2075 .collect_into(&mut blocks_to_persist);
2076
2077 if blocks_to_persist.len() == len_before {
2078 break;
2079 }
2080 }
2081
2082 let mut persisted_blocks = Vec::with_capacity(blocks_to_persist.len());
2087 {
2088 let mut storage_backend_adapter = state.storage_backend_adapter.write().await;
2089
2090 for block_to_persist in blocks_to_persist.into_iter().rev() {
2091 let BlockToPersist {
2092 block_offset,
2093 fork_offset,
2094 block,
2095 block_details,
2096 } = block_to_persist;
2097
2098 let write_location = storage_backend_adapter
2099 .write_storage_item(StorageItemTemporary::Block(StorageItemTemporaryBlock {
2100 header: block.header().buffer().clone(),
2101 body: block.body().buffer().clone(),
2102 mmr_with_block: Arc::clone(&block_details.mmr_with_block),
2103 system_contract_states: Arc::clone(&block_details.system_contract_states),
2104 }))
2105 .await?;
2106
2107 persisted_blocks.push(PersistedBlock {
2108 block_offset,
2109 fork_offset,
2110 write_location,
2111 });
2112 }
2113 }
2114
2115 let mut state = RwLockUpgradableReadGuard::upgrade(state).await;
2117 for persisted_block in persisted_blocks {
2118 let PersistedBlock {
2119 block_offset,
2120 fork_offset,
2121 write_location,
2122 } = persisted_block;
2123
2124 let block = state
2125 .data
2126 .blocks
2127 .get_mut(block_offset)
2128 .expect("Still holding the same lock since last check; qed")
2129 .get_mut(fork_offset)
2130 .expect("Still holding the same lock since last check; qed");
2131
2132 replace_with_or_abort(block, |block| {
2133 if let ClientDatabaseBlock::InMemory {
2134 block,
2135 block_details,
2136 beacon_chain_block_details,
2137 } = block
2138 {
2139 let (header, _body) = block.split();
2140
2141 ClientDatabaseBlock::Persisted {
2142 header,
2143 block_details,
2144 beacon_chain_block_details,
2145 write_location,
2146 }
2147 } else {
2148 unreachable!("Still holding the same lock since last check; qed");
2149 }
2150 });
2151 }
2152
2153 Ok(())
2165 }
2166
2167 #[must_use = "The return value indicates whether all parent blocks were found"]
2172 fn adjust_ancestor_block_forks(
2173 blocks: &mut VecDeque<SmallVec<[ClientDatabaseBlock<Block>; 2]>>,
2174 mut parent_block_root: BlockRoot,
2175 walk: AncestorBlockForksWalk,
2176 ) -> bool {
2177 for (block_offset, parent_blocks) in blocks.iter_mut().enumerate() {
2178 if let AncestorBlockForksWalk::UpToBlockOffset { max_block_offset } = walk
2179 && block_offset > max_block_offset
2180 {
2181 break;
2182 }
2183
2184 let Some(fork_offset_parent_block_root) =
2185 parent_blocks
2186 .iter()
2187 .enumerate()
2188 .find_map(|(fork_offset, fork_block)| {
2189 let fork_header = fork_block.header().header();
2190 if *fork_header.root() == parent_block_root {
2191 Some((fork_offset, fork_header.prefix.parent_root))
2192 } else {
2193 None
2194 }
2195 })
2196 else {
2197 return false;
2198 };
2199
2200 let fork_offset;
2201 (fork_offset, parent_block_root) = fork_offset_parent_block_root;
2202
2203 if fork_offset == 0 && matches!(walk, AncestorBlockForksWalk::UntilCanonical) {
2204 break;
2206 }
2207
2208 parent_blocks.swap(0, fork_offset);
2209 }
2210
2211 true
2212 }
2213
2214 fn prune_outdated_fork_tips(
2221 best_number: BlockNumber,
2222 state: &mut StateData<Block>,
2223 options: &ClientDatabaseInnerOptions,
2224 ) {
2225 let state = &mut *state;
2226
2227 let mut candidate_forks_to_remove = Vec::with_capacity(options.max_fork_tips.get());
2230
2231 state.fork_tips.retain(|fork_tip| {
2233 if best_number - fork_tip.number > options.max_fork_tip_distance {
2234 candidate_forks_to_remove.push(*fork_tip);
2235 false
2236 } else {
2237 true
2238 }
2239 });
2240 if state.fork_tips.len() > options.max_fork_tips.get() {
2242 state
2243 .fork_tips
2244 .drain(options.max_fork_tips.get()..)
2245 .collect_into(&mut candidate_forks_to_remove);
2246 }
2247
2248 candidate_forks_to_remove
2250 .retain(|fork_tip| !Self::prune_outdated_fork(best_number, fork_tip, state));
2251 state.fork_tips.extend(candidate_forks_to_remove);
2253 }
2254
2255 #[must_use = "The return value indicates whether the fork tip was pruned"]
2258 fn prune_outdated_fork(
2259 best_number: BlockNumber,
2260 fork_tip: &ForkTip,
2261 state: &mut StateData<Block>,
2262 ) -> bool {
2263 let block_offset = u64::from(best_number - fork_tip.number) as usize;
2264
2265 let mut block_root_to_prune = fork_tip.root;
2267 let mut pruned_tip = false;
2268 for block_offset in block_offset.. {
2269 let Some(fork_blocks) = state.blocks.get_mut(block_offset) else {
2270 if !pruned_tip {
2271 error!(
2272 %best_number,
2273 ?fork_tip,
2274 block_offset,
2275 "Block offset was not present in the database, this is an implementation \
2276 bug #1"
2277 );
2278 }
2279 break;
2281 };
2282
2283 if fork_blocks.len() == 1 {
2284 if !pruned_tip {
2285 error!(
2286 %best_number,
2287 ?fork_tip,
2288 block_offset,
2289 "Block offset was not present in the database, this is an implementation \
2290 bug #2"
2291 );
2292 }
2293
2294 break;
2296 }
2297
2298 let Some((fork_offset, block)) = fork_blocks
2299 .iter()
2300 .enumerate()
2301 .skip(1)
2303 .find(|(_fork_offset, block)| {
2304 *block.header().header().root() == block_root_to_prune
2305 })
2306 else {
2307 if !pruned_tip {
2308 error!(
2309 %best_number,
2310 ?fork_tip,
2311 block_offset,
2312 "Block offset was not present in the database, this is an implementation \
2313 bug #3"
2314 );
2315 }
2316
2317 break;
2319 };
2320
2321 let header = block.header();
2322
2323 if header.ref_count() > 1 {
2326 break;
2327 }
2328
2329 #[expect(
2331 clippy::rest_pattern_accessible_field,
2332 reason = "Do not care about fields"
2333 )]
2334 match block {
2335 ClientDatabaseBlock::InMemory { .. } => {
2336 }
2338 ClientDatabaseBlock::Persisted { .. }
2339 | ClientDatabaseBlock::PersistedConfirmed { .. } => {
2340 pruned_tip = true;
2342 break;
2343 }
2344 }
2345
2346 let parent_root = header.header().prefix.parent_root;
2347 state.block_roots.remove(&block_root_to_prune);
2348 fork_blocks.swap_remove(fork_offset);
2349
2350 pruned_tip = true;
2351
2352 if fork_blocks
2354 .iter()
2355 .any(|fork_block| fork_block.header().header().prefix.parent_root == parent_root)
2356 {
2357 break;
2358 }
2359
2360 block_root_to_prune = parent_root;
2361 }
2362
2363 pruned_tip
2364 }
2365
2366 fn confirm_canonical_block(
2373 best_number: BlockNumber,
2374 state_data: &mut StateData<Block>,
2375 options: &ClientDatabaseInnerOptions,
2376 ) {
2377 let block_offset = u64::from(options.block_confirmation_depth) as usize;
2388
2389 let Some(fork_blocks) = state_data.blocks.get_mut(block_offset) else {
2390 return;
2392 };
2393
2394 let Some(canonical_block) = fork_blocks.first_mut() else {
2396 error!(
2397 %best_number,
2398 block_offset,
2399 "Have not found a canonical block to confirm, this is an implementation bug"
2400 );
2401 return;
2402 };
2403
2404 replace_with_or_abort(canonical_block, |block| {
2405 #[expect(
2406 clippy::rest_pattern_accessible_field,
2407 reason = "Do not need other fields"
2408 )]
2409 match block {
2410 ClientDatabaseBlock::InMemory { .. } => {
2411 error!(
2412 %best_number,
2413 block_offset,
2414 header = ?block.header(),
2415 "Block to be confirmed must not be in memory, this is an implementation bug"
2416 );
2417 block
2418 }
2419 ClientDatabaseBlock::Persisted {
2420 header,
2421 block_details: _,
2422 beacon_chain_block_details,
2423 write_location,
2424 } => ClientDatabaseBlock::PersistedConfirmed {
2425 header,
2426 beacon_chain_block_details,
2427 write_location,
2428 },
2429 ClientDatabaseBlock::PersistedConfirmed { .. } => {
2430 error!(
2431 %best_number,
2432 block_offset,
2433 header = ?block.header(),
2434 "Block to be confirmed must not be confirmed yet, this is an \
2435 implementation bug"
2436 );
2437 block
2438 }
2439 }
2440 });
2441 }
2442
2443 fn prune_non_canonical_blocks(block_offset: usize, state_data: &mut StateData<Block>) {
2445 let Some(fork_blocks) = state_data.blocks.get_mut(block_offset) else {
2446 return;
2447 };
2448
2449 let mut block_roots_to_prune = fork_blocks
2450 .drain(1..)
2451 .map(|block| *block.header().header().root())
2452 .collect::<Vec<_>>();
2453 let mut current_block_offset = block_offset;
2454 while !block_roots_to_prune.is_empty() {
2455 state_data
2457 .fork_tips
2458 .retain(|fork_tip| !block_roots_to_prune.contains(&fork_tip.root));
2459
2460 for block_root in &block_roots_to_prune {
2462 state_data.block_roots.remove(block_root);
2463 }
2464
2465 if let Some(next_block_offset) = current_block_offset.checked_sub(1) {
2467 current_block_offset = next_block_offset;
2468 } else {
2469 break;
2471 }
2472
2473 let fork_blocks = state_data
2474 .blocks
2475 .get_mut(current_block_offset)
2476 .expect("Lower block offset always exists; qed");
2477
2478 block_roots_to_prune = fork_blocks
2480 .drain_filter(|block| {
2481 let header = block.header().header();
2482
2483 block_roots_to_prune.contains(&header.prefix.parent_root)
2484 })
2485 .map(|block| *block.header().header().root())
2486 .collect();
2487 }
2488 }
2489}