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}