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