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}