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};
67/// 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.
14fn chain_info(&self) -> ProviderResult<ChainInfo>;
1516/// Returns the best block number in the chain.
17fn best_block_number(&self) -> ProviderResult<BlockNumber>;
1819/// Returns the last block number associated with the last canonical header in the database.
20fn last_block_number(&self) -> ProviderResult<BlockNumber>;
2122/// Gets the `BlockNumber` for the given hash. Returns `None` if no block with this hash exists.
23fn block_number(&self, hash: B256) -> ProviderResult<Option<BlockNumber>>;
2425/// Gets the block number for the given `BlockHashOrNumber`. Returns `None` if no block with
26 /// this hash exists. If the `BlockHashOrNumber` is a `Number`, it is returned as is.
27fn convert_hash_or_number(&self, id: BlockHashOrNumber) -> ProviderResult<Option<BlockNumber>> {
28match id {
29 BlockHashOrNumber::Hash(hash) => self.block_number(hash),
30 BlockHashOrNumber::Number(num) => Ok(Some(num)),
31 }
32 }
3334/// Gets the block hash for the given `BlockHashOrNumber`. Returns `None` if no block with this
35 /// number exists. If the `BlockHashOrNumber` is a `Hash`, it is returned as is.
36fn convert_number(&self, id: BlockHashOrNumber) -> ProviderResult<Option<B256>> {
37match id {
38 BlockHashOrNumber::Hash(hash) => Ok(Some(hash)),
39 BlockHashOrNumber::Number(num) => self.block_hash(num),
40 }
41 }
42}
4344/// Client trait for transforming [`BlockId`] into block numbers or hashes.
45///
46/// Types that implement this trait must be able to resolve all variants of [`BlockNumberOrTag`] to
47/// block numbers or hashes. Automatic implementations for resolving [`BlockNumberOrTag`] variants
48/// are provided if the type implements the `pending_block_num_hash`, `finalized_block_num`, and
49/// `safe_block_num` methods.
50///
51/// The resulting block numbers can be converted to hashes using the underlying [BlockNumReader]
52/// methods, and vice versa.
53#[auto_impl::auto_impl(&, Arc)]
54pub trait BlockIdReader: BlockNumReader + Send + Sync {
55/// Converts the `BlockNumberOrTag` variants to a block number.
56fn convert_block_number(&self, num: BlockNumberOrTag) -> ProviderResult<Option<BlockNumber>> {
57let num = match num {
58 BlockNumberOrTag::Latest => self.best_block_number()?,
59 BlockNumberOrTag::Earliest => 0,
60 BlockNumberOrTag::Pending => {
61return self62.pending_block_num_hash()
63 .map(|res_opt| res_opt.map(|num_hash| num_hash.number))
64 }
65 BlockNumberOrTag::Number(num) => num,
66 BlockNumberOrTag::Finalized => {
67self.finalized_block_number()?.ok_or(ProviderError::FinalizedBlockNotFound)?
68}
69 BlockNumberOrTag::Safe => {
70self.safe_block_number()?.ok_or(ProviderError::SafeBlockNotFound)?
71}
72 };
73Ok(Some(num))
74 }
7576/// Get the hash of the block by matching the given id.
77fn block_hash_for_id(&self, block_id: BlockId) -> ProviderResult<Option<B256>> {
78match block_id {
79 BlockId::Hash(hash) => Ok(Some(hash.into())),
80 BlockId::Number(num) => match num {
81 BlockNumberOrTag::Latest => Ok(Some(self.chain_info()?.best_hash)),
82 BlockNumberOrTag::Pending => self83.pending_block_num_hash()
84 .map(|res_opt| res_opt.map(|num_hash| num_hash.hash)),
85 BlockNumberOrTag::Finalized => self.finalized_block_hash(),
86 BlockNumberOrTag::Safe => self.safe_block_hash(),
87 BlockNumberOrTag::Earliest => self.block_hash(0),
88 BlockNumberOrTag::Number(num) => self.block_hash(num),
89 },
90 }
91 }
9293/// Get the number of the block by matching the given id.
94fn block_number_for_id(&self, block_id: BlockId) -> ProviderResult<Option<BlockNumber>> {
95match block_id {
96 BlockId::Hash(hash) => self.block_number(hash.into()),
97 BlockId::Number(num) => self.convert_block_number(num),
98 }
99 }
100101/// Get the current pending block number and hash.
102fn pending_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>>;
103104/// Get the current safe block number and hash.
105fn safe_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>>;
106107/// Get the current finalized block number and hash.
108fn finalized_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>>;
109110/// Get the safe block number.
111fn safe_block_number(&self) -> ProviderResult<Option<BlockNumber>> {
112self.safe_block_num_hash().map(|res_opt| res_opt.map(|num_hash| num_hash.number))
113 }
114115/// Get the finalized block number.
116fn finalized_block_number(&self) -> ProviderResult<Option<BlockNumber>> {
117self.finalized_block_num_hash().map(|res_opt| res_opt.map(|num_hash| num_hash.number))
118 }
119120/// Get the safe block hash.
121fn safe_block_hash(&self) -> ProviderResult<Option<B256>> {
122self.safe_block_num_hash().map(|res_opt| res_opt.map(|num_hash| num_hash.hash))
123 }
124125/// Get the finalized block hash.
126fn finalized_block_hash(&self) -> ProviderResult<Option<B256>> {
127self.finalized_block_num_hash().map(|res_opt| res_opt.map(|num_hash| num_hash.hash))
128 }
129}
130131#[cfg(test)]
132fn _object_safe(_: Box<dyn BlockIdReader>) {}