reth_storage_api/
block_id.rs

1use crate::BlockHashReader;
2use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumberOrTag};
3use alloy_primitives::{BlockNumber, B256};
4use reth_chainspec::ChainInfo;
5use reth_storage_errors::provider::{ProviderError, ProviderResult};
6
7/// Client trait for getting important block numbers (such as the latest block number), converting
8/// block hashes to numbers, and fetching a block hash from its block number.
9///
10/// This trait also supports fetching block hashes and block numbers from a [`BlockHashOrNumber`].
11#[auto_impl::auto_impl(&, Arc)]
12pub trait BlockNumReader: BlockHashReader + Send + Sync {
13    /// Returns the current info for the chain.
14    fn chain_info(&self) -> ProviderResult<ChainInfo>;
15
16    /// Returns the best block number in the chain.
17    fn best_block_number(&self) -> ProviderResult<BlockNumber>;
18
19    /// Returns the last block number associated with the last canonical header in the database.
20    fn last_block_number(&self) -> ProviderResult<BlockNumber>;
21
22    /// Returns earliest block number to keep track of the expired block range.
23    fn earliest_block_number(&self) -> ProviderResult<BlockNumber> {
24        Ok(0)
25    }
26
27    /// Gets the `BlockNumber` for the given hash. Returns `None` if no block with this hash exists.
28    fn block_number(&self, hash: B256) -> ProviderResult<Option<BlockNumber>>;
29
30    /// Gets the block number for the given `BlockHashOrNumber`. Returns `None` if no block with
31    /// this hash exists. If the `BlockHashOrNumber` is a `Number`, it is returned as is.
32    fn convert_hash_or_number(&self, id: BlockHashOrNumber) -> ProviderResult<Option<BlockNumber>> {
33        match id {
34            BlockHashOrNumber::Hash(hash) => self.block_number(hash),
35            BlockHashOrNumber::Number(num) => Ok(Some(num)),
36        }
37    }
38
39    /// Gets the block hash for the given `BlockHashOrNumber`. Returns `None` if no block with this
40    /// number exists. If the `BlockHashOrNumber` is a `Hash`, it is returned as is.
41    fn convert_number(&self, id: BlockHashOrNumber) -> ProviderResult<Option<B256>> {
42        match id {
43            BlockHashOrNumber::Hash(hash) => Ok(Some(hash)),
44            BlockHashOrNumber::Number(num) => self.block_hash(num),
45        }
46    }
47}
48
49/// Client trait for transforming [`BlockId`] into block numbers or hashes.
50///
51/// Types that implement this trait must be able to resolve all variants of [`BlockNumberOrTag`] to
52/// block numbers or hashes. Automatic implementations for resolving [`BlockNumberOrTag`] variants
53/// are provided if the type implements the `pending_block_num_hash`, `finalized_block_num`, and
54/// `safe_block_num` methods.
55///
56/// The resulting block numbers can be converted to hashes using the underlying [`BlockNumReader`]
57/// methods, and vice versa.
58#[auto_impl::auto_impl(&, Arc)]
59pub trait BlockIdReader: BlockNumReader + Send + Sync {
60    /// Converts the `BlockNumberOrTag` variants to a block number.
61    fn convert_block_number(&self, num: BlockNumberOrTag) -> ProviderResult<Option<BlockNumber>> {
62        let num = match num {
63            BlockNumberOrTag::Latest => self.best_block_number()?,
64            BlockNumberOrTag::Earliest => self.earliest_block_number()?,
65            BlockNumberOrTag::Pending => {
66                return self
67                    .pending_block_num_hash()
68                    .map(|res_opt| res_opt.map(|num_hash| num_hash.number))
69            }
70            BlockNumberOrTag::Number(num) => num,
71            BlockNumberOrTag::Finalized => {
72                self.finalized_block_number()?.ok_or(ProviderError::FinalizedBlockNotFound)?
73            }
74            BlockNumberOrTag::Safe => {
75                self.safe_block_number()?.ok_or(ProviderError::SafeBlockNotFound)?
76            }
77        };
78        Ok(Some(num))
79    }
80
81    /// Get the hash of the block by matching the given id.
82    fn block_hash_for_id(&self, block_id: BlockId) -> ProviderResult<Option<B256>> {
83        match block_id {
84            BlockId::Hash(hash) => Ok(Some(hash.into())),
85            BlockId::Number(num) => match num {
86                BlockNumberOrTag::Latest => Ok(Some(self.chain_info()?.best_hash)),
87                BlockNumberOrTag::Pending => self
88                    .pending_block_num_hash()
89                    .map(|res_opt| res_opt.map(|num_hash| num_hash.hash)),
90                BlockNumberOrTag::Finalized => self.finalized_block_hash(),
91                BlockNumberOrTag::Safe => self.safe_block_hash(),
92                BlockNumberOrTag::Earliest => self.block_hash(self.earliest_block_number()?),
93                BlockNumberOrTag::Number(num) => self.block_hash(num),
94            },
95        }
96    }
97
98    /// Get the number of the block by matching the given id.
99    fn block_number_for_id(&self, block_id: BlockId) -> ProviderResult<Option<BlockNumber>> {
100        match block_id {
101            BlockId::Hash(hash) => self.block_number(hash.into()),
102            BlockId::Number(num) => self.convert_block_number(num),
103        }
104    }
105
106    /// Get the current pending block number and hash.
107    fn pending_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>>;
108
109    /// Get the current safe block number and hash.
110    fn safe_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>>;
111
112    /// Get the current finalized block number and hash.
113    fn finalized_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>>;
114
115    /// Get the safe block number.
116    fn safe_block_number(&self) -> ProviderResult<Option<BlockNumber>> {
117        self.safe_block_num_hash().map(|res_opt| res_opt.map(|num_hash| num_hash.number))
118    }
119
120    /// Get the finalized block number.
121    fn finalized_block_number(&self) -> ProviderResult<Option<BlockNumber>> {
122        self.finalized_block_num_hash().map(|res_opt| res_opt.map(|num_hash| num_hash.number))
123    }
124
125    /// Get the safe block hash.
126    fn safe_block_hash(&self) -> ProviderResult<Option<B256>> {
127        self.safe_block_num_hash().map(|res_opt| res_opt.map(|num_hash| num_hash.hash))
128    }
129
130    /// Get the finalized block hash.
131    fn finalized_block_hash(&self) -> ProviderResult<Option<B256>> {
132        self.finalized_block_num_hash().map(|res_opt| res_opt.map(|num_hash| num_hash.hash))
133    }
134}
135
136#[cfg(test)]
137fn _object_safe(_: Box<dyn BlockIdReader>) {}