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
57use crate::page_group::temporary::StorageItemTemporary;
58use crate::page_group::temporary::block::StorageItemTemporaryBlock;
59use crate::page_group::temporary::segment_headers::StorageItemTemporarySegmentHeaders;
60use crate::page_group::temporary::super_segment_headers::StorageItemTemporarySuperSegmentHeaders;
61use crate::storage_backend::ClientDatabaseStorageBackend;
62use crate::storage_backend_adapter::{
63 StorageBackendAdapter, StorageItemHandlerArg, StorageItemHandlers, WriteLocation,
64};
65use ab_client_api::{
66 BeaconChainInfo, BeaconChainInfoWrite, BlockDetails, BlockMerkleMountainRange, ChainInfo,
67 ChainInfoWrite, ContractSlotState, PersistBlockError, PersistSegmentHeadersError,
68 PersistSuperSegmentHeadersError, ReadBlockError, ShardSegmentRoot, ShardSegmentRootsError,
69};
70use ab_core_primitives::block::body::BeaconChainBody;
71use ab_core_primitives::block::body::owned::{GenericOwnedBlockBody, OwnedBeaconChainBody};
72use ab_core_primitives::block::header::GenericBlockHeader;
73use ab_core_primitives::block::header::owned::GenericOwnedBlockHeader;
74use ab_core_primitives::block::owned::{GenericOwnedBlock, OwnedBeaconChainBlock};
75use ab_core_primitives::block::{BlockNumber, BlockRoot, GenericBlock};
76use ab_core_primitives::segments::{
77 LocalSegmentIndex, SegmentHeader, SegmentIndex, SuperSegmentHeader, SuperSegmentIndex,
78};
79use ab_core_primitives::shard::RealShardKind;
80use ab_io_type::trivial_type::TrivialType;
81use async_lock::{
82 RwLock as AsyncRwLock, RwLockUpgradableReadGuard, RwLockWriteGuard as AsyncRwLockWriteGuard,
83};
84use rand::rngs::SysError;
85use replace_with::replace_with_or_abort;
86use smallvec::{SmallVec, smallvec};
87use std::any::Any;
88use std::collections::{HashMap, VecDeque};
89use std::hash::{BuildHasherDefault, Hasher};
90use std::num::{NonZeroU32, NonZeroUsize};
91use std::ops::Deref;
92use std::{fmt, io};
93use tracing::error;
94use triomphe::Arc;
95
96#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
98#[repr(C)]
99pub struct DatabaseId([u8; 32]);
100
101impl Deref for DatabaseId {
102 type Target = [u8; 32];
103
104 #[inline(always)]
105 fn deref(&self) -> &Self::Target {
106 &self.0
107 }
108}
109
110impl AsRef<[u8]> for DatabaseId {
111 #[inline(always)]
112 fn as_ref(&self) -> &[u8] {
113 &self.0
114 }
115}
116
117impl DatabaseId {
118 #[inline(always)]
119 pub const fn new(bytes: [u8; 32]) -> Self {
120 Self(bytes)
121 }
122}
123
124#[derive(Default)]
125struct BlockRootHasher(u64);
126
127impl Hasher for BlockRootHasher {
128 #[inline(always)]
129 fn finish(&self) -> u64 {
130 self.0
131 }
132
133 #[inline(always)]
134 fn write(&mut self, bytes: &[u8]) {
135 let Some(state) = bytes.as_chunks().0.first().copied().map(u64::from_le_bytes) else {
136 return;
137 };
138
139 self.0 = state;
140 }
141}
142
143#[derive(Debug)]
144pub struct GenesisBlockBuilderResult<Block> {
145 pub block: Block,
147 pub system_contract_states: Arc<[ContractSlotState]>,
149}
150
151#[derive(Debug, Copy, Clone)]
153pub struct ClientDatabaseOptions<GBB, StorageBackend> {
154 pub write_buffer_size: usize = 5,
162 pub block_confirmation_depth: BlockNumber,
168 pub soft_confirmation_depth: BlockNumber = BlockNumber::from(3),
182 pub max_fork_tips: NonZeroUsize = NonZeroUsize::new(3).expect("Not zero; qed"),
193 pub max_fork_tip_distance: BlockNumber = BlockNumber::from(5),
204 pub genesis_block_builder: GBB,
207 pub storage_backend: StorageBackend,
209}
210
211#[derive(Debug, Copy, Clone)]
213pub struct ClientDatabaseFormatOptions {
214 pub page_group_size: NonZeroU32,
231 pub force: bool,
235}
236
237#[derive(Debug, thiserror::Error)]
238pub enum ClientDatabaseError {
239 #[error("Invalid soft confirmation depth, it must be smaller than confirmation depth k")]
241 InvalidSoftConfirmationDepth,
242 #[error("Invalid max fork tip distance, it must be smaller or equal to confirmation depth k")]
244 InvalidMaxForkTipDistance,
245 #[error("Storage backend has canceled read request")]
247 ReadRequestCancelled,
248 #[error("Storage backend read error: {error}")]
250 ReadError {
251 error: io::Error,
253 },
254 #[error("Unsupported database version: {database_version}")]
256 UnsupportedDatabaseVersion {
257 database_version: u8,
259 },
260 #[error("Page group size is too small ({page_group_size}), must be at least two pages")]
262 PageGroupSizeTooSmall {
263 page_group_size: u32,
265 },
266 #[error(
268 "Unexpected sequence number {actual} at page offset {page_offset} (expected \
269 {expected})"
270 )]
271 UnexpectedSequenceNumber {
272 actual: u64,
274 expected: u64,
276 page_offset: u32,
278 },
279 #[error("Unexpected storage item at offset {page_offset}: {storage_item:?}")]
281 UnexpectedStorageItem {
282 storage_item: Box<dyn fmt::Debug + Send + Sync>,
284 page_offset: u32,
286 },
287 #[error("Invalid block at offset {page_offset}")]
289 InvalidBlock {
290 page_offset: u32,
292 },
293 #[error("Invalid segment headers at offset {page_offset}")]
295 InvalidSegmentHeaders {
296 page_offset: u32,
298 },
299 #[error("Failed to adjust ancestor block forks")]
301 FailedToAdjustAncestorBlockForks,
302 #[error("Database is not formatted yet")]
304 Unformatted,
305 #[error("Non-permanent first page group")]
307 NonPermanentFirstPageGroup,
308}
309
310#[derive(Debug, thiserror::Error)]
312pub enum ClientDatabaseFormatError {
313 #[error("Storage backend has canceled read request")]
315 ReadRequestCancelled,
316 #[error("Storage backend read error: {error}")]
318 ReadError {
319 error: io::Error,
321 },
322 #[error("Failed to generate database id")]
324 FailedToGenerateDatabaseId {
325 #[from]
327 error: SysError,
328 },
329 #[error("Database is already formatted yet")]
331 AlreadyFormatted,
332 #[error("Storage backend has canceled a writing request")]
334 WriteRequestCancelled,
335 #[error("Storage item write error")]
337 StorageItemWriteError {
338 #[from]
340 error: io::Error,
341 },
342}
343
344#[derive(Debug, Copy, Clone)]
345struct ForkTip {
346 number: BlockNumber,
347 root: BlockRoot,
348}
349
350enum FullBlock<'a, Block>
351where
352 Block: GenericOwnedBlock,
353{
354 InMemory(&'a Block),
355 Persisted {
356 header: &'a Block::Header,
357 write_location: WriteLocation,
358 },
359}
360
361#[derive(Debug)]
362struct BeaconChainBlockDetails {
363 shard_segment_roots: Arc<[ShardSegmentRoot]>,
365}
366
367impl BeaconChainBlockDetails {
368 fn from_body(body: &BeaconChainBody<'_>) -> Self {
369 let shard_segment_roots = body
370 .intermediate_shard_blocks()
371 .iter()
372 .flat_map(|intermediate_shard_block_info| {
373 let own_segments = intermediate_shard_block_info
374 .own_segments
375 .into_iter()
376 .flat_map({
377 let shard_index = intermediate_shard_block_info.header.prefix.shard_index;
378
379 move |own_segments| {
380 (own_segments.first_local_segment_index..)
381 .zip(own_segments.segment_roots)
382 .map(move |(segment_index, &segment_root)| ShardSegmentRoot {
383 shard_index,
384 segment_index,
385 segment_root,
386 })
387 }
388 });
389 let child_shard_segment_roots = intermediate_shard_block_info
390 .leaf_shards_segments()
391 .flat_map(move |(shard_index, own_segments)| {
392 (own_segments.first_local_segment_index..)
393 .zip(own_segments.segment_roots)
394 .map(move |(segment_index, &segment_root)| ShardSegmentRoot {
395 shard_index,
396 segment_index,
397 segment_root,
398 })
399 });
400
401 own_segments.chain(child_shard_segment_roots)
402 })
403 .collect();
404
405 Self {
406 shard_segment_roots,
407 }
408 }
409}
410
411#[derive(Debug)]
418enum ClientDatabaseBlock<Block>
419where
420 Block: GenericOwnedBlock,
421{
422 InMemory {
424 block: Block,
425 block_details: BlockDetails,
426 beacon_chain_block_details: Option<BeaconChainBlockDetails>,
428 },
429 Persisted {
431 header: Block::Header,
432 block_details: BlockDetails,
433 beacon_chain_block_details: Option<BeaconChainBlockDetails>,
435 write_location: WriteLocation,
436 },
437 PersistedConfirmed {
440 header: Block::Header,
441 beacon_chain_block_details: Option<BeaconChainBlockDetails>,
443 write_location: WriteLocation,
444 },
445}
446
447impl<Block> ClientDatabaseBlock<Block>
448where
449 Block: GenericOwnedBlock,
450{
451 #[inline(always)]
452 fn header(&self) -> &Block::Header {
453 #[expect(
454 clippy::rest_pattern_accessible_field,
455 reason = "Do not need other fields"
456 )]
457 match self {
458 Self::InMemory { block, .. } => block.header(),
459 Self::Persisted { header, .. } | Self::PersistedConfirmed { header, .. } => header,
460 }
461 }
462
463 #[inline(always)]
464 fn full_block(&self) -> FullBlock<'_, Block> {
465 #[expect(
466 clippy::rest_pattern_accessible_field,
467 reason = "Do not need other fields"
468 )]
469 match self {
470 Self::InMemory { block, .. } => FullBlock::InMemory(block),
471 Self::Persisted {
472 header,
473 write_location,
474 ..
475 }
476 | Self::PersistedConfirmed {
477 header,
478 write_location,
479 ..
480 } => FullBlock::Persisted {
481 header,
482 write_location: *write_location,
483 },
484 }
485 }
486
487 #[inline(always)]
488 fn block_details(&self) -> Option<&BlockDetails> {
489 #[expect(
490 clippy::rest_pattern_accessible_field,
491 reason = "Do not need other fields"
492 )]
493 match self {
494 Self::InMemory { block_details, .. } | Self::Persisted { block_details, .. } => {
495 Some(block_details)
496 }
497 Self::PersistedConfirmed { .. } => None,
498 }
499 }
500
501 #[inline(always)]
502 fn beacon_chain_block_details(&self) -> Option<&BeaconChainBlockDetails> {
503 #[expect(
504 clippy::rest_pattern_accessible_field,
505 reason = "Do not need other fields"
506 )]
507 match self {
508 Self::InMemory {
509 beacon_chain_block_details,
510 ..
511 }
512 | Self::Persisted {
513 beacon_chain_block_details,
514 ..
515 }
516 | Self::PersistedConfirmed {
517 beacon_chain_block_details,
518 ..
519 } => beacon_chain_block_details.as_ref(),
520 }
521 }
522}
523
524#[derive(Debug)]
525struct StateData<Block>
526where
527 Block: GenericOwnedBlock,
528{
529 fork_tips: VecDeque<ForkTip>,
534 block_roots: HashMap<BlockRoot, BlockNumber, BuildHasherDefault<BlockRootHasher>>,
539 blocks: VecDeque<SmallVec<[ClientDatabaseBlock<Block>; 2]>>,
554}
555
556#[derive(Debug)]
557struct SegmentHeadersCache {
558 segment_headers_cache: Vec<SegmentHeader>,
559}
560
561impl SegmentHeadersCache {
562 #[inline(always)]
563 fn last_segment_header(&self) -> Option<SegmentHeader> {
564 self.segment_headers_cache.last().copied()
565 }
566
567 #[inline(always)]
568 fn max_local_segment_index(&self) -> Option<LocalSegmentIndex> {
569 self.segment_headers_cache
570 .last()
571 .map(|segment_header| segment_header.index.as_inner())
572 }
573
574 #[inline(always)]
575 fn get_segment_header(&self, local_segment_index: LocalSegmentIndex) -> Option<SegmentHeader> {
576 self.segment_headers_cache
577 .get(u64::from(local_segment_index) as usize)
578 .copied()
579 }
580
581 fn add_segment_headers(
583 &mut self,
584 mut segment_headers: Vec<SegmentHeader>,
585 ) -> Result<Vec<SegmentHeader>, PersistSegmentHeadersError> {
586 self.segment_headers_cache.reserve(segment_headers.len());
587
588 let mut maybe_last_local_segment_index = self.max_local_segment_index();
589
590 if let Some(last_segment_index) = maybe_last_local_segment_index {
591 segment_headers
593 .retain(|segment_header| segment_header.index.as_inner() > last_segment_index);
594 }
595
596 for segment_header in segment_headers.iter().copied() {
599 let local_segment_index = segment_header.index.as_inner();
600 if let Some(last_local_segment_index) = maybe_last_local_segment_index {
601 if local_segment_index != last_local_segment_index + LocalSegmentIndex::ONE {
602 return Err(PersistSegmentHeadersError::MustFollowLastSegmentIndex {
603 local_segment_index,
604 last_local_segment_index,
605 });
606 }
607
608 self.segment_headers_cache.push(segment_header);
609 maybe_last_local_segment_index.replace(local_segment_index);
610 } else {
611 if local_segment_index != LocalSegmentIndex::ZERO {
612 return Err(PersistSegmentHeadersError::FirstSegmentIndexZero {
613 local_segment_index,
614 });
615 }
616
617 self.segment_headers_cache.push(segment_header);
618 maybe_last_local_segment_index.replace(local_segment_index);
619 }
620 }
621
622 Ok(segment_headers)
623 }
624}
625
626#[derive(Debug)]
627struct SuperSegmentHeadersCache {
628 super_segment_headers_cache: Vec<SuperSegmentHeader>,
629}
630
631impl SuperSegmentHeadersCache {
632 #[inline(always)]
633 fn last_super_segment_header(&self) -> Option<SuperSegmentHeader> {
634 self.super_segment_headers_cache.last().copied()
635 }
636
637 #[inline]
638 fn previous_super_segment_header(
639 &self,
640 target_block_number: BlockNumber,
641 ) -> Option<SuperSegmentHeader> {
642 let block_number = target_block_number.checked_sub(BlockNumber::ONE)?;
643 let index = match self.super_segment_headers_cache.binary_search_by_key(
644 &block_number,
645 |super_segment_header| {
646 super_segment_header
647 .target_beacon_chain_block_number
648 .as_inner()
649 },
650 ) {
651 Ok(found_index) => found_index,
652 Err(insert_index) => insert_index.checked_sub(1)?,
653 };
654
655 self.super_segment_headers_cache.get(index).copied()
656 }
657
658 #[inline(always)]
659 fn get_super_segment_header(
660 &self,
661 local_segment_index: SuperSegmentIndex,
662 ) -> Option<SuperSegmentHeader> {
663 self.super_segment_headers_cache
664 .get(u64::from(local_segment_index) as usize)
665 .copied()
666 }
667
668 #[inline(always)]
669 fn get_super_segment_header_for_segment_index(
670 &self,
671 segment_index: SegmentIndex,
672 ) -> Option<SuperSegmentHeader> {
673 let index = self
674 .super_segment_headers_cache
675 .binary_search_by_key(&segment_index, |super_segment_header| {
676 super_segment_header.max_segment_index.as_inner()
677 })
678 .unwrap_or_else(|insert_index| insert_index);
679
680 let super_segment_header = self.super_segment_headers_cache.get(index).copied()?;
681
682 let max_segment_index = super_segment_header.max_segment_index.as_inner();
683 let first_segment_index = max_segment_index
684 - SegmentIndex::from(u64::from(super_segment_header.num_segments))
685 + SegmentIndex::ONE;
686
687 (first_segment_index..=max_segment_index)
688 .contains(&segment_index)
689 .then_some(super_segment_header)
690 }
691
692 fn add_super_segment_headers(
694 &mut self,
695 mut super_segment_headers: Vec<SuperSegmentHeader>,
696 ) -> Result<Vec<SuperSegmentHeader>, PersistSuperSegmentHeadersError> {
697 self.super_segment_headers_cache
698 .reserve(super_segment_headers.len());
699
700 let mut maybe_last_super_segment_index = self
701 .super_segment_headers_cache
702 .last()
703 .map(|header| header.index.as_inner());
704
705 if let Some(last_super_segment_index) = maybe_last_super_segment_index {
706 super_segment_headers.retain(|super_segment_header| {
708 super_segment_header.index.as_inner() > last_super_segment_index
709 });
710 }
711
712 for super_segment_header in super_segment_headers.iter().copied() {
715 let super_segment_index = super_segment_header.index.as_inner();
716 if let Some(last_super_segment_index) = maybe_last_super_segment_index {
717 if super_segment_index != last_super_segment_index + SuperSegmentIndex::ONE {
718 return Err(
719 PersistSuperSegmentHeadersError::MustFollowLastSegmentIndex {
720 super_segment_index,
721 last_super_segment_index,
722 },
723 );
724 }
725
726 self.super_segment_headers_cache.push(super_segment_header);
727 maybe_last_super_segment_index.replace(super_segment_index);
728 } else {
729 if super_segment_index != SuperSegmentIndex::ZERO {
730 return Err(PersistSuperSegmentHeadersError::FirstSegmentIndexZero {
731 super_segment_index,
732 });
733 }
734
735 self.super_segment_headers_cache.push(super_segment_header);
736 maybe_last_super_segment_index.replace(super_segment_index);
737 }
738 }
739
740 Ok(super_segment_headers)
741 }
742}
743
744#[derive(Debug)]
746struct State<Block, StorageBackend>
747where
748 Block: GenericOwnedBlock,
749{
750 data: StateData<Block>,
751 segment_headers_cache: SegmentHeadersCache,
752 super_segment_headers_cache: SuperSegmentHeadersCache,
753 storage_backend_adapter: AsyncRwLock<StorageBackendAdapter<StorageBackend>>,
754}
755
756impl<Block, StorageBackend> State<Block, StorageBackend>
757where
758 Block: GenericOwnedBlock,
759{
760 #[inline(always)]
761 fn best_tip(&self) -> &ForkTip {
762 self.data
763 .fork_tips
764 .front()
765 .expect("The best block is always present; qed")
766 }
767
768 #[inline(always)]
769 fn best_block(&self) -> &ClientDatabaseBlock<Block> {
770 self.data
771 .blocks
772 .front()
773 .expect("The best block is always present; qed")
774 .first()
775 .expect("The best block is always present; qed")
776 }
777}
778
779#[derive(Debug)]
780struct BlockToPersist<'a, Block>
781where
782 Block: GenericOwnedBlock,
783{
784 block_offset: usize,
785 fork_offset: usize,
786 block: &'a Block,
787 block_details: &'a BlockDetails,
788}
789
790#[derive(Debug)]
791struct PersistedBlock {
792 block_offset: usize,
793 fork_offset: usize,
794 write_location: WriteLocation,
795}
796
797#[derive(Debug)]
798struct ClientDatabaseInnerOptions {
799 block_confirmation_depth: BlockNumber,
800 soft_confirmation_depth: BlockNumber,
801 max_fork_tips: NonZeroUsize,
802 max_fork_tip_distance: BlockNumber,
803}
804
805#[derive(Debug)]
806struct Inner<Block, StorageBackend>
807where
808 Block: GenericOwnedBlock,
809{
810 state: AsyncRwLock<State<Block, StorageBackend>>,
811 options: ClientDatabaseInnerOptions,
812}
813
814#[derive(Debug)]
816pub struct ClientDatabase<Block, StorageBackend>
817where
818 Block: GenericOwnedBlock,
819{
820 inner: Arc<Inner<Block, StorageBackend>>,
821}
822
823impl<Block, StorageBackend> Clone for ClientDatabase<Block, StorageBackend>
824where
825 Block: GenericOwnedBlock,
826{
827 fn clone(&self) -> Self {
828 Self {
829 inner: self.inner.clone(),
830 }
831 }
832}
833
834#[expect(clippy::empty_drop, reason = "Not implemented yet")]
835impl<Block, StorageBackend> Drop for ClientDatabase<Block, StorageBackend>
836where
837 Block: GenericOwnedBlock,
838{
839 fn drop(&mut self) {
840 }
842}
843
844impl<Block, StorageBackend> ChainInfo<Block> for ClientDatabase<Block, StorageBackend>
845where
846 Block: GenericOwnedBlock,
847 StorageBackend: ClientDatabaseStorageBackend,
848{
849 #[inline]
850 fn best_root(&self) -> BlockRoot {
851 self.inner.state.read_blocking().best_tip().root
854 }
855
856 #[inline]
857 fn best_header(&self) -> Block::Header {
858 self.inner
861 .state
862 .read_blocking()
863 .best_block()
864 .header()
865 .clone()
866 }
867
868 #[inline]
869 fn best_header_with_details(&self) -> (Block::Header, BlockDetails) {
870 let state = self.inner.state.read_blocking();
873 let best_block = state.best_block();
874 (
875 best_block.header().clone(),
876 best_block
877 .block_details()
878 .expect("Always present for the best block; qed")
879 .clone(),
880 )
881 }
882
883 #[inline]
885 fn ancestor_header(
886 &self,
887 ancestor_block_number: BlockNumber,
888 descendant_block_root: &BlockRoot,
889 ) -> Option<Block::Header> {
890 let state = self.inner.state.read_blocking();
893 let best_number = state.best_tip().number;
894
895 let ancestor_block_offset =
896 u64::from(best_number.checked_sub(ancestor_block_number)?) as usize;
897 let ancestor_block_candidates = state.data.blocks.get(ancestor_block_offset)?;
898
899 let descendant_block_number = *state.data.block_roots.get(descendant_block_root)?;
900 if ancestor_block_number > descendant_block_number {
901 return None;
902 }
903 let descendant_block_offset =
904 u64::from(best_number.checked_sub(descendant_block_number)?) as usize;
905
906 let mut blocks_range_iter = state
908 .data
909 .blocks
910 .iter()
911 .enumerate()
912 .skip(descendant_block_offset);
913
914 let (_offset, descendant_block_candidates) = blocks_range_iter.next()?;
915 let descendant_header = descendant_block_candidates
916 .iter()
917 .find(|block| &*block.header().header().root() == descendant_block_root)?
918 .header()
919 .header();
920
921 if descendant_block_candidates.len() == 1 || ancestor_block_candidates.len() == 1 {
926 return ancestor_block_candidates
927 .iter()
928 .next()
929 .map(|block| block.header().clone());
930 }
931
932 let mut parent_block_root = &descendant_header.prefix.parent_root;
933
934 for (block_offset, parent_candidates) in blocks_range_iter {
936 let parent_header = parent_candidates
937 .iter()
938 .find(|header| &*header.header().header().root() == parent_block_root)?
939 .header();
940
941 if block_offset == ancestor_block_offset {
943 return Some(parent_header.clone());
944 }
945
946 parent_block_root = &parent_header.header().prefix.parent_root;
947 }
948
949 None
950 }
951
952 #[inline]
953 fn header(&self, block_root: &BlockRoot) -> Option<Block::Header> {
954 let state = self.inner.state.read_blocking();
957 let best_number = state.best_tip().number;
958
959 let block_number = *state.data.block_roots.get(block_root)?;
960 let block_offset = u64::from(best_number.checked_sub(block_number)?) as usize;
961 let block_candidates = state.data.blocks.get(block_offset)?;
962
963 block_candidates.iter().find_map(|block| {
964 let header = block.header();
965
966 if &*header.header().root() == block_root {
967 Some(header.clone())
968 } else {
969 None
970 }
971 })
972 }
973
974 #[inline]
975 fn header_with_details(&self, block_root: &BlockRoot) -> Option<(Block::Header, BlockDetails)> {
976 let state = self.inner.state.read_blocking();
979 let best_number = state.best_tip().number;
980
981 let block_number = *state.data.block_roots.get(block_root)?;
982 let block_offset = u64::from(best_number.checked_sub(block_number)?) as usize;
983 let block_candidates = state.data.blocks.get(block_offset)?;
984
985 block_candidates.iter().find_map(|block| {
986 let header = block.header();
987 let block_details = block.block_details().cloned()?;
988
989 if &*header.header().root() == block_root {
990 Some((header.clone(), block_details))
991 } else {
992 None
993 }
994 })
995 }
996
997 #[inline]
998 async fn block(&self, block_root: &BlockRoot) -> Result<Block, ReadBlockError> {
999 let state = self.inner.state.read().await;
1000 let best_number = state.best_tip().number;
1001
1002 let block_number = *state
1003 .data
1004 .block_roots
1005 .get(block_root)
1006 .ok_or(ReadBlockError::UnknownBlockRoot)?;
1007 let block_offset = u64::from(
1008 best_number
1009 .checked_sub(block_number)
1010 .expect("Known block roots always have valid block offset; qed"),
1011 ) as usize;
1012 let block_candidates = state
1013 .data
1014 .blocks
1015 .get(block_offset)
1016 .expect("Valid block offsets always have block entries; qed");
1017
1018 for block_candidate in block_candidates {
1019 let header = block_candidate.header();
1020
1021 if &*header.header().root() == block_root {
1022 return match block_candidate.full_block() {
1023 FullBlock::InMemory(block) => Ok(block.clone()),
1024 FullBlock::Persisted {
1025 header,
1026 write_location,
1027 } => {
1028 let storage_backend_adapter = state.storage_backend_adapter.read().await;
1029
1030 let storage_item = storage_backend_adapter
1031 .read_storage_item::<StorageItemTemporary>(write_location)
1032 .await?;
1033
1034 let storage_item_block = match storage_item {
1035 StorageItemTemporary::Block(storage_item_block) => storage_item_block,
1036 StorageItemTemporary::SegmentHeaders(_) => {
1037 return Err(ReadBlockError::StorageItemReadError {
1038 error: io::Error::other(
1039 "Unexpected storage item: `SegmentHeaders`",
1040 ),
1041 });
1042 }
1043 StorageItemTemporary::SuperSegmentHeaders(_) => {
1044 return Err(ReadBlockError::StorageItemReadError {
1045 error: io::Error::other(
1046 "Unexpected storage item: `SuperSegmentHeaders`",
1047 ),
1048 });
1049 }
1050 };
1051
1052 let StorageItemTemporaryBlock {
1053 header: _,
1054 body,
1055 mmr_with_block: _,
1056 system_contract_states: _,
1057 } = storage_item_block;
1058
1059 Block::from_buffers(header.buffer().clone(), body)
1060 .ok_or(ReadBlockError::FailedToDecode)
1061 }
1062 };
1063 }
1064 }
1065
1066 unreachable!("Known block root always has block candidate associated with it; qed")
1067 }
1068
1069 #[inline]
1070 fn last_segment_header(&self) -> Option<SegmentHeader> {
1071 let state = self.inner.state.read_blocking();
1074 state.segment_headers_cache.last_segment_header()
1075 }
1076
1077 #[inline]
1078 fn get_segment_header(&self, segment_index: LocalSegmentIndex) -> Option<SegmentHeader> {
1079 let state = self.inner.state.read_blocking();
1082
1083 state
1084 .segment_headers_cache
1085 .get_segment_header(segment_index)
1086 }
1087
1088 fn segment_headers_for_block(&self, block_number: BlockNumber) -> Vec<SegmentHeader> {
1089 let state = self.inner.state.read_blocking();
1092
1093 let Some(last_local_segment_index) = state.segment_headers_cache.max_local_segment_index()
1094 else {
1095 return Vec::new();
1097 };
1098
1099 if Block::Block::SHARD_KIND == RealShardKind::BeaconChain
1101 && block_number == BlockNumber::ONE
1102 {
1103 return vec![
1106 state
1107 .segment_headers_cache
1108 .get_segment_header(LocalSegmentIndex::ZERO)
1109 .expect("Segment headers are stored in monotonically increasing order; qed"),
1110 ];
1111 }
1112
1113 if last_local_segment_index == LocalSegmentIndex::ZERO {
1114 return Vec::new();
1116 }
1117
1118 let mut current_local_segment_index = last_local_segment_index;
1119 loop {
1120 let current_segment_header = state
1123 .segment_headers_cache
1124 .get_segment_header(current_local_segment_index)
1125 .expect("Segment headers are stored in monotonically increasing order; qed");
1126
1127 let target_block_number = current_segment_header.last_archived_block.number()
1129 + BlockNumber::ONE
1130 + self.inner.options.block_confirmation_depth;
1131 if target_block_number == block_number {
1132 let mut headers_for_block = vec![current_segment_header];
1133
1134 let last_archived_block_number = current_segment_header.last_archived_block.number;
1136 let mut local_segment_index = current_local_segment_index - LocalSegmentIndex::ONE;
1137
1138 while let Some(segment_header) = state
1139 .segment_headers_cache
1140 .get_segment_header(local_segment_index)
1141 {
1142 if segment_header.last_archived_block.number == last_archived_block_number {
1143 headers_for_block.insert(0, segment_header);
1144 local_segment_index -= LocalSegmentIndex::ONE;
1145 } else {
1146 break;
1147 }
1148 }
1149
1150 return headers_for_block;
1151 }
1152
1153 if target_block_number > block_number {
1155 if current_local_segment_index > LocalSegmentIndex::ONE {
1157 current_local_segment_index -= LocalSegmentIndex::ONE;
1158 } else {
1159 break;
1160 }
1161 } else {
1162 return Vec::new();
1164 }
1165 }
1166
1167 Vec::new()
1169 }
1170}
1171
1172impl<Block, StorageBackend> ChainInfoWrite<Block> for ClientDatabase<Block, StorageBackend>
1173where
1174 Block: GenericOwnedBlock,
1175 StorageBackend: ClientDatabaseStorageBackend,
1176{
1177 async fn persist_block(
1178 &self,
1179 block: Block,
1180 block_details: BlockDetails,
1181 ) -> Result<(), PersistBlockError> {
1182 let mut state = self.inner.state.write().await;
1183 let best_number = state.best_tip().number;
1184
1185 let header = block.header().header();
1186
1187 let block_number = header.prefix.number;
1188
1189 if best_number == BlockNumber::ZERO && block_number != BlockNumber::ONE {
1190 Self::insert_first_block(&mut state.data, block, block_details);
1192
1193 return Ok(());
1194 }
1195
1196 if block_number == best_number + BlockNumber::ONE {
1197 return Self::insert_new_best_block(state, &self.inner, block, block_details).await;
1198 }
1199
1200 let block_offset = u64::from(
1201 best_number
1202 .checked_sub(block_number)
1203 .ok_or(PersistBlockError::MissingParent)?,
1204 ) as usize;
1205
1206 if block_offset >= u64::from(self.inner.options.block_confirmation_depth) as usize {
1207 return Err(PersistBlockError::OutsideAcceptableRange);
1208 }
1209
1210 let state = &mut *state;
1211
1212 let block_forks = state.data.blocks.get_mut(block_offset).ok_or_else(|| {
1213 error!(
1214 %block_number,
1215 %block_offset,
1216 "Failed to store block fork, header offset is missing despite being within \
1217 acceptable range"
1218 );
1219
1220 PersistBlockError::OutsideAcceptableRange
1221 })?;
1222
1223 for (index, fork_tip) in state.data.fork_tips.iter_mut().enumerate() {
1224 if fork_tip.root == header.prefix.parent_root {
1226 state.data.fork_tips.remove(index);
1227 break;
1228 }
1229 }
1230
1231 let block_root = *header.root();
1232 state.data.fork_tips.insert(
1235 1,
1236 ForkTip {
1237 number: block_number,
1238 root: block_root,
1239 },
1240 );
1241 state.data.block_roots.insert(block_root, block_number);
1242 let beacon_chain_block_details = <dyn Any>::downcast_ref::<OwnedBeaconChainBlock>(&block)
1243 .map(|block| BeaconChainBlockDetails::from_body(block.body.body()));
1244 block_forks.push(ClientDatabaseBlock::InMemory {
1245 block,
1246 block_details,
1247 beacon_chain_block_details,
1248 });
1249
1250 Self::prune_outdated_fork_tips(block_number, &mut state.data, &self.inner.options);
1251
1252 Ok(())
1253 }
1254
1255 async fn persist_segment_headers(
1256 &self,
1257 segment_headers: Vec<SegmentHeader>,
1258 ) -> Result<(), PersistSegmentHeadersError> {
1259 let mut state = self.inner.state.write().await;
1260
1261 let added_segment_headers = state
1262 .segment_headers_cache
1263 .add_segment_headers(segment_headers)?;
1264
1265 if added_segment_headers.is_empty() {
1266 return Ok(());
1267 }
1268
1269 let state = AsyncRwLockWriteGuard::downgrade_to_upgradable(state);
1274
1275 let mut storage_backend_adapter = state.storage_backend_adapter.write().await;
1276
1277 storage_backend_adapter
1278 .write_storage_item(StorageItemTemporary::SegmentHeaders(
1279 StorageItemTemporarySegmentHeaders {
1280 segment_headers: added_segment_headers,
1281 },
1282 ))
1283 .await?;
1284
1285 Ok(())
1286 }
1287}
1288
1289impl<StorageBackend> BeaconChainInfo for ClientDatabase<OwnedBeaconChainBlock, StorageBackend>
1290where
1291 StorageBackend: ClientDatabaseStorageBackend,
1292{
1293 fn shard_segment_roots(
1294 &self,
1295 block_number: BlockNumber,
1296 ) -> Result<Arc<[ShardSegmentRoot]>, ShardSegmentRootsError> {
1297 let state = self.inner.state.read_blocking();
1300 let best_number = state.best_tip().number;
1301
1302 let block_offset = u64::from(
1303 best_number
1304 .checked_sub(block_number)
1305 .ok_or(ShardSegmentRootsError::BlockMissing { block_number })?,
1306 ) as usize;
1307
1308 let block = state
1309 .data
1310 .blocks
1311 .get(block_offset)
1312 .ok_or(ShardSegmentRootsError::BlockMissing { block_number })?
1313 .first()
1314 .expect("There is always at least one block candidate; qed");
1315
1316 Ok(Arc::clone(
1317 &block
1318 .beacon_chain_block_details()
1319 .as_ref()
1320 .expect("Always present in the beacon chain block; qed")
1321 .shard_segment_roots,
1322 ))
1323 }
1324
1325 #[inline]
1326 fn last_super_segment_header(&self) -> Option<SuperSegmentHeader> {
1327 let state = self.inner.state.read_blocking();
1330 state
1331 .super_segment_headers_cache
1332 .last_super_segment_header()
1333 }
1334
1335 #[inline]
1336 fn previous_super_segment_header(
1337 &self,
1338 block_number: BlockNumber,
1339 ) -> Option<SuperSegmentHeader> {
1340 let state = self.inner.state.read_blocking();
1343
1344 state
1345 .super_segment_headers_cache
1346 .previous_super_segment_header(block_number)
1347 }
1348
1349 #[inline]
1350 fn get_super_segment_header(
1351 &self,
1352 super_segment_index: SuperSegmentIndex,
1353 ) -> Option<SuperSegmentHeader> {
1354 let state = self.inner.state.read_blocking();
1357
1358 state
1359 .super_segment_headers_cache
1360 .get_super_segment_header(super_segment_index)
1361 }
1362
1363 fn get_super_segment_header_for_segment_index(
1364 &self,
1365 segment_index: SegmentIndex,
1366 ) -> Option<SuperSegmentHeader> {
1367 let state = self.inner.state.read_blocking();
1370
1371 state
1372 .super_segment_headers_cache
1373 .get_super_segment_header_for_segment_index(segment_index)
1374 }
1375}
1376
1377impl<StorageBackend> BeaconChainInfoWrite for ClientDatabase<OwnedBeaconChainBlock, StorageBackend>
1378where
1379 StorageBackend: ClientDatabaseStorageBackend,
1380{
1381 async fn persist_super_segment_header(
1382 &self,
1383 super_segment_header: SuperSegmentHeader,
1384 ) -> Result<bool, PersistSuperSegmentHeadersError> {
1385 let mut state = self.inner.state.write().await;
1386
1387 let added_super_segment_headers = state
1388 .super_segment_headers_cache
1389 .add_super_segment_headers(vec![super_segment_header])?;
1390
1391 if added_super_segment_headers.is_empty() {
1392 return Ok(false);
1393 }
1394
1395 let state = AsyncRwLockWriteGuard::downgrade_to_upgradable(state);
1400
1401 let mut storage_backend_adapter = state.storage_backend_adapter.write().await;
1402
1403 storage_backend_adapter
1404 .write_storage_item(StorageItemTemporary::SuperSegmentHeaders(
1405 StorageItemTemporarySuperSegmentHeaders {
1406 super_segment_headers: added_super_segment_headers,
1407 },
1408 ))
1409 .await?;
1410
1411 Ok(true)
1412 }
1413
1414 async fn persist_super_segment_headers(
1415 &self,
1416 super_segment_headers: Vec<SuperSegmentHeader>,
1417 ) -> Result<(), PersistSuperSegmentHeadersError> {
1418 let mut state = self.inner.state.write().await;
1419
1420 let added_super_segment_headers = state
1421 .super_segment_headers_cache
1422 .add_super_segment_headers(super_segment_headers)?;
1423
1424 if added_super_segment_headers.is_empty() {
1425 return Ok(());
1426 }
1427
1428 let state = AsyncRwLockWriteGuard::downgrade_to_upgradable(state);
1433
1434 let mut storage_backend_adapter = state.storage_backend_adapter.write().await;
1435
1436 storage_backend_adapter
1437 .write_storage_item(StorageItemTemporary::SuperSegmentHeaders(
1438 StorageItemTemporarySuperSegmentHeaders {
1439 super_segment_headers: added_super_segment_headers,
1440 },
1441 ))
1442 .await?;
1443
1444 Ok(())
1445 }
1446}
1447
1448impl<Block, StorageBackend> ClientDatabase<Block, StorageBackend>
1449where
1450 Block: GenericOwnedBlock,
1451 StorageBackend: ClientDatabaseStorageBackend,
1452{
1453 pub async fn open<GBB>(
1457 options: ClientDatabaseOptions<GBB, StorageBackend>,
1458 ) -> Result<Self, ClientDatabaseError>
1459 where
1460 GBB: FnOnce() -> GenesisBlockBuilderResult<Block>,
1461 {
1462 let ClientDatabaseOptions {
1463 write_buffer_size,
1464 block_confirmation_depth,
1465 soft_confirmation_depth,
1466 max_fork_tips,
1467 max_fork_tip_distance,
1468 genesis_block_builder,
1469 storage_backend,
1470 } = options;
1471 if soft_confirmation_depth >= block_confirmation_depth {
1472 return Err(ClientDatabaseError::InvalidSoftConfirmationDepth);
1473 }
1474
1475 if max_fork_tip_distance > block_confirmation_depth {
1476 return Err(ClientDatabaseError::InvalidMaxForkTipDistance);
1477 }
1478
1479 let mut state_data = StateData {
1480 fork_tips: VecDeque::new(),
1481 block_roots: HashMap::default(),
1482 blocks: VecDeque::new(),
1483 };
1484 let mut segment_headers_cache = SegmentHeadersCache {
1485 segment_headers_cache: Vec::new(),
1486 };
1487 let mut super_segment_headers_cache = SuperSegmentHeadersCache {
1488 super_segment_headers_cache: Vec::new(),
1489 };
1490
1491 let options = ClientDatabaseInnerOptions {
1492 block_confirmation_depth,
1493 soft_confirmation_depth,
1494 max_fork_tips,
1495 max_fork_tip_distance,
1496 };
1497
1498 let storage_item_handlers = StorageItemHandlers {
1499 permanent: |_arg| {
1500 Ok(())
1502 },
1503 temporary: |arg| {
1504 let StorageItemHandlerArg {
1505 storage_item,
1506 page_offset,
1507 num_pages,
1508 } = arg;
1509 let storage_item_block = match storage_item {
1510 StorageItemTemporary::Block(storage_item_block) => storage_item_block,
1511 StorageItemTemporary::SegmentHeaders(segment_headers) => {
1512 let num_segment_headers = segment_headers.segment_headers.len();
1513 return match segment_headers_cache
1514 .add_segment_headers(segment_headers.segment_headers)
1515 {
1516 Ok(_) => Ok(()),
1517 Err(error) => {
1518 error!(
1519 %page_offset,
1520 %num_segment_headers,
1521 %error,
1522 "Failed to add segment headers from storage item"
1523 );
1524
1525 Err(ClientDatabaseError::InvalidSegmentHeaders { page_offset })
1526 }
1527 };
1528 }
1529 StorageItemTemporary::SuperSegmentHeaders(super_segment_headers) => {
1530 let num_super_segment_headers =
1531 super_segment_headers.super_segment_headers.len();
1532 return match super_segment_headers_cache
1533 .add_super_segment_headers(super_segment_headers.super_segment_headers)
1534 {
1535 Ok(_) => Ok(()),
1536 Err(error) => {
1537 error!(
1538 %page_offset,
1539 %num_super_segment_headers,
1540 %error,
1541 "Failed to add segment headers from storage item"
1542 );
1543
1544 Err(ClientDatabaseError::InvalidSegmentHeaders { page_offset })
1545 }
1546 };
1547 }
1548 };
1549
1550 let StorageItemTemporaryBlock {
1553 header,
1554 body,
1555 mmr_with_block,
1556 system_contract_states,
1557 } = storage_item_block;
1558
1559 let header = Block::Header::from_buffer(header).map_err(|_buffer| {
1560 error!(%page_offset, "Failed to decode block header from bytes");
1561
1562 ClientDatabaseError::InvalidBlock { page_offset }
1563 })?;
1564 let body = Block::Body::from_buffer(body).map_err(|_buffer| {
1565 error!(%page_offset, "Failed to decode block body from bytes");
1566
1567 ClientDatabaseError::InvalidBlock { page_offset }
1568 })?;
1569
1570 let block_root = *header.header().root();
1571 let block_number = header.header().prefix.number;
1572
1573 state_data.block_roots.insert(block_root, block_number);
1574
1575 let maybe_best_number = state_data
1576 .blocks
1577 .front()
1578 .and_then(|block_forks| block_forks.first())
1579 .map(|best_block| {
1580 let header: &Block::Header = best_block.header();
1582
1583 header.header().prefix.number
1584 });
1585
1586 let block_offset = if let Some(best_number) = maybe_best_number {
1587 if block_number <= best_number {
1588 u64::from(best_number - block_number) as usize
1589 } else {
1590 if block_number - best_number != BlockNumber::ONE {
1592 error!(
1593 %page_offset,
1594 %best_number,
1595 %block_number,
1596 "Invalid new best block number, it must be only one block \
1597 higher than the best block"
1598 );
1599
1600 return Err(ClientDatabaseError::InvalidBlock { page_offset });
1601 }
1602
1603 state_data.blocks.push_front(SmallVec::new());
1604 0
1606 }
1607 } else {
1608 state_data.blocks.push_front(SmallVec::new());
1609 0
1611 };
1612
1613 let Some(block_forks) = state_data.blocks.get_mut(block_offset) else {
1614 return Ok(());
1617 };
1618
1619 let beacon_chain_block_details =
1621 <dyn Any>::downcast_ref::<OwnedBeaconChainBody>(&body)
1622 .map(|body| BeaconChainBlockDetails::from_body(body.body()));
1623 block_forks.push(ClientDatabaseBlock::Persisted {
1624 header,
1625 block_details: BlockDetails {
1626 mmr_with_block,
1627 system_contract_states,
1628 },
1629 beacon_chain_block_details,
1630 write_location: WriteLocation {
1631 page_offset,
1632 num_pages,
1633 },
1634 });
1635
1636 if block_offset == 0 && block_forks.len() == 1 {
1639 Self::confirm_canonical_block(block_number, &mut state_data, &options);
1640 }
1641
1642 Ok(())
1643 },
1644 };
1645
1646 let storage_backend_adapter =
1647 StorageBackendAdapter::open(write_buffer_size, storage_item_handlers, storage_backend)
1648 .await?;
1649
1650 if let Some(best_block) = state_data.blocks.front().and_then(|block_forks| {
1651 block_forks.last()
1654 }) {
1655 let header: &Block::Header = best_block.header();
1657 let header = header.header();
1658 let block_number = header.prefix.number;
1659 let block_root = *header.root();
1660
1661 if !Self::adjust_ancestor_block_forks(&mut state_data.blocks, block_root) {
1662 return Err(ClientDatabaseError::FailedToAdjustAncestorBlockForks);
1663 }
1664
1665 state_data.fork_tips.push_front(ForkTip {
1667 number: block_number,
1668 root: block_root,
1669 });
1670 } else {
1671 let GenesisBlockBuilderResult {
1672 block,
1673 system_contract_states,
1674 } = genesis_block_builder();
1675
1676 let header = block.header().header();
1678 let block_number = header.prefix.number;
1679 let block_root = *header.root();
1680
1681 state_data.fork_tips.push_front(ForkTip {
1682 number: block_number,
1683 root: block_root,
1684 });
1685 state_data.block_roots.insert(block_root, block_number);
1686 let beacon_chain_block_details =
1687 <dyn Any>::downcast_ref::<OwnedBeaconChainBlock>(&block)
1688 .map(|block| BeaconChainBlockDetails::from_body(block.body.body()));
1689 state_data
1690 .blocks
1691 .push_front(smallvec![ClientDatabaseBlock::InMemory {
1692 block,
1693 block_details: BlockDetails {
1694 system_contract_states,
1695 mmr_with_block: Arc::new({
1696 let mut mmr = BlockMerkleMountainRange::new();
1697 mmr.add_leaf(&block_root);
1698 mmr
1699 })
1700 },
1701 beacon_chain_block_details,
1702 }]);
1703 }
1704
1705 let state = State {
1706 data: state_data,
1707 segment_headers_cache,
1708 super_segment_headers_cache,
1709 storage_backend_adapter: AsyncRwLock::new(storage_backend_adapter),
1710 };
1711
1712 let inner = Inner {
1713 state: AsyncRwLock::new(state),
1714 options,
1715 };
1716
1717 Ok(Self {
1718 inner: Arc::new(inner),
1719 })
1720 }
1721
1722 pub async fn format(
1724 storage_backend: &StorageBackend,
1725 options: ClientDatabaseFormatOptions,
1726 ) -> Result<(), ClientDatabaseFormatError> {
1727 StorageBackendAdapter::format(storage_backend, options).await
1728 }
1729
1730 fn insert_first_block(state: &mut StateData<Block>, block: Block, block_details: BlockDetails) {
1731 let header = block.header().header();
1733 let block_number = header.prefix.number;
1734 let block_root = *header.root();
1735
1736 state.fork_tips.clear();
1737 state.fork_tips.push_front(ForkTip {
1738 number: block_number,
1739 root: block_root,
1740 });
1741 state.block_roots.clear();
1742 state.block_roots.insert(block_root, block_number);
1743 state.blocks.clear();
1744 let beacon_chain_block_details = <dyn Any>::downcast_ref::<OwnedBeaconChainBlock>(&block)
1745 .map(|block| BeaconChainBlockDetails::from_body(block.body.body()));
1746 state
1747 .blocks
1748 .push_front(smallvec![ClientDatabaseBlock::InMemory {
1749 block,
1750 block_details,
1751 beacon_chain_block_details,
1752 }]);
1753 }
1754
1755 async fn insert_new_best_block(
1756 mut state: AsyncRwLockWriteGuard<'_, State<Block, StorageBackend>>,
1757 inner: &Inner<Block, StorageBackend>,
1758 block: Block,
1759 block_details: BlockDetails,
1760 ) -> Result<(), PersistBlockError> {
1761 let header = block.header().header();
1762 let block_number = header.prefix.number;
1763 let block_root = *header.root();
1764 let parent_root = header.prefix.parent_root;
1765
1766 if !Self::adjust_ancestor_block_forks(&mut state.data.blocks, parent_root) {
1769 return Err(PersistBlockError::MissingParent);
1770 }
1771
1772 {
1774 for (index, fork_tip) in state.data.fork_tips.iter_mut().enumerate() {
1775 if fork_tip.root == parent_root {
1777 state.data.fork_tips.remove(index);
1778 break;
1779 }
1780 }
1781
1782 state.data.fork_tips.push_front(ForkTip {
1783 number: block_number,
1784 root: block_root,
1785 });
1786 state.data.block_roots.insert(block_root, block_number);
1787 let beacon_chain_block_details =
1788 <dyn Any>::downcast_ref::<OwnedBeaconChainBlock>(&block)
1789 .map(|block| BeaconChainBlockDetails::from_body(block.body.body()));
1790 state
1791 .data
1792 .blocks
1793 .push_front(smallvec![ClientDatabaseBlock::InMemory {
1794 block,
1795 block_details: block_details.clone(),
1796 beacon_chain_block_details,
1797 }]);
1798 }
1799
1800 let options = &inner.options;
1801
1802 Self::confirm_canonical_block(block_number, &mut state.data, options);
1803 Self::prune_outdated_fork_tips(block_number, &mut state.data, options);
1804
1805 let state = AsyncRwLockWriteGuard::downgrade_to_upgradable(state);
1810
1811 let mut blocks_to_persist = Vec::new();
1812 for block_offset in u64::from(options.soft_confirmation_depth) as usize.. {
1813 let Some(fork_blocks) = state.data.blocks.get(block_offset) else {
1814 break;
1815 };
1816
1817 let len_before = blocks_to_persist.len();
1818 fork_blocks
1819 .iter()
1820 .enumerate()
1821 .filter_map(|(fork_offset, client_database_block)| {
1822 #[expect(
1823 clippy::rest_pattern_accessible_field,
1824 reason = "Do not need other fields"
1825 )]
1826 match client_database_block {
1827 ClientDatabaseBlock::InMemory {
1828 block,
1829 block_details,
1830 beacon_chain_block_details: _,
1831 } => Some(BlockToPersist {
1832 block_offset,
1833 fork_offset,
1834 block,
1835 block_details,
1836 }),
1837 ClientDatabaseBlock::Persisted { .. }
1838 | ClientDatabaseBlock::PersistedConfirmed { .. } => {
1839 None
1841 }
1842 }
1843 })
1844 .collect_into(&mut blocks_to_persist);
1845
1846 if blocks_to_persist.len() == len_before {
1847 break;
1848 }
1849 }
1850
1851 let mut persisted_blocks = Vec::with_capacity(blocks_to_persist.len());
1853 {
1854 let mut storage_backend_adapter = state.storage_backend_adapter.write().await;
1855
1856 for block_to_persist in blocks_to_persist.into_iter().rev() {
1857 let BlockToPersist {
1858 block_offset,
1859 fork_offset,
1860 block,
1861 block_details,
1862 } = block_to_persist;
1863
1864 let write_location = storage_backend_adapter
1865 .write_storage_item(StorageItemTemporary::Block(StorageItemTemporaryBlock {
1866 header: block.header().buffer().clone(),
1867 body: block.body().buffer().clone(),
1868 mmr_with_block: Arc::clone(&block_details.mmr_with_block),
1869 system_contract_states: Arc::clone(&block_details.system_contract_states),
1870 }))
1871 .await?;
1872
1873 persisted_blocks.push(PersistedBlock {
1874 block_offset,
1875 fork_offset,
1876 write_location,
1877 });
1878 }
1879 }
1880
1881 let mut state = RwLockUpgradableReadGuard::upgrade(state).await;
1883 for persisted_block in persisted_blocks {
1884 let PersistedBlock {
1885 block_offset,
1886 fork_offset,
1887 write_location,
1888 } = persisted_block;
1889
1890 let block = state
1891 .data
1892 .blocks
1893 .get_mut(block_offset)
1894 .expect("Still holding the same lock since last check; qed")
1895 .get_mut(fork_offset)
1896 .expect("Still holding the same lock since last check; qed");
1897
1898 replace_with_or_abort(block, |block| {
1899 if let ClientDatabaseBlock::InMemory {
1900 block,
1901 block_details,
1902 beacon_chain_block_details,
1903 } = block
1904 {
1905 let (header, _body) = block.split();
1906
1907 ClientDatabaseBlock::Persisted {
1908 header,
1909 block_details,
1910 beacon_chain_block_details,
1911 write_location,
1912 }
1913 } else {
1914 unreachable!("Still holding the same lock since last check; qed");
1915 }
1916 });
1917 }
1918
1919 Ok(())
1923 }
1924
1925 #[must_use]
1930 fn adjust_ancestor_block_forks(
1931 blocks: &mut VecDeque<SmallVec<[ClientDatabaseBlock<Block>; 2]>>,
1932 mut parent_block_root: BlockRoot,
1933 ) -> bool {
1934 let mut ancestor_blocks = blocks.iter_mut();
1935
1936 loop {
1937 if ancestor_blocks.len() == 1 {
1938 break;
1940 }
1941
1942 let Some(parent_blocks) = ancestor_blocks.next() else {
1943 break;
1945 };
1946
1947 let Some(fork_offset_parent_block_root) =
1948 parent_blocks
1949 .iter()
1950 .enumerate()
1951 .find_map(|(fork_offset, fork_block)| {
1952 let fork_header = fork_block.header().header();
1953 if *fork_header.root() == parent_block_root {
1954 Some((fork_offset, fork_header.prefix.parent_root))
1955 } else {
1956 None
1957 }
1958 })
1959 else {
1960 return false;
1961 };
1962
1963 let fork_offset;
1964 (fork_offset, parent_block_root) = fork_offset_parent_block_root;
1965
1966 parent_blocks.swap(0, fork_offset);
1967 }
1968
1969 true
1970 }
1971
1972 fn prune_outdated_fork_tips(
1979 best_number: BlockNumber,
1980 state: &mut StateData<Block>,
1981 options: &ClientDatabaseInnerOptions,
1982 ) {
1983 let state = &mut *state;
1984
1985 let mut candidate_forks_to_remove = Vec::with_capacity(options.max_fork_tips.get());
1988
1989 state.fork_tips.retain(|fork_tip| {
1991 if best_number - fork_tip.number > options.max_fork_tip_distance {
1992 candidate_forks_to_remove.push(*fork_tip);
1993 false
1994 } else {
1995 true
1996 }
1997 });
1998 if state.fork_tips.len() > options.max_fork_tips.get() {
2000 state
2001 .fork_tips
2002 .drain(options.max_fork_tips.get()..)
2003 .collect_into(&mut candidate_forks_to_remove);
2004 }
2005
2006 candidate_forks_to_remove
2008 .retain(|fork_tip| !Self::prune_outdated_fork(best_number, fork_tip, state));
2009 state.fork_tips.extend(candidate_forks_to_remove);
2011 }
2012
2013 #[must_use]
2016 fn prune_outdated_fork(
2017 best_number: BlockNumber,
2018 fork_tip: &ForkTip,
2019 state: &mut StateData<Block>,
2020 ) -> bool {
2021 let block_offset = u64::from(best_number - fork_tip.number) as usize;
2022
2023 let mut block_root_to_prune = fork_tip.root;
2025 let mut pruned_tip = false;
2026 for block_offset in block_offset.. {
2027 let Some(fork_blocks) = state.blocks.get_mut(block_offset) else {
2028 if !pruned_tip {
2029 error!(
2030 %best_number,
2031 ?fork_tip,
2032 block_offset,
2033 "Block offset was not present in the database, this is an implementation \
2034 bug #1"
2035 );
2036 }
2037 break;
2039 };
2040
2041 if fork_blocks.len() == 1 {
2042 if !pruned_tip {
2043 error!(
2044 %best_number,
2045 ?fork_tip,
2046 block_offset,
2047 "Block offset was not present in the database, this is an implementation \
2048 bug #2"
2049 );
2050 }
2051
2052 break;
2054 }
2055
2056 let Some((fork_offset, block)) = fork_blocks
2057 .iter()
2058 .enumerate()
2059 .skip(1)
2061 .find(|(_fork_offset, block)| {
2062 *block.header().header().root() == block_root_to_prune
2063 })
2064 else {
2065 if !pruned_tip {
2066 error!(
2067 %best_number,
2068 ?fork_tip,
2069 block_offset,
2070 "Block offset was not present in the database, this is an implementation \
2071 bug #3"
2072 );
2073 }
2074
2075 break;
2077 };
2078
2079 if block.header().ref_count() > 1 {
2081 break;
2082 }
2083
2084 #[expect(
2086 clippy::rest_pattern_accessible_field,
2087 reason = "Do not care about fields"
2088 )]
2089 match block {
2090 ClientDatabaseBlock::InMemory { .. } => {
2091 }
2093 ClientDatabaseBlock::Persisted { .. }
2094 | ClientDatabaseBlock::PersistedConfirmed { .. } => {
2095 pruned_tip = true;
2097 break;
2098 }
2099 }
2100
2101 state.block_roots.get_mut(&block_root_to_prune);
2102 block_root_to_prune = block.header().header().prefix.parent_root;
2103 fork_blocks.swap_remove(fork_offset);
2104
2105 pruned_tip = true;
2106 }
2107
2108 pruned_tip
2109 }
2110
2111 fn confirm_canonical_block(
2114 best_number: BlockNumber,
2115 state_data: &mut StateData<Block>,
2116 options: &ClientDatabaseInnerOptions,
2117 ) {
2118 let block_offset = u64::from(options.block_confirmation_depth + BlockNumber::ONE) as usize;
2122
2123 let Some(fork_blocks) = state_data.blocks.get_mut(block_offset) else {
2124 return;
2126 };
2127
2128 {
2130 let Some(canonical_block) = fork_blocks.first_mut() else {
2131 error!(
2132 %best_number,
2133 block_offset,
2134 "Have not found a canonical block to confirm, this is an implementation bug"
2135 );
2136 return;
2137 };
2138
2139 replace_with_or_abort(canonical_block, |block| {
2140 #[expect(
2141 clippy::rest_pattern_accessible_field,
2142 reason = "Do not need other fields"
2143 )]
2144 match block {
2145 ClientDatabaseBlock::InMemory { .. } => {
2146 error!(
2147 %best_number,
2148 block_offset,
2149 header = ?block.header(),
2150 "Block to be confirmed must not be in memory, this is an implementation bug"
2151 );
2152 block
2153 }
2154 ClientDatabaseBlock::Persisted {
2155 header,
2156 block_details: _,
2157 beacon_chain_block_details,
2158 write_location,
2159 } => ClientDatabaseBlock::PersistedConfirmed {
2160 header,
2161 beacon_chain_block_details,
2162 write_location,
2163 },
2164 ClientDatabaseBlock::PersistedConfirmed { .. } => {
2165 error!(
2166 %best_number,
2167 block_offset,
2168 header = ?block.header(),
2169 "Block to be confirmed must not be confirmed yet, this is an \
2170 implementation bug"
2171 );
2172 block
2173 }
2174 }
2175 });
2176 }
2177
2178 let mut block_roots_to_prune = fork_blocks
2180 .drain(1..)
2181 .map(|block| *block.header().header().root())
2182 .collect::<Vec<_>>();
2183 let mut current_block_offset = block_offset;
2184 while !block_roots_to_prune.is_empty() {
2185 state_data
2187 .fork_tips
2188 .retain(|fork_tip| !block_roots_to_prune.contains(&fork_tip.root));
2189
2190 for block_root in &block_roots_to_prune {
2192 state_data.block_roots.remove(block_root);
2193 }
2194
2195 if let Some(next_block_offset) = current_block_offset.checked_sub(1) {
2197 current_block_offset = next_block_offset;
2198 } else {
2199 break;
2201 }
2202
2203 let fork_blocks = state_data
2204 .blocks
2205 .get_mut(current_block_offset)
2206 .expect("Lower block offset always exists; qed");
2207
2208 block_roots_to_prune = fork_blocks
2210 .drain_filter(|block| {
2211 let header = block.header().header();
2212
2213 block_roots_to_prune.contains(&header.prefix.parent_root)
2214 })
2215 .map(|block| *block.header().header().root())
2216 .collect();
2217 }
2218 }
2219}