Skip to main content

Storage

Basalt's storage layer persists blockchain state, blocks, receipts, and indexing data. It uses RocksDB as the primary storage engine, with a Merkle Patricia Trie (MPT) providing authenticated state access and proof generation.

RocksDB Column Families

Data is organized into separate RocksDB column families, each serving a distinct purpose:

Column FamilyPurpose
stateAccount state data (balances, nonces, storage roots)
blocksSerialized block headers and bodies
receiptsTransaction receipts (execution results, logs, gas used)
metadataChain metadata (current head hash, finalized height)
trie_nodesMerkle Patricia Trie node data
block_indexBlock number to block hash index
stakingValidator stakes and unbonding records

Column family separation allows RocksDB to optimize compaction and caching independently for each data type. For example, trie_nodes experiences heavy random-access reads during state queries, while blocks is predominantly append-only.

Account State

Each account is encoded into a 137-byte fixed-size record:

FieldSizeDescription
Nonce8 bytesTransaction sequence number, incremented with each transaction
Balance32 bytesAccount balance as UInt256
StorageRoot32 bytesHash256 root of the account's storage trie
CodeHash32 bytesHash256 of the deployed contract bytecode (zero for EOAs)
AccountType1 byteAccount classification
ComplianceHash32 bytesHash256 of the account's compliance attestation data

Account Types

ValueTypeDescription
0ExternallyOwnedStandard user account (EOA)
1ContractUser-deployed smart contract
2SystemContractProtocol-level system contract
3ValidatorRegistered validator account

Merkle Patricia Trie

The MPT provides cryptographic authentication of the entire account state. Every state query can produce a proof that the returned data is consistent with the state root committed in the block header.

Node Types

TypeDescription
EmptyRepresents an absent key in the trie
LeafTerminal node containing the value for a specific key
ExtensionIntermediate node compressing a shared key prefix
Branch16-way branching node (one slot per hex nibble, plus an optional value slot)

Implementation Details

PropertyValue
Hash functionBLAKE3
Path encodingNibble-path with Ethereum hex-prefix compact encoding
Proof supportMerkle inclusion/exclusion proofs for light clients

The hex-prefix encoding compacts nibble paths by packing two nibbles per byte, with a prefix nibble indicating whether the path is odd-length and whether the node is a leaf or extension. This matches the Ethereum trie specification.

Proof Generation

The trie supports generating Merkle proofs for light client verification. A proof consists of the sequence of trie nodes along the path from the root to the target key. A verifier can reconstruct the root hash from the proof nodes and confirm it matches the state root in the block header, without downloading the full state.

State Database Implementations

Basalt provides three StateDb implementations for different use cases:

ImplementationBacking StoreUse Case
TrieStateDbRocksDB + MPTProduction. Full authenticated state with proof generation.
FlatStateDbFlat key-value storeAlternative flat state representation for faster reads without trie overhead.
InMemoryStateDbIn-memory dictionaryTesting and development. No persistence.

TrieStateDb is the default for all production nodes. It maintains the full Merkle Patricia Trie, enabling state root computation and proof generation at every block height. FlatStateDb provides a simpler key-value mapping when trie proofs are not needed. InMemoryStateDb is used exclusively in unit and integration tests.