reth_storage_api/
chain.rs1use crate::{DBProvider, StorageLocation};
2use alloy_primitives::BlockNumber;
3use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
4use reth_db::{
5 cursor::{DbCursorRO, DbCursorRW},
6 models::{StoredBlockOmmers, StoredBlockWithdrawals},
7 tables,
8 transaction::{DbTx, DbTxMut},
9 DbTxUnwindExt,
10};
11use reth_primitives_traits::{Block, BlockBody, FullNodePrimitives};
12use reth_storage_errors::provider::ProviderResult;
13
14#[auto_impl::auto_impl(&, Arc)]
19pub trait BlockBodyWriter<Provider, Body: BlockBody> {
20 fn write_block_bodies(
22 &self,
23 provider: &Provider,
24 bodies: Vec<(BlockNumber, Option<Body>)>,
25 write_to: StorageLocation,
26 ) -> ProviderResult<()>;
27
28 fn remove_block_bodies_above(
30 &self,
31 provider: &Provider,
32 block: BlockNumber,
33 remove_from: StorageLocation,
34 ) -> ProviderResult<()>;
35}
36
37pub trait ChainStorageWriter<Provider, Primitives: FullNodePrimitives>:
39 BlockBodyWriter<Provider, <Primitives::Block as Block>::Body>
40{
41}
42impl<T, Provider, Primitives: FullNodePrimitives> ChainStorageWriter<Provider, Primitives> for T where
43 T: BlockBodyWriter<Provider, <Primitives::Block as Block>::Body>
44{
45}
46
47pub type ReadBodyInput<'a, B> =
50 (&'a <B as Block>::Header, Vec<<<B as Block>::Body as BlockBody>::Transaction>);
51
52#[auto_impl::auto_impl(&, Arc)]
58pub trait BlockBodyReader<Provider> {
59 type Block: Block;
61
62 fn read_block_bodies(
64 &self,
65 provider: &Provider,
66 inputs: Vec<ReadBodyInput<'_, Self::Block>>,
67 ) -> ProviderResult<Vec<<Self::Block as Block>::Body>>;
68}
69
70pub trait ChainStorageReader<Provider, Primitives: FullNodePrimitives>:
72 BlockBodyReader<Provider, Block = Primitives::Block>
73{
74}
75impl<T, Provider, Primitives: FullNodePrimitives> ChainStorageReader<Provider, Primitives> for T where
76 T: BlockBodyReader<Provider, Block = Primitives::Block>
77{
78}
79
80#[derive(Debug, Default, Clone, Copy)]
82pub struct EthStorage;
83
84impl<Provider> BlockBodyWriter<Provider, reth_primitives::BlockBody> for EthStorage
85where
86 Provider: DBProvider<Tx: DbTxMut>,
87{
88 fn write_block_bodies(
89 &self,
90 provider: &Provider,
91 bodies: Vec<(u64, Option<reth_primitives::BlockBody>)>,
92 _write_to: StorageLocation,
93 ) -> ProviderResult<()> {
94 let mut ommers_cursor = provider.tx_ref().cursor_write::<tables::BlockOmmers>()?;
95 let mut withdrawals_cursor =
96 provider.tx_ref().cursor_write::<tables::BlockWithdrawals>()?;
97
98 for (block_number, body) in bodies {
99 let Some(body) = body else { continue };
100
101 if !body.ommers.is_empty() {
103 ommers_cursor.append(block_number, StoredBlockOmmers { ommers: body.ommers })?;
104 }
105
106 if let Some(withdrawals) = body.withdrawals {
108 if !withdrawals.is_empty() {
109 withdrawals_cursor
110 .append(block_number, StoredBlockWithdrawals { withdrawals })?;
111 }
112 }
113 }
114
115 Ok(())
116 }
117
118 fn remove_block_bodies_above(
119 &self,
120 provider: &Provider,
121 block: BlockNumber,
122 _remove_from: StorageLocation,
123 ) -> ProviderResult<()> {
124 provider.tx_ref().unwind_table_by_num::<tables::BlockWithdrawals>(block)?;
125 provider.tx_ref().unwind_table_by_num::<tables::BlockOmmers>(block)?;
126
127 Ok(())
128 }
129}
130
131impl<Provider> BlockBodyReader<Provider> for EthStorage
132where
133 Provider: DBProvider + ChainSpecProvider<ChainSpec: EthereumHardforks>,
134{
135 type Block = reth_primitives::Block;
136
137 fn read_block_bodies(
138 &self,
139 provider: &Provider,
140 inputs: Vec<ReadBodyInput<'_, Self::Block>>,
141 ) -> ProviderResult<Vec<<Self::Block as Block>::Body>> {
142 let chain_spec = provider.chain_spec();
144
145 let mut ommers_cursor = provider.tx_ref().cursor_read::<tables::BlockOmmers>()?;
146 let mut withdrawals_cursor = provider.tx_ref().cursor_read::<tables::BlockWithdrawals>()?;
147
148 let mut bodies = Vec::with_capacity(inputs.len());
149
150 for (header, transactions) in inputs {
151 let withdrawals = if chain_spec.is_shanghai_active_at_timestamp(header.timestamp) {
154 withdrawals_cursor
155 .seek_exact(header.number)?
156 .map(|(_, w)| w.withdrawals)
157 .unwrap_or_default()
158 .into()
159 } else {
160 None
161 };
162 let ommers = if chain_spec.final_paris_total_difficulty(header.number).is_some() {
163 Vec::new()
164 } else {
165 ommers_cursor.seek_exact(header.number)?.map(|(_, o)| o.ommers).unwrap_or_default()
166 };
167
168 bodies.push(reth_primitives::BlockBody { transactions, ommers, withdrawals });
169 }
170
171 Ok(bodies)
172 }
173}