ab_client_block_import/
beacon_chain.rs1use crate::importing_blocks::{ImportingBlockEntry, ImportingBlockHandle, ImportingBlocks};
2use crate::{BlockImport, BlockImportError};
3use ab_client_api::{BlockOrigin, ChainInfoWrite};
4use ab_client_block_verification::{BlockVerification, BlockVerificationError};
5use ab_core_primitives::block::header::owned::OwnedBeaconChainHeader;
6use ab_core_primitives::block::owned::OwnedBeaconChainBlock;
7use ab_core_primitives::hashes::Blake3Hash;
8use ab_proof_of_space::Table;
9use rclite::Arc;
10use send_future::SendFuture;
11use std::marker::PhantomData;
12
13#[derive(Debug, thiserror::Error)]
15pub enum BeaconChainBlockImportError {
16 #[error("Block verification error: {error}")]
18 VerificationError {
19 #[from]
21 error: BlockVerificationError,
22 },
23}
24
25impl From<BeaconChainBlockImportError> for BlockImportError {
26 #[inline(always)]
27 fn from(error: BeaconChainBlockImportError) -> Self {
28 Self::Custom {
29 error: error.into(),
30 }
31 }
32}
33
34#[derive(Debug)]
35pub struct BeaconChainBlockImport<PosTable, CI, BV> {
36 chain_info: CI,
37 block_verification: BV,
38 importing_blocks: ImportingBlocks<OwnedBeaconChainHeader>,
39 _pos_table: PhantomData<PosTable>,
40}
41
42impl<PosTable, CI, BV> BlockImport<OwnedBeaconChainBlock>
43 for BeaconChainBlockImport<PosTable, CI, BV>
44where
45 PosTable: Table,
46 CI: ChainInfoWrite<OwnedBeaconChainBlock>,
47 BV: BlockVerification<OwnedBeaconChainBlock>,
48{
49 fn import(
50 &self,
51 block: OwnedBeaconChainBlock,
52 origin: BlockOrigin,
53 ) -> Result<impl Future<Output = Result<(), BlockImportError>> + Send, BlockImportError> {
54 let parent_root = &block.header.header().prefix.parent_root;
55
56 let (parent_header, parent_block_mmr, maybe_parent_importing_entry) =
57 if let Some(parent_header) = self.chain_info.header(parent_root) {
58 let parent_block_mmr = self
59 .chain_info
60 .mmr_with_block(parent_root)
61 .ok_or(BlockImportError::ParentBlockMmrMissing)?;
62
63 (parent_header, parent_block_mmr, None)
64 } else if let Some(importing_entry) = self.importing_blocks.get(parent_root) {
65 (
66 importing_entry.header().clone(),
67 Arc::clone(importing_entry.mmr()),
68 Some(importing_entry),
69 )
70 } else {
71 return Err(BlockImportError::UnknownParentBlock {
72 block_root: *parent_root,
73 });
74 };
75
76 let parent_block_mmr_root = Blake3Hash::from(
77 parent_block_mmr
78 .root()
79 .ok_or(BlockImportError::ParentBlockMmrInvalid)?,
80 );
81 let mut block_mmr = *parent_block_mmr;
82
83 if !block_mmr.add_leaf(&block.header.header().root()) {
84 return Err(BlockImportError::CantExtendMmr);
85 }
86
87 let importing_handle = self
88 .importing_blocks
89 .insert(block.header.clone(), Arc::new(block_mmr))
90 .ok_or(BlockImportError::AlreadyImporting)?;
91
92 if self
93 .chain_info
94 .header(&block.header.header().root())
95 .is_some()
96 {
97 return Err(BlockImportError::AlreadyImported);
98 }
99
100 Ok(self.import(
101 parent_header,
102 parent_block_mmr_root,
103 block,
104 origin,
105 importing_handle,
106 maybe_parent_importing_entry,
107 ))
108 }
109}
110
111impl<PosTable, CI, BV> BeaconChainBlockImport<PosTable, CI, BV>
112where
113 PosTable: Table,
114 CI: ChainInfoWrite<OwnedBeaconChainBlock>,
115 BV: BlockVerification<OwnedBeaconChainBlock>,
116{
117 #[inline(always)]
119 pub fn new(chain_info: CI, block_verification: BV) -> Self {
120 Self {
121 chain_info,
122 block_verification,
123 importing_blocks: ImportingBlocks::new(),
124 _pos_table: PhantomData,
125 }
126 }
127
128 async fn import(
129 &self,
130 parent_header: OwnedBeaconChainHeader,
131 parent_block_mmr_root: Blake3Hash,
132 block: OwnedBeaconChainBlock,
133 origin: BlockOrigin,
134 importing_handle: ImportingBlockHandle<OwnedBeaconChainHeader>,
135 maybe_parent_importing_entry: Option<ImportingBlockEntry<OwnedBeaconChainHeader>>,
136 ) -> Result<(), BlockImportError> {
137 let parent_header = parent_header.header();
138 let header = block.header.header();
139 let body = block.body.body();
140
141 self.block_verification
144 .verify(parent_header, &parent_block_mmr_root, header, body, origin)
145 .send()
146 .await
147 .map_err(BeaconChainBlockImportError::from)?;
148
149 if maybe_parent_importing_entry
150 .as_ref()
151 .map(ImportingBlockEntry::has_failed)
152 .unwrap_or_default()
153 {
154 return Err(BlockImportError::ParentBlockImportFailed);
156 }
157
158 if maybe_parent_importing_entry
161 .as_ref()
162 .map(ImportingBlockEntry::has_failed)
163 .unwrap_or_default()
164 {
165 return Err(BlockImportError::ParentBlockImportFailed);
167 }
168
169 if let Some(parent_importing_entry) = maybe_parent_importing_entry
173 && !parent_importing_entry.wait_success().await
174 {
175 return Err(BlockImportError::ParentBlockImportFailed);
176 }
177
178 self.chain_info
179 .persist_block(block, Arc::clone(importing_handle.mmr()))
180 .await?;
181
182 importing_handle.set_success();
183
184 Ok(())
185 }
186}