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