Skip to main content

ab_client_api/
lib.rs

1//! Client API
2
3use ab_aligned_buffer::SharedAlignedBuffer;
4use ab_core_primitives::address::Address;
5use ab_core_primitives::block::owned::{GenericOwnedBlock, OwnedBeaconChainBlock};
6use ab_core_primitives::block::{BlockNumber, BlockRoot};
7use ab_core_primitives::segments::{
8    LocalSegmentIndex, SegmentHeader, SegmentIndex, SegmentRoot, SuperSegmentHeader,
9    SuperSegmentIndex,
10};
11use ab_core_primitives::shard::ShardIndex;
12use ab_core_primitives::trees::BlockMerkleMountainRange;
13use std::io;
14use triomphe::Arc;
15
16/// State of a contract slot
17#[derive(Debug, Clone)]
18pub struct ContractSlotState {
19    /// Owner of the slot
20    pub owner: Address,
21    /// Contract that manages the slot
22    pub contract: Address,
23    /// Slot contents
24    pub contents: SharedAlignedBuffer,
25}
26
27/// Additional details about a block
28#[derive(Debug, Clone)]
29pub struct BlockDetails {
30    /// Merkle Mountain Range with block
31    pub mmr_with_block: Arc<BlockMerkleMountainRange>,
32    /// System contracts state after block
33    pub system_contract_states: Arc<[ContractSlotState]>,
34}
35
36// TODO: Probably move it elsewhere
37/// Origin
38#[derive(Debug, Clone)]
39pub enum BlockOrigin {
40    // TODO: Take advantage of this in block import
41    /// Created locally by block builder
42    LocalBlockBuilder {
43        /// Additional details about a block
44        block_details: BlockDetails,
45    },
46    /// Received during the sync process
47    Sync,
48    /// Broadcast on the network during normal operation (not sync)
49    Broadcast,
50}
51
52/// Intermediate or leaf shard segment root information
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub struct ShardSegmentRoot {
55    /// Shard index
56    pub shard_index: ShardIndex,
57    /// Local segment index
58    pub segment_index: LocalSegmentIndex,
59    /// Segment root
60    pub segment_root: SegmentRoot,
61}
62
63/// Error for [`ChainInfo::block()`]
64#[derive(Debug, thiserror::Error)]
65pub enum ReadBlockError {
66    /// Unknown block root
67    #[error("Unknown block root")]
68    UnknownBlockRoot,
69    /// Failed to decode the block
70    #[error("Failed to decode the block")]
71    FailedToDecode,
72    /// Storage item read error
73    #[error("Storage item read error")]
74    StorageItemReadError {
75        /// Low-level error
76        #[from]
77        error: io::Error,
78    },
79}
80
81/// Error for [`ChainInfoWrite::persist_block()`]
82#[derive(Debug, thiserror::Error)]
83pub enum PersistBlockError {
84    /// Block is already known
85    #[error("Block is already known")]
86    AlreadyKnown,
87    /// Missing parent
88    #[error("Missing parent")]
89    MissingParent,
90    /// Block is outside the acceptable range
91    #[error("Block is outside the acceptable range")]
92    OutsideAcceptableRange,
93    /// Storage item write error
94    #[error("Storage item write error")]
95    StorageItemWriteError {
96        /// Low-level error
97        #[from]
98        error: io::Error,
99    },
100}
101
102/// Error for [`ChainInfoWrite::persist_segment_headers()`]
103#[derive(Debug, thiserror::Error)]
104pub enum PersistSegmentHeadersError {
105    /// Segment index must strictly follow the last segment index, can't store segment header
106    #[error(
107        "Segment index {local_segment_index} must strictly follow last segment index \
108        {last_local_segment_index}, can't store segment header"
109    )]
110    MustFollowLastSegmentIndex {
111        /// Segment index that was attempted to be inserted
112        local_segment_index: LocalSegmentIndex,
113        /// Last segment index
114        last_local_segment_index: LocalSegmentIndex,
115    },
116    /// The first segment index must be zero
117    #[error("First segment index must be zero, found {local_segment_index}")]
118    FirstSegmentIndexZero {
119        /// Segment index that was attempted to be inserted
120        local_segment_index: LocalSegmentIndex,
121    },
122    /// Storage item write error
123    #[error("Storage item write error")]
124    StorageItemWriteError {
125        /// Low-level error
126        #[from]
127        error: io::Error,
128    },
129}
130
131/// Error for [`BeaconChainInfo::shard_segment_roots()`]
132#[derive(Debug, thiserror::Error)]
133pub enum ShardSegmentRootsError {
134    /// Block missing
135    #[error("Block {block_number} is missing")]
136    BlockMissing {
137        /// The block number that is missing in the database
138        block_number: BlockNumber,
139    },
140}
141
142/// Error for [`BeaconChainInfoWrite::persist_super_segment_headers()`]
143#[derive(Debug, thiserror::Error)]
144pub enum PersistSuperSegmentHeadersError {
145    /// Super segment index must strictly follow the last super segment index, can't store super
146    /// segment header
147    #[error(
148        "Super segment index {super_segment_index} must strictly follow last super segment index \
149        {last_super_segment_index}, can't store super segment header"
150    )]
151    MustFollowLastSegmentIndex {
152        /// Super segment index that was attempted to be inserted
153        super_segment_index: SuperSegmentIndex,
154        /// Last super segment index
155        last_super_segment_index: SuperSegmentIndex,
156    },
157    /// The first super segment index must be zero
158    #[error("First super segment index must be zero, found {super_segment_index}")]
159    FirstSegmentIndexZero {
160        /// Super segment index that was attempted to be inserted
161        super_segment_index: SuperSegmentIndex,
162    },
163    /// Storage item write error
164    #[error("Storage item write error")]
165    StorageItemWriteError {
166        /// Low-level error
167        #[from]
168        error: io::Error,
169    },
170}
171
172// TODO: Split this into different more narrow traits
173/// Chain info.
174///
175/// NOTE:
176/// <div class="warning">
177/// Blocks or their parts returned from these APIs are reference-counted and cheap to clone.
178/// However, it is not expected that they will be retained in memory for a long time. Blocks and
179/// headers will not be pruned until their reference count goes down to one. This is imported when
180/// there is an ongoing block import happening and its parent must exist until the import
181/// finishes. Forks that can't become a part of the best chain anymore are the exception (see
182/// `ConsensusConstants::block_confirmation_depth`), importing their blocks fails instead.
183/// </div>
184pub trait ChainInfo<Block>: Clone + Send + Sync + 'static
185where
186    Block: GenericOwnedBlock,
187{
188    /// Best block root
189    fn best_root(&self) -> BlockRoot;
190
191    // TODO: Uncomment if/when necessary
192    // /// Find root of ancestor block number for descendant block root
193    // fn ancestor_root(
194    //     &self,
195    //     ancestor_block_number: BlockNumber,
196    //     descendant_block_root: &BlockRoot,
197    // ) -> Option<BlockRoot>;
198
199    /// Best block header
200    fn best_header(&self) -> Block::Header;
201
202    /// Returns the best block header like [`Self::best_header()`] with additional block details
203    fn best_header_with_details(&self) -> (Block::Header, BlockDetails);
204
205    /// Get the header of the block at `ancestor_block_number` on the chain ending at
206    /// `descendant_block_root`.
207    ///
208    /// If `ancestor_block_number` is the descendant's own number, the descendant's header is
209    /// returned. Returns `None` if `ancestor_block_number` is higher than the descendant's number
210    /// or if either block is not available.
211    fn ancestor_header(
212        &self,
213        ancestor_block_number: BlockNumber,
214        descendant_block_root: &BlockRoot,
215    ) -> Option<Block::Header>;
216
217    /// Block header
218    fn header(&self, block_root: &BlockRoot) -> Option<Block::Header>;
219
220    /// Returns a block header like [`Self::header()`] with additional block details
221    fn header_with_details(&self, block_root: &BlockRoot) -> Option<(Block::Header, BlockDetails)>;
222
223    fn block(
224        &self,
225        block_root: &BlockRoot,
226    ) -> impl Future<Output = Result<Block, ReadBlockError>> + Send;
227
228    /// Returns the last observed local segment header of this shard
229    fn last_segment_header(&self) -> Option<SegmentHeader>;
230
231    /// Get a single segment header
232    fn get_segment_header(&self, segment_index: LocalSegmentIndex) -> Option<SegmentHeader>;
233
234    /// Get segment headers that are expected to be included at specified block number
235    fn segment_headers_for_block(&self, block_number: BlockNumber) -> Vec<SegmentHeader>;
236}
237
238/// [`ChainInfo`] extension for writing information
239pub trait ChainInfoWrite<Block>: ChainInfo<Block>
240where
241    Block: GenericOwnedBlock,
242{
243    /// Persist newly imported block
244    fn persist_block(
245        &self,
246        block: Block,
247        block_details: BlockDetails,
248    ) -> impl Future<Output = Result<(), PersistBlockError>> + Send;
249
250    /// Persist segment headers.
251    ///
252    /// Multiple can be inserted for efficiency purposes.
253    fn persist_segment_headers(
254        &self,
255        segment_headers: Vec<SegmentHeader>,
256    ) -> impl Future<Output = Result<(), PersistSegmentHeadersError>> + Send;
257}
258
259/// Beacon chain info
260pub trait BeaconChainInfo: ChainInfo<OwnedBeaconChainBlock> {
261    /// Returns intermediate and leaf shard segment roots included in the specified block number.
262    ///
263    /// NOTE: Only meant for confirmed blocks (see `ConsensusConstants::block_confirmation_depth`),
264    /// which are the same on every chain that can still be extended, so only a block number is
265    /// needed as a reference.
266    fn shard_segment_roots(
267        &self,
268        block_number: BlockNumber,
269    ) -> Result<Arc<[ShardSegmentRoot]>, ShardSegmentRootsError>;
270
271    /// Returns the last observed super segment header
272    fn last_super_segment_header(&self) -> Option<SuperSegmentHeader>;
273
274    /// Returns the previous super segment header for the block built with the specified target
275    /// block number.
276    ///
277    /// `None` is returned for blocks <= 1.
278    fn previous_super_segment_header(
279        &self,
280        block_number: BlockNumber,
281    ) -> Option<SuperSegmentHeader>;
282
283    /// Get a single super segment header
284    fn get_super_segment_header(
285        &self,
286        super_segment_index: SuperSegmentIndex,
287    ) -> Option<SuperSegmentHeader>;
288
289    /// Get a single super segment header for a segment index
290    fn get_super_segment_header_for_segment_index(
291        &self,
292        segment_index: SegmentIndex,
293    ) -> Option<SuperSegmentHeader>;
294}
295
296/// [`BeaconChainInfo`] extension for writing information
297pub trait BeaconChainInfoWrite: BeaconChainInfo + ChainInfoWrite<OwnedBeaconChainBlock> {
298    /// Persist a new super segment header.
299    ///
300    /// Returns `Ok(true)` if the header was inserted, `Ok(false)` if it was already present.
301    fn persist_super_segment_header(
302        &self,
303        super_segment_header: SuperSegmentHeader,
304    ) -> impl Future<Output = Result<bool, PersistSuperSegmentHeadersError>> + Send;
305
306    /// Persist super segment headers.
307    ///
308    /// Multiple can be inserted for efficiency purposes.
309    fn persist_super_segment_headers(
310        &self,
311        super_segment_headers: Vec<SuperSegmentHeader>,
312    ) -> impl Future<Output = Result<(), PersistSuperSegmentHeadersError>> + Send;
313}
314
315/// Chain sync status
316pub trait ChainSyncStatus: Clone + Send + Sync + 'static {
317    /// The block number that the sync process is targeting right now.
318    ///
319    /// Can be zero if not syncing actively.
320    fn target_block_number(&self) -> BlockNumber;
321
322    /// Returns `true` if the chain is currently syncing
323    fn is_syncing(&self) -> bool;
324
325    /// Returns `true` if the node is currently offline
326    fn is_offline(&self) -> bool;
327}