ab_client_block_builder/
beacon_chain.rs1use crate::{BlockBuilder, BlockBuilderError};
2use ab_client_api::ChainInfo;
3use ab_client_archiving::segment_headers_store::SegmentHeadersStore;
4use ab_client_consensus_common::ConsensusConstants;
5use ab_client_consensus_common::consensus_parameters::{
6 DeriveConsensusParametersError, derive_consensus_parameters,
7};
8use ab_core_primitives::block::body::owned::OwnedBeaconChainBodyError;
9use ab_core_primitives::block::header::owned::{
10 GenericOwnedBlockHeader, OwnedBeaconChainHeader, OwnedBeaconChainHeaderError,
11};
12use ab_core_primitives::block::header::{
13 BeaconChainHeader, BlockHeaderConsensusInfo, BlockHeaderPrefix,
14 OwnedBlockHeaderConsensusParameters, OwnedBlockHeaderSeal,
15};
16use ab_core_primitives::block::owned::OwnedBeaconChainBlock;
17use ab_core_primitives::block::{BlockNumber, BlockRoot, BlockTimestamp};
18use ab_core_primitives::hashes::Blake3Hash;
19use ab_core_primitives::pot::{PotCheckpoints, SlotNumber};
20use ab_core_primitives::shard::ShardIndex;
21use std::iter;
22use std::time::SystemTime;
23
24#[derive(Debug, thiserror::Error)]
26pub enum BeaconChainBlockBuilderError {
27 #[error("Consensus parameters derivation error: {error}")]
29 ConsensusParametersDerivation {
30 #[from]
32 error: DeriveConsensusParametersError,
33 },
34 #[error("Failed to create body: {error}")]
36 FailedToCreateBody {
37 #[from]
39 error: OwnedBeaconChainBodyError,
40 },
41 #[error("Failed to create header: {error}")]
43 FailedToCreateHeader {
44 #[from]
46 error: OwnedBeaconChainHeaderError,
47 },
48}
49
50impl From<BeaconChainBlockBuilderError> for BlockBuilderError {
51 #[inline(always)]
52 fn from(error: BeaconChainBlockBuilderError) -> Self {
53 Self::Custom {
54 error: error.into(),
55 }
56 }
57}
58
59#[derive(Debug)]
64pub struct BeaconChainBlockBuilder<CI> {
65 segment_headers_store: SegmentHeadersStore,
66 consensus_constants: ConsensusConstants,
67 chain_info: CI,
68}
69
70impl<CI> BlockBuilder<OwnedBeaconChainBlock> for BeaconChainBlockBuilder<CI>
71where
72 CI: ChainInfo<OwnedBeaconChainBlock>,
73{
74 async fn build<SealBlock, SealBlockFut>(
75 &mut self,
76 parent_block_root: &BlockRoot,
77 parent_header: &<OwnedBeaconChainHeader as GenericOwnedBlockHeader>::Header<'_>,
78 consensus_info: &BlockHeaderConsensusInfo,
79 checkpoints: &[PotCheckpoints],
80 seal_block: SealBlock,
81 ) -> Result<OwnedBeaconChainBlock, BlockBuilderError>
82 where
83 SealBlock: FnOnce(Blake3Hash) -> SealBlockFut + Send,
84 SealBlockFut: Future<Output = Option<OwnedBlockHeaderSeal>> + Send,
85 {
86 let block_number = parent_header.prefix.number.saturating_add(BlockNumber::ONE);
87
88 let header_prefix = self.create_header_prefix(
89 parent_block_root,
90 parent_header.prefix.timestamp,
91 block_number,
92 );
93 let consensus_parameters = self.derive_consensus_parameters(
94 parent_block_root,
95 parent_header,
96 block_number,
97 consensus_info.slot,
98 )?;
99
100 let block_builder = OwnedBeaconChainBlock::init(
101 self.segment_headers_store
102 .segment_headers_for_block(block_number)
103 .into_iter()
104 .map(|segment_header| segment_header.segment_root),
105 iter::empty(),
107 checkpoints,
108 )
109 .map_err(BeaconChainBlockBuilderError::from)?;
110
111 let block_unsealed = block_builder
112 .with_header(
113 &header_prefix,
114 Default::default(),
116 consensus_info,
117 consensus_parameters.as_ref(),
118 )
119 .map_err(BeaconChainBlockBuilderError::from)?;
120
121 let seal = seal_block(block_unsealed.pre_seal_hash())
122 .await
123 .ok_or(BlockBuilderError::FailedToSeal)?;
124 let block = block_unsealed.with_seal(seal.as_ref());
125
126 Ok(block)
127 }
128}
129
130impl<CI> BeaconChainBlockBuilder<CI>
131where
132 CI: ChainInfo<OwnedBeaconChainBlock>,
133{
134 pub fn new(
136 segment_headers_store: SegmentHeadersStore,
137 consensus_constants: ConsensusConstants,
138 chain_info: CI,
139 ) -> Self {
140 Self {
141 segment_headers_store,
142 consensus_constants,
143 chain_info,
144 }
145 }
146
147 fn create_header_prefix(
148 &self,
149 parent_block_root: &BlockRoot,
150 parent_timestamp: BlockTimestamp,
151 block_number: BlockNumber,
152 ) -> BlockHeaderPrefix {
153 let timestamp = SystemTime::now()
154 .duration_since(SystemTime::UNIX_EPOCH)
155 .unwrap_or_default()
156 .as_millis();
157 let mut timestamp = BlockTimestamp::new(u64::try_from(timestamp).unwrap_or(u64::MAX));
158
159 if timestamp <= parent_timestamp {
160 timestamp = BlockTimestamp::new(parent_timestamp.as_ms().saturating_add(1));
161 }
162
163 BlockHeaderPrefix {
164 number: block_number,
165 shard_index: ShardIndex::BEACON_CHAIN,
166 padding_0: [0; _],
167 timestamp,
168 parent_root: *parent_block_root,
169 mmr_root: Default::default(),
171 }
172 }
173
174 fn derive_consensus_parameters(
175 &self,
176 parent_block_root: &BlockRoot,
177 parent_header: &BeaconChainHeader<'_>,
178 block_number: BlockNumber,
179 slot: SlotNumber,
180 ) -> Result<OwnedBlockHeaderConsensusParameters, BeaconChainBlockBuilderError> {
181 let derived_consensus_parameters = derive_consensus_parameters(
182 &self.consensus_constants,
183 &self.chain_info,
184 parent_block_root,
185 parent_header.consensus_parameters(),
186 parent_header.consensus_info.slot,
187 block_number,
188 slot,
189 )?;
190
191 Ok(OwnedBlockHeaderConsensusParameters {
192 fixed_parameters: derived_consensus_parameters.fixed_parameters,
193 super_segment_root: None,
195 next_solution_range: derived_consensus_parameters.next_solution_range,
196 pot_parameters_change: derived_consensus_parameters.pot_parameters_change,
197 })
198 }
199}