Skip to main content

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