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