docs/design/database.md
Transaction as a non-leaky abstraction with helpers for strictly-typed and unit-tested higher-level database abstractions.Table::Key and Table::Values generic.
bitfield set on Table "PlainState" which adds a bitfield to Accounts.modular_bitfield crate, which compacts this information.no_codec in the codebase)reth_codec that delegates to one of Compact (default), Scale, Postcard or Passthrough encoding. This is derived on every struct we need, and lets us experiment with different encoding formats without having to modify the entire codebase each time.Historical state changes are indexed by BlockNumber. This means that reth stores the state for every account after every block that touched it, and it provides indexes for accessing that data quickly. While this may make the database size bigger (needs benchmark once reth is closer to prod), it provides fast access to the historical state.
Below, you can see the table design that implements this scheme:
erDiagram
CanonicalHeaders {
u64 BlockNumber "PK"
B256 HeaderHash "Value for CanonicalHeaders"
}
HeaderNumbers {
B256 BlockHash "PK"
u64 BlockNumber
}
Headers {
u64 BlockNumber "PK"
Header Data
}
BlockBodyIndices {
u64 BlockNumber "PK"
u64 first_tx_num
u64 tx_count
}
BlockOmmers {
u64 BlockNumber "PK"
Header[] Ommers
}
BlockWithdrawals {
u64 BlockNumber "PK"
Withdrawal[] Withdrawals
}
Transactions {
u64 TxNumber "PK"
TransactionSigned Data
}
TransactionHashNumbers {
B256 TxHash "PK"
u64 TxNumber
}
TransactionBlocks {
u64 MaxTxNumber "PK"
u64 BlockNumber
}
Receipts {
u64 TxNumber "PK"
Receipt Data
}
Bytecodes {
B256 CodeHash "PK"
Bytes Code
}
PlainAccountState {
Address Account "PK"
Account Data
}
PlainStorageState {
Address Account "PK"
B256 StorageKey "PK"
U256 StorageValue
}
AccountsHistory {
B256 Account "PK"
BlockNumberList BlockNumberList "List of transitions where account was changed"
}
StoragesHistory {
B256 Account "PK"
B256 StorageKey "PK"
BlockNumberList BlockNumberList "List of transitions where account storage entry was changed"
}
AccountChangeSets {
u64 BlockNumber "PK"
B256 Account "PK"
ChangeSet AccountChangeSets "Account before transition"
}
StorageChangeSets {
u64 BlockNumber "PK"
B256 Account "PK"
B256 StorageKey "PK"
ChangeSet StorageChangeSets "Storage entry before transition"
}
HashedAccounts {
B256 HashedAddress "PK"
Account Data
}
HashedStorages {
B256 HashedAddress "PK"
B256 HashedStorageKey "PK"
U256 StorageValue
}
AccountsTrie {
StoredNibbles Nibbles "PK"
BranchNodeCompact Node
}
StoragesTrie {
B256 HashedAddress "PK"
StoredNibblesSubKey NibblesSubKey "PK"
StorageTrieEntry Node
}
TransactionSenders {
u64 TxNumber "PK"
Address Sender
}
TransactionHashNumbers ||--|| Transactions : "hash -> tx id"
TransactionBlocks ||--|{ Transactions : "tx id -> block number"
BlockBodyIndices ||--o{ Transactions : "block number -> tx ids"
Headers ||--o{ AccountChangeSets : "each block has zero or more changesets"
Headers ||--o{ StorageChangeSets : "each block has zero or more changesets"
AccountsHistory }|--|{ AccountChangeSets : index
StoragesHistory }|--|{ StorageChangeSets : index
Headers ||--o| BlockOmmers : "each block has 0 or more ommers"
BlockBodyIndices ||--|| Headers : "index"
HeaderNumbers |o--|| Headers : "block hash -> block number"
CanonicalHeaders |o--|| Headers : "canonical chain block number -> block hash"
Transactions ||--|| Receipts : "each tx has a receipt"
PlainAccountState }o--o| Bytecodes : "an account can have a bytecode"
PlainAccountState ||--o{ PlainStorageState : "an account has 0 or more storage slots"
Transactions ||--|| TransactionSenders : "a tx has exactly 1 sender"
PlainAccountState ||--|| HashedAccounts : "hashed representation"
PlainStorageState ||--|| HashedStorages : "hashed representation"