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}