> ## Documentation Index
> Fetch the complete documentation index at: https://seilabs-docs-bridge-release-v6-6-0.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# SeiDB: Performance-Optimized Blockchain Database

> Learn how SeiDB's specialized storage architecture accelerates blockchain operations through multi-level caching, optimized state access, and concurrency control designed specifically for EVM workloads.

## Introduction

SeiDB is a specialized database system designed to optimize blockchain state storage for the Ethereum Virtual Machine (EVM). It addresses fundamental performance constraints in traditional blockchain storage systems through targeted optimizations for EVM's specific state access patterns. This document explains the technical design and key components of SeiDB.

<Warning>**IAVL Removed — SeiDB Required:** The legacy IAVL backend has been fully removed. SeiDB state-commit is now mandatory: if `sc-enable` is set to `false`, the node will panic on startup with `SeiDB state-commit (SC) must be enabled; IAVL backend has been fully deprecated` instead of falling back to IAVL. Node operators must ensure SeiDB is enabled by setting `sc-enable = true` (and `ss-enable = true` for the state store) in their node configuration before upgrading. All IAVL-related CLI commands (such as `compact`, `prune`, `latest_version`, and `debug dump-iavl`) and IAVL configuration fields (including `iavl-cache-size`, the `[iavl]` section, and the orphan-storage settings) have been removed and no longer take effect. Legacy IAVL-based snapshot and restore are also no longer supported.</Warning>

## Core Technical Design

Traditional blockchain databases store state in structures optimized for cryptographic verification rather than transaction execution speed. SeiDB uses a hybrid architecture that preserves cryptographic verifiability while accelerating state access operations.

Key design goals include:

* Minimizing storage slot access latency even at peak load
* Maximizing state operation throughput for both reads and writes
* Enabling parallel execution for non-conflicting state operations
* Maintaining consistent performance under variable workloads

## System Architecture

SeiDB implements a multi-layered architecture optimized for EVM state management:

**SeiDB Core**

<Columns cols={3}>
  <Card horizontal title="EVM Cache System" />

  <Card horizontal title="Query Processor" />

  <Card horizontal title="Storage Engine" />
</Columns>

<Columns cols={3}>
  <Card horizontal title="Merkle Trie Optimizer" />

  <Card horizontal title="Storage Indexer" />

  <Card horizontal title="LSM-Tree Manager" />
</Columns>

<Columns cols={3}>
  <Card horizontal title="Concurrency Control" />

  <Card horizontal title="Version Manager" />

  <Card horizontal title="I/O Scheduler" />
</Columns>

<Card horizontal title="Ethereum Compatibility Layer" />

Each component in this architecture addresses specific performance bottlenecks found in traditional blockchain storage systems. The integrated design enables specialized optimization at each level while maintaining a cohesive system.

### EVM-Optimized Storage Engine

The storage engine forms the foundation of SeiDB and represents its most significant departure from traditional blockchain state databases. While standard Ethereum implementations use a single Merkle Patricia Trie for all storage, SeiDB employs a hybrid approach combining cryptographic verification with performance optimizations from modern database systems.

Key technical innovations include:

* **Enhanced Merkle Patricia Trie**: The implementation preserves cryptographic properties required for consensus validation while addressing performance bottlenecks. SeiDB's node caching dramatically reduces I/O overhead. Hot nodes remain in memory through a priority retention system that analyzes access frequency and recency patterns across multiple blocks.

* **Incremental State Root Calculation**: The system employs specialized techniques that avoid recalculating entire trie branches when only leaf nodes change. This method accelerates block finalization for blocks with transactions affecting different state areas. The calculation process intelligently reuses intermediate hash values from unchanged subtrees, allowing rapid state root derivation even after thousands of storage modifications.

* **Direct Storage Slot Indexing**: SeiDB provides mapping between composite keys (address + slot) and their storage location. This technique reduces lookup complexity from O(log n) to near-constant time for most operations. The indexing system maintains consistency through a dual-update mechanism that modifies both the index and underlying trie atomically.

* **Account-Level Optimizations**: The system applies different strategies to external accounts (user wallets) and contract accounts. Contract accounts receive specialized treatment with code caching and execution context preservation. The code caching mechanism exploits the immutability of contract bytecode once deployed, keeping frequently accessed contracts in memory with custom deserialization to minimize runtime overhead.

* **Optimized Bloom Filters**: The storage engine accelerates negative lookups (checking for non-existent keys) during contract execution. These filters use multi-layer filtering with dynamic sizing based on the active working set to minimize false positives during typical workloads.

### Multi-Level Cache Architecture

The caching system implements multiple specialized caches optimized for particular EVM access patterns, unlike general-purpose databases that employ uniform caching strategies.

The system includes:

* **Hot Slot Cache**: This component maintains frequently used storage slots in memory using a frequency-recency hybrid eviction policy tuned for blockchain workloads. This adaptive approach achieves improved hit rates compared to static caching policies. The cache intelligently separates frequently accessed slots from burst-access slots to prevent cache thrashing during high-intensity operations.

* **Account State Cache**: This cache maintains complete information for recently accessed addresses, including code, balance, nonce, and metadata. It implements predictive loading based on transaction analysis for improved hit rates during smart contract interactions. The predictive engine analyzes calldata patterns and historical interaction graphs to preload likely-to-be-accessed contract accounts.

* **Execution Context Cache**: This specialized cache preserves partial execution environments for frequently called contracts. When the same contract executes repeatedly with similar call patterns, this contextual caching reduces setup overhead compared to cold execution. The context includes pre-validated jump destinations, resolved address references, and warmed storage slots.

### Concurrency Management

SeiDB's concurrency control system employs optimistic concurrency control (OCC) adapted specifically for EVM's state access patterns. The system incorporates semantic knowledge of common smart contract behavior to minimize conflicts.

The transaction execution process follows these steps:

1. Analysis of transaction targets, calldata patterns, and historical access data to create an initial dependency graph
2. Parallel execution of transactions without overlapping state dependencies in isolated worker threads
3. Monitoring of actual storage accesses during execution to identify conflicts against predictions
4. Selective reexecution of minimal conflict sets in sequential order when conflicts occur

For common operations like token transfers, SeiDB applies specialized conflict handlers that understand operation semantics. The semantic analysis identifies token sender and recipient addresses from calldata and method signatures. This understanding reduces false conflicts for common ERC-20 token operations.

The worker pool adjusts parallelism dynamically based on observed conflict rates. During periods with few conflicts, the system increases worker count to maximize throughput. When conflict rates rise, it reduces parallelism to avoid wasting resources on speculative execution that might require reversion. The scheduler incorporates a feedback loop that monitors aborted transactions and adjusts the parallelism factor within milliseconds of detecting changing workload patterns.

### I/O Optimization

SeiDB implements storage I/O optimizations designed specifically for blockchain workloads, which typically involve append-heavy state changes.

Key optimization techniques include:

* **Log-Structured Storage**: The system organizes state into multiple levels, with recent changes in memory and older state in progressively larger but slower storage tiers. This architecture transforms random writes into sequential operations, improving write throughput. The storage layer maintains a memory-resident delta table that captures recent modifications and periodically flushes these changes to persistent storage in optimized batches.

* **Priority-Based I/O Scheduling**: The I/O subsystem prioritizes operations based on critical path status. State reads required for transaction validation receive highest priority, followed by state updates, and background operations receive lowest priority. The scheduler also employs operation batching techniques that combine multiple small I/O operations into more efficient larger operations.

* **State Versioning**: SeiDB uses multi-version concurrency control designed for blockchain's block-based execution model. Each block creates a new state version, using full state snapshots at epoch boundaries and delta encoding between intermediate blocks. The versioning system enables point-in-time queries against historical state with minimal storage overhead through a combination of differential storage and periodic compaction.

* **Configurable Persistence**: The database offers adjustable durability guarantees based on node type and network requirements, from fully synchronous writes to asynchronous persistence with periodic checkpoints. The configuration system allows operators to make explicit tradeoffs between performance and durability based on their specific node's role in the network.

### Descending-Version MVCC Encoding (State Store)

SeiDB's PebbleDB-backed state store uses multi-version concurrency control (MVCC) to keep every historical version of a key. Each logical key is stored on disk with its version appended, so a single key may have many versioned entries. The order in which those versions are laid out on disk directly affects how quickly the store can serve the most common query: reading the latest version of a key.

**Descending-version encoding for fresh databases.** Newly created state stores now encode the version component of each MVCC key in *descending* byte order, so that newer versions of a logical key sort *before* older ones on disk. Because the newest visible version sits first, a latest-version read lands directly on the target entry via a single forward seek (`First()` / `SeekGE`) instead of scanning past older versions. This is the fast path and delivers faster latest-version reads for validators and API nodes that overwhelmingly query recent state.

**Transparent compatibility with legacy databases.** State stores written by the previous build used *ascending*-version encoding, where older versions sort first. To avoid forcing a migration, SeiDB detects the on-disk encoding when a database is opened and reads legacy stores using the ascending-version path automatically — no error is raised and no data conversion occurs. Encoding mode is fixed for the lifetime of an open database.

**How detection works.** Fresh databases are stamped with an on-disk sentinel key (`s/_mvcc_descending`) the first time they are opened, marking them as descending. On subsequent opens:

* If the sentinel is present, the database opens in descending (fast-path) mode.
* If the sentinel is absent but the database already contains data (a legacy database written by the previous ascending-version build), it opens in ascending (legacy) mode and is intentionally left unmarked.
* If both the sentinel and existing data are absent, the database is treated as fresh: the sentinel is written and descending mode is used.

**Migration guidance for node operators.** Operators upgrading with an existing PebbleDB state store will continue to run in legacy ascending mode; this is safe and requires no action. However, legacy databases stay unmarked and cannot benefit from the descending fast path unless the state store is recreated or migrated (for example, by resyncing the state store). Archive nodes that cannot practically migrate their historical state will continue to operate correctly on the legacy ascending path.

**`UseDefaultComparer` and iteration.** The `UseDefaultComparer` field of the state store configuration influences how the descending-mode iterator advances to the next logical key. When enabled, the iterator falls back to a scan-based approach to locate the next logical key rather than using the MVCC comparer's key-successor logic. This affects iterator advancement behavior only in descending mode.

## Performance Characteristics

SeiDB is designed to deliver substantial performance improvements compared to traditional EVM state implementations. The architecture focuses on enhancing both throughput and latency across various operation types.

<Info>**Note:** Performance characteristics described in this section represent design targets rather than verified benchmarks. Actual performance will vary based on hardware configuration, workload patterns, and network conditions. Production deployments should conduct their own benchmarking to validate performance in their specific environment.</Info>

### Storage Operation Throughput

SeiDB is architected to significantly improve operation throughput across all major storage operation categories, particularly for storage reads and account lookups. These improvements result from architectural innovations rather than hardware scaling, with performance gains across all operation types.

### Latency Profile

The system is designed to maintain consistent low latency across different load conditions, from low to peak usage. This latency stability represents one of SeiDB's most significant advantages for applications requiring predictable performance. The system aims to maintain relatively stable response times even at high utilization levels, unlike traditional implementations that may exhibit severe latency spikes during high network activity.

## Optimization Patterns

Understanding certain storage access patterns allows developers to take maximum advantage of SeiDB's architecture. While existing contracts work without modification, those designed with these patterns achieve even greater performance.

### Localized Storage Access

SeiDB's caching mechanisms work most effectively when related data exists in localized regions:

```solidity theme={"dark"}
// Suboptimal: Random storage access pattern
contract BasicStorage {
    mapping(uint256 => uint256) public values;

    function processValues(uint256[] calldata keys) external {
        for (uint i = 0; i < keys.length; i++) {
            values[keys[i]] = values[keys[i]] + 1;
        }
    }
}

// Optimized: Localized storage access
contract OptimizedStorage {
    mapping(uint256 => mapping(uint256 => uint256)) public valuesByBucket;

    function processValuesBatch(uint256 bucket, uint256[] calldata keys, uint256[] calldata vals) external {
        for (uint i = 0; i < keys.length; i++) {
            valuesByBucket[bucket][keys[i]] = vals[i];
        }
    }
}
```

In the optimized version, related values cluster under common bucket keys. This organization aligns with SeiDB's caching strategy, which loads entire buckets into memory as a unit. The pattern improves performance compared to randomized access, particularly for operations processing many values in a single transaction.

### Contention Reduction

Smart contracts handling high transaction volumes benefit from storage designs that minimize contentious storage locations:

```solidity theme={"dark"}
// Suboptimal: High contention design
contract HighContentionContract {
    uint256 public totalOperations;

    function recordOperation() external {
        totalOperations++; // High contention point
        // Other operation logic
    }
}

// Optimized: Sharded counter design
contract LowContentionContract {
    mapping(uint256 => uint256) public operationsByDay;

    function recordOperation() external {
        uint256 today = block.timestamp / 86400;
        operationsByDay[today]++; // Temporal sharding reduces contention
        // Other operation logic
    }

    function getTotalOperations(uint256 daysToInclude) external view returns (uint256) {
        uint256 total = 0;
        uint256 today = block.timestamp / 86400;

        for (uint256 i = 0; i < daysToInclude; i++) {
            total += operationsByDay[today - i];
        }

        return total;
    }
}
```

The optimized contract shards the counter across time-based buckets, dramatically reducing contention when multiple transactions execute concurrently. SeiDB's concurrency control system recognizes these sharded patterns and executes transactions affecting different shards in parallel. This approach increases throughput for high-volume contracts during peak load conditions.

## Technical Integration

### EVM Compatibility

SeiDB maintains complete compatibility with the Ethereum protocol specifications while delivering performance enhancements:

* Full support for all EVM opcodes and precompiled contracts
* Identical state transition logic to standard Ethereum implementations
* Consistent gas cost model for all operations
* Complete compatibility with JSON-RPC API endpoints

These compatibility guarantees ensure existing smart contracts, development tools, and infrastructure components work without modification. The system undergoes extensive compatibility testing against the official Ethereum test suites to verify identical results compared to reference implementations.

### Deployment Configurations

SeiDB's architecture supports various deployment configurations optimized for different node roles:

* **Validator nodes** prioritize state consistency and durability through synchronous I/O operations and redundant state verification
* **API service nodes** optimize for query throughput and low latency responses with larger cache allocations and specialized read paths
* **Archive nodes** employ specialized storage strategies for efficient historical state access, including custom indexing for time-based queries
* **Light clients** benefit from optimized state proof generation with compact inclusion proofs for partial state verification

Each configuration tunes the SeiDB components to match specific requirements while maintaining protocol compatibility. The configuration framework provides fine-grained control over cache sizes, worker pools, I/O policies, and persistence strategies to match the operational needs of different node types.

## Profiling State Access with `trace-profile-report`

The `seidb` tool includes an offline `trace-profile-report` command for analyzing where time is spent while executing historical transactions. It runs the `debug_traceTransactionProfile` JSON-RPC method against a running node across a range of blocks and produces detailed timing and store-access reports. This is useful for identifying transactions and modules that dominate execution time or that generate heavy historical database lookups.

For each transaction in the requested block range, the command captures a full trace along with a profile that breaks down total execution time into per-phase timings (transaction lookup, block loading, historical transaction replay, block-context construction, transaction preparation, execution, and trace-result assembly) and per-module KVStore access statistics (Get/Has/Set/Delete counts and durations, plus iterator samples).

### Usage

```bash theme={"dark"}
seidb trace-profile-report \
  --endpoint http://localhost:8545 \
  --start-block <START> \
  --end-block <END> \
  --output-dir ./profile-out
```

### Flags

| Flag                  | Alias | Default | Description                                                                    |
| --------------------- | ----- | ------- | ------------------------------------------------------------------------------ |
| `--endpoint`          |       |         | RPC endpoint to query, e.g. `http://localhost:8545`. Required.                 |
| `--start-block`       |       |         | Starting block number (must be positive). Required.                            |
| `--end-block`         |       |         | Ending block number (must be `>= --start-block`). Required.                    |
| `--output-dir`        | `-o`  |         | Directory where `raw_profiles.jsonl` and `summary.json` are written. Required. |
| `--concurrency`       | `-c`  | `4`     | Number of concurrent `debug_traceTransactionProfile` requests.                 |
| `--trace-config-json` |       | `{}`    | JSON object passed as the trace config for each request.                       |
| `--max-transactions`  |       | `0`     | Optional cap on the number of transactions processed (`0` means no cap).       |

### Output

The command writes two files to the output directory:

* **`raw_profiles.jsonl`** — one JSON line per transaction, containing the block number, block hash, transaction hash, and either the full trace-profile result or an error.
* **`summary.json`** — an aggregated report including total/success/error counts, average and P50/P95 latencies for total and historical-database-lookup time, per-phase totals, per-module store-access totals, and the top transactions and blocks by total execution time.

<Info>Because `trace-profile-report` replays historical transactions, point it at a node (such as an archive node) that retains the historical state for the block range you want to profile.</Info>

## Dumping FlatKV State with `dump-flatkv`

The `seidb` tool includes a `dump-flatkv` command that iterates a FlatKV store and dumps every physical `(key, value)` pair into per-bucket files. FlatKV physical keys are grouped into four logical buckets — `account`, `code`, `storage`, and `legacy` — and each bucket is written to its own file inside the output directory. The output is formatted to match `dump-iavl` so the same diff tooling works on both dumps.

Each output file begins with a header line (`Bucket <name> at version <V>`) followed by one `Key: <HEX>, Value: <HEX>` line per physical row. Physical keys are emitted verbatim, including their `<module>/` and type-prefix header. The FlatKV metadata rows are intentionally excluded, as they are internal bookkeeping.

Under the hood, the tool clones the selected FlatKV snapshot and changelog into a temporary directory and opens that isolated copy, so it never contends for the FlatKV writer lock on a live node.

### Usage

```bash theme={"dark"}
seidb dump-flatkv \
  --db-dir /path/to/flatkv \
  --output-dir ./flatkv-dump \
  --height 0 \
  --bucket storage
```

### Flags

| Flag           | Alias | Default | Description                                                                                                             |
| -------------- | ----- | ------- | ----------------------------------------------------------------------------------------------------------------------- |
| `--db-dir`     | `-d`  |         | FlatKV database directory. Required.                                                                                    |
| `--output-dir` | `-o`  |         | Output directory; one file is written per bucket. Required.                                                             |
| `--height`     |       | `0`     | FlatKV target version; `0` selects the latest available version.                                                        |
| `--bucket`     | `-b`  |         | Restrict the dump to a single bucket (`account`, `code`, `storage`, or `legacy`). When omitted, all buckets are dumped. |

## Analyzing FlatKV with `state-size`

The `state-size` command now folds an optional FlatKV analysis into its output alongside the existing memIAVL module breakdown. When a FlatKV directory is present and `--module` is empty or `evm`, the tool scans FlatKV, reports a per-DB size breakdown (`account`, `code`, `storage`, `legacy`) and a table of the top EVM contracts by storage size, and — when exporting — includes the FlatKV row in the same DynamoDB batch as the memIAVL module rows.

Use the new `--flatkv-dir` flag to point at the FlatKV data directory. When it is not set, the tool auto-detects a sibling `flatkv/` directory next to `--db-dir` (for example, `<home>/data/committer.db` → `<home>/data/flatkv`), which is the standard layout on a Sei node. If no such directory exists, FlatKV analysis is skipped and only the memIAVL modules are reported.

FlatKV analysis is strictly additive: if the FlatKV directory is missing or the store cannot be opened, the tool logs the reason and continues with the memIAVL analysis.

| Flag           | Alias | Default                          | Description                                                                                           |
| -------------- | ----- | -------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `--db-dir`     | `-d`  |                                  | memIAVL database directory.                                                                           |
| `--flatkv-dir` |       | auto-detect `<db-dir>/../flatkv` | FlatKV data directory. When unset, a sibling `flatkv/` directory next to `--db-dir` is auto-detected. |

## Reading the Latest memIAVL Version with `memiavl-latest-version`

The `memiavl-latest-version` command prints the latest committed memIAVL version of a stopped node. It is the read-only companion to `import-flatkv-from-memiavl`: an orchestration script can read each validator's version after stopping `seid`, pick a single common height across a multi-validator cluster, and use that as the import height.

<Warning>Run this command against a stopped node. It reads the on-disk memIAVL state directly and is intended for offline use.</Warning>

### Usage

```bash theme={"dark"}
seidb memiavl-latest-version --data-dir /path/to/.sei/data
```

### Flags

| Flag         | Default      | Description                                                                                                |
| ------------ | ------------ | ---------------------------------------------------------------------------------------------------------- |
| `--home`     | `$HOME/.sei` | Sei home directory.                                                                                        |
| `--data-dir` |              | Sei data directory or home directory. If the basename is `data`, its parent is used as the home directory. |

The command prints a single integer — the latest memIAVL version — to standard output.

## Importing memIAVL Modules into FlatKV with `import-flatkv-from-memiavl`

The `import-flatkv-from-memiavl` command performs an offline import of selected memIAVL modules into FlatKV. It is used when migrating the EVM module's state-commit (SC) layer from memIAVL to FlatKV storage. The command reads the selected module data from memIAVL at a target height, translates it into FlatKV's on-disk layout, and bulk-imports it into the FlatKV store.

<Warning>This is a restore-style import: it **resets** the FlatKV directory before loading the imported rows. If FlatKV already contains committed data, the command refuses to run unless `--force` is supplied.</Warning>

**EVM-only initial scope.** The initial production scope is intentionally narrow — only the `evm` module is accepted. Non-EVM modules remain in memIAVL and are not copied into FlatKV; passing any other module name is rejected at the CLI boundary.

### Usage

```bash theme={"dark"}
seidb import-flatkv-from-memiavl \
  --modules evm \
  --data-dir /path/to/.sei/data \
  --height <H> \
  [--force]
```

### Flags

| Flag         | Default      | Description                                                                                                |
| ------------ | ------------ | ---------------------------------------------------------------------------------------------------------- |
| `--home`     | `$HOME/.sei` | Sei home directory.                                                                                        |
| `--data-dir` |              | Sei data directory or home directory. If the basename is `data`, its parent is used as the home directory. |
| `--modules`  | `evm`        | Comma-separated module names to import. Initial production scope supports only `evm`.                      |
| `--height`   | `0`          | memIAVL version to import. `0` selects the latest available version.                                       |
| `--force`    | `false`      | Overwrite existing committed FlatKV data. Required when FlatKV already has a committed version.            |

### Height constraints

The import must be run at the memIAVL **latest** height. The command refuses to import at a height `H` below the memIAVL latest version, because a subsequent `GIGA_STORAGE` startup would call `reconcileVersions` and silently roll memIAVL back to `H`, truncating every cosmos block in `(H, latest]`. Operators who genuinely want a non-latest height must first roll memIAVL back to that height themselves — this command deliberately does not perform a destructive cosmos rollback on their behalf. A height ahead of the memIAVL latest version is likewise rejected.

<Info>If the import is interrupted (for example by context cancellation or an exporter/translator failure), the in-progress import is aborted rather than finalized: the FlatKV directory is left at its pre-import committed version, so the operation can be retried without `--force`.</Info>

### Migration configuration constraints

When restarting a node after the import, keep `evm-ss-split = false` across the import boundary. The import moves only the EVM module's SC-layer data into FlatKV; the EVM state-store history stays in the existing combined cosmos store, so enabling `evm-ss-split` would trigger a startup panic.

<Info>There is no longer any `sc-enable-lattice-hash` setting to manage. That configuration field has been removed; whether the FlatKV lattice hash participates in the AppHash is now derived automatically from the node's write mode and migration state, so operators do not need to toggle it across the import boundary.</Info>

## Polling FlatKV EVM Migration Status with `migrate-evm-status`

The `migrate-evm-status` command reports the on-disk FlatKV EVM migration state of a FlatKV directory as JSON. It exists so an orchestration script driving the in-flight `migrate_evm` migration can poll "is the migration done yet?" against each validator's data directory from the host — without adding a custom RPC handler or grepping through node logs.

The command reads two reserved keys from the FlatKV migration store:

* **`migration-version`** — an 8-byte big-endian `uint64` written exactly once per migration lifecycle, on the block that finalizes the migration. Absent or zero means the EVM migration has not yet completed.
* **`migration-boundary`** — the in-flight cursor encoding the `(module, key)` pair the next batch should resume from. It is present only while the migration is strictly between not-started and complete.

To stay aligned with the other `seidb` tools, the read goes through the same read-only path used by `dump-flatkv`: the tool hardlink-clones the latest snapshot and copies the WAL into a temporary directory before opening. This avoids contending with a live node for the FlatKV writer lock and yields a stable view even if the live writer rolls snapshots mid-run, so the command can be run against a running validator.

### Usage

```bash theme={"dark"}
seidb migrate-evm-status \
  --db-dir /path/to/flatkv \
  [--height <H>]
```

### Flags

| Flag       | Alias | Default | Description                                                      |
| ---------- | ----- | ------- | ---------------------------------------------------------------- |
| `--db-dir` | `-d`  |         | FlatKV database directory. Required.                             |
| `--height` |       | `0`     | FlatKV target version; `0` selects the latest available version. |

### Output

The command prints a single JSON object to standard output:

```json theme={"dark"}
{
  "version_at": 12345,
  "migration_version": 1,
  "migrate_evm_complete": true,
  "boundary_present": false,
  "version_raw_hex": "0000000000000001"
}
```

| Field                  | Description                                                               |
| ---------------------- | ------------------------------------------------------------------------- |
| `version_at`           | The FlatKV version that was opened.                                       |
| `migration_version`    | The on-disk migration version (`0` = memiavl-only, `1` = EVM migrated).   |
| `migrate_evm_complete` | `true` once `migration_version` has reached the EVM-migrated version.     |
| `boundary_present`     | `true` while the migration is in flight (the boundary cursor is present). |
| `boundary_hex`         | Hex encoding of the in-flight boundary cursor; omitted when absent.       |
| `version_raw_hex`      | Hex encoding of the raw `migration-version` bytes; omitted when absent.   |

<Info>A migration is complete when `migrate_evm_complete` is `true` and `boundary_present` is `false`. Poll every validator until all report completion before flipping `sc-write-mode` from `migrate_evm` to `evm_migrated`.</Info>

## Comparing Backends with `evm-logical-digest`

The `evm-logical-digest` command computes a backend-independent digest of the EVM logical state (the canonical `account`, `code`, and `storage` buckets) so a memIAVL node and a FlatKV node can be compared at the same chain height. Because the two backends store the same EVM state in different physical layouts, a naive byte-for-byte comparison diverges: every FlatKV value embeds a per-key `blockHeight` stamp recording when the key was last written or migrated, and a freshly migrated FlatKV node stamps migration-time heights that differ from the memIAVL leaf versions. This tool strips the serialization-version and `blockHeight` header on both sides and digests only the height-independent logical payload (storage word, bytecode, and balance/nonce/codeHash), so identical EVM state produces identical digests regardless of backend.

Each bucket is accumulated as an order-independent XOR of `sha256(len(key) || key || len(val) || val)`, so it does not matter that FlatKV iterates in Pebble global order while memIAVL is scanned by leaf index. The command prints a `bucket_digest` line per bucket and a single `FINAL_DIGEST` line covering `account+code+storage+legacy`; the two backends' `FINAL_DIGEST` values should match when the underlying state is identical.

The `legacy` bucket is reported separately, along with a marker-adjusted comparison line, because a migrated FlatKV node can contain a FlatKV-only `migration/migration-version` row that a memIAVL-only node never owns. That row is folded into the legacy bucket but omitted from the final comparison so the two sides line up apples-to-apples.

### Normalization modes

For the memIAVL backend, `--memiavl-normalization` selects how raw EVM leaves are turned into logical buckets:

* **`semantic`** (default, also accepted as `independent`) — independently decodes raw EVM keys and values into the same `account` / `code` / `storage` / `legacy` buckets without calling `flatkv.ImportTranslator`.
* **`translator`** — feeds each EVM leaf through `flatkv.ImportTranslator`, applying the exact same `classifyAndPrefix` and account-merge logic FlatKV uses. This is useful for proving FlatKV state matches the current migration mapping and for debugging the translator.

FlatKV reads WAL-replay to the requested `--height`; memIAVL does not replay WAL and instead opens `snapshot-<height>/evm`, or `current/evm` when `--height` is `0`.

### Usage

```bash theme={"dark"}
# FlatKV digest at a height (WAL-replays to it).
seidb evm-logical-digest --backend flatkv \
  --db-dir /path/to/.sei/data/state_commit/flatkv --height 213200000

# memIAVL digest at the same height using the default semantic decoder.
seidb evm-logical-digest --backend memiavl \
  --db-dir /path/to/.sei/data/state_commit/memiavl --height 213200000

# Translator-based memIAVL digest.
seidb evm-logical-digest --backend memiavl \
  --db-dir /path/to/.sei/data/state_commit/memiavl --height 213200000 \
  --memiavl-normalization translator

# Inspect one bucket instead of the global digest: list storage rows under a
# key prefix, sharded by the next 2 bytes.
seidb evm-logical-digest --backend flatkv -d /path/to/flatkv --height 213200000 \
  --inspect-bucket storage --key-prefix 03 --shard-next-bytes 2

# List account rows with backend-specific version metadata.
seidb evm-logical-digest --backend flatkv -d /path/to/flatkv --height 213200000 \
  --inspect-bucket account --list --list-limit 50 --details
```

### Flags

| Flag                      | Alias | Default    | Description                                                                                                                                                                                                         |
| ------------------------- | ----- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--backend`               |       |            | Backend to read: `flatkv` or `memiavl`. Required.                                                                                                                                                                   |
| `--db-dir`                | `-d`  |            | For `flatkv`: the FlatKV data directory. For `memiavl`: the memIAVL root directory (contains `current/` and `snapshot-*`). Required.                                                                                |
| `--height`                |       | `0`        | Target version. FlatKV WAL-replays to it; memIAVL resolves `snapshot-<height>/evm` (`0` selects the `current` symlink).                                                                                             |
| `--memiavl-normalization` |       | `semantic` | memIAVL normalization: `semantic`/`independent` (raw EVM key/value decoder) or `translator` (current migration mapping).                                                                                            |
| `--inspect-bucket`        |       |            | Inspect one normalized bucket (`account`, `code`, `storage`, or `legacy`) instead of printing the global digest.                                                                                                    |
| `--key-offset`            |       | `0`        | Inspect mode: byte offset into the physical key before applying `--key-prefix` / sharding.                                                                                                                          |
| `--key-prefix`            |       |            | Inspect mode: hex prefix, relative to `--key-offset`, used to filter physical keys.                                                                                                                                 |
| `--shard-next-bytes`      |       | `0`        | Inspect mode: group matching keys by this many bytes after `--key-prefix`.                                                                                                                                          |
| `--list`                  |       | `false`    | Inspect mode: list matching key/logical-value pairs instead of shard `bucket_digest` values.                                                                                                                        |
| `--list-limit`            |       | `1000`     | Inspect mode: maximum pairs to print with `--list`; `<= 0` means unlimited.                                                                                                                                         |
| `--details`               |       | `false`    | Inspect list mode: include backend-specific version metadata.                                                                                                                                                       |
| `--find-hash`             |       |            | Optional 32-byte hex per-entry hash to hunt for. When two `bucket_digest` values differ by exactly one entry, their XOR equals that entry's hash; every entry matching this hash is printed as a `FOUND-HASH` line. |

<Info>To locate a single diverging row between two runs, XOR the two differing 32-byte `bucket_digest` hex values and pass the result to `--find-hash`; every matching entry is printed with its bucket, physical key, and values.</Info>
