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