reth_rpc_eth_api/helpers/
block.rs1use std::sync::Arc;
4
5use alloy_eips::BlockId;
6use alloy_primitives::Sealable;
7use alloy_rlp::Encodable;
8use alloy_rpc_types_eth::{Block, BlockTransactions, Header, Index};
9use futures::Future;
10use reth_node_api::BlockBody;
11use reth_primitives::{SealedBlockFor, SealedBlockWithSenders};
12use reth_provider::{
13 BlockIdReader, BlockReader, BlockReaderIdExt, ProviderHeader, ProviderReceipt,
14};
15use reth_rpc_types_compat::block::from_block;
16use revm_primitives::U256;
17
18use crate::{
19 node::RpcNodeCoreExt, EthApiTypes, FromEthApiError, FullEthApiTypes, RpcBlock, RpcNodeCore,
20 RpcReceipt,
21};
22
23use super::{LoadPendingBlock, LoadReceipt, SpawnBlocking};
24
25pub type BlockReceiptsResult<N, E> = Result<Option<Vec<RpcReceipt<N>>>, E>;
27pub type BlockAndReceiptsResult<Eth> = Result<
29 Option<(
30 SealedBlockFor<<<Eth as RpcNodeCore>::Provider as BlockReader>::Block>,
31 Arc<Vec<ProviderReceipt<<Eth as RpcNodeCore>::Provider>>>,
32 )>,
33 <Eth as EthApiTypes>::Error,
34>;
35
36pub trait EthBlocks: LoadBlock {
39 #[expect(clippy::type_complexity)]
41 fn rpc_block_header(
42 &self,
43 block_id: BlockId,
44 ) -> impl Future<Output = Result<Option<Header<ProviderHeader<Self::Provider>>>, Self::Error>> + Send
45 where
46 Self: FullEthApiTypes,
47 {
48 async move { Ok(self.rpc_block(block_id, false).await?.map(|block| block.header)) }
49 }
50
51 fn rpc_block(
56 &self,
57 block_id: BlockId,
58 full: bool,
59 ) -> impl Future<Output = Result<Option<RpcBlock<Self::NetworkTypes>>, Self::Error>> + Send
60 where
61 Self: FullEthApiTypes,
62 {
63 async move {
64 let Some(block) = self.block_with_senders(block_id).await? else { return Ok(None) };
65 let block_hash = block.hash();
66
67 let block = from_block(
68 (*block).clone().unseal(),
69 full.into(),
70 Some(block_hash),
71 self.tx_resp_builder(),
72 )?;
73 Ok(Some(block))
74 }
75 }
76
77 fn block_transaction_count(
81 &self,
82 block_id: BlockId,
83 ) -> impl Future<Output = Result<Option<usize>, Self::Error>> + Send {
84 async move {
85 if block_id.is_pending() {
86 return Ok(self
88 .provider()
89 .pending_block()
90 .map_err(Self::Error::from_eth_err)?
91 .map(|block| block.body.transactions().len()))
92 }
93
94 let block_hash = match self
95 .provider()
96 .block_hash_for_id(block_id)
97 .map_err(Self::Error::from_eth_err)?
98 {
99 Some(block_hash) => block_hash,
100 None => return Ok(None),
101 };
102
103 Ok(self
104 .cache()
105 .get_sealed_block_with_senders(block_hash)
106 .await
107 .map_err(Self::Error::from_eth_err)?
108 .map(|b| b.body.transactions().len()))
109 }
110 }
111
112 #[allow(clippy::type_complexity)]
116 fn block_receipts(
117 &self,
118 block_id: BlockId,
119 ) -> impl Future<Output = BlockReceiptsResult<Self::NetworkTypes, Self::Error>> + Send
120 where
121 Self: LoadReceipt;
122
123 #[allow(clippy::type_complexity)]
125 fn load_block_and_receipts(
126 &self,
127 block_id: BlockId,
128 ) -> impl Future<Output = BlockAndReceiptsResult<Self>> + Send
129 where
130 Self: LoadReceipt,
131 {
132 async move {
133 if block_id.is_pending() {
134 if let Some((block, receipts)) = self
137 .provider()
138 .pending_block_and_receipts()
139 .map_err(Self::Error::from_eth_err)?
140 {
141 return Ok(Some((block, Arc::new(receipts))));
142 }
143
144 if let Some((block, receipts)) = self.local_pending_block().await? {
146 return Ok(Some((block.block, Arc::new(receipts))));
147 }
148 }
149
150 if let Some(block_hash) =
151 self.provider().block_hash_for_id(block_id).map_err(Self::Error::from_eth_err)?
152 {
153 return self
154 .cache()
155 .get_block_and_receipts(block_hash)
156 .await
157 .map_err(Self::Error::from_eth_err)
158 .map(|b| b.map(|(b, r)| (b.block.clone(), r)))
159 }
160
161 Ok(None)
162 }
163 }
164
165 #[expect(clippy::type_complexity)]
169 fn ommers(
170 &self,
171 block_id: BlockId,
172 ) -> Result<Option<Vec<ProviderHeader<Self::Provider>>>, Self::Error> {
173 self.provider().ommers_by_id(block_id).map_err(Self::Error::from_eth_err)
174 }
175
176 fn ommer_by_block_and_index(
180 &self,
181 block_id: BlockId,
182 index: Index,
183 ) -> impl Future<Output = Result<Option<RpcBlock<Self::NetworkTypes>>, Self::Error>> + Send
184 {
185 async move {
186 let uncles = if block_id.is_pending() {
187 self.provider()
189 .pending_block()
190 .map_err(Self::Error::from_eth_err)?
191 .and_then(|block| block.body.ommers().map(|o| o.to_vec()))
192 } else {
193 self.provider().ommers_by_id(block_id).map_err(Self::Error::from_eth_err)?
194 }
195 .unwrap_or_default();
196
197 Ok(uncles.into_iter().nth(index.into()).map(|header| {
198 let block = alloy_consensus::Block::<alloy_consensus::TxEnvelope, _>::uncle(header);
199 let size = U256::from(block.length());
200 Block {
201 uncles: vec![],
202 header: Header::from_consensus(block.header.seal_slow(), None, Some(size)),
203 transactions: BlockTransactions::Uncle,
204 withdrawals: None,
205 }
206 }))
207 }
208 }
209}
210
211pub trait LoadBlock: LoadPendingBlock + SpawnBlocking + RpcNodeCoreExt {
215 #[expect(clippy::type_complexity)]
217 fn block_with_senders(
218 &self,
219 block_id: BlockId,
220 ) -> impl Future<
221 Output = Result<
222 Option<Arc<SealedBlockWithSenders<<Self::Provider as BlockReader>::Block>>>,
223 Self::Error,
224 >,
225 > + Send {
226 async move {
227 if block_id.is_pending() {
228 if let Some(pending_block) = self
230 .provider()
231 .pending_block_with_senders()
232 .map_err(Self::Error::from_eth_err)?
233 {
234 return Ok(Some(Arc::new(pending_block)));
235 }
236
237 return match self.local_pending_block().await? {
239 Some((block, _)) => Ok(Some(Arc::new(block))),
240 None => Ok(None),
241 };
242 }
243
244 let block_hash = match self
245 .provider()
246 .block_hash_for_id(block_id)
247 .map_err(Self::Error::from_eth_err)?
248 {
249 Some(block_hash) => block_hash,
250 None => return Ok(None),
251 };
252
253 self.cache()
254 .get_sealed_block_with_senders(block_hash)
255 .await
256 .map_err(Self::Error::from_eth_err)
257 }
258 }
259}