reth_db_api/tables/
mod.rs

1//! Tables and data models.
2//!
3//! # Overview
4//!
5//! This module defines the tables in reth, as well as some table-related abstractions:
6//!
7//! - [`codecs`] integrates different codecs into [`Encode`] and [`Decode`]
8//! - [`models`](crate::models) defines the values written to tables
9//!
10//! # Database Tour
11//!
12//! TODO(onbjerg): Find appropriate format for this...
13
14pub mod codecs;
15
16mod raw;
17pub use raw::{RawDupSort, RawKey, RawTable, RawValue, TableRawRow};
18
19use crate::{
20    models::{
21        accounts::BlockNumberAddress,
22        blocks::{HeaderHash, StoredBlockOmmers},
23        storage_sharded_key::StorageShardedKey,
24        AccountBeforeTx, BlockNumberHashedAddress, ClientVersion, CompactU256, IntegerList,
25        ShardedKey, StoredBlockBodyIndices, StoredBlockWithdrawals,
26    },
27    table::{Decode, DupSort, Encode, Table, TableInfo},
28};
29use alloy_consensus::Header;
30use alloy_primitives::{Address, BlockHash, BlockNumber, TxHash, TxNumber, B256};
31use reth_ethereum_primitives::{Receipt, TransactionSigned};
32use reth_primitives_traits::{Account, Bytecode, StorageEntry};
33use reth_prune_types::{PruneCheckpoint, PruneSegment};
34use reth_stages_types::StageCheckpoint;
35use reth_trie_common::{
36    BranchNodeCompact, StorageTrieEntry, StoredNibbles, StoredNibblesSubKey, TrieChangeSetsEntry,
37};
38use serde::{Deserialize, Serialize};
39use std::fmt;
40
41/// Enum for the types of tables present in libmdbx.
42#[derive(Debug, PartialEq, Eq, Copy, Clone)]
43pub enum TableType {
44    /// key value table
45    Table,
46    /// Duplicate key value table
47    DupSort,
48}
49
50/// The general purpose of this is to use with a combination of Tables enum,
51/// by implementing a `TableViewer` trait you can operate on db tables in an abstract way.
52///
53/// # Example
54///
55/// ```
56/// use reth_db_api::{
57///     table::{DupSort, Table},
58///     TableViewer, Tables,
59/// };
60///
61/// struct MyTableViewer;
62///
63/// impl TableViewer<()> for MyTableViewer {
64///     type Error = &'static str;
65///
66///     fn view<T: Table>(&self) -> Result<(), Self::Error> {
67///         // operate on table in a generic way
68///         Ok(())
69///     }
70///
71///     fn view_dupsort<T: DupSort>(&self) -> Result<(), Self::Error> {
72///         // operate on a dupsort table in a generic way
73///         Ok(())
74///     }
75/// }
76///
77/// let viewer = MyTableViewer {};
78///
79/// let _ = Tables::Headers.view(&viewer);
80/// let _ = Tables::Transactions.view(&viewer);
81/// ```
82pub trait TableViewer<R> {
83    /// The error type returned by the viewer.
84    type Error;
85
86    /// Calls `view` with the correct table type.
87    fn view_rt(&self, table: Tables) -> Result<R, Self::Error> {
88        table.view(self)
89    }
90
91    /// Operate on the table in a generic way.
92    fn view<T: Table>(&self) -> Result<R, Self::Error>;
93
94    /// Operate on the dupsort table in a generic way.
95    ///
96    /// By default, the `view` function is invoked unless overridden.
97    fn view_dupsort<T: DupSort>(&self) -> Result<R, Self::Error>
98    where
99        T::Value: reth_primitives_traits::ValueWithSubKey<SubKey = T::SubKey>,
100    {
101        self.view::<T>()
102    }
103}
104
105/// General trait for defining the set of tables
106/// Used to initialize database
107pub trait TableSet {
108    /// Returns an iterator over the tables
109    fn tables() -> Box<dyn Iterator<Item = Box<dyn TableInfo>>>;
110}
111
112/// Defines all the tables in the database.
113#[macro_export]
114macro_rules! tables {
115    (@bool) => { false };
116    (@bool $($t:tt)+) => { true };
117
118    (@view $name:ident $v:ident) => { $v.view::<$name>() };
119    (@view $name:ident $v:ident $_subkey:ty) => { $v.view_dupsort::<$name>() };
120
121    (@value_doc $key:ty, $value:ty) => {
122        concat!("[`", stringify!($value), "`]")
123    };
124    // Don't generate links if we have generics
125    (@value_doc $key:ty, $value:ty, $($generic:ident),*) => {
126        concat!("`", stringify!($value), "`")
127    };
128
129    ($($(#[$attr:meta])* table $name:ident$(<$($generic:ident $(= $default:ty)?),*>)? { type Key = $key:ty; type Value = $value:ty; $(type SubKey = $subkey:ty;)? } )*) => {
130        // Table marker types.
131        $(
132            $(#[$attr])*
133            ///
134            #[doc = concat!("Marker type representing a database table mapping [`", stringify!($key), "`] to ", tables!(@value_doc $key, $value, $($($generic),*)?), ".")]
135            $(
136                #[doc = concat!("\n\nThis table's `DUPSORT` subkey is [`", stringify!($subkey), "`].")]
137            )?
138            pub struct $name$(<$($generic $( = $default)?),*>)? {
139                _private: std::marker::PhantomData<($($($generic,)*)?)>,
140            }
141
142            // Ideally this implementation wouldn't exist, but it is necessary to derive `Debug`
143            // when a type is generic over `T: Table`. See: https://github.com/rust-lang/rust/issues/26925
144            impl$(<$($generic),*>)? fmt::Debug for $name$(<$($generic),*>)? {
145                fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
146                    unreachable!("this type cannot be instantiated")
147                }
148            }
149
150            impl$(<$($generic),*>)? $crate::table::Table for $name$(<$($generic),*>)?
151            where
152                $value: $crate::table::Value + 'static
153                $($(,$generic: Send + Sync)*)?
154            {
155                const NAME: &'static str = table_names::$name;
156                const DUPSORT: bool = tables!(@bool $($subkey)?);
157
158                type Key = $key;
159                type Value = $value;
160            }
161
162            $(
163                impl DupSort for $name {
164                    type SubKey = $subkey;
165                }
166            )?
167        )*
168
169        // Tables enum.
170
171        /// A table in the database.
172        #[derive(Clone, Copy, PartialEq, Eq, Hash)]
173        pub enum Tables {
174            $(
175                #[doc = concat!("The [`", stringify!($name), "`] database table.")]
176                $name,
177            )*
178        }
179
180        impl Tables {
181            /// All the tables in the database.
182            pub const ALL: &'static [Self] = &[$(Self::$name,)*];
183
184            /// The number of tables in the database.
185            pub const COUNT: usize = Self::ALL.len();
186
187            /// Returns the name of the table as a string.
188            pub const fn name(&self) -> &'static str {
189                match self {
190                    $(
191                        Self::$name => table_names::$name,
192                    )*
193                }
194            }
195
196            /// Returns `true` if the table is a `DUPSORT` table.
197            pub const fn is_dupsort(&self) -> bool {
198                match self {
199                    $(
200                        Self::$name => tables!(@bool $($subkey)?),
201                    )*
202                }
203            }
204
205            /// The type of the given table in database.
206            pub const fn table_type(&self) -> TableType {
207                if self.is_dupsort() {
208                    TableType::DupSort
209                } else {
210                    TableType::Table
211                }
212            }
213
214            /// Allows to operate on specific table type
215            pub fn view<T, R>(&self, visitor: &T) -> Result<R, T::Error>
216            where
217                T: ?Sized + TableViewer<R>,
218            {
219                match self {
220                    $(
221                        Self::$name => tables!(@view $name visitor $($subkey)?),
222                    )*
223                }
224            }
225        }
226
227        impl fmt::Debug for Tables {
228            #[inline]
229            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230                f.write_str(self.name())
231            }
232        }
233
234        impl fmt::Display for Tables {
235            #[inline]
236            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237                self.name().fmt(f)
238            }
239        }
240
241        impl std::str::FromStr for Tables {
242            type Err = String;
243
244            fn from_str(s: &str) -> Result<Self, Self::Err> {
245                match s {
246                    $(
247                        table_names::$name => Ok(Self::$name),
248                    )*
249                    s => Err(format!("unknown table: {s:?}")),
250                }
251            }
252        }
253
254        impl TableInfo for Tables {
255            fn name(&self) -> &'static str {
256                self.name()
257            }
258
259            fn is_dupsort(&self) -> bool {
260                self.is_dupsort()
261            }
262        }
263
264        impl TableSet for Tables {
265            fn tables() -> Box<dyn Iterator<Item = Box<dyn TableInfo>>> {
266                Box::new(Self::ALL.iter().map(|table| Box::new(*table) as Box<dyn TableInfo>))
267            }
268        }
269
270        // Need constants to match on in the `FromStr` implementation.
271        #[expect(non_upper_case_globals)]
272        mod table_names {
273            $(
274                pub(super) const $name: &'static str = stringify!($name);
275            )*
276        }
277
278        /// Maps a run-time [`Tables`] enum value to its corresponding compile-time [`Table`] type.
279        ///
280        /// This is a simpler alternative to [`TableViewer`].
281        ///
282        /// # Examples
283        ///
284        /// ```
285        /// use reth_db_api::{table::Table, Tables, tables_to_generic};
286        ///
287        /// let table = Tables::Headers;
288        /// let result = tables_to_generic!(table, |GenericTable| <GenericTable as Table>::NAME);
289        /// assert_eq!(result, table.name());
290        /// ```
291        #[macro_export]
292        macro_rules! tables_to_generic {
293            ($table:expr, |$generic_name:ident| $e:expr) => {
294                match $table {
295                    $(
296                        Tables::$name => {
297                            use $crate::tables::$name as $generic_name;
298                            $e
299                        },
300                    )*
301                }
302            };
303        }
304    };
305}
306
307tables! {
308    /// Stores the header hashes belonging to the canonical chain.
309    table CanonicalHeaders {
310        type Key = BlockNumber;
311        type Value = HeaderHash;
312    }
313
314    /// Stores the total difficulty from block headers.
315    /// Note: Deprecated.
316    table HeaderTerminalDifficulties {
317        type Key = BlockNumber;
318        type Value = CompactU256;
319    }
320
321    /// Stores the block number corresponding to a header.
322    table HeaderNumbers {
323        type Key = BlockHash;
324        type Value = BlockNumber;
325    }
326
327    /// Stores header bodies.
328    table Headers<H = Header> {
329        type Key = BlockNumber;
330        type Value = H;
331    }
332
333    /// Stores block indices that contains indexes of transaction and the count of them.
334    ///
335    /// More information about stored indices can be found in the [`StoredBlockBodyIndices`] struct.
336    table BlockBodyIndices {
337        type Key = BlockNumber;
338        type Value = StoredBlockBodyIndices;
339    }
340
341    /// Stores the uncles/ommers of the block.
342    table BlockOmmers<H = Header> {
343        type Key = BlockNumber;
344        type Value = StoredBlockOmmers<H>;
345    }
346
347    /// Stores the block withdrawals.
348    table BlockWithdrawals {
349        type Key = BlockNumber;
350        type Value = StoredBlockWithdrawals;
351    }
352
353    /// Canonical only Stores the transaction body for canonical transactions.
354    table Transactions<T = TransactionSigned> {
355        type Key = TxNumber;
356        type Value = T;
357    }
358
359    /// Stores the mapping of the transaction hash to the transaction number.
360    table TransactionHashNumbers {
361        type Key = TxHash;
362        type Value = TxNumber;
363    }
364
365    /// Stores the mapping of transaction number to the blocks number.
366    ///
367    /// The key is the highest transaction ID in the block.
368    table TransactionBlocks {
369        type Key = TxNumber;
370        type Value = BlockNumber;
371    }
372
373    /// Canonical only Stores transaction receipts.
374    table Receipts<R = Receipt> {
375        type Key = TxNumber;
376        type Value = R;
377    }
378
379    /// Stores all smart contract bytecodes.
380    /// There will be multiple accounts that have same bytecode
381    /// So we would need to introduce reference counter.
382    /// This will be small optimization on state.
383    table Bytecodes {
384        type Key = B256;
385        type Value = Bytecode;
386    }
387
388    /// Stores the current state of an [`Account`].
389    table PlainAccountState {
390        type Key = Address;
391        type Value = Account;
392    }
393
394    /// Stores the current value of a storage key.
395    table PlainStorageState {
396        type Key = Address;
397        type Value = StorageEntry;
398        type SubKey = B256;
399    }
400
401    /// Stores pointers to block changeset with changes for each account key.
402    ///
403    /// Last shard key of the storage will contain `u64::MAX` `BlockNumber`,
404    /// this would allows us small optimization on db access when change is in plain state.
405    ///
406    /// Imagine having shards as:
407    /// * `Address | 100`
408    /// * `Address | u64::MAX`
409    ///
410    /// What we need to find is number that is one greater than N. Db `seek` function allows us to fetch
411    /// the shard that equal or more than asked. For example:
412    /// * For N=50 we would get first shard.
413    /// * for N=150 we would get second shard.
414    /// * If max block number is 200 and we ask for N=250 we would fetch last shard and know that needed entry is in `AccountPlainState`.
415    /// * If there were no shard we would get `None` entry or entry of different storage key.
416    ///
417    /// Code example can be found in `reth_provider::HistoricalStateProviderRef`
418    table AccountsHistory {
419        type Key = ShardedKey<Address>;
420        type Value = BlockNumberList;
421    }
422
423    /// Stores pointers to block number changeset with changes for each storage key.
424    ///
425    /// Last shard key of the storage will contain `u64::MAX` `BlockNumber`,
426    /// this would allows us small optimization on db access when change is in plain state.
427    ///
428    /// Imagine having shards as:
429    /// * `Address | StorageKey | 100`
430    /// * `Address | StorageKey | u64::MAX`
431    ///
432    /// What we need to find is number that is one greater than N. Db `seek` function allows us to fetch
433    /// the shard that equal or more than asked. For example:
434    /// * For N=50 we would get first shard.
435    /// * for N=150 we would get second shard.
436    /// * If max block number is 200 and we ask for N=250 we would fetch last shard and know that needed entry is in `StoragePlainState`.
437    /// * If there were no shard we would get `None` entry or entry of different storage key.
438    ///
439    /// Code example can be found in `reth_provider::HistoricalStateProviderRef`
440    table StoragesHistory {
441        type Key = StorageShardedKey;
442        type Value = BlockNumberList;
443    }
444
445    /// Stores the state of an account before a certain transaction changed it.
446    /// Change on state can be: account is created, selfdestructed, touched while empty
447    /// or changed balance,nonce.
448    table AccountChangeSets {
449        type Key = BlockNumber;
450        type Value = AccountBeforeTx;
451        type SubKey = Address;
452    }
453
454    /// Stores the state of a storage key before a certain transaction changed it.
455    /// If [`StorageEntry::value`] is zero, this means storage was not existing
456    /// and needs to be removed.
457    table StorageChangeSets {
458        type Key = BlockNumberAddress;
459        type Value = StorageEntry;
460        type SubKey = B256;
461    }
462
463    /// Stores the current state of an [`Account`] indexed with `keccak256Address`
464    /// This table is in preparation for merklization and calculation of state root.
465    /// We are saving whole account data as it is needed for partial update when
466    /// part of storage is changed. Benefit for merklization is that hashed addresses are sorted.
467    table HashedAccounts {
468        type Key = B256;
469        type Value = Account;
470    }
471
472    /// Stores the current storage values indexed with `keccak256Address` and
473    /// hash of storage key `keccak256key`.
474    /// This table is in preparation for merklization and calculation of state root.
475    /// Benefit for merklization is that hashed addresses/keys are sorted.
476    table HashedStorages {
477        type Key = B256;
478        type Value = StorageEntry;
479        type SubKey = B256;
480    }
481
482    /// Stores the current state's Merkle Patricia Tree.
483    table AccountsTrie {
484        type Key = StoredNibbles;
485        type Value = BranchNodeCompact;
486    }
487
488    /// From `HashedAddress` => `NibblesSubKey` => Intermediate value
489    table StoragesTrie {
490        type Key = B256;
491        type Value = StorageTrieEntry;
492        type SubKey = StoredNibblesSubKey;
493    }
494
495    /// Stores the state of a node in the accounts trie prior to a particular block being executed.
496    table AccountsTrieChangeSets {
497        type Key = BlockNumber;
498        type Value = TrieChangeSetsEntry;
499        type SubKey = StoredNibblesSubKey;
500    }
501
502    /// Stores the state of a node in a storage trie prior to a particular block being executed.
503    table StoragesTrieChangeSets {
504        type Key = BlockNumberHashedAddress;
505        type Value = TrieChangeSetsEntry;
506        type SubKey = StoredNibblesSubKey;
507    }
508
509    /// Stores the transaction sender for each canonical transaction.
510    /// It is needed to speed up execution stage and allows fetching signer without doing
511    /// transaction signed recovery
512    table TransactionSenders {
513        type Key = TxNumber;
514        type Value = Address;
515    }
516
517    /// Stores the highest synced block number and stage-specific checkpoint of each stage.
518    table StageCheckpoints {
519        type Key = StageId;
520        type Value = StageCheckpoint;
521    }
522
523    /// Stores arbitrary data to keep track of a stage first-sync progress.
524    table StageCheckpointProgresses {
525        type Key = StageId;
526        type Value = Vec<u8>;
527    }
528
529    /// Stores the highest pruned block number and prune mode of each prune segment.
530    table PruneCheckpoints {
531        type Key = PruneSegment;
532        type Value = PruneCheckpoint;
533    }
534
535    /// Stores the history of client versions that have accessed the database with write privileges by unix timestamp in seconds.
536    table VersionHistory {
537        type Key = u64;
538        type Value = ClientVersion;
539    }
540
541    /// Stores generic chain state info, like the last finalized block.
542    table ChainState {
543        type Key = ChainStateKey;
544        type Value = BlockNumber;
545    }
546
547    /// Stores generic node metadata as key-value pairs.
548    /// Can store feature flags, configuration markers, and other node-specific data.
549    table Metadata {
550        type Key = String;
551        type Value = Vec<u8>;
552    }
553}
554
555/// Keys for the `ChainState` table.
556#[derive(Ord, Clone, Eq, PartialOrd, PartialEq, Debug, Deserialize, Serialize, Hash)]
557pub enum ChainStateKey {
558    /// Last finalized block key
559    LastFinalizedBlock,
560    /// Last safe block key
561    LastSafeBlock,
562}
563
564impl Encode for ChainStateKey {
565    type Encoded = [u8; 1];
566
567    fn encode(self) -> Self::Encoded {
568        match self {
569            Self::LastFinalizedBlock => [0],
570            Self::LastSafeBlock => [1],
571        }
572    }
573}
574
575impl Decode for ChainStateKey {
576    fn decode(value: &[u8]) -> Result<Self, crate::DatabaseError> {
577        match value {
578            [0] => Ok(Self::LastFinalizedBlock),
579            [1] => Ok(Self::LastSafeBlock),
580            _ => Err(crate::DatabaseError::Decode),
581        }
582    }
583}
584
585// Alias types.
586
587/// List with transaction numbers.
588pub type BlockNumberList = IntegerList;
589
590/// Encoded stage id.
591pub type StageId = String;
592
593#[cfg(test)]
594mod tests {
595    use super::*;
596    use std::str::FromStr;
597
598    #[test]
599    fn parse_table_from_str() {
600        for table in Tables::ALL {
601            assert_eq!(format!("{table:?}"), table.name());
602            assert_eq!(table.to_string(), table.name());
603            assert_eq!(Tables::from_str(table.name()).unwrap(), *table);
604        }
605    }
606}