From 8fff96c47d2da7e032da1c0a67ac04af8523edda Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 00:22:59 +0000 Subject: [PATCH 01/81] docs: The Tendermint P2P config was overhauled: MaxOutboundConnections becomes a config field with new default behavior, and internal RouterOptions replace MaxPeers/MaxConnected/MaxConcurrentDials/MaxOutboundConnections with new MaxInbound/MaxOutbound semantics affecting connection limits. (sei-protocol/sei-chain#3037) --- node/node-operators.mdx | 11 +++++++++++ node/technical-reference.mdx | 11 +++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/node/node-operators.mdx b/node/node-operators.mdx index a198665..a0ff208 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -963,6 +963,17 @@ upnp = false # Maximum number of connections (inbound and outbound). max-connections = 100 +# Maximum number of outbound connections to regular (non-persistent) peers. +# Inbound and outbound connections are managed as two fully separate pools, so +# a single peer can hold both an inbound and an outbound connection to this +# node at the same time. +# If unset, MaxOutbound defaults to min(20, (max-connections+1)/2), i.e. 20 +# unless max-connections < 40, in which case it defaults to half of +# max-connections. The inbound pool is then sized as +# MaxInbound = max-connections - MaxOutbound. +# Persistent and unconditional connections are not counted towards either limit. +# max-outbound-connections = 20 + # Rate limits the number of incoming connection attempts per IP address. max-incoming-connection-attempts = 100 diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 186396a..3ceba70 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -135,8 +135,15 @@ external-address = "" seeds = "" persistent_peers = "" upnp = false -max_num_inbound_peers = 40 -max_num_outbound_peers = 10 +# Total connection budget. Inbound and outbound connections are now tracked in +# fully separate pools, so a single peer may hold both an inbound and an +# outbound connection at the same time. +max-connections = 100 +# Maximum number of outbound connections to regular (non-persistent) peers. +# Defaults to min(20, (max-connections+1)/2). Inbound capacity is derived as +# max-connections - max-outbound-connections. Persistent and unconditional +# peers are not counted against either limit. +max-outbound-connections = 20 allowed_pools = "" max_packet_msg_payload_size = 10240 handshake_timeout = "20s" From e71b9015f8525ac06bb971ba049a7cdfe0ffd098 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:05:46 +0000 Subject: [PATCH 02/81] docs: eth_getBlockByNumber now returns null (per Ethereum spec) for future/non-existent numeric block heights instead of an error, and eth_getProof now works across additional store backends (tracekv, Giga cache, prefix stores) instead of only classic IAVL. (sei-protocol/sei-chain#3119) --- evm/evm-parity/evm-compatibility.mdx | 2 +- evm/reference.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/evm/evm-parity/evm-compatibility.mdx b/evm/evm-parity/evm-compatibility.mdx index f994b82..1d6892e 100644 --- a/evm/evm-parity/evm-compatibility.mdx +++ b/evm/evm-parity/evm-compatibility.mdx @@ -37,7 +37,7 @@ Standard EVM tooling — viem, wagmi, ethers, Foundry, Hardhat — works on Sei | `eth_getTransactionCount` (nonce) | Supported | | | `eth_getCode` | Supported | | | `eth_getStorageAt` | Supported — differences | SSTORE cost is governance-adjustable; do not hard-code gas assumptions. [See Gas and Fees.](/evm/evm-parity/gas-and-fees) | -| `eth_getProof` | Supported — differences | Returns IAVL proof data rather than Ethereum Merkle Patricia Trie proofs. Proof verification logic must account for this. [See State Proofs.](/evm/evm-parity/state-proofs) | +| `eth_getProof` | Supported — differences | Returns IAVL proof data rather than Ethereum Merkle Patricia Trie proofs. Proof verification logic must account for this. Proofs resolve across supported store backends (classic IAVL, store/v2 memiavl, and other proof-capable queryable stores), so the method works across a broader range of node configurations. [See State Proofs.](/evm/evm-parity/state-proofs) | ## Blocks and Finality diff --git a/evm/reference.mdx b/evm/reference.mdx index aef1579..324ea31 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -485,7 +485,7 @@ Every method below is also browsable interactively in the explorer above; this s **Limited.** Returns a Merkle proof for an account and the requested storage slots. -**Sei-specific behavior:** Sei stores state in an IAVL tree, not an Ethereum Merkle-Patricia trie. The result is a Sei-specific ProofResult{address, hexValues, storageProof} where storageProof entries are CometBFT/IAVL crypto.ProofOps, NOT eth-style MPT proof nodes. There is no accountProof, balance, codeHash, nonce, or storageHash field (Sei has no per-account state root); standard eth_getProof verifiers will not work. +**Sei-specific behavior:** Sei stores state in an IAVL tree, not an Ethereum Merkle-Patricia trie. The result is a Sei-specific ProofResult{address, hexValues, storageProof} where storageProof entries are CometBFT/IAVL crypto.ProofOps, NOT eth-style MPT proof nodes. There is no accountProof, balance, codeHash, nonce, or storageHash field (Sei has no per-account state root); standard eth_getProof verifiers will not work. The EVM store is resolved by unwrapping any wrapping KVStore layers (cachekv, Giga cache, tracekv, and prefix stores) to reach the underlying proof-capable queryable store, so proofs succeed across more node/store configurations (classic IAVL, store/v2 memiavl, and future proof-capable roots) rather than only the classic IAVL store. **Parameters:** From 55c961e59a521c221bab56dbba57c50108dccfc7 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:07:09 +0000 Subject: [PATCH 03/81] docs: The eth_getBlockTransactionCountByNumber and eth_getBlockTransactionCountByHash JSON-RPC methods now return a count consistent with eth_getBlockByNumber, filtering out EVM txs without a receipt and including wasm/bank transfer transactions. (sei-protocol/sei-chain#3125) --- evm/reference.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm/reference.mdx b/evm/reference.mdx index 324ea31..8bd212f 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -579,9 +579,9 @@ Every method below is also browsable interactively in the explorer above; this s #### `eth_getBlockTransactionCountByNumber` -**Supported.** Returns the number of EVM transactions in a block by number, as a hex quantity. +**Supported.** Returns the number of transactions in a block by number, as a hex quantity. -**Sei-specific behavior:** Counts EVM transactions only (via getEvmTxCount); synthetic/bank-transfer txs are excluded. Genesis returns 0x0; non-existent/future blocks return null. +**Sei-specific behavior:** The count now matches the transaction list returned by `eth_getBlockByNumber`: EVM transactions are counted only when their receipt lookup succeeds (EVM txs without a valid receipt are excluded), and `MsgExecuteContract` (wasm) and `MsgSend` (bank transfer) messages are included. Previously this counted all decodable EVM txs regardless of receipt. Genesis returns 0x0; non-existent/future blocks return null. **Parameters:** From b076b1e175a97fac9fb99a8f649d9c6e81530d87 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:07:43 +0000 Subject: [PATCH 04/81] docs: Adds a new parallelized/profiled block trace path for debug_traceBlockByNumber and debug_traceBlockByHash when using the default (struct) tracer, changing internal execution behavior while keeping the same RPC surface. (sei-protocol/sei-chain#3058) --- evm/reference.mdx | 2 +- evm/tracing/index.mdx | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/evm/reference.mdx b/evm/reference.mdx index 8bd212f..d32ba64 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -1118,7 +1118,7 @@ The `filter` object applies only to `logs` subscriptions. For `newHeads`, pass t **Supported.** Traces all transactions in a block by number and returns per-transaction execution traces. -**Sei-specific behavior:** HTTP-only. safe/finalized/latest are equivalent due to instant finality. +**Sei-specific behavior:** HTTP-only. safe/finalized/latest are equivalent due to instant finality. When no custom tracer is specified (the default struct/opcode logger), block traces run through a parallelized, profiled execution path that returns per-transaction result/error entries. A transaction that fails no longer aborts the whole block trace — its entry carries an `error` field while the remaining transactions still return their traces. Specifying a custom tracer (e.g. `callTracer`) uses the standard tracing path. **Parameters:** diff --git a/evm/tracing/index.mdx b/evm/tracing/index.mdx index 3473127..dd3d066 100644 --- a/evm/tracing/index.mdx +++ b/evm/tracing/index.mdx @@ -54,6 +54,10 @@ Debug tracing is your primary tool for understanding EVM transaction execution o | -------------------------- | -------------------------- | ----------------------------- | | `debug_traceTransaction` | Trace specific transaction | Debugging failed transactions | | `debug_traceBlockByNumber` | Trace entire block | Block-level analysis | + + +When `debug_traceBlockByNumber` or `debug_traceBlockByHash` run with the default (struct) tracer — that is, when no custom `tracer` is specified — a failed transaction no longer aborts the entire block trace. Instead, each transaction produces its own per-tx entry in the result array: successful transactions include a `result` field, while failed transactions include an `error` field. This lets you inspect every transaction in a block even when one or more of them fail. + | `debug_traceCall` | Simulate and trace | Testing before execution | | `debug_traceStateAccess` | State access patterns | Performance optimization | From f509a64ca7dd04625cbab6c40cdb4ecde32ba758 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:08:32 +0000 Subject: [PATCH 05/81] docs: Three TOML config fields (sc-write-mode, sc-read-mode, sc-enable-lattice-hash) were removed from the state-commit config template, and a new validation rule now requires lattice hash to be enabled when using split_write mode. (sei-protocol/sei-chain#3128) --- node/giga-storage-migration.mdx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/node/giga-storage-migration.mdx b/node/giga-storage-migration.mdx index 755f614..9b6bcbd 100644 --- a/node/giga-storage-migration.mdx +++ b/node/giga-storage-migration.mdx @@ -21,6 +21,20 @@ Only the **SS** layer changes for this migration. SC layer config is untouched and `memiavl` remains the authoritative source for the app hash, so this is invisible to the network. + +The SC-layer routing fields `sc-write-mode`, `sc-read-mode`, and +`sc-enable-lattice-hash` are no longer emitted in the generated `app.toml` +template. They still exist on the underlying `[state-commit]` config and +default to `cosmos_only` / `cosmos_only` / `false`, but you no longer need to +set them for this migration. + +If you do configure the SC layer to use `split_write` mode +(`sc-write-mode = "split_write"`), the lattice hash must be enabled +(`sc-enable-lattice-hash = true`). State-commit config validation now rejects +`split_write` with the lattice hash disabled — the composite commit store +panics on creation with `lattice hash must be enabled when using split_write mode`. + + This guide tracks the canonical procedure in [`docs/migration/giga_store_migration.md`](https://github.com/sei-protocol/sei-chain/blob/main/docs/migration/giga_store_migration.md) inside `sei-chain`. Open an issue there if anything here drifts. ## Prerequisites From e0df07990037c16a256815ffac0a53b4a15bc11c Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:10:03 +0000 Subject: [PATCH 06/81] docs: The oracle module's default MinValidPerWindow parameter changed from 5% to 0% since the Oracle Price Feeder is retired, altering default slashing behavior. (sei-protocol/sei-chain#3157) --- node/technical-reference.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 3ceba70..f58af2b 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -194,6 +194,10 @@ Slashing Parameters: - slash_fraction_downtime: 0% (no stake slash; jail only) - slash_fraction_double_sign: 0% (no stake slash; double-signing still triggers permanent tombstoning) + +Oracle Slashing Parameters: + - min_valid_per_window: 0% (default now 0% — no oracle vote slashing, + since the Oracle Price Feeder is retired) ``` From 04fadd53bb069e5dab05a6637cc8e792bc225f69 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:10:32 +0000 Subject: [PATCH 07/81] docs: Log messages now warn that IAVL will be deprecated soon and recommend migrating to SeiDB to avoid data corruption or panic. (sei-protocol/sei-chain#3159) --- learn/seidb.mdx | 3 +++ node/node-operators.mdx | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/learn/seidb.mdx b/learn/seidb.mdx index 172ba02..9b42423 100644 --- a/learn/seidb.mdx +++ b/learn/seidb.mdx @@ -8,6 +8,9 @@ keywords: ['seidb', 'blockchain database', 'state storage', 'ethereum optimizati 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. + +**IAVL Deprecation:** IAVL is being deprecated and will be fully removed soon. Node operators should migrate to SeiDB to avoid data corruption or panic. Nodes still running on IAVL now emit warning logs on every commit and when SeiDB is disabled. To migrate, enable SeiDB by setting `sc-enable = true` (and `ss-enable = true` for state store) in your node configuration. + ## 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. diff --git a/node/node-operators.mdx b/node/node-operators.mdx index a0ff208..4f5da84 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -86,6 +86,24 @@ max-open-connections = 1000 # SeiDB state-commit (memiavl + FlatKV). Recommended on every node. sc-enable = true + + + + **IAVL is being deprecated.** Running a node with SeiDB state-commit disabled + falls back to the legacy IAVL store. As of recent `seid` releases, this path + emits a warning log on startup and on every commit: + + ``` + IAVL will be deprecated soon, please migrate to SeiDB to avoid data corruption or panic + ``` + + IAVL will be fully removed in an upcoming release, and continuing to run on it + risks data corruption or node panics. Make sure `sc-enable = true` under + `[state-commit]` so your node runs on SeiDB. Nodes with SeiDB SC enabled will + still log an informational reminder (`SeiDB SC is enabled now, IAVL will be + fully deprecated soon`) until the migration window closes. + + [state-store] # Historical SS layer for queries. Required for any node serving RPC. ss-enable = true From f0be2e4fd2a1463aed1c715a7b03819564a75934 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:11:28 +0000 Subject: [PATCH 08/81] docs: Legacy sei_*/sei2_* JSON-RPC HTTP gating now handles batch requests by forwarding only allowed elements and merging responses by id, and reduces the legacy HTTP body limit from 32MiB to 5MiB to match go-ethereum's default. (sei-protocol/sei-chain#3160) --- evm/reference.mdx | 4 +++- node/node-operators.mdx | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/evm/reference.mdx b/evm/reference.mdx index d32ba64..d9f9d97 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -1240,7 +1240,9 @@ Sei extends the standard Ethereum JSON-RPC API with custom endpoints that enhanc **Deprecation Notice:** All `sei_*` and `sei2_*` JSON-RPC methods are deprecated and scheduled for removal. Do not build new integrations on these endpoints. Use standard `eth_*` and `debug_*` methods instead. -Access is controlled by the `enabled_legacy_sei_apis` setting under `[evm]` in `app.toml`. Only methods explicitly listed in this allowlist are available. Disabled methods return a standard JSON-RPC error (code `-32601`, data `"legacy_sei_deprecated"`). Allowed methods pass through unchanged, with an optional `Sei-Legacy-RPC-Deprecation` HTTP response header signaling deprecation. +Access is controlled by the `enabled_legacy_sei_apis` setting under `[evm]` in `app.toml`. Only methods explicitly listed in this allowlist are available. Disabled methods return a standard JSON-RPC error (code `-32601`, data `"legacy_sei_deprecated"`). Allowed single-object requests pass through unchanged, with an optional `Sei-Legacy-RPC-Deprecation` HTTP response header signaling deprecation. + +JSON-RPC batch requests over HTTP are handled element-by-element: only allowlisted methods are forwarded to the inner handler as a filtered subset, and their responses are merged back into the original batch positions by JSON-RPC `id`. Disabled methods in the batch receive the standard `-32601` gate error in place, and any non-object batch element returns a JSON-RPC `-32600` Invalid Request without being forwarded — so a malformed element can never bypass the gate. The legacy HTTP request body limit is 5 MiB (matching go-ethereum's default). ### Legacy API Configuration diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 4f5da84..071bc81 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -432,6 +432,14 @@ deny_list = [] # gate errors use standard JSON-RPC error encoding (see evmrpc/AGENTS.md). Successful allowlisted # responses are unchanged; nodes may set HTTP header Sei-Legacy-RPC-Deprecation (see AGENTS.md). # +# Gating applies to both single-object requests and JSON-RPC batches. Single-object allowed calls +# pass through unchanged. For batches, only the allowlisted (and otherwise valid) elements are +# forwarded to the inner handler as a filtered subset, and the inner responses are merged back into +# the original batch by JSON-RPC id; blocked elements return the standard gate error and any +# non-object batch element returns a JSON-RPC -32600 Invalid Request, so the gate cannot be +# bypassed. The legacy HTTP request body is capped at 5 MiB, matching go-ethereum's default +# (rpc.defaultBodyLimit). +# # Only methods listed in enabled_legacy_sei_apis are allowed. Init defaults enable the three # address/Cosmos helpers; uncomment optional lines below to enable more legacy methods (include # sei2_* block methods at the end of the list if you need them). From 5fb5dce04a630a1db081f607c733606ffbc07d4c Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:13:17 +0000 Subject: [PATCH 09/81] docs: IAVL backend is fully removed and SeiDB state-commit is now mandatory; nodes will panic if sc-enable is false, and several IAVL-related CLI commands and config fields have been removed. (sei-protocol/sei-chain#3146) --- evm/installing-seid-cli.mdx | 3 --- learn/seidb.mdx | 2 +- node/node-operators.mdx | 20 +++++++++++--------- node/technical-reference.mdx | 9 +++++++++ node/troubleshooting.mdx | 6 ++++-- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/evm/installing-seid-cli.mdx b/evm/installing-seid-cli.mdx index d0d726f..ab42067 100644 --- a/evm/installing-seid-cli.mdx +++ b/evm/installing-seid-cli.mdx @@ -65,7 +65,6 @@ Available Commands: add-wasm-genesis-message Wasm genesis subcommands blocktest run EF blocktest collect-gentxs Collect genesis txs and output a genesis.json file - compact Compact the application DB fully (only if it is a levelDB) config Create or query an application CLI configuration file debug Tool for helping with debugging your application ethreplay replay EVM transactions @@ -74,9 +73,7 @@ Available Commands: help Help about any command init Initialize private validator, p2p, genesis, and application configuration files keys Manage your application's keys - latest_version Prints the latest version of the app DB migrate Migrate genesis to a specified target version - prune Prune app history states by keeping the recent heights and deleting old heights query Querying subcommands rollback rollback cosmos-sdk and tendermint state by one height start Run the full node diff --git a/learn/seidb.mdx b/learn/seidb.mdx index 9b42423..b8f1c58 100644 --- a/learn/seidb.mdx +++ b/learn/seidb.mdx @@ -9,7 +9,7 @@ keywords: ['seidb', 'blockchain database', 'state storage', 'ethereum optimizati 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. -**IAVL Deprecation:** IAVL is being deprecated and will be fully removed soon. Node operators should migrate to SeiDB to avoid data corruption or panic. Nodes still running on IAVL now emit warning logs on every commit and when SeiDB is disabled. To migrate, enable SeiDB by setting `sc-enable = true` (and `ss-enable = true` for state store) in your node configuration. +**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. ## Core Technical Design diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 071bc81..a47b85c 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -89,19 +89,21 @@ sc-enable = true - **IAVL is being deprecated.** Running a node with SeiDB state-commit disabled - falls back to the legacy IAVL store. As of recent `seid` releases, this path - emits a warning log on startup and on every commit: + **IAVL has been fully removed.** SeiDB state-commit is now mandatory. Running a + node with SeiDB state-commit disabled no longer falls back to the legacy IAVL + store. As of recent `seid` releases, a node started with `sc-enable = false` + panics on startup with: ``` - IAVL will be deprecated soon, please migrate to SeiDB to avoid data corruption or panic + SeiDB state-commit (SC) must be enabled; IAVL backend has been fully deprecated ``` - IAVL will be fully removed in an upcoming release, and continuing to run on it - risks data corruption or node panics. Make sure `sc-enable = true` under - `[state-commit]` so your node runs on SeiDB. Nodes with SeiDB SC enabled will - still log an informational reminder (`SeiDB SC is enabled now, IAVL will be - fully deprecated soon`) until the migration window closes. + Make sure `sc-enable = true` under `[state-commit]` before upgrading so your + node runs on SeiDB. All IAVL-related configuration fields and CLI commands + (for example `iavl-cache-size`, the `[iavl]` section, and the `compact`, + `prune`, `latest_version`, and `debug dump-iavl` commands) have been removed + and no longer take effect. Nodes with SeiDB SC enabled log `SeiDB SC is + enabled now` on startup. [state-store] diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index f58af2b..ce28c37 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -112,6 +112,11 @@ size = 5000 max-txs-bytes = 1073741824 cache-size = 10000 +# State commit configuration (SeiDB). State-commit is mandatory: +# the node will panic on startup if sc-enable is false. +[state-commit] +sc-enable = true + # State store configuration [state-store] ss-enable = true @@ -120,6 +125,10 @@ ss-keep-recent = 100000 ss-prune-interval = 600 ``` + + The legacy IAVL backend has been fully removed. SeiDB state-commit is now required, so `sc-enable` must be `true` or the node will panic on startup. The former `iavl-cache-size` field, the entire `[iavl]` config section, and the IAVL-related base fields (`iavl-disable-fastnode`, `no-versioning`, `separate-orphan-storage`, `separate-orphan-versions-to-keep`, `num-orphan-per-file`, `orphan-dir`) are no longer valid and have no effect. The removed `compact`, `prune`, `latest_version`, and `debug dump-iavl` CLI commands and their IAVL/orphan-related start flags are also gone. Ensure `sc-enable = true` before upgrading. + + ### Config.toml Parameters diff --git a/node/troubleshooting.mdx b/node/troubleshooting.mdx index 2d129dd..2aedf52 100644 --- a/node/troubleshooting.mdx +++ b/node/troubleshooting.mdx @@ -98,10 +98,12 @@ systemctl stop seid seidb dump-iavl -d $HOME/.sei/data/committer.db -o /home/ubuntu/iavl-dump systemctl restart seid -# For Legacy IAVL DB: -seid debug dump-iavl ``` + +The legacy IAVL backend has been fully removed. SeiDB state-commit is now mandatory (`sc-enable = true`), so all nodes should use the `seidb dump-iavl` tooling shown above. The former `seid debug dump-iavl` command has been removed. + + Always include the app hash, commit hash, and block height from your logs when reporting issues. ### Identifying AppHash Errors From fb3c726b2925d2a38dac3e1cff5d9e57c3886fae Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:16:10 +0000 Subject: [PATCH 10/81] docs: Adds a new node config field `evm.enable_parallelized_block_trace` (default false) that gates the parallelized default debug_traceBlock* path. (sei-protocol/sei-chain#3187) --- evm/reference.mdx | 2 +- evm/tracing/index.mdx | 4 +++- node/node-operators.mdx | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/evm/reference.mdx b/evm/reference.mdx index d9f9d97..a3d4c17 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -1118,7 +1118,7 @@ The `filter` object applies only to `logs` subscriptions. For `newHeads`, pass t **Supported.** Traces all transactions in a block by number and returns per-transaction execution traces. -**Sei-specific behavior:** HTTP-only. safe/finalized/latest are equivalent due to instant finality. When no custom tracer is specified (the default struct/opcode logger), block traces run through a parallelized, profiled execution path that returns per-transaction result/error entries. A transaction that fails no longer aborts the whole block trace — its entry carries an `error` field while the remaining transactions still return their traces. Specifying a custom tracer (e.g. `callTracer`) uses the standard tracing path. +**Sei-specific behavior:** HTTP-only. safe/finalized/latest are equivalent due to instant finality. When no custom tracer is specified (the default struct/opcode logger), block traces can run through a parallelized, profiled execution path that returns per-transaction result/error entries, but only when the node has `evm.enable_parallelized_block_trace = true` set in `app.toml` (default `false`). On that path, a transaction that fails no longer aborts the whole block trace — its entry carries an `error` field while the remaining transactions still return their traces. When `evm.enable_parallelized_block_trace` is `false` (the default), or when a custom tracer (e.g. `callTracer`) is specified, block traces use the standard tracing path instead. **Parameters:** diff --git a/evm/tracing/index.mdx b/evm/tracing/index.mdx index dd3d066..0b875c0 100644 --- a/evm/tracing/index.mdx +++ b/evm/tracing/index.mdx @@ -56,7 +56,9 @@ Debug tracing is your primary tool for understanding EVM transaction execution o | `debug_traceBlockByNumber` | Trace entire block | Block-level analysis | -When `debug_traceBlockByNumber` or `debug_traceBlockByHash` run with the default (struct) tracer — that is, when no custom `tracer` is specified — a failed transaction no longer aborts the entire block trace. Instead, each transaction produces its own per-tx entry in the result array: successful transactions include a `result` field, while failed transactions include an `error` field. This lets you inspect every transaction in a block even when one or more of them fail. +When `debug_traceBlockByNumber` or `debug_traceBlockByHash` run with the default (struct) tracer — that is, when no custom `tracer` is specified — Sei can use a parallelized block trace path in which a failed transaction no longer aborts the entire block trace. Instead, each transaction produces its own per-tx entry in the result array: successful transactions include a `result` field, while failed transactions include an `error` field. This lets you inspect every transaction in a block even when one or more of them fail. + +This parallelized path is opt-in and gated by the node config field `evm.enable_parallelized_block_trace` (default `false`). When it is disabled, or when an explicit `tracer` is specified, the legacy trace path is used. Node operators can enable it by setting `enable_parallelized_block_trace = true` in the `[evm]` section of `app.toml` (or via the `--evm.enable_parallelized_block_trace` flag). | `debug_traceCall` | Simulate and trace | Testing before execution | | `debug_traceStateAccess` | State access patterns | Performance optimization | diff --git a/node/node-operators.mdx b/node/node-operators.mdx index a47b85c..6450f48 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -507,6 +507,9 @@ max_trace_lookback_blocks = 10000 trace_timeout = "30s" # Enable the parallelized default debug_traceBlock* path. +# When true, debug_traceBlock* requests that do not specify an explicit +# tracer use the parallelized block trace path; requests with an explicit +# tracer continue to use the legacy path. Default false. enable_parallelized_block_trace = false # WorkerPoolSize defines the number of workers in the worker pool. From 789862672e7aa23e612fb1dfff3a297a2c9bc164 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:17:20 +0000 Subject: [PATCH 11/81] docs: The mempool now tracks block-failed transactions and prevents infinite re-entry: a tx that fails during block execution is allowed one retry, but subsequent failures leave it in the cache and cause CheckTx to reject re-submission. (sei-protocol/sei-chain#3200) --- node/technical-reference.mdx | 17 +++++++++++++++++ node/troubleshooting.mdx | 21 +++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index ce28c37..b3795ef 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -112,6 +112,23 @@ size = 5000 max-txs-bytes = 1073741824 cache-size = 10000 + + +#### Block-Failed Transaction Re-Entry Protection + +The mempool tracks transactions that fail during block execution to prevent them from re-entering the mempool indefinitely. Some transactions consistently fail before fee charging in `DeliverTx`, which historically let them be re-submitted without limit and waste block and proxy-app resources. + +The mempool now applies the following policy on top of the existing `keep-invalid-txs-in-cache` setting: + +- When a committed transaction succeeds (`Code == OK`), it is kept in the cache and its entry in the block-failure tracker is cleared. +- When a committed transaction fails and `keep-invalid-txs-in-cache` is `false`: + - **First block failure:** the transaction is removed from the cache, allowing it to be re-submitted and retried once. + - **Second (and subsequent) block failure:** the transaction is left in the cache. Any attempt to re-submit it is rejected by `CheckTx` with `ErrTxInCache`, preventing infinite re-entry. +- A successful block inclusion resets the failure tracker, so a transaction that later succeeds regains its first-failure grace period. + +The block-failure tracker uses an LRU cache sized to match the mempool `cache-size`. When `cache-size` is `0`, tracking is disabled. This behavior is automatic and requires no additional configuration. + + # State commit configuration (SeiDB). State-commit is mandatory: # the node will panic on startup if sc-enable is false. [state-commit] diff --git a/node/troubleshooting.mdx b/node/troubleshooting.mdx index 2aedf52..ac3f392 100644 --- a/node/troubleshooting.mdx +++ b/node/troubleshooting.mdx @@ -57,6 +57,27 @@ Commands: ### Database Errors + +### Mempool Errors + +```text +Error: "tx already exists in cache" (ErrTxInCache) when re-submitting a previously failed tx +Solution: This is expected behavior for txs that repeatedly fail during block execution +``` + +The mempool tracks transactions that fail during block execution to prevent infinite re-entry. A tx that fails while being included in a block is allowed **one** retry — it is removed from the cache so it can be re-submitted. If it fails a **second** time during block execution, it is left in the cache and subsequent `CheckTx` calls return `ErrTxInCache`, rejecting re-submission. + +This prevents transactions that consistently fail before fee charging (for example, out-of-gas failures) from being resubmitted indefinitely and repeatedly consuming block execution resources. + +The failure tracker is reset when the transaction is successfully included in a block. After a successful inclusion, the tx is treated as fresh again and would once more be granted a single retry on any future failure. + +**What to check if you see this:** + +- Confirm the transaction is one that has failed block execution at least twice (e.g. persistent out-of-gas or other pre-fee failures). +- If the failure is caused by a fixable condition (such as insufficient gas), rebuild and re-sign the transaction with corrected parameters — a new tx hash is admitted normally. +- A different transaction (different hash) is unaffected and will be admitted as usual. + + Database corruption can require immediate attention: ```text From 2c78f3aeb143376ef1aaa0b5d883a68adf67cd6f Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:19:12 +0000 Subject: [PATCH 12/81] docs: Adds a new `autobahn-config-file` node config field enabling the Autobahn (GigaRouter) feature, which loads validator committee and consensus/producer parameters from a JSON config file; setting a remote validator signer (priv-validator.laddr) is incompatible with Autobahn. (sei-protocol/sei-chain#3194) --- learn/sei-giga.mdx | 60 +++++++++++++++++++++++++++++++++ node/node-operators.mdx | 64 ++++++++++++++++++++++++++++++++++++ node/technical-reference.mdx | 51 ++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) diff --git a/learn/sei-giga.mdx b/learn/sei-giga.mdx index bd6cbe0..d7c1fca 100644 --- a/learn/sei-giga.mdx +++ b/learn/sei-giga.mdx @@ -149,6 +149,66 @@ The protocol operates through two complementary layers: - Two-phase BFT agreement with fast and slow paths - Pipelined slots for minimal latency + + +#### Enabling Autobahn on a Node + +**Node Operators**: Autobahn (GigaRouter) can now be enabled experimentally on a node by pointing the `autobahn-config-file` field in `config.toml` to a JSON configuration file. Leave the field empty to keep Autobahn disabled. + +To enable Autobahn, set the following in your node's `config.toml`: + +```toml +# Path to a JSON file containing the Autobahn (GigaRouter) configuration. +# Leave empty to disable Autobahn. +autobahn-config-file = "/path/to/autobahn.json" +``` + +The node must be a committee member: its own validator public key and node public key must appear in the `validators` list of the referenced config file. + +**Remote signers are not supported**: When `autobahn-config-file` is set, the node fails to start if `priv-validator.laddr` is also configured. A local validator key is required — non-validator (observer) nodes are not yet supported. + +**Autobahn JSON Configuration Schema** + +The file referenced by `autobahn-config-file` is a JSON document with the following fields: + +| Field | Type | Description | +| --- | --- | --- | +| `validators` | array | The committee. Each entry is an object with `validator_key` (Autobahn validator public key), `node_key` (p2p node public key), and `address` (network `host:port`). | +| `max_gas_per_block` | number | Maximum gas allowed per block. Must be greater than 0. | +| `max_txs_per_block` | number | Maximum transactions per block. Must be greater than 0. | +| `max_txs_per_second` | number \| null | Optional cap on transactions per second. Omit or set null for no limit. | +| `mempool_size` | number | Maximum mempool size. Must be greater than 0. | +| `block_interval` | duration | Target interval between blocks. Must be greater than 0. | +| `allow_empty_blocks` | boolean | Whether empty blocks may be produced. | +| `view_timeout` | duration | Consensus view timeout. Must be greater than 0. | +| `persistent_state_dir` | string \| null | Optional directory for persisting consensus state. | +| `dial_interval` | duration | Interval at which peers are dialed. Must be greater than 0. | + +Example configuration file: + +```json +{ + "validators": [ + { + "validator_key": "ed25519:public:...", + "node_key": "node:ed25519:public:...", + "address": "peer1.example.com:26660" + } + ], + "max_gas_per_block": 50000000, + "max_txs_per_block": 5000, + "max_txs_per_second": 1000, + "mempool_size": 20000, + "block_interval": "200ms", + "allow_empty_blocks": false, + "view_timeout": "1.5s", + "persistent_state_dir": "/tmp/autobahn-state", + "dial_interval": "10s" +} +``` + +The node validates this file on startup and refuses to start if any required field is missing, if the `validators` list is empty, if a `validator_key` or `node_key` is duplicated, or if the node's own validator and node keys are not present as a matching entry in the `validators` list. + ### 3. Advanced Parallel Execution The parallel execution architecture extends beyond current OCC capabilities to include: diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 6450f48..0d9ce9b 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -117,6 +117,70 @@ ss-keep-recent = 100000 rs-backend = "pebbledb" ``` + +#### Autobahn / GigaRouter (config.toml) + +Autobahn (the GigaRouter consensus path) is enabled by pointing the +`autobahn-config-file` field at a JSON file describing the validator +committee and the consensus/producer parameters. Leave it empty (the +default) to disable Autobahn entirely. + +```toml +# Path to a JSON file containing the Autobahn (GigaRouter) configuration. +# Leave empty to disable Autobahn. +autobahn-config-file = "" +``` + +When `autobahn-config-file` is set the node loads its committee membership +and block-production parameters from the referenced JSON file. The node must +be a committee member: its own validator key and node key must appear in the +`validators` list, otherwise startup fails. + + + Autobahn does **not** support remote validator signers. If + `autobahn-config-file` is set together with `priv-validator.laddr` (a remote + signer listen address), the node fails to start. A local validator key is + required — non-validator (observer) nodes are not yet supported under + Autobahn. + + +The referenced JSON file supports the following fields: + +```json +{ + "validators": [ + { + "validator_key": "ed25519:public:...", + "node_key": "node:ed25519:public:...", + "address": "host:port" + } + ], + "max_gas_per_block": 50000000, + "max_txs_per_block": 5000, + "max_txs_per_second": 1000, + "mempool_size": 20000, + "block_interval": "400ms", + "allow_empty_blocks": false, + "view_timeout": "1500ms", + "persistent_state_dir": "/path/to/state", + "dial_interval": "10s" +} +``` + +| Field | Description | +| --- | --- | +| `validators` | Committee membership. Each entry is `{ validator_key, node_key, address }`. Validator keys and node keys must be unique across the list, and the node's own keys must be present. | +| `max_gas_per_block` | Maximum gas per produced block. Must be `> 0`. | +| `max_txs_per_block` | Maximum transactions per produced block. Must be `> 0`. | +| `max_txs_per_second` | Optional cap on transactions per second (omit to leave unset). | +| `mempool_size` | Producer mempool capacity. Must be `> 0`. | +| `block_interval` | Target interval between blocks. Must be `> 0`. | +| `allow_empty_blocks` | Whether to produce blocks when there are no transactions. | +| `view_timeout` | Consensus view timeout. Must be `> 0`. | +| `persistent_state_dir` | Optional directory for persistent consensus state. | +| `dial_interval` | Interval between dial attempts to committee peers. Must be `> 0`. | + + ### Default Configurations The full unmodified `app.toml`, `config.toml`, and `client.toml` produced by diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index b3795ef..9af981b 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -199,6 +199,57 @@ double_sign_check_height = 0 + +### Autobahn (GigaRouter) Configuration + +The `autobahn-config-file` field in `config.toml` enables the Autobahn (GigaRouter) feature. It specifies the path to a JSON file containing the Autobahn configuration, which defines the validator committee and the consensus/producer parameters. Leave it empty to disable Autobahn. + +```toml +# Path to a JSON file containing the Autobahn (GigaRouter) configuration. +# Leave empty to disable Autobahn. +autobahn-config-file = "" +``` + +When Autobahn is enabled, the referenced JSON file supports the following fields: + +```json +{ + "validators": [ + { + "validator_key": "", + "node_key": "node:ed25519:public:", + "address": "host:port" + } + ], + "max_gas_per_block": 50000000, + "max_txs_per_block": 5000, + "max_txs_per_second": 1000, + "mempool_size": 20000, + "block_interval": "400ms", + "allow_empty_blocks": false, + "view_timeout": "1500ms", + "persistent_state_dir": "/path/to/state", + "dial_interval": "10s" +} +``` + +| Field | Description | +| --- | --- | +| `validators` | List of committee members, each with a `validator_key`, `node_key`, and `address`. Must not be empty. | +| `max_gas_per_block` | Maximum gas allowed per block. Must be greater than 0. | +| `max_txs_per_block` | Maximum number of transactions per block. Must be greater than 0. | +| `max_txs_per_second` | Optional cap on transactions per second. | +| `mempool_size` | Maximum mempool size. Must be greater than 0. | +| `block_interval` | Target interval between blocks (e.g. `400ms`). Must be greater than 0. | +| `allow_empty_blocks` | Whether to produce empty blocks. | +| `view_timeout` | Consensus view timeout. Must be greater than 0. | +| `persistent_state_dir` | Optional directory for persistent consensus state. | +| `dial_interval` | Interval between peer dial attempts. Must be greater than 0. | + + + When Autobahn is enabled, remote validator signers are not supported: the node fails to start if `priv-validator.laddr` is set. A local validator key is required — non-validator (observer) nodes are not yet supported. The node must be a committee member, so its own validator key and node key must appear in the `validators` list. + + ## Network Parameters Understanding network parameters helps you operate your node effectively. From 26ab32bc876969c2d5574f60a4b87c469499ec26 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:20:00 +0000 Subject: [PATCH 13/81] docs: Adds a new `disable-tx-index-lookup` config field to the receipt store config (defaulting to true and required to remain true, as setting it false panics), plus internal benchmark/metrics changes. (sei-protocol/sei-chain#3081) --- node/node-operators.mdx | 8 ++++++++ node/technical-reference.mdx | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 0d9ce9b..bfadb29 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -426,6 +426,14 @@ async-write-buffer = 100 # defaults to 600 seconds prune-interval-seconds = 600 + + +# DisableTxIndexLookup must remain true. The tx_hash -> block_number lookup +# path used by the parquet backend is intentionally unsupported; setting this +# to false will panic during parquet store initialization. +# defaults to true (required) +disable-tx-index-lookup = true + ############################################################################### ### EVM Configuration ### ############################################################################### diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 9af981b..50bcae7 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -140,6 +140,13 @@ ss-enable = true ss-backend = "pebbledb" ss-keep-recent = 100000 ss-prune-interval = 600 + +# Receipt store configuration +[state-store.receipt-store] +# The tx_hash -> block_number lookup path is intentionally unsupported. +# This field defaults to true and must remain true; setting it to false +# causes the node to panic during parquet receipt store initialization. +disable-tx-index-lookup = true ``` From 9e0b5ea40febf72f4138cc576d1c6e14e683f100 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:21:03 +0000 Subject: [PATCH 14/81] docs: The ABCI peer filtering feature has been removed, deprecating the `filter-peers` config option and removing the `/p2p/filter/addr` and `/p2p/filter/id` ABCI query paths. (sei-protocol/sei-chain#3225) --- node/technical-reference.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 50bcae7..904966f 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -204,6 +204,10 @@ timeout_commit = "1s" double_sign_check_height = 0 ``` + + ABCI peer filtering has been removed. The deprecated `filter-peers` field in `config.toml` (under `[base]`) no longer has any effect and is no longer emitted in generated config templates. Tendermint no longer sends `/p2p/filter/addr/` or `/p2p/filter/id/` queries to the application, so peers can no longer be filtered by IP or node ID through the ABCI app. You can safely remove any `filter-peers` line from existing configs. + + From af3be998d9d76b9373bcdaef88ce5e98c653fc93 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:22:23 +0000 Subject: [PATCH 15/81] =?UTF-8?q?docs:=20Adds=20a=20new=20`receipt-store.t?= =?UTF-8?q?x-index-backend`=20config=20field=20(defaulting=20to=20"pebbled?= =?UTF-8?q?b")=20that=20enables=20a=20Pebble-backed=20tx=5Fhash=E2=86=92bl?= =?UTF-8?q?ock=5Fnumber=20index=20for=20faster=20receipt-by-hash=20lookups?= =?UTF-8?q?=20on=20the=20parquet=20receipt=20store,=20replacing=20the=20pr?= =?UTF-8?q?eviously=20unsupported=20`disable-tx-index-lookup`=20field.=20(?= =?UTF-8?q?sei-protocol/sei-chain#3222)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node/node-operators.mdx | 13 ++++++++----- node/technical-reference.mdx | 12 ++++++++---- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/node/node-operators.mdx b/node/node-operators.mdx index bfadb29..d4bceb3 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -428,11 +428,14 @@ prune-interval-seconds = 600 -# DisableTxIndexLookup must remain true. The tx_hash -> block_number lookup -# path used by the parquet backend is intentionally unsupported; setting this -# to false will panic during parquet store initialization. -# defaults to true (required) -disable-tx-index-lookup = true +# TxIndexBackend selects the tx-hash index implementation for parquet receipts. +# Set to "pebbledb" to maintain a Pebble-backed tx_hash -> block_number index +# alongside parquet files so receipt-by-hash lookups can target a single file +# instead of scanning all files. Set to "" to disable the index and fall back +# to a full DuckDB scan. +# Ignored unless rs-backend = "parquet". +# defaults to "pebbledb" +tx-index-backend = "pebbledb" ############################################################################### ### EVM Configuration ### diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 904966f..8fe0da1 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -143,10 +143,14 @@ ss-prune-interval = 600 # Receipt store configuration [state-store.receipt-store] -# The tx_hash -> block_number lookup path is intentionally unsupported. -# This field defaults to true and must remain true; setting it to false -# causes the node to panic during parquet receipt store initialization. -disable-tx-index-lookup = true +# TxIndexBackend selects the tx-hash index implementation for the parquet +# receipt store. Set to "pebbledb" (the default) to maintain a Pebble-backed +# tx_hash -> block_number index alongside the parquet files so receipt-by-hash +# lookups can target a single file instead of scanning all files. The index is +# kept in sync on writes, rebuilt during WAL replay, and pruned alongside the +# parquet files. Set to "" to disable the index and fall back to a full DuckDB +# scan. This field is ignored unless rs-backend = "parquet". +tx-index-backend = "pebbledb" ``` From 0e00df239b63942853df756620034a46f1d2be06 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:23:22 +0000 Subject: [PATCH 16/81] docs: Adds a new `seid tendermint gen-autobahn-config` CLI command to generate Autobahn (GigaRouter) JSON config from node pubkey files, along with side-effect files (validator_pubkey.txt, node_pubkey.txt) now written when keys are saved. (sei-protocol/sei-chain#3220) --- learn/sei-giga.mdx | 32 ++++++++++++++++++++++++++++++++ node/node-operators.mdx | 34 ++++++++++++++++++++++++++++++++++ node/technical-reference.mdx | 23 +++++++++++++++++++++++ 3 files changed, 89 insertions(+) diff --git a/learn/sei-giga.mdx b/learn/sei-giga.mdx index d7c1fca..9362b46 100644 --- a/learn/sei-giga.mdx +++ b/learn/sei-giga.mdx @@ -209,6 +209,38 @@ Example configuration file: The node validates this file on startup and refuses to start if any required field is missing, if the `validators` list is empty, if a `validator_key` or `node_key` is duplicated, or if the node's own validator and node keys are not present as a matching entry in the `validators` list. + + +**Generating the config with `gen-autobahn-config`** + +Rather than hand-authoring the JSON file, you can generate it from per-node pubkey files using the `seid tendermint gen-autobahn-config` command: + +```bash +seid tendermint gen-autobahn-config [node-dirs...] --output +``` + +The command reads three files from each node directory passed as an argument and assembles one `validators` entry per directory: + +- `validator_pubkey.txt` — the Autobahn validator public key, in `validator:` format +- `node_pubkey.txt` — the p2p node public key, in `node:ed25519:public:` format +- `autobahn_address.txt` — the node's network address in `host:port` format + +The `--output` (or `-o`) flag is required and specifies where the generated JSON config is written. The generated file uses default consensus parameters (for example, a 400ms block interval and a 1.5s view timeout), which you can adjust afterward if needed. + +The `validator_pubkey.txt` and `node_pubkey.txt` files are written automatically alongside the validator private key and node key whenever those keys are saved (for example, during `seid init`), so each node's config directory already contains the pubkey files needed for generation. You still need to create the `autobahn_address.txt` file with the node's reachable `host:port` address. + +Example generating a config across three node directories: + +```bash +seid tendermint gen-autobahn-config \ + build/generated/node_0 \ + build/generated/node_1 \ + build/generated/node_2 \ + --output ~/.sei/config/autobahn.json +``` + +Once generated, point `autobahn-config-file` in `config.toml` at the resulting file to enable Autobahn. + ### 3. Advanced Parallel Execution The parallel execution architecture extends beyond current OCC capabilities to include: diff --git a/node/node-operators.mdx b/node/node-operators.mdx index d4bceb3..38022cf 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -181,6 +181,40 @@ The referenced JSON file supports the following fields: | `dial_interval` | Interval between dial attempts to committee peers. Must be `> 0`. | +#### Generating the Autobahn config + +Rather than hand-writing the `validators` list, you can generate the JSON +config file from a set of node directories with the `seid tendermint +gen-autobahn-config` command: + +```bash +seid tendermint gen-autobahn-config [node-dirs...] --output +``` + +Each `node-dir` argument must contain three files describing that committee +member: + +- `validator_pubkey.txt` — the validator public key in `validator:` + format +- `node_pubkey.txt` — the p2p node public key in `node:ed25519:public:` + format +- `autobahn_address.txt` — the node's network address in `host:port` format + +The command reads these files from each directory, assembles the `validators` +list, and writes a complete Autobahn JSON config (with default consensus and +producer parameters) to the path given by `--output` (short flag `-o`). The +`--output` flag is required. + +The `validator_pubkey.txt` and `node_pubkey.txt` files are produced +automatically: whenever `seid` saves the validator private key +(`priv_validator_key.json`) it also writes `validator_pubkey.txt`, and whenever +it saves the node key (`node_key.json`) it also writes `node_pubkey.txt`, both +in the same directory as the key file. You only need to supply +`autobahn_address.txt` yourself. Point `autobahn-config-file` at the generated +file to enable Autobahn. + + + ### Default Configurations The full unmodified `app.toml`, `config.toml`, and `client.toml` produced by diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 8fe0da1..61094a0 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -37,6 +37,29 @@ seid tendermint show-validator seid query node info ``` + +### Autobahn Config Generation + +Generate an Autobahn (GigaRouter) JSON config from a set of node directories. Each node directory must contain `validator_pubkey.txt`, `node_pubkey.txt`, and `autobahn_address.txt`. These pubkey files are written automatically alongside the key files when the validator key and node key are saved (in `validator:` and `node:ed25519:public:` formats, respectively). + +```bash +# Generate an autobahn config from one or more node directories +seid tendermint gen-autobahn-config [node-dirs...] --output + +# Using the short flag for the output path +seid tendermint gen-autobahn-config node_0 node_1 node_2 -o autobahn.json +``` + +The `--output` / `-o` flag is required and specifies the destination file path for the generated config. The command reads the following files from each supplied node directory: + +| File | Description | +| --- | --- | +| `validator_pubkey.txt` | Autobahn validator public key in `validator:` format. | +| `node_pubkey.txt` | p2p node public key in `node:ed25519:public:` format. | +| `autobahn_address.txt` | Network address (`host:port`) for the node. | + +The resulting JSON file can then be referenced from `config.toml` via the `autobahn-config-file` field to enable Autobahn wiring at node startup. + ### Key Management Proper key management is crucial for security. These commands help you manage From 094867c34784f466490585233d1bf73623e15025 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:24:40 +0000 Subject: [PATCH 17/81] docs: The `receipt-store.keep-recent` config field was removed; receipt store retention is now always derived from the global `min-retain-blocks` flag. (sei-protocol/sei-chain#3237) --- node/node-operators.mdx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 38022cf..22086bc 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -456,7 +456,10 @@ db-directory = "" async-write-buffer = 100 # PruneIntervalSeconds defines the interval in seconds to trigger pruning. -# Receipt retention is controlled by the global min-retain-blocks flag. +# Receipt retention is controlled by the global min-retain-blocks flag: the +# receipt store keeps the last min-retain-blocks blocks (0 = keep everything, +# no pruning). The dedicated receipt-store.keep-recent field has been removed +# and is ignored if set. # defaults to 600 seconds prune-interval-seconds = 600 From 27457030e8f5646a3afead471d26fb75391293a4 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:25:54 +0000 Subject: [PATCH 18/81] docs: Giga/Autobahn nodes now build blocks directly from the shared TxMempool and disable the mempool, consensus, statesync, and blocksync reactors, introducing hard block limits (max 2000 txs, ~2MB total) and changing behavior when the autobahn config is enabled. (sei-protocol/sei-chain#3224) --- learn/sei-giga-specs.mdx | 22 ++++++++++++++++++++++ learn/sei-giga.mdx | 17 +++++++++++++++++ node/node-operators.mdx | 13 +++++++++++-- node/technical-reference.mdx | 20 ++++++++++++++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) diff --git a/learn/sei-giga-specs.mdx b/learn/sei-giga-specs.mdx index 65b9c13..2bbb5ba 100644 --- a/learn/sei-giga-specs.mdx +++ b/learn/sei-giga-specs.mdx @@ -65,6 +65,28 @@ The specifications are organized to clearly distinguish between what is currentl + +### Upcoming: Autobahn Block Limits + +When a node runs with Autobahn (Sei Giga) consensus enabled, the block producer builds payloads by reaping transactions directly from the shared mempool, subject to hard on-chain block size constraints that are enforced during payload construction. + + + + + | Property | Value | + | --- | --- | + | Max transactions per block | 2000 (`MaxTxsPerBlock`) | + | Max total tx bytes per block | ~2 MB (`MaxTxsBytesPerBlock` = 2000 × 1024) | + | Block proto size bound | Derived from `MaxTxsPerBlock` and `MaxTxsBytesPerBlock` (`MaxBlockProtoSize`) | + + + - Total tx bytes may be split arbitrarily across transactions (one large tx or many small ones), up to the `MaxTxsPerBlock` limit. + - Limits are validated when the payload is built; payloads exceeding the transaction count or total byte limit are rejected. + - The block proto size bound derives an upper limit on the encoded block used to size networking message windows. + + + + ## Execution Engine ### Current: Parallel EVM Execution diff --git a/learn/sei-giga.mdx b/learn/sei-giga.mdx index 9362b46..6ca15a5 100644 --- a/learn/sei-giga.mdx +++ b/learn/sei-giga.mdx @@ -241,6 +241,23 @@ seid tendermint gen-autobahn-config \ Once generated, point `autobahn-config-file` in `config.toml` at the resulting file to enable Autobahn. + + +**Reactor changes when Autobahn is enabled** + +**Behavior change**: When a node runs with `autobahn-config-file` set, several standard reactors are disabled because they are incompatible with Autobahn's block production model. + +Enabling Autobahn changes how the node builds and synchronizes blocks: + +- **Mempool gossip reactor disabled**: Transaction gossip across the standard mempool reactor is turned off. The shared `TxMempool` still accepts and stores transactions, but they are no longer broadcast peer-to-peer through the legacy mempool channel. +- **Consensus reactor disabled**: The Tendermint consensus reactor is not started; block ordering is handled entirely by the Autobahn (GigaRouter) protocol. +- **State sync and block sync disabled**: Both the statesync and blocksync reactors are skipped, so a node cannot catch up through those paths while Autobahn is active. +- **Direct reaping from the shared mempool**: The block producer no longer uses a separate producer mempool channel. Instead, it reaps transactions directly from the shared `TxMempool` when assembling each block's payload. + +Because of these changes, an Autobahn-enabled node relies solely on the Autobahn data-dissemination and consensus layers for ordering and propagation, rather than the legacy gossip, consensus, and sync reactors. + +**Block limits**: Autobahn blocks are bounded by hard on-chain limits — at most 2000 transactions per block and roughly 2 MB of total transaction bytes — in addition to the `max_gas_per_block` and `max_txs_per_block` values in the config file. These limits are enforced while the payload is built. + ### 3. Advanced Parallel Execution The parallel execution architecture extends beyond current OCC capabilities to include: diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 22086bc..4b8ead6 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -171,9 +171,18 @@ The referenced JSON file supports the following fields: | --- | --- | | `validators` | Committee membership. Each entry is `{ validator_key, node_key, address }`. Validator keys and node keys must be unique across the list, and the node's own keys must be present. | | `max_gas_per_block` | Maximum gas per produced block. Must be `> 0`. | -| `max_txs_per_block` | Maximum transactions per produced block. Must be `> 0`. | +| `max_txs_per_block` | Maximum transactions per produced block. Must be `> 0`. Note that Autobahn also enforces hard on-chain per-block caps of **2000 transactions** and roughly **2 MB** of total transaction bytes; `max_txs_per_block` is effectively clamped to the 2000-tx limit, so setting it higher has no effect. | | `max_txs_per_second` | Optional cap on transactions per second (omit to leave unset). | -| `mempool_size` | Producer mempool capacity. Must be `> 0`. | +| `mempool_size` | Retained for compatibility. Must be `> 0`. Note that the Autobahn producer no longer maintains a separate producer mempool channel — blocks are now built by reaping transactions directly from the shared node `TxMempool` (configured under the `[mempool]` section of `config.toml`). | + + + When Autobahn is enabled, the node builds blocks directly from the shared + `TxMempool` and disables the mempool gossip reactor, the consensus reactor, + state sync, and block sync — those subsystems are not compatible with the + GigaRouter consensus path. Each produced block is bounded by the on-chain + caps of 2000 transactions and ~2 MB of total transaction bytes in addition to + the `max_gas_per_block` and `max_txs_per_block` limits from the config file. + | `block_interval` | Target interval between blocks. Must be `> 0`. | | `allow_empty_blocks` | Whether to produce blocks when there are no transactions. | | `view_timeout` | Consensus view timeout. Must be `> 0`. | diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 61094a0..232e4d0 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -288,6 +288,26 @@ When Autobahn is enabled, the referenced JSON file supports the following fields When Autobahn is enabled, remote validator signers are not supported: the node fails to start if `priv-validator.laddr` is set. A local validator key is required — non-validator (observer) nodes are not yet supported. The node must be a committee member, so its own validator key and node key must appear in the `validators` list. +#### Block Production and Disabled Reactors + +When Autobahn is enabled, block production and network wiring change significantly: + +- **Shared mempool as the block source:** The Autobahn producer builds blocks by reaping transactions directly from the shared `TxMempool` (the same mempool used for `CheckTx`), rather than from a separate producer mempool channel. Transactions that are included in a block are popped from the shared mempool. +- **Disabled reactors:** Because Autobahn drives consensus and block dissemination itself, the node skips starting the mempool gossip reactor, the consensus reactor, statesync, and blocksync when Autobahn is enabled. As a result, transactions are not gossiped over the standard mempool p2p channel, and the node does not perform block sync or state sync. + +#### Hard Per-Block Limits + +In addition to the configurable `max_gas_per_block` and `max_txs_per_block` fields, Autobahn enforces on-chain hard limits when building a block's payload. These are protocol-level caps and always apply, regardless of the values set in the config file: + +| Limit | Value | Description | +| --- | --- | --- | +| Maximum transactions per block | 2000 | No more than 2000 transactions may be included in a single Autobahn block. | +| Maximum total transaction bytes | ~2 MB (2000 × 1024 bytes) | The combined size of all transactions in a block may not exceed roughly 2 MB. This budget can be distributed arbitrarily across transactions (e.g. one large tx or many small ones) up to the transaction-count limit. | + + + The effective per-block transaction count is the smaller of the configured `max_txs_per_block` and the hard limit of 2000. If you configure a larger value, the 2000-tx cap still applies. The block proto size upper bound used for p2p message sizing is derived from these limits. + + ## Network Parameters Understanding network parameters helps you operate your node effectively. From f9b55f439e4fc06437ae8f21b8f60888ba7e4a38 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:26:23 +0000 Subject: [PATCH 19/81] docs: The legacy sei_*/sei2_* JSON-RPC gateway now follows JSON-RPC 2.0 batch rules: notifications (requests without an id) produce no entry in the batch response, and when there would be no response objects the server returns an empty HTTP body instead of an empty JSON array. (sei-protocol/sei-chain#3246) --- evm/reference.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/reference.mdx b/evm/reference.mdx index a3d4c17..1095a11 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -1242,7 +1242,7 @@ Sei extends the standard Ethereum JSON-RPC API with custom endpoints that enhanc Access is controlled by the `enabled_legacy_sei_apis` setting under `[evm]` in `app.toml`. Only methods explicitly listed in this allowlist are available. Disabled methods return a standard JSON-RPC error (code `-32601`, data `"legacy_sei_deprecated"`). Allowed single-object requests pass through unchanged, with an optional `Sei-Legacy-RPC-Deprecation` HTTP response header signaling deprecation. -JSON-RPC batch requests over HTTP are handled element-by-element: only allowlisted methods are forwarded to the inner handler as a filtered subset, and their responses are merged back into the original batch positions by JSON-RPC `id`. Disabled methods in the batch receive the standard `-32601` gate error in place, and any non-object batch element returns a JSON-RPC `-32600` Invalid Request without being forwarded — so a malformed element can never bypass the gate. The legacy HTTP request body limit is 5 MiB (matching go-ethereum's default). +JSON-RPC batch requests over HTTP are handled element-by-element: only allowlisted methods are forwarded to the inner handler as a filtered subset, and their responses are merged back by JSON-RPC `id`. Disabled methods in the batch receive the standard `-32601` gate error in place, and any non-object batch element returns a JSON-RPC `-32600` Invalid Request without being forwarded — so a malformed element can never bypass the gate. Batch responses follow JSON-RPC 2.0 semantics: notification requests (those without an `id`) produce no response entry, so the merged response array is not necessarily 1:1 with the request batch when notifications are present. If a batch would yield no response objects at all, the gateway returns an empty HTTP body rather than an empty JSON array (`[]`), which JSON-RPC 2.0 forbids. The legacy HTTP request body limit is 5 MiB (matching go-ethereum's default). ### Legacy API Configuration From 44518f33c028f5f6a7aff6ed65aa133c1e606546 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:27:59 +0000 Subject: [PATCH 20/81] docs: Adds new state-store config fields (sc-write-mode, sc-read-mode, sc-enable-lattice-hash) for Giga Storage and a GIGA_STORAGE env var that toggles FlatKV SC dual-write plus EVM SS split-read/write modes, along with EVM store iteration support. (sei-protocol/sei-chain#3268) --- node/giga-storage-migration.mdx | 21 ++++++++++++++------- node/node-operators.mdx | 13 ++++++++++--- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/node/giga-storage-migration.mdx b/node/giga-storage-migration.mdx index 9b6bcbd..8a81a2e 100644 --- a/node/giga-storage-migration.mdx +++ b/node/giga-storage-migration.mdx @@ -23,14 +23,21 @@ invisible to the network. The SC-layer routing fields `sc-write-mode`, `sc-read-mode`, and -`sc-enable-lattice-hash` are no longer emitted in the generated `app.toml` -template. They still exist on the underlying `[state-commit]` config and -default to `cosmos_only` / `cosmos_only` / `false`, but you no longer need to -set them for this migration. - -If you do configure the SC layer to use `split_write` mode +`sc-enable-lattice-hash` are emitted in the generated `app.toml` template under +the `[state-store]` section. They default to `cosmos_only` / `cosmos_only` / +`false`, so leaving them at their defaults keeps the SC layer untouched for this +migration. + +- `sc-write-mode` — write routing mode for EVM data in the SC layer. Valid + values: `cosmos_only`, `dual_write`, `split_write`. +- `sc-read-mode` — read routing mode for EVM data in the SC layer. Valid + values: `cosmos_only`, `evm_first`, `split_read`. +- `sc-enable-lattice-hash` — whether the lattice hash participates in the final + app hash. + +If you configure the SC layer to use `split_write` mode (`sc-write-mode = "split_write"`), the lattice hash must be enabled -(`sc-enable-lattice-hash = true`). State-commit config validation now rejects +(`sc-enable-lattice-hash = true`). State-commit config validation rejects `split_write` with the lattice hash disabled — the composite commit store panics on creation with `lattice hash must be enabled when using split_write mode`. diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 4b8ead6..1280773 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -358,9 +358,16 @@ sc-snapshot-prefetch-threshold = 0.8 sc-snapshot-write-rate-mbps = 100 # WriteMode defines the write routing mode for EVM data in the SC layer. -# Valid values: memiavl_only, migrate_evm, evm_migrated, migrate_all_but_bank, -# all_migrated_but_bank, migrate_bank, flatkv_only, test_only_dual_write -sc-write-mode = "memiavl_only" +# Valid values: cosmos_only, dual_write, split_write +sc-write-mode = "cosmos_only" + +# ReadMode defines the read routing mode for EVM data in the SC layer. +# Valid values: cosmos_only, evm_first, split_read +sc-read-mode = "cosmos_only" + +# EnableLatticeHash controls whether lattice hash participates in the final app hash. +# Must be enabled when using split_write mode. +sc-enable-lattice-hash = false # KeysToMigratePerBlock controls how many EVM keys the in-flight migration # (sc-write-mode = migrate_evm / migrate_bank / migrate_all_but_bank) drains From 289e52f608104c87a992cd249639b156c6697eef Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:28:46 +0000 Subject: [PATCH 21/81] docs: Two new Prometheus metrics (proposer_priority_hash and proposer_priority_hash_height) are exported every 1024 blocks so node operators can detect ProposerPriority divergence between validators. (sei-protocol/sei-chain#3277) --- node/advanced-config-monitoring.mdx | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/node/advanced-config-monitoring.mdx b/node/advanced-config-monitoring.mdx index 4fc13d9..0aa2608 100644 --- a/node/advanced-config-monitoring.mdx +++ b/node/advanced-config-monitoring.mdx @@ -447,6 +447,54 @@ seid query slashing signing-info $(seid tendermint show-validator) seid query staking delegations-to $(seid keys show -a $VALIDATOR_KEY) ``` + +### ProposerPriority Divergence Detection + +Sei nodes export two Prometheus gauges that let operators detect when a validator's `ProposerPriority` state diverges from the rest of the network. Divergence indicates corrupted consensus state and should be investigated immediately. + +| Metric | Type | Description | +| --- | --- | --- | +| `tendermint_state_proposer_priority_hash` | gauge | Encodes the first 8 bytes of the hash of the current validator set's proposer priorities, packed as a big-endian `uint64` and cast to a `float64`. | +| `tendermint_state_proposer_priority_hash_height` | gauge | The block height at which the most recent `tendermint_state_proposer_priority_hash` was computed. | + +Both metrics are emitted together every 1024 heights (roughly every few minutes at Sei block times). Emitting the hash as a numeric value instead of a Prometheus label keeps series cardinality constant at one series per node, rather than creating a new time series on every priority change. + +#### How to use these metrics + +Compare `tendermint_state_proposer_priority_hash` across your validators, but **only compare samples taken at the same `tendermint_state_proposer_priority_hash_height`**. Since the hash is only meaningful at a shared height, always pair it with the height gauge before comparing: + +- If every node reports the **same** hash value at the same height, their `ProposerPriority` state agrees. +- If a node reports a **different** hash value at the same height, its `ProposerPriority` state has diverged and likely indicates corrupted state on that node. + +Example alert rule that flags divergence across scraped nodes at a shared height: + +```yaml +groups: + - name: proposer_priority_alerts + rules: + - alert: ProposerPriorityDivergence + expr: > + count( + count by (tendermint_state_proposer_priority_hash) ( + tendermint_state_proposer_priority_hash + * on(instance) group_left + (tendermint_state_proposer_priority_hash_height == scalar(max(tendermint_state_proposer_priority_hash_height))) + ) + ) > 1 + for: 10m + labels: + severity: critical + annotations: + summary: 'ProposerPriority has diverged between validators' +``` + +Each checkpoint also writes a `proposer priority hash checkpoint` log line containing the full 32-byte hash and the packed value, which can be used for grep-based comparison across nodes. + + + Prometheus gauges are held in memory, so after a process restart these gauges reset to zero until the next emission at the following multiple of 1024 heights (up to roughly 8.5 minutes of stale or zero data). This is expected for a monitoring signal that is only consulted in response to incidents. + + + ## Backup Management From c264c227dcac89f1dc0d8caac55a07a9e022bb30 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:29:17 +0000 Subject: [PATCH 22/81] docs: The autobahn config generator now defaults AllowEmptyBlocks to true instead of false, changing the default behavior of generated autobahn configs. (sei-protocol/sei-chain#3234) --- learn/sei-giga.mdx | 2 +- node/node-operators.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/learn/sei-giga.mdx b/learn/sei-giga.mdx index 6ca15a5..46b212e 100644 --- a/learn/sei-giga.mdx +++ b/learn/sei-giga.mdx @@ -200,7 +200,7 @@ Example configuration file: "max_txs_per_second": 1000, "mempool_size": 20000, "block_interval": "200ms", - "allow_empty_blocks": false, + "allow_empty_blocks": true, "view_timeout": "1.5s", "persistent_state_dir": "/tmp/autobahn-state", "dial_interval": "10s" diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 1280773..44ce239 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -160,7 +160,7 @@ The referenced JSON file supports the following fields: "max_txs_per_second": 1000, "mempool_size": 20000, "block_interval": "400ms", - "allow_empty_blocks": false, + "allow_empty_blocks": true, "view_timeout": "1500ms", "persistent_state_dir": "/path/to/state", "dial_interval": "10s" From 15a975a8cef6f0ea35606604d6718b4b9e227697 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:29:40 +0000 Subject: [PATCH 23/81] docs: The EVM JSON-RPC methods eth_getFilterChanges and eth_getFilterLogs now return an empty array ([]) instead of null when no logs match or a bounded filter's range is exhausted, aligning with the Ethereum JSON-RPC spec. (sei-protocol/sei-chain#3292) --- evm/reference.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/evm/reference.mdx b/evm/reference.mdx index 1095a11..b88f2f4 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -786,6 +786,8 @@ Every method below is also browsable interactively in the explorer above; this s **Supported.** Polls a filter and returns new logs (log filters) or block hashes (block filters) since the last poll. +**Sei-specific behavior:** For log filters, an empty array (`[]`) is returned instead of `null` when there are no matching logs — including once a bounded filter (one created with a `blockHash` or a `toBlock`) has had its range fully consumed. This aligns with the Ethereum JSON-RPC spec, which always expects an array result. + **Parameters:** | # | Name | Type | Description | From 9155a75bedc705abaeee267707ab9844db7e4f30 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:31:21 +0000 Subject: [PATCH 24/81] =?UTF-8?q?docs:=20Sei=20node=20data=20directory=20l?= =?UTF-8?q?ayout=20changed=20for=20new=20nodes=E2=80=94state/receipt/EVM/t?= =?UTF-8?q?endermint=20databases=20now=20use=20organized=20subdirectories?= =?UTF-8?q?=20(e.g.=20data/state=5Fcommit/memiavl,=20data/ledger/receipt/{?= =?UTF-8?q?backend},=20data/tendermint/),=20with=20automatic=20legacy-path?= =?UTF-8?q?=20fallback=20for=20existing=20nodes.=20(sei-protocol/sei-chain?= =?UTF-8?q?#3155)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node/giga-storage-migration.mdx | 19 +++++++++++++++---- node/node-operators.mdx | 2 +- node/technical-reference.mdx | 20 +++++++++++++------- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/node/giga-storage-migration.mdx b/node/giga-storage-migration.mdx index 8a81a2e..f09c0ba 100644 --- a/node/giga-storage-migration.mdx +++ b/node/giga-storage-migration.mdx @@ -230,10 +230,21 @@ To fully reclaim the disk used by EVM SS, stop the node and delete ### Where do the data files live after migrating? -- Cosmos SS data lives under the same directory as before, typically - `data/pebbledb/` for the default `pebbledb` backend. -- EVM SS data lives under `data/evm_ss/`. -- SC data (`memiavl` + FlatKV) is untouched by this migration. +New nodes use an organized subdirectory layout under `data/`. Existing nodes +with data in the legacy flat layout keep using their legacy paths automatically +(legacy takes precedence when present). + +- Cosmos SS data lives under `data/state_store/cosmos/{backend}` on new nodes + (e.g. `data/state_store/cosmos/pebbledb/` for the default `pebbledb` backend). + Existing nodes with data under `data/{backend}` (e.g. `data/pebbledb/`) + continue using that legacy path. +- EVM SS data lives under `data/state_store/evm/{backend}` on new nodes + (e.g. `data/state_store/evm/pebbledb/`). Existing nodes with data under + `data/evm_ss/` continue using that legacy path. The `evm-db-directory` + config, when unset, defaults to `data/state_store/evm/{backend}`. +- SC data (`memiavl` + FlatKV) is untouched by this migration; on new nodes it + lives under `data/state_commit/memiavl` and `data/state_commit/flatkv`, with + legacy `data/committer.db` and `data/flatkv` retained when present. ### Does Giga SS Store change the app hash or consensus? diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 44ce239..53bbaf8 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -438,7 +438,7 @@ ss-prune-interval = 600 ss-import-num-workers = 1 # EVMDBDirectory defines the directory for the optional EVM state-store DB(s). -# If unset, defaults to /data/evm_ss when EVM SS is enabled. +# If unset, defaults to /data/state_store/evm/{backend} when EVM SS is enabled. evm-ss-db-directory = "" # EVMSplit controls whether EVM data is routed to a dedicated SS backend. diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 232e4d0..000aac2 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -354,15 +354,21 @@ $HOME/.sei/ │ ├── node_key.json # Node identity key │ └── priv_validator_key.json # Validator signing key ├── data/ -│ ├── application.db # Application state -│ ├── blockstore.db # Block data -│ ├── cs.wal/ # Consensus write-ahead logs -│ ├── evidence.db # Evidence of misbehavior -│ ├── state.db # Tendermint state -│ └── tx_index.db # Transaction index -└── keyring-file/ # Local key storage +│ ├── application.db # Application state +│ └── tendermint/ # Tendermint databases (new subdirectory layout) +│ ├── blockstore.db # Block data +│ ├── cs.wal/ # Consensus write-ahead logs +│ ├── evidence.db # Evidence of misbehavior +│ ├── peerstore.db # Peer store +│ ├── state.db # Tendermint state +│ └── tx_index.db # Transaction index +└── keyring-file/ # Local key storage ``` + + New nodes place the Tendermint databases (`blockstore.db`, `state.db`, `tx_index.db`, `evidence.db`, `peerstore.db`, and `cs.wal`) under `data/tendermint/`. Existing nodes that already have these databases in the legacy flat `data/` layout are detected automatically and continue using the legacy paths — no migration is required. This automatic legacy-path fallback also applies to `reset`, `reindex-event`, and consensus WAL path resolution. + + This reference guide provides essential technical information for operating Sei nodes and validators. For API documentation and other detailed specifications, please refer to the respective sections in our documentation set. From 696184d7ee86b73867996bb1ff2d0a59693851cd Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:32:12 +0000 Subject: [PATCH 25/81] docs: When the parquet receipt store's pebble tx hash index is disabled, receipt-by-tx-hash lookups that miss the cache now fail fast (returning not-found) instead of performing a full parquet scan, affecting node operators who run with the tx index disabled. (sei-protocol/sei-chain#3294) --- node/node-operators.mdx | 12 ++++++++++-- node/technical-reference.mdx | 8 ++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 53bbaf8..6f5402f 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -484,8 +484,16 @@ prune-interval-seconds = 600 # TxIndexBackend selects the tx-hash index implementation for parquet receipts. # Set to "pebbledb" to maintain a Pebble-backed tx_hash -> block_number index # alongside parquet files so receipt-by-hash lookups can target a single file -# instead of scanning all files. Set to "" to disable the index and fall back -# to a full DuckDB scan. +# instead of scanning all files. Set to "" to disable the index. +# +# WARNING: with the index disabled, a receipt-by-tx-hash lookup (e.g. +# eth_getTransactionReceipt) that misses the in-memory cache fails fast and +# returns a not-found result instead of falling back to a full parquet scan +# (a full scan reads every file on disk and is prohibitively expensive at +# production scale). Operators that must serve historical receipts by tx hash +# should keep the index enabled; otherwise receipts that are no longer cached +# will appear as not-found. Block-range queries such as log filtering are +# unaffected since they do not use the tx hash index. # Ignored unless rs-backend = "parquet". # defaults to "pebbledb" tx-index-backend = "pebbledb" diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 000aac2..af3c108 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -171,8 +171,12 @@ ss-prune-interval = 600 # tx_hash -> block_number index alongside the parquet files so receipt-by-hash # lookups can target a single file instead of scanning all files. The index is # kept in sync on writes, rebuilt during WAL replay, and pruned alongside the -# parquet files. Set to "" to disable the index and fall back to a full DuckDB -# scan. This field is ignored unless rs-backend = "parquet". +# parquet files. Set to "" to disable the index. When the index is disabled, a +# receipt-by-tx-hash lookup that misses the in-memory cache fails fast and +# returns not-found instead of performing a full parquet scan (which would be +# prohibitively expensive at production scale). Operators who rely on tx-hash +# receipt lookups for historical receipts that are no longer cached must keep +# the index enabled. This field is ignored unless rs-backend = "parquet". tx-index-backend = "pebbledb" ``` From cf3d370b8362b9adebad92703f591ec9be01436d Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:32:50 +0000 Subject: [PATCH 26/81] docs: When GIGA_STORAGE=true, the receipt backend now defaults to parquet unless RECEIPT_BACKEND is explicitly set, changing the default behavior for nodes running with Giga Storage enabled. (sei-protocol/sei-chain#3298) --- node/giga-storage-migration.mdx | 23 +++++++++++++++++++++++ node/node-operators.mdx | 4 ++++ 2 files changed, 27 insertions(+) diff --git a/node/giga-storage-migration.mdx b/node/giga-storage-migration.mdx index f09c0ba..62f14ea 100644 --- a/node/giga-storage-migration.mdx +++ b/node/giga-storage-migration.mdx @@ -213,6 +213,29 @@ If any check fires, the correct fix is either (a) complete the state sync described above, or (b) set `evm-ss-split = false` and restart. If `data/evm_ss/` is stale from a failed attempt, remove it before state syncing. + + +## Receipt backend default + +When Giga Storage is enabled (`GIGA_STORAGE=true`), the receipt backend now +defaults to `parquet`. Previously the receipt backend was left unchanged and +had to be set explicitly through the `RECEIPT_BACKEND` environment variable. + +This default is applied implicitly: enabling Giga Storage sets +`RECEIPT_BACKEND=parquet` unless you have already provided an explicit value. +To use a different receipt backend, set `RECEIPT_BACKEND` explicitly before +starting the node — an explicit value always takes precedence over the +parquet default. + +```bash copy +# Giga Storage on, receipt backend defaults to parquet +export GIGA_STORAGE=true + +# Override the parquet default with an explicit backend +export GIGA_STORAGE=true +export RECEIPT_BACKEND= +``` + ## Rollback To roll back: diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 6f5402f..c48e5a5 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -114,6 +114,10 @@ ss-keep-recent = 100000 [receipt-store] # Storage backend for EVM transaction receipts (pebbledb or parquet). +# Defaults to pebbledb, but when Giga Storage is enabled (GIGA_STORAGE=true) +# the receipt backend defaults to parquet instead. You can still force a +# specific backend by setting rs-backend explicitly (or the RECEIPT_BACKEND +# env var in the containerized node scripts), which always takes precedence. rs-backend = "pebbledb" ``` From 9b934f6bc421cce229851bc0ac74f25cd824ec52 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:34:13 +0000 Subject: [PATCH 27/81] docs: Adds a new debug_traceTransactionProfile JSON-RPC method that returns a transaction trace plus detailed timing/store-access profiling, and a new seidb trace-profile-report CLI command to batch-run it across a block range. (sei-protocol/sei-chain#3267) --- evm/reference.mdx | 31 +++++++++++++++++++++++++++++++ evm/tracing/index.mdx | 3 +++ learn/seidb.mdx | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/evm/reference.mdx b/evm/reference.mdx index b88f2f4..cc0a3b3 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -1233,6 +1233,37 @@ The `filter` object applies only to `logs` subscriptions. For `newHeads`, pass t } ``` + + +#### `debug_traceTransactionProfile` + +**Limited.** Sei extension that replays a transaction by hash and returns its execution trace alongside a detailed timing and store-access profile. + +**Sei-specific behavior:** Sei-specific extension (not part of upstream go-ethereum's debug namespace). HTTP-only (the debug namespace is not registered on the WebSocket server) and subject to historical-debug-trace/archive availability guards for the target height. The response is an object with two fields: `trace` (the standard trace produced by the configured tracer, identical to `debug_traceTransaction`) and `profile` (timing and KVStore access instrumentation collected while replaying the tx). The `profile` object reports `totalNanos` (end-to-end profiling time), `historicalDbLookupNanos` (time spent in historical DB reads — the sum of `get`/`has`/`iterator`/`iteratorNext` store latencies), `otherNanos` (remaining time), a `phases` object with per-phase timings (`lookupTransactionNanos`, `loadBlockNanos`, `replayHistoricalTxsNanos`, `buildBlockContextNanos`, `prepareTxNanos`, `executionNanos`, `traceResultNanos`), and a `store` object with per-module access statistics under `store.modules..stats` (each op maps to `{count, totalNanos}`) plus per-module `iterators` samples (bounds, direction, surfaced keys, `nextCount`, and cumulative timing). Iterator and key samples are capped per module to bound response size. To batch-run this method across a block range, see the `seidb trace-profile-report` command. + +**Parameters:** + +| # | Name | Type | Description | +| :- | :- | :- | :- | +| 1 | `hash` | DATA, 32 bytes | Transaction hash to trace and profile. | +| 2 | `config` | object | Optional tracer config (tracer name, tracerConfig, timeout, reexec, disableStorage/Stack/Memory). | + +**Example request:** + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "debug_traceTransactionProfile", + "params": [ + "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060", + { + "timeout": "60s" + } + ] +} +``` + ## Sei Custom Endpoints diff --git a/evm/tracing/index.mdx b/evm/tracing/index.mdx index 0b875c0..8e5bae0 100644 --- a/evm/tracing/index.mdx +++ b/evm/tracing/index.mdx @@ -406,6 +406,9 @@ debug_traceCall(tx, "latest", {tracer: "callTracer"}) # State access debug_traceStateAccess(hash) + +# Trace transaction with timing/store-access profiling +debug_traceTransactionProfile(hash, {}) ``` ### Common Tracers diff --git a/learn/seidb.mdx b/learn/seidb.mdx index b8f1c58..c212deb 100644 --- a/learn/seidb.mdx +++ b/learn/seidb.mdx @@ -218,3 +218,42 @@ SeiDB's architecture supports various deployment configurations optimized for di - **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 +seidb trace-profile-report \ + --endpoint http://localhost:8545 \ + --start-block \ + --end-block \ + --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. + +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. From 4755e777de96772d69ddcf089d0b8651eba01d90 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:36:36 +0000 Subject: [PATCH 28/81] docs: The /status RPC endpoint now returns a new SyncInfo field `last_committed_block_height` and, under Autobahn, populates block height/app hash from the app layer so /status works when the CometBFT block store is not fed. (sei-protocol/sei-chain#3309) --- evm/reference.mdx | 12 +++++++++++ node/node-operators.mdx | 42 ++++++++++++++++++++++++++++++++++++ node/technical-reference.mdx | 11 ++++++++++ 3 files changed, 65 insertions(+) diff --git a/evm/reference.mdx b/evm/reference.mdx index cc0a3b3..e2172d7 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -736,6 +736,18 @@ Every method below is also browsable interactively in the explorer above; this s **Parameters:** none. + + +#### `status` (CometBFT RPC) + +**Supported.** The underlying CometBFT `/status` RPC endpoint returns node info, validator info, and a `sync_info` object describing block-sync state. It is exposed on the Tendermint RPC port (not the EVM JSON-RPC endpoint). + +**Sei-specific behavior:** The `sync_info` object now includes an additional field, `last_committed_block_height` — the height of the last block finalized by consensus, serialized as a JSON string-encoded `int64`. Under standard CometBFT consensus this always equals `latest_block_height`, because a block's commit and app-apply happen in a single step. Under Autobahn consensus the two can briefly differ: consensus finalizes a block (advancing `last_committed_block_height`, derived from the latest `CommitQC`) before the app executes it, so the invariant is `last_committed_block_height >= latest_block_height`. + + +**Autobahn `/status` behavior.** When a node runs under Autobahn (i.e. `AutobahnConfigFile` is set), the CometBFT block store is not populated, so `/status` derives `latest_block_height` and `latest_app_hash` from the app layer (via `ABCIInfo`) instead of the block store. Several other `sync_info` fields remain unpopulated under Autobahn and should not be relied on: `latest_block_hash`, `latest_block_time`, the `earliest_*` fields, and `max_peer_block_height`; `catching_up` is currently hardcoded to `true`. Additionally, block-data endpoints such as `/block`, `/block_results`, `/commit`, and the EVM endpoints that walk through them (e.g. `eth_getBlockByNumber`) still fail under Autobahn because the block store height reports `0`. + + #### `web3_clientVersion` **Supported.** Returns the client version string. diff --git a/node/node-operators.mdx b/node/node-operators.mdx index c48e5a5..1ed76f6 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -187,6 +187,48 @@ The referenced JSON file supports the following fields: caps of 2000 transactions and ~2 MB of total transaction bytes in addition to the `max_gas_per_block` and `max_txs_per_block` limits from the config file. + + + +#### Monitoring under Autobahn + +Enabling Autobahn changes what several CometBFT RPC endpoints report, because +the CometBFT block store and consensus reactor are not fed on the GigaRouter +path. Operators relying on status and monitoring endpoints should be aware of +the following. + +**`/status` additions** + +The `SyncInfo` object returned by `/status` now includes a +`last_committed_block_height` field (a JSON string-encoded integer) reporting +the last block finalized by consensus: + +- Under CometBFT, commit and app-apply happen in a single step, so + `last_committed_block_height` always equals `latest_block_height`. +- Under Autobahn, the value is derived from the latest `CommitQC`. Consensus + finalizes a block before the app executes it, so + `last_committed_block_height` can briefly lead `latest_block_height` + (the invariant is `last_committed_block_height >= latest_block_height`). + +Under Autobahn, `/status` derives `latest_block_height` and `latest_app_hash` +from the app layer (via `ABCIInfo`) rather than from the CometBFT block store, +so these fields report live values instead of `0`. + +**Fields that remain unpopulated under Autobahn** + +Because the CometBFT block store and consensus reactor are not fed, the +following `SyncInfo` fields are not currently populated under Autobahn: +`latest_block_hash`, `latest_block_time`, all `earliest_*` fields, and +`max_peer_block_height`. `catching_up` is hardcoded to `true`. + + + Block-data RPC endpoints remain unavailable under Autobahn. Because the + CometBFT block store height stays at `0`, `/block`, `/block_results`, + `/commit`, and the EVM RPC endpoints that walk through them (for example + `eth_getBlockByNumber` and `eth_gasPrice`) still fail on Autobahn nodes. + Plan your monitoring and tooling accordingly until block-data reads are + routed through an Autobahn-aware path. + | `block_interval` | Target interval between blocks. Must be `> 0`. | | `allow_empty_blocks` | Whether to produce blocks when there are no transactions. | | `view_timeout` | Consensus view timeout. Must be `> 0`. | diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index af3c108..252b87a 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -299,6 +299,17 @@ When Autobahn is enabled, block production and network wiring change significant - **Shared mempool as the block source:** The Autobahn producer builds blocks by reaping transactions directly from the shared `TxMempool` (the same mempool used for `CheckTx`), rather than from a separate producer mempool channel. Transactions that are included in a block are popped from the shared mempool. - **Disabled reactors:** Because Autobahn drives consensus and block dissemination itself, the node skips starting the mempool gossip reactor, the consensus reactor, statesync, and blocksync when Autobahn is enabled. As a result, transactions are not gossiped over the standard mempool p2p channel, and the node does not perform block sync or state sync. + +#### RPC Behavior Under Autobahn + +Because the CometBFT block store and consensus reactor are not fed under Autobahn, some RPC responses behave differently: + +- **`/status` derives height and app hash from the app layer:** With Autobahn enabled the CometBFT block store height stays at 0, so the `/status` handler pulls `SyncInfo.latest_block_height` and `SyncInfo.latest_app_hash` from the application layer (via `ABCIInfo`) instead of the block store. This reports the last height the app committed in `FinalizeBlock` and its matching app hash. +- **New `last_committed_block_height` field:** The `SyncInfo` object in the `/status` response now includes a `last_committed_block_height` field (JSON string-encoded int64) reporting the last block finalized by consensus. Under CometBFT this always equals `latest_block_height` (commit and app-apply happen in one step). Under Autobahn it is derived from the latest CommitQC and may briefly lead `latest_block_height`, since consensus finalizes a block before the app executes it. +- **Unpopulated `/status` fields:** Several `SyncInfo` fields remain unpopulated under Autobahn: `latest_block_hash`, `latest_block_time`, the `earliest_*` fields, and `max_peer_block_height`. `catching_up` is currently hardcoded to `true` because the consensus reactor is nil. +- **Block-data endpoints still fail:** Endpoints that read from the CometBFT block store — including `/block`, `/block_results`, `/commit`, and the EVM RPC endpoints that walk through them (`eth_getBlockByNumber`, `eth_gasPrice`, etc.) — still fail under Autobahn because the block store height is 0. + + #### Hard Per-Block Limits In addition to the configurable `max_gas_per_block` and `max_txs_per_block` fields, Autobahn enforces on-chain hard limits when building a block's payload. These are protocol-level caps and always apply, regardless of the values set in the config file: From c30c988f47548cd77de235ccbbe459e0bb66bbac Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:36:57 +0000 Subject: [PATCH 29/81] docs: The Sei legacy JSON-RPC HTTP handler now treats requests with "id": null as normal requests requiring a response, rather than as notifications that get omitted from batch responses. (sei-protocol/sei-chain#3303) --- evm/reference.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/reference.mdx b/evm/reference.mdx index e2172d7..8c34d22 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -1287,7 +1287,7 @@ Sei extends the standard Ethereum JSON-RPC API with custom endpoints that enhanc Access is controlled by the `enabled_legacy_sei_apis` setting under `[evm]` in `app.toml`. Only methods explicitly listed in this allowlist are available. Disabled methods return a standard JSON-RPC error (code `-32601`, data `"legacy_sei_deprecated"`). Allowed single-object requests pass through unchanged, with an optional `Sei-Legacy-RPC-Deprecation` HTTP response header signaling deprecation. -JSON-RPC batch requests over HTTP are handled element-by-element: only allowlisted methods are forwarded to the inner handler as a filtered subset, and their responses are merged back by JSON-RPC `id`. Disabled methods in the batch receive the standard `-32601` gate error in place, and any non-object batch element returns a JSON-RPC `-32600` Invalid Request without being forwarded — so a malformed element can never bypass the gate. Batch responses follow JSON-RPC 2.0 semantics: notification requests (those without an `id`) produce no response entry, so the merged response array is not necessarily 1:1 with the request batch when notifications are present. If a batch would yield no response objects at all, the gateway returns an empty HTTP body rather than an empty JSON array (`[]`), which JSON-RPC 2.0 forbids. The legacy HTTP request body limit is 5 MiB (matching go-ethereum's default). +JSON-RPC batch requests over HTTP are handled element-by-element: only allowlisted methods are forwarded to the inner handler as a filtered subset, and their responses are merged back by JSON-RPC `id`. Disabled methods in the batch receive the standard `-32601` gate error in place, and any non-object batch element returns a JSON-RPC `-32600` Invalid Request without being forwarded — so a malformed element can never bypass the gate. Batch responses follow JSON-RPC 2.0 semantics: only notification requests — those that omit the `id` member entirely — produce no response entry, so the merged response array is not necessarily 1:1 with the request batch when notifications are present. A request with an explicit `"id": null` is *not* a notification; it receives a response like any other request. If a batch would yield no response objects at all, the gateway returns an empty HTTP body rather than an empty JSON array (`[]`), which JSON-RPC 2.0 forbids. The legacy HTTP request body limit is 5 MiB (matching go-ethereum's default). ### Legacy API Configuration From 6d391ee950d9752acd77d7550b1da79599a4747e Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:37:31 +0000 Subject: [PATCH 30/81] docs: The v6.5 upgrade adds versioned copies of precompiles and retires the oracle precompile, which now reverts on getExchangeRates and getOracleTwaps queries. (sei-protocol/sei-chain#3293) --- evm/precompiles/oracle.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/precompiles/oracle.mdx b/evm/precompiles/oracle.mdx index 6ee1132..efcffed 100644 --- a/evm/precompiles/oracle.mdx +++ b/evm/precompiles/oracle.mdx @@ -6,4 +6,4 @@ keywords: ['oracle precompile', 'ethers.js', 'price feeds', 'exchange rates', 't --- **Address:** `0x0000000000000000000000000000000000001008` -**Deprecation Notice:** The native Sei Oracle is deprecated and will be shut off soon. We strongly recommend migrating to one of the third-party oracle providers, such as [Chainlink](/evm/oracles/chainlink), [Pyth](/evm/oracles/pyth-network), [Redstone](/evm/oracles/redstone), or [API3](/evm/oracles/api3). +**Retired as of v6.5:** The native Sei Oracle precompile has been retired. As of the v6.5 chain upgrade, both `getExchangeRates` and `getOracleTwaps` now revert with the error `oracle precompile is retired; oracle data queries are disabled` instead of returning data. Any contract that relies on on-chain oracle exchange rate or TWAP queries via this precompile will break after the upgrade. Migrate to one of the third-party oracle providers, such as [Chainlink](/evm/oracles/chainlink), [Pyth](/evm/oracles/pyth-network), [Redstone](/evm/oracles/redstone), or [API3](/evm/oracles/api3). From 4de6146ead9344697678eb5e415e96f949a0aa01 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:37:57 +0000 Subject: [PATCH 31/81] docs: Adds a new temporary consensus config field `stateless-leader-election` to sei-tendermint that enables an alternative stateless leader election mechanism as a disaster recovery measure, defaulting to false. (sei-protocol/sei-chain#3305) --- node/technical-reference.mdx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 252b87a..1888508 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -235,6 +235,20 @@ timeout_commit = "1s" double_sign_check_height = 0 ``` + + + The `[consensus]` section also supports a temporary disaster-recovery flag, `stateless-leader-election` (default `false`). When enabled, the consensus engine selects each round's leader via a deterministic stateless computation instead of the traditional stateful proposer-priority selection. + + This flag is intended **only** as an emergency recovery mechanism in the event of a chain stall, and it **requires coordination of a majority of validators** to be set to `true` together. If you set `stateless-leader-election = true` for only your own node, that node will be unable to participate in consensus and will effectively isolate itself from the network. Leave this set to `false` under normal operation. + + ```toml + [consensus] + # Temporary disaster-recovery leader-election mechanism. Defaults to false. + # Only enable with coordination of a majority of validators. + stateless-leader-election = false + ``` + + ABCI peer filtering has been removed. The deprecated `filter-peers` field in `config.toml` (under `[base]`) no longer has any effect and is no longer emitted in generated config templates. Tendermint no longer sends `/p2p/filter/addr/` or `/p2p/filter/id/` queries to the application, so peers can no longer be filtered by IP or node ID through the ABCI app. You can safely remove any `filter-peers` line from existing configs. From e3c6efc0adb4dd81d797ad01afdf00308dde6577 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:38:23 +0000 Subject: [PATCH 32/81] docs: The consensus config field 'stateless-leader-election' now defaults to true instead of false, changing the disaster recovery coordination requirement. (sei-protocol/sei-chain#3318) --- node/technical-reference.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 1888508..6a8801f 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -237,15 +237,15 @@ double_sign_check_height = 0 - The `[consensus]` section also supports a temporary disaster-recovery flag, `stateless-leader-election` (default `false`). When enabled, the consensus engine selects each round's leader via a deterministic stateless computation instead of the traditional stateful proposer-priority selection. + The `[consensus]` section also supports a temporary disaster-recovery flag, `stateless-leader-election` (default `true`). When enabled, the consensus engine selects each round's leader via a deterministic stateless computation instead of the traditional stateful proposer-priority selection. - This flag is intended **only** as an emergency recovery mechanism in the event of a chain stall, and it **requires coordination of a majority of validators** to be set to `true` together. If you set `stateless-leader-election = true` for only your own node, that node will be unable to participate in consensus and will effectively isolate itself from the network. Leave this set to `false` under normal operation. + This flag is intended **only** as an emergency recovery mechanism in the event of a chain stall. Disabling it **requires coordination of a majority of validators** to be set to `false` together. If you set `stateless-leader-election = false` for only your own node, that node will be unable to participate in consensus and will effectively isolate itself from the network. Leave this set to `true` under normal operation. ```toml [consensus] - # Temporary disaster-recovery leader-election mechanism. Defaults to false. - # Only enable with coordination of a majority of validators. - stateless-leader-election = false + # Temporary disaster-recovery leader-election mechanism. Defaults to true. + # Only disable with coordination of a majority of validators. + stateless-leader-election = true ``` From df43180dbef1ff6aab586889e659386d236b3344 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:39:11 +0000 Subject: [PATCH 33/81] docs: Adds a new `dump-flatkv` subcommand to the seidb tool and a `--flatkv-dir` flag to the `state-size` command for analyzing FlatKV stores, plus improved state-size console output. (sei-protocol/sei-chain#3312) --- learn/seidb.mdx | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/learn/seidb.mdx b/learn/seidb.mdx index c212deb..2aa2cd6 100644 --- a/learn/seidb.mdx +++ b/learn/seidb.mdx @@ -257,3 +257,46 @@ The command writes two files to the output directory: - **`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. 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. + + + +## 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 at version `) followed by one `Key: , Value: ` line per physical row. Physical keys are emitted verbatim, including their `/` 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 +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, `/data/committer.db` → `/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 `/../flatkv` | FlatKV data directory. When unset, a sibling `flatkv/` directory next to `--db-dir` is auto-detected. | + From 53c5d9b56fd49fc4030f6b26f712e1128f0baac3 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:41:11 +0000 Subject: [PATCH 34/81] docs: The `stateless-leader-election` consensus config field is now deprecated and ignored; stateless leader election is always enabled. (sei-protocol/sei-chain#3319) --- node/technical-reference.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 6a8801f..06eeca7 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -237,14 +237,14 @@ double_sign_check_height = 0 - The `[consensus]` section also supports a temporary disaster-recovery flag, `stateless-leader-election` (default `true`). When enabled, the consensus engine selects each round's leader via a deterministic stateless computation instead of the traditional stateful proposer-priority selection. + The `[consensus]` section still parses a `stateless-leader-election` field, but it is now **deprecated and ignored**. Stateless leader election is always enabled: the consensus engine always selects each round's leader via a deterministic seeded stateless computation. The former stateful proposer-priority leader-election mode is no longer supported. - This flag is intended **only** as an emergency recovery mechanism in the event of a chain stall. Disabling it **requires coordination of a majority of validators** to be set to `false` together. If you set `stateless-leader-election = false` for only your own node, that node will be unable to participate in consensus and will effectively isolate itself from the network. Leave this set to `true` under normal operation. + The field is retained only for config-parsing compatibility. Setting it to `false` no longer has any effect — it will not fall back to proposer-priority selection. You can safely remove any `stateless-leader-election` line from existing `config.toml` files. ```toml [consensus] - # Temporary disaster-recovery leader-election mechanism. Defaults to true. - # Only disable with coordination of a majority of validators. + # Deprecated and ignored. Stateless leader election is always enabled; + # setting this to false has no effect. stateless-leader-election = true ``` From fd5327f41bfdf47c458e95e92bc84f1c58ceddad Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:41:59 +0000 Subject: [PATCH 35/81] docs: The eth_feeHistory JSON-RPC endpoint now returns baseFeePerGas with one extra element (the projected child base fee) to match Ethereum's execution-apis spec, and uses the block header base fee for each block. (sei-protocol/sei-chain#3321) --- evm/reference.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/reference.mdx b/evm/reference.mdx index 8c34d22..ec670ff 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -699,7 +699,7 @@ Every method below is also browsable interactively in the explorer above; this s **Supported.** Returns base fees, gas-used ratios, and reward percentile data over a range of blocks. -**Sei-specific behavior:** Base fees and rewards reflect Sei's x/evm fee market (GetNextBaseFee), not an Ethereum EIP-1559 mempool, and Sei does not burn the base fee. Watermark-aware: pruned/historical blocks may not be available as far back as on Ethereum archive nodes. +**Sei-specific behavior:** Base fees and rewards reflect Sei's x/evm fee market, not an Ethereum EIP-1559 mempool, and Sei does not burn the base fee. Each block's base fee is the block-header base fee (derived from `GetNextBaseFee` at the parent committed height), matching the value reported by the block header and transactions. Following the execution-apis/go-ethereum spec, `baseFeePerGas` contains one more element than `gasUsedRatio` (`len(baseFeePerGas) == len(gasUsedRatio) + 1`): the trailing element is the projected base fee for the child of the newest block in the requested range. Watermark-aware: pruned/historical blocks may not be available as far back as on Ethereum archive nodes, and heights that lack a header base fee (pruned or partial data) are skipped. **Parameters:** From 478fe3cb263e58be23d92cc8f543b0a1a78d682a Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:44:17 +0000 Subject: [PATCH 36/81] docs: Under Autobahn consensus, the Tendermint RPC endpoints /block, /block_by_hash, /block_results, and /validators now serve data by routing through the GigaRouter's in-memory state instead of the unpopulated CometBFT BlockStore/StateStore, changing their behavior and limitations under Autobahn. (sei-protocol/sei-chain#3310) --- evm/reference.mdx | 11 ++++++++- node/node-operators.mdx | 45 +++++++++++++++++++++++++++++------- node/technical-reference.mdx | 8 ++++++- 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/evm/reference.mdx b/evm/reference.mdx index ec670ff..743f024 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -745,7 +745,16 @@ Every method below is also browsable interactively in the explorer above; this s **Sei-specific behavior:** The `sync_info` object now includes an additional field, `last_committed_block_height` — the height of the last block finalized by consensus, serialized as a JSON string-encoded `int64`. Under standard CometBFT consensus this always equals `latest_block_height`, because a block's commit and app-apply happen in a single step. Under Autobahn consensus the two can briefly differ: consensus finalizes a block (advancing `last_committed_block_height`, derived from the latest `CommitQC`) before the app executes it, so the invariant is `last_committed_block_height >= latest_block_height`. -**Autobahn `/status` behavior.** When a node runs under Autobahn (i.e. `AutobahnConfigFile` is set), the CometBFT block store is not populated, so `/status` derives `latest_block_height` and `latest_app_hash` from the app layer (via `ABCIInfo`) instead of the block store. Several other `sync_info` fields remain unpopulated under Autobahn and should not be relied on: `latest_block_hash`, `latest_block_time`, the `earliest_*` fields, and `max_peer_block_height`; `catching_up` is currently hardcoded to `true`. Additionally, block-data endpoints such as `/block`, `/block_results`, `/commit`, and the EVM endpoints that walk through them (e.g. `eth_getBlockByNumber`) still fail under Autobahn because the block store height reports `0`. +**Autobahn `/status` behavior.** When a node runs under Autobahn (i.e. `AutobahnConfigFile` is set), the CometBFT block store is not populated, so `/status` derives `latest_block_height` and `latest_app_hash` from the app layer (via `ABCIInfo`) instead of the block store. Several other `sync_info` fields remain unpopulated under Autobahn and should not be relied on: `latest_block_hash`, `latest_block_time`, the `earliest_*` fields, and `max_peer_block_height`; `catching_up` is currently hardcoded to `true`. + +Block-data endpoints are now served under Autobahn by routing through the GigaRouter's in-memory state (data.State) instead of the unpopulated CometBFT block store, though with some limitations: + +- `/block` returns the translated finalized block at the requested height (`BlockID.Hash`, `ChainID`, `Height`, `Time`, and `Data.Txs` are populated; fields such as `AppHash`, `ProposerAddress`, and `LastCommit` stay at zero values). +- `/block_by_hash` resolves by hash for heights within the retain window; hashes below the pruning watermark or otherwise unknown return an empty block (`{Block: nil}`) with no error, matching CometBFT semantics. +- `/block_results` returns the requested height with `ConsensusParamUpdates.Block.MaxGas` populated from the producer config, but `TxsResults` is intentionally empty because `FinalizeBlock` responses are not persisted under Autobahn (no per-tx `ExecTxResult` details). +- `/validators` returns the genesis committee for any retained height, with `block_height` matching the requested height (fixing the prior behavior where it could report a stale/stuck height). + +EVM endpoints that walk through these (e.g. `eth_getBlockByNumber`) therefore work under Autobahn, rendering the block envelope correctly — just without per-tx result details from `/block_results`. `/commit` remains unpopulated under Autobahn. #### `web3_clientVersion` diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 1ed76f6..0cac6c2 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -221,14 +221,43 @@ following `SyncInfo` fields are not currently populated under Autobahn: `latest_block_hash`, `latest_block_time`, all `earliest_*` fields, and `max_peer_block_height`. `catching_up` is hardcoded to `true`. - - Block-data RPC endpoints remain unavailable under Autobahn. Because the - CometBFT block store height stays at `0`, `/block`, `/block_results`, - `/commit`, and the EVM RPC endpoints that walk through them (for example - `eth_getBlockByNumber` and `eth_gasPrice`) still fail on Autobahn nodes. - Plan your monitoring and tooling accordingly until block-data reads are - routed through an Autobahn-aware path. - +**Block-data RPC endpoints under Autobahn** + +The CometBFT block store and state store are not populated under Autobahn. +Instead, `/block`, `/block_by_hash`, `/block_results`, and `/validators` are +now served by routing through the GigaRouter's in-memory finalized state, so +these endpoints return real data on Autobahn nodes (previously they returned +nil/empty because the block store height stayed at `0`). Downstream consumers +such as the EVM RPC endpoints (for example `eth_getBlockByNumber`) that walk +through these endpoints keep working as a result. + +Be aware of the following Autobahn-specific limitations: + +- **`/block`** returns the finalized block translated from Autobahn's + in-memory state at the requested height. Only a subset of the CometBFT + block fields are populated (block ID hash, chain ID, height, time, and the + transaction list); fields such as `AppHash`, `ProposerAddress`, and + `LastCommit` stay at their zero values. +- **`/block_by_hash`** resolves a block by its header hash via an in-memory + hash index that tracks the same retain window as `/block`. Unknown hashes, + or hashes below the pruning watermark, return an empty block + (`{"block": null}`) with no error, matching CometBFT semantics. +- **`/block_results`** returns a valid-but-empty result at the requested + height: `TxsResults` is intentionally empty because `FinalizeBlock` + responses are not persisted under Autobahn, but + `ConsensusParamUpdates.Block.MaxGas` is populated from the producer's + `max_gas_per_block` config so consumers relying on the gas limit keep + working. Per-transaction execution details are not available. +- **`/validators`** returns the genesis committee for any retained height, + with `block_height` matching the requested height. (This fixes the prior + behavior where the height could get stuck at `1` due to the unpopulated + state store.) + + + Requesting a height that has already been pruned out of Autobahn's retain + window returns an `ErrHeightNotAvailable`-class error, mirroring the + CometBFT path so external tooling sees consistent error shapes. + | `block_interval` | Target interval between blocks. Must be `> 0`. | | `allow_empty_blocks` | Whether to produce blocks when there are no transactions. | | `view_timeout` | Consensus view timeout. Must be `> 0`. | diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 06eeca7..f445c15 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -321,7 +321,13 @@ Because the CometBFT block store and consensus reactor are not fed under Autobah - **`/status` derives height and app hash from the app layer:** With Autobahn enabled the CometBFT block store height stays at 0, so the `/status` handler pulls `SyncInfo.latest_block_height` and `SyncInfo.latest_app_hash` from the application layer (via `ABCIInfo`) instead of the block store. This reports the last height the app committed in `FinalizeBlock` and its matching app hash. - **New `last_committed_block_height` field:** The `SyncInfo` object in the `/status` response now includes a `last_committed_block_height` field (JSON string-encoded int64) reporting the last block finalized by consensus. Under CometBFT this always equals `latest_block_height` (commit and app-apply happen in one step). Under Autobahn it is derived from the latest CommitQC and may briefly lead `latest_block_height`, since consensus finalizes a block before the app executes it. - **Unpopulated `/status` fields:** Several `SyncInfo` fields remain unpopulated under Autobahn: `latest_block_hash`, `latest_block_time`, the `earliest_*` fields, and `max_peer_block_height`. `catching_up` is currently hardcoded to `true` because the consensus reactor is nil. -- **Block-data endpoints still fail:** Endpoints that read from the CometBFT block store — including `/block`, `/block_results`, `/commit`, and the EVM RPC endpoints that walk through them (`eth_getBlockByNumber`, `eth_gasPrice`, etc.) — still fail under Autobahn because the block store height is 0. +- **Block-data endpoints now serve data via the GigaRouter:** Because the CometBFT block store and state store are not populated under Autobahn, `/block`, `/block_by_hash`, `/block_results`, and `/validators` are routed through the GigaRouter's in-memory state instead of the block store. This keeps these endpoints — and the EVM RPC endpoints that walk through them (e.g. `eth_getBlockByNumber`) — working, with the following caveats: + - **`/block`** returns the finalized global block at the requested height, translated into the CometBFT `ResultBlock` shape (populating `BlockID.Hash`, `ChainID`, `Height`, `Time`, and `Data.Txs`). Requests for pruned heights return an `ErrHeightNotAvailable`-class error. + - **`/block_by_hash`** resolves a block by its Autobahn header hash via an in-memory hash index. Matching CometBFT semantics, an unknown hash — or a hash below the pruning watermark — returns `{Block: nil}` with no error. + - **`/block_results`** returns a valid-but-empty result at the requested height. `ConsensusParamUpdates.Block.MaxGas` is populated from the producer's configured `max_gas_per_block`, but `TxsResults` is intentionally empty because `FinalizeBlock` responses are not persisted under Autobahn (no per-tx `ExecTxResult` details). + - **`/validators`** returns the genesis committee for any retained height, with `block_height` matching the requested height (fixing the prior behavior where the height could get stuck at 1). + + Note that these endpoints read from the GigaRouter's in-memory state, which is pruned according to the node's retain height; historical queries below the retain window are not available. Endpoints that still depend on the unpopulated CometBFT block/state store — such as `/commit` — remain unaffected by this routing and behave as before. #### Hard Per-Block Limits From a21c92737cd030002c698e64746704b2c55276fe Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:45:53 +0000 Subject: [PATCH 37/81] docs: The Autobahn config field max_gas_per_block was removed; the producer's max-gas-per-block is now sourced from genesis consensus_params.block.max_gas, and eth_getBlockByNumber gasLimit now reflects the active consensus params. (sei-protocol/sei-chain#3341) --- evm/reference.mdx | 4 +++- learn/sei-giga-specs.mdx | 6 ++++++ node/node-operators.mdx | 1 - node/technical-reference.mdx | 6 ++++-- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/evm/reference.mdx b/evm/reference.mdx index 743f024..16961c9 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -751,7 +751,9 @@ Block-data endpoints are now served under Autobahn by routing through the GigaRo - `/block` returns the translated finalized block at the requested height (`BlockID.Hash`, `ChainID`, `Height`, `Time`, and `Data.Txs` are populated; fields such as `AppHash`, `ProposerAddress`, and `LastCommit` stay at zero values). - `/block_by_hash` resolves by hash for heights within the retain window; hashes below the pruning watermark or otherwise unknown return an empty block (`{Block: nil}`) with no error, matching CometBFT semantics. -- `/block_results` returns the requested height with `ConsensusParamUpdates.Block.MaxGas` populated from the producer config, but `TxsResults` is intentionally empty because `FinalizeBlock` responses are not persisted under Autobahn (no per-tx `ExecTxResult` details). +- `/block_results` returns the requested height with `ConsensusParamUpdates.Block.MaxGas` populated from the genesis `consensus_params.block.max_gas` (the same gas-limit value the producer's `MaxGasPerBlock` is derived from), but `TxsResults` is intentionally empty because `FinalizeBlock` responses are not persisted under Autobahn (no per-tx `ExecTxResult` details). + +Note: `eth_getBlockByNumber`'s `gasLimit` field is sourced from the active consensus params in the SDK context (`ctx.ConsensusParams().Block.MaxGas`) rather than from `blockRes.ConsensusParamUpdates`. This means the reported `gasLimit` matches the value the EVM runtime returns for the `GASLIMIT` opcode, and stays consistent under Autobahn where `/block_results` only synthesizes a placeholder. - `/validators` returns the genesis committee for any retained height, with `block_height` matching the requested height (fixing the prior behavior where it could report a stale/stuck height). EVM endpoints that walk through these (e.g. `eth_getBlockByNumber`) therefore work under Autobahn, rendering the block envelope correctly — just without per-tx result details from `/block_results`. `/commit` remains unpopulated under Autobahn. diff --git a/learn/sei-giga-specs.mdx b/learn/sei-giga-specs.mdx index 2bbb5ba..0e8785b 100644 --- a/learn/sei-giga-specs.mdx +++ b/learn/sei-giga-specs.mdx @@ -70,6 +70,10 @@ The specifications are organized to clearly distinguish between what is currentl When a node runs with Autobahn (Sei Giga) consensus enabled, the block producer builds payloads by reaping transactions directly from the shared mempool, subject to hard on-chain block size constraints that are enforced during payload construction. +The block gas limit is no longer a configurable Autobahn field. The producer's `MaxGasPerBlock` is derived directly from the genesis `consensus_params.block.max_gas` value — the same gas limit the EVM runtime reads via `ctx.ConsensusParams().Block.MaxGas`. This ensures `eth_getBlockByNumber`'s reported `gasLimit` matches the `GASLIMIT` opcode value seen during execution. The `max_gas_per_block` field has been removed from the Autobahn config file, so it should be omitted from existing configs. + +Genesis `consensus_params.block.max_gas` must be a positive value. If it is missing or non-positive, node startup fails with `ErrGenesisMaxGasInvalid` (`genesis consensus_params.block.max_gas must be > 0`). + @@ -77,10 +81,12 @@ When a node runs with Autobahn (Sei Giga) consensus enabled, the block producer | --- | --- | | Max transactions per block | 2000 (`MaxTxsPerBlock`) | | Max total tx bytes per block | ~2 MB (`MaxTxsBytesPerBlock` = 2000 × 1024) | + | Max gas per block | Derived from genesis `consensus_params.block.max_gas` (`MaxGasPerBlock`) | | Block proto size bound | Derived from `MaxTxsPerBlock` and `MaxTxsBytesPerBlock` (`MaxBlockProtoSize`) | - Total tx bytes may be split arbitrarily across transactions (one large tx or many small ones), up to the `MaxTxsPerBlock` limit. + - The block gas limit is sourced from genesis `consensus_params.block.max_gas`; genesis must set this to a value greater than zero or the node will refuse to start. - Limits are validated when the payload is built; payloads exceeding the transaction count or total byte limit are rejected. - The block proto size bound derives an upper limit on the encoded block used to size networking message windows. diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 0cac6c2..c4452e5 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -159,7 +159,6 @@ The referenced JSON file supports the following fields: "address": "host:port" } ], - "max_gas_per_block": 50000000, "max_txs_per_block": 5000, "max_txs_per_second": 1000, "mempool_size": 20000, diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index f445c15..20e74cf 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -277,7 +277,6 @@ When Autobahn is enabled, the referenced JSON file supports the following fields "address": "host:port" } ], - "max_gas_per_block": 50000000, "max_txs_per_block": 5000, "max_txs_per_second": 1000, "mempool_size": 20000, @@ -289,10 +288,13 @@ When Autobahn is enabled, the referenced JSON file supports the following fields } ``` + + The `max_gas_per_block` field has been removed from the Autobahn config file. The producer's max-gas-per-block is now derived from the chain's genesis `consensus_params.block.max_gas` — the same gas-limit consensus rule the EVM runtime reads. This value must be greater than 0, otherwise the node fails to start with an `ErrGenesisMaxGasInvalid` error (`genesis consensus_params.block.max_gas must be > 0`). Node operators upgrading from an earlier release must remove any `max_gas_per_block` line from their Autobahn config file. + + | Field | Description | | --- | --- | | `validators` | List of committee members, each with a `validator_key`, `node_key`, and `address`. Must not be empty. | -| `max_gas_per_block` | Maximum gas allowed per block. Must be greater than 0. | | `max_txs_per_block` | Maximum number of transactions per block. Must be greater than 0. | | `max_txs_per_second` | Optional cap on transactions per second. | | `mempool_size` | Maximum mempool size. Must be greater than 0. | From 422da2ed9212f6558ccf7ebdeb47b67b290d5d46 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 03:46:39 +0000 Subject: [PATCH 38/81] docs: The v6.5 release changelog references several developer-facing changes including a new consolidated evm-ss-mode config, an EVM RPC behavior fix for out-of-range indices, and StatelessLeaderElection now defaulting to true. (sei-protocol/sei-chain#3377) --- node/node-operators.mdx | 10 ++++------ node/technical-reference.mdx | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/node/node-operators.mdx b/node/node-operators.mdx index c4452e5..07d48b9 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -431,13 +431,11 @@ sc-snapshot-prefetch-threshold = 0.8 # Maximum snapshot write rate in MB/s (global across all trees). 0 = unlimited. Default 100. sc-snapshot-write-rate-mbps = 100 -# WriteMode defines the write routing mode for EVM data in the SC layer. +# EVMSSMode consolidates the previous separate SC-layer EVM write/read routing +# modes (sc-write-mode / sc-read-mode) into a single setting. It controls how +# EVM state store data is written and read. # Valid values: cosmos_only, dual_write, split_write -sc-write-mode = "cosmos_only" - -# ReadMode defines the read routing mode for EVM data in the SC layer. -# Valid values: cosmos_only, evm_first, split_read -sc-read-mode = "cosmos_only" +evm-ss-mode = "cosmos_only" # EnableLatticeHash controls whether lattice hash participates in the final app hash. # Must be enabled when using split_write mode. diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 20e74cf..e5637a3 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -239,7 +239,7 @@ double_sign_check_height = 0 The `[consensus]` section still parses a `stateless-leader-election` field, but it is now **deprecated and ignored**. Stateless leader election is always enabled: the consensus engine always selects each round's leader via a deterministic seeded stateless computation. The former stateful proposer-priority leader-election mode is no longer supported. - The field is retained only for config-parsing compatibility. Setting it to `false` no longer has any effect — it will not fall back to proposer-priority selection. You can safely remove any `stateless-leader-election` line from existing `config.toml` files. + Historically `stateless-leader-election` defaulted to `false`, selecting leaders via the stateful proposer-priority mode. As of v6.5 stateless leader election defaults to `true`, and the field is now retained only for config-parsing compatibility. Setting it to `false` no longer has any effect — it will not fall back to proposer-priority selection. You can safely remove any `stateless-leader-election` line from existing `config.toml` files. ```toml [consensus] From 2046204a816195551e47ebdad6c54d5edd931e58 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:02:13 +0000 Subject: [PATCH 39/81] docs: Fixed EVM transaction receipts to report the correct EIP-1559 effective gas price (min(baseFee+tip, maxFee)) instead of the fee cap for dynamic-fee transactions. (sei-protocol/sei-chain#3384) --- evm/evm-parity/gas-and-fees.mdx | 8 ++++++++ evm/transactions.mdx | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/evm/evm-parity/gas-and-fees.mdx b/evm/evm-parity/gas-and-fees.mdx index f4665b5..5827302 100644 --- a/evm/evm-parity/gas-and-fees.mdx +++ b/evm/evm-parity/gas-and-fees.mdx @@ -53,6 +53,14 @@ const feeData = await provider.getFeeData(); + +### Effective Gas Price on Receipts + +For dynamic-fee (type 2) transactions, the transaction receipt's `effectiveGasPrice` field reports the **actual price charged** — `min(baseFee + maxPriorityFeePerGas, maxFeePerGas)` — not the fee cap. This matches standard EIP-1559 semantics, so clients such as ethers and hardhat see the same `effectiveGasPrice` behavior they expect from Ethereum. + +In practice, when your priority tip plus the base fee stays below `maxFeePerGas`, the receipt reports `baseFee + maxPriorityFeePerGas` rather than `maxFeePerGas`. Use the receipt's `effectiveGasPrice` (not `maxFeePerGas`) when computing what a transaction actually paid. + + ## SSTORE Cost The gas cost of `SSTORE` (writing to contract storage) is governance-adjustable on Sei. It is currently **72,000 gas** — the same on mainnet and testnet (see [Divergence from Ethereum](/evm/differences-with-ethereum#sstore-gas-cost)) — but treat that as the current value, not a constant: do not hard-code storage write estimates in your application. diff --git a/evm/transactions.mdx b/evm/transactions.mdx index 6b9861b..d9eacbe 100644 --- a/evm/transactions.mdx +++ b/evm/transactions.mdx @@ -258,7 +258,7 @@ EVM transactions in Sei follow the Ethereum transaction format with standard pro "logs": [], "status": "0x1", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "effectiveGasPrice": "0x1234", + "effectiveGasPrice": "0x77359400", "type": "0x2" } } From 1cea9868b20a1bf1630a978cd90bbf0b941121fa Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:03:25 +0000 Subject: [PATCH 40/81] docs: Adds new OpenTelemetry-based EVM RPC metrics (evmrpc_request_latency_seconds histogram and evmrpc_websocket_connects_total counter) emitted alongside legacy sei_* metrics, which node operators monitoring RPC would need to know about. (sei-protocol/sei-chain#3265) --- node/advanced-config-monitoring.mdx | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/node/advanced-config-monitoring.mdx b/node/advanced-config-monitoring.mdx index 0aa2608..22eb77c 100644 --- a/node/advanced-config-monitoring.mdx +++ b/node/advanced-config-monitoring.mdx @@ -490,6 +490,37 @@ groups: Each checkpoint also writes a `proposer priority hash checkpoint` log line containing the full 32-byte hash and the packed value, which can be used for grep-based comparison across nodes. + + +## EVM RPC Metrics + +Sei nodes emit OpenTelemetry-based metrics for the EVM JSON-RPC layer through the process-wide `MeterProvider` (for example, a Prometheus exporter). These `evmrpc_*` metrics are the recommended source for monitoring RPC performance and websocket activity. + +| Metric | Type | Description | +| --- | --- | --- | +| `evmrpc_request_latency_seconds` | histogram | RPC request latency in seconds, labeled by endpoint, connection, success, error class, and JSON-RPC code bucket. | +| `evmrpc_websocket_connects_total` | counter | Number of new websocket connections. | + +### `evmrpc_request_latency_seconds` labels + +| Label | Description | +| --- | --- | +| `endpoint` | The RPC method being served (e.g. `eth_call`, `eth_getBalance`). | +| `connection` | The connection type serving the request (e.g. `http`, `websocket`). | +| `success` | Boolean indicating whether the request completed without error or panic. | +| `error_class` | Low-cardinality classification of the failure. Empty for successful requests. Possible values: `panic`, `execution_reverted`, `evm_not_supported`, `sei_legacy_disabled`, `association_missing`, `jsonrpc_error`, `unknown`. | +| `jsonrpc_code` | Bucketed JSON-RPC error code. Empty when there is no code (success or an untyped error). Possible values: `spec` (predefined codes `-32700`..`-32600`), `server` (server-defined codes `-32099`..`-32000`), and `other`. | + +The histogram uses the following explicit bucket boundaries (in seconds): + +``` +0.0005, 0.001, 0.0025, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30 +``` + +### Legacy metric deprecation + +The legacy `sei_*` RPC metrics — including `sei_rpc_request_latency_ms` and `sei_websocket_connect` — are still emitted alongside the new `evmrpc_*` metrics for backward compatibility, but they are deprecated and scheduled for removal (PLT-326) once dashboards migrate to the OpenTelemetry `evmrpc_*` metrics. When building or updating dashboards and alerts, prefer the `evmrpc_request_latency_seconds` histogram and `evmrpc_websocket_connects_total` counter over their legacy counterparts. + Prometheus gauges are held in memory, so after a process restart these gauges reset to zero until the next emission at the following multiple of 1024 heights (up to roughly 8.5 minutes of stale or zero data). This is expected for a monitoring signal that is only consulted in response to incidents. From 6430ab473a843b5b99d7e1fa1e911ea38c1462e2 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:04:38 +0000 Subject: [PATCH 41/81] docs: FlatKV state DB adds a suite of OpenTelemetry metrics and introduces an EnablePebbleMetrics config knob that overrides per-DB metrics settings. (sei-protocol/sei-chain#3366) --- node/advanced-config-monitoring.mdx | 48 +++++++++++++++++++++++++++++ node/node-operators.mdx | 9 ++++++ 2 files changed, 57 insertions(+) diff --git a/node/advanced-config-monitoring.mdx b/node/advanced-config-monitoring.mdx index 22eb77c..8c65e78 100644 --- a/node/advanced-config-monitoring.mdx +++ b/node/advanced-config-monitoring.mdx @@ -521,6 +521,54 @@ The histogram uses the following explicit bucket boundaries (in seconds): The legacy `sei_*` RPC metrics — including `sei_rpc_request_latency_ms` and `sei_websocket_connect` — are still emitted alongside the new `evmrpc_*` metrics for backward compatibility, but they are deprecated and scheduled for removal (PLT-326) once dashboards migrate to the OpenTelemetry `evmrpc_*` metrics. When building or updating dashboards and alerts, prefer the `evmrpc_request_latency_seconds` histogram and `evmrpc_websocket_connects_total` counter over their legacy counterparts. + + +## FlatKV State DB Metrics + +Sei nodes emit OpenTelemetry-based metrics for the FlatKV state database through the process-wide `MeterProvider` (for example, a Prometheus exporter). These `flatkv_*` metrics let operators observe FlatKV performance and progress across commits, catchup, snapshots, rollbacks, and snapshot imports. + +### Latency metrics + +Each latency metric is a histogram reported in seconds (unit `s`). Unless otherwise noted, they carry a `success` boolean label indicating whether the operation completed without error. + +| Metric | Type | Labels | Description | +| --- | --- | --- | --- | +| `flatkv_open_latency` | histogram | `success`, `read_only` | Time taken to open the FlatKV store (`LoadVersion`). | +| `flatkv_apply_changesets_latency` | histogram | `success` | Time taken to apply changesets to FlatKV. | +| `flatkv_commit_latency` | histogram | `success` | Time taken to commit FlatKV changes. | +| `flatkv_commit_batch_latency` | histogram | `success`, `db` | Time taken to commit a per-DB PebbleDB batch. | +| `flatkv_batch_read_old_values_latency` | histogram | `success` | Time taken to batch read old FlatKV values. | +| `flatkv_catchup_latency` | histogram | `success` | Time taken to replay FlatKV WAL entries during catchup. | +| `flatkv_snapshot_write_latency` | histogram | `success` | Time taken to write a FlatKV snapshot. | +| `flatkv_snapshot_prune_latency` | histogram | — | Time taken to prune old FlatKV snapshots. | +| `flatkv_rollback_latency` | histogram | `success` | Time taken to roll back FlatKV state. | +| `flatkv_import_latency` | histogram | `success` | Time taken to import FlatKV snapshot data. | +| `flatkv_import_worker_flush_latency` | histogram | `success`, `db` | Time taken to flush a FlatKV import worker batch. | +| `flatkv_flush_latency` | histogram | `success`, `db` | Time taken to flush a per-DB data DB. | + +### Counter metrics + +| Metric | Type | Labels | Description | +| --- | --- | --- | --- | +| `flatkv_num_kv_pairs` | counter | `db` | Number of key-value pairs applied to FlatKV. | +| `flatkv_catchup_replay_num_blocks` | counter | — | Number of FlatKV WAL entries replayed during catchup. | +| `flatkv_snapshot_prune_attempts` | counter | `success` | Total number of FlatKV snapshot prune attempts. | +| `flatkv_import_kv_pairs` | counter | `db` | Number of key-value pairs imported into FlatKV. | + +### Gauge metrics + +| Metric | Type | Labels | Description | +| --- | --- | --- | --- | +| `flatkv_pending_writes` | gauge | `db` | Current number of pending FlatKV writes per data DB. | +| `flatkv_current_version` | gauge | — | Current committed FlatKV version. | +| `flatkv_current_snapshot_height` | gauge | — | Current FlatKV snapshot height. | + +The `db` label identifies the underlying data DB (for example, the account, storage, code, or legacy data directory), letting operators break down applied writes, pending writes, batch commits, and flush latency per DB. + + + Emission of Pebble's own internal metrics is controlled separately by the FlatKV-level `EnablePebbleMetrics` configuration knob. When set, it overrides the per-DB `EnableMetrics` settings for all data DBs (account, code, storage, legacy, and metadata), so Pebble internal metrics are toggled uniformly rather than individually per DB. + + Prometheus gauges are held in memory, so after a process restart these gauges reset to zero until the next emission at the following multiple of 1024 heights (up to roughly 8.5 minutes of stale or zero data). This is expected for a monitoring signal that is only consulted in response to incidents. diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 07d48b9..e0936c2 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -471,6 +471,15 @@ snapshot-interval = 10000 # 0 = keep only the current snapshot. Default: 2. snapshot-keep-recent = 2 + + +# EnablePebbleMetrics is a single FlatKV-level knob that controls whether +# PebbleDB internal metrics are emitted for all FlatKV data DBs (account, +# code, storage, legacy, and metadata). During initialization this value +# overrides any per-DB EnableMetrics settings, so all data DBs share the same +# behavior. Default: false. +enable-pebble-metrics = false + ############################################################################### ### State Store Configuration ### ############################################################################### From d2efa592ca8dd72562cb40c1eb015209adc88bc0 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:05:42 +0000 Subject: [PATCH 42/81] docs: Introduces a new `mock_block_validation` build tag that produces a seid binary bypassing AppHash and DataHash block validation checks, published as a distinct Docker image tag. (sei-protocol/sei-chain#3401) --- node/index.mdx | 13 +++++++++++++ node/technical-reference.mdx | 23 +++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/node/index.mdx b/node/index.mdx index 3b7977a..c6eedb0 100644 --- a/node/index.mdx +++ b/node/index.mdx @@ -100,6 +100,19 @@ seid version See Network Versions table above for current recommended version. + + + + **Mock block validation builds are for testing/mock environments only — never run them in production.** Building with the `mock_block_validation` Go build tag produces a `seid` binary that bypasses `AppHash` and `DataHash` validation during block execution and validation. Default (production) builds always enforce every consensus check. + + ```bash + # Build a seid binary that skips AppHash/DataHash validation (testing only) + GO_BUILD_TAGS=mock_block_validation make install + ``` + + A dedicated Docker image is published for this build in ECR, tagged `sei/sei-chain:mock_block_validation-` (built with `GO_BUILD_TAGS=mock_block_validation`). Because these binaries skip integrity checks that guard against divergent or malformed state, they must not be used on mainnet, testnets, or any network carrying real value. + + Official Docker images are available at GitHub Container Registry. diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index e5637a3..cd69d91 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -347,6 +347,29 @@ In addition to the configurable `max_gas_per_block` and `max_txs_per_block` fiel ## Network Parameters + + +### Build Tags + +The `seid` binary can be compiled with optional Go build tags that alter consensus behavior. Build tags are passed via the `GO_BUILD_TAGS` build argument. + +#### `mock_block_validation` + +Building with `GO_BUILD_TAGS=mock_block_validation` produces a `seid` binary that bypasses `AppHash` and `DataHash` block validation checks during block execution and validation. This is controlled at compile time by the `ConsensusPolicy` type: production (default) builds enforce every check, while `mock_block_validation` builds have `ConsensusPolicy.SkipAppHashValidation()` and `ConsensusPolicy.SkipDataHashValidation()` return `true` unconditionally. + + + The `mock_block_validation` build is intended for testing and mock environments only. It disables cryptographic block-content validation and must never be used for a production or mainnet node. + + +A corresponding Docker image is published to ECR for this build: + +```text +sei/sei-chain:mock_block_validation- +``` + +This image is built with `GO_BUILD_TAGS=mock_block_validation` and is distinct from the standard `sei/sei-chain` image tags. + + Understanding network parameters helps you operate your node effectively. ### Chain Parameters From 72cade35267949b86f5bc2da9481a9a302bf2797 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:06:32 +0000 Subject: [PATCH 43/81] docs: Several advanced state-sync tuning knobs (backfill-blocks, backfill-duration, discovery-time, temp-dir, chunk-request-timeout, fetchers, verify-light-block-timeout, blacklist-ttl) are no longer emitted in the generated config.toml template, though they are still parsed if set explicitly. (sei-protocol/sei-chain#3352) --- node/statesync.mdx | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/node/statesync.mdx b/node/statesync.mdx index 2edde39..dcbb97d 100644 --- a/node/statesync.mdx +++ b/node/statesync.mdx @@ -96,6 +96,26 @@ cp -r $HOME/.sei/wasm $HOME/.sei_backup/ 2>/dev/null || true # ignore error if mkdir -p /home/ubuntu/statesync-temp sed -i 's|temp-dir = ""|temp-dir = "/home/ubuntu/statesync-temp"|' ~/.sei/config/config.toml + + +Recent versions of the chain no longer emit the advanced state-sync tuning knobs (`temp-dir`, `backfill-blocks`, `backfill-duration`, `discovery-time`, `chunk-request-timeout`, `fetchers`, `verify-light-block-timeout`, `blacklist-ttl`) in the generated `config.toml`. These fields are still parsed and honored if you add them manually, otherwise sensible defaults are used. + +Because `temp-dir = ""` may no longer be present in a freshly generated `config.toml`, the `sed` command above can silently do nothing. If you need a custom temp directory for snapshot chunk staging, add the field explicitly under the `[statesync]` section instead: + +```bash +mkdir -p /home/ubuntu/statesync-temp +# Append temp-dir under the [statesync] section only if it is not already present +if ! grep -qE '^\s*temp-dir\s*=' $HOME/.sei/config/config.toml; then + sed -i '/^\[statesync\]/a temp-dir = "/home/ubuntu/statesync-temp"' $HOME/.sei/config/config.toml +else + sed -i 's|^temp-dir = .*|temp-dir = "/home/ubuntu/statesync-temp"|' $HOME/.sei/config/config.toml +fi +``` + +Setting a custom `temp-dir` is optional; if omitted, state sync stages chunks in the system default temporary directory. + + + # Fetch the latest block height from the State Sync RPC endpoint LATEST_HEIGHT=$(curl -s $STATE_SYNC_RPC/block | jq -r .block.header.height) # Calculate the trust height (rounded down to the nearest 100,000) From f4aa326aa0a214ae27cad79fefc609cd895ba653 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:08:19 +0000 Subject: [PATCH 44/81] =?UTF-8?q?docs:=20New=20internal=20migration=20Writ?= =?UTF-8?q?eModes=20(MemiavlOnly,=20FlatKVOnly,=20TestOnlyDualWrite)=20and?= =?UTF-8?q?=20a=20BuildRouter=20entrypoint=20were=20added=20to=20the=20sei?= =?UTF-8?q?-db=20state=20migration=20package,=20expanding=20the=20memiavl?= =?UTF-8?q?=E2=86=92flatKV=20migration=20state=20machine=20that=20node=20o?= =?UTF-8?q?perators=20encounter=20during=20storage=20migration.=20(sei-pro?= =?UTF-8?q?tocol/sei-chain#3336)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node/giga-storage-migration.mdx | 34 +++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/node/giga-storage-migration.mdx b/node/giga-storage-migration.mdx index 62f14ea..19f8dc4 100644 --- a/node/giga-storage-migration.mdx +++ b/node/giga-storage-migration.mdx @@ -42,6 +42,40 @@ If you configure the SC layer to use `split_write` mode panics on creation with `lattice hash must be enabled when using split_write mode`. + + +The `sc-write-mode` / `sc-read-mode` fields above configure EVM routing in the +legacy composite commit store and are **distinct** from the internal +`memiavl → flatKV` **migration state machine** used when converting the SC +layer's state DB from `memiavl` to `flatKV`. That migration is driven by its +own `WriteMode` enum inside the state-migration package, not by +`sc-write-mode`. Node operators encounter these modes as the migration +progresses through a linear sequence of on-disk **migration versions**: + +| WriteMode | Migration version | Behavior | +|---|---|---| +| `MemiavlOnly` (`memiavl_only`) | 0 | Pre-migration baseline: every module routes to `memiavl`; `flatKV` is not in the data path (bootstrap passes `nil` for `flatKV`). | +| `MigrateEVM` (`migrate_evm`) | 0 → 1 | Migrates the `evm/` module from `memiavl` to `flatKV` in batches; un-migrated EVM keys still read from `memiavl`. | +| `EVMMigrated` (`evm_migrated`) | 1 | Steady state: `evm/` lives in `flatKV`, every other module in `memiavl`; no migration manager in the path. | +| `MigrateAllButBank` (`migrate_all_but_bank`) | 1 → 2 | Migrates every module except `bank/` (and the already-migrated `evm/`) from `memiavl` to `flatKV`. | +| `AllMigratedButBank` (`all_migrated_but_bank`) | 2 | Steady state: everything except `bank/` lives in `flatKV`; `bank/` remains in `memiavl`. | +| `MigrateBank` (`migrate_bank`) | 2 → 3 | Migrates the final `bank/` module from `memiavl` to `flatKV`. | +| `FlatKVOnly` (`flatkv_only`) | 3 | Terminal state: every module routes to `flatKV`; `memiavl` is not in the data path (bootstrap passes `nil` for `memiavl`). | +| `TestOnlyDualWrite` (`test_only_dual_write`) | — | Test-only mode that dual-writes `evm/` traffic to both `memiavl` and `flatKV` while routing all other modules to `memiavl`; reads, proofs, and iteration are served exclusively by `memiavl`. | + + +`TestOnlyDualWrite` exists only to preserve parity with legacy +composite-store dual-write tests and **must never be deployed to production +machines**. + + +The appropriate router for a given `WriteMode` is constructed by the +state-migration package's `BuildRouter` entrypoint, which returns the +steady-state or in-flight migration router for that mode. Router construction +requires a non-`nil` `memiavl` handle for every mode except `FlatKVOnly`, and a +non-`nil` `flatKV` handle for every mode except `MemiavlOnly`. + + This guide tracks the canonical procedure in [`docs/migration/giga_store_migration.md`](https://github.com/sei-protocol/sei-chain/blob/main/docs/migration/giga_store_migration.md) inside `sei-chain`. Open an issue there if anything here drifts. ## Prerequisites From f8897b65a623edcf54a02fbe57a0ff6baae5bd2d Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:09:22 +0000 Subject: [PATCH 45/81] docs: PebbleDB state store now uses a new descending-version MVCC encoding for freshly created DBs while transparently reading legacy ascending-encoded DBs, with a new on-disk sentinel key and a UseDefaultComparer config field affecting iteration behavior. (sei-protocol/sei-chain#3266) --- learn/seidb.mdx | 19 +++++++++++++++++++ node/node-operators.mdx | 10 ++++++++++ node/rocksdb-backend.mdx | 8 ++++++++ 3 files changed, 37 insertions(+) diff --git a/learn/seidb.mdx b/learn/seidb.mdx index 2aa2cd6..6cb8f99 100644 --- a/learn/seidb.mdx +++ b/learn/seidb.mdx @@ -107,6 +107,25 @@ Key optimization techniques include: - **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. diff --git a/node/node-operators.mdx b/node/node-operators.mdx index e0936c2..644edd1 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -533,6 +533,16 @@ evm-ss-split = false # When true, data is routed to separate DBs while preserving the same evm key prefix format. evm-ss-separate-dbs = false +# UseDefaultComparer controls how the state-store iterator advances to the next +# logical key when the PebbleDB backend uses the descending-version MVCC +# encoding (the default for freshly created DBs). When false, the iterator uses +# the MVCC comparer's ImmediateSuccessor to seek directly to the next logical +# key. When true, the iterator falls back to a scan-based advance that steps +# through entries until it reaches the next logical key. Only affects the +# descending fast path; legacy (ascending-encoded) DBs are unaffected. +# defaults to false +use-default-comparer = false + ############################################################################### ### Receipt Store Configuration ### ############################################################################### diff --git a/node/rocksdb-backend.mdx b/node/rocksdb-backend.mdx index 587b477..05098a4 100644 --- a/node/rocksdb-backend.mdx +++ b/node/rocksdb-backend.mdx @@ -26,6 +26,14 @@ By contrast, **RocksDB** supports native user-defined timestamps and optimized c In Sei’s benchmarks, RocksDB achieved up to **10–30× faster traceBlock iteration times** compared to PebbleDB, with even greater benefits observed on archive nodes. + + +### PebbleDB descending-version encoding + +Recent PebbleDB builds partly narrow this gap for latest-version reads. Because PebbleDB has no native MVCC, Sei encodes the version into each key. Freshly created PebbleDB state stores now use a **descending-version MVCC encoding**, which sorts newer versions before older ones for the same logical key. This lets latest-version reads land directly on the newest visible version instead of scanning through older versions, improving read performance on the fast path. Fresh stores are marked on disk with a sentinel key (`s/_mvcc_descending`) so the mode is detected automatically on open. + +Legacy PebbleDB stores written by earlier builds use the older **ascending-version encoding**. These are detected automatically on open and read using the legacy ascending path—no error is raised—but they stay unmarked and cannot benefit from the descending fast path unless the store is recreated or migrated. This mirrors the migration constraint on RocksDB: archive nodes that cannot recreate their state store will continue running on the slower legacy path. Note that even with descending encoding, PebbleDB still lacks native MVCC and column-family support, so RocksDB remains the recommended backend for iteration-heavy archive and long-history RPC workloads. + ## Example: TraceBlock Latency Comparison The following chart compares iteration (trace time) performance between **PebbleDB** and **RocksDB** over a 3 million block history: From 3f212a5b4d90dfd5b0d3a11e2beb53c390f7fdf2 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:10:15 +0000 Subject: [PATCH 46/81] docs: Adds a suite of new OpenTelemetry (Prometheus) metrics exposed by the node (e.g. app_abci_*_duration, app_tx_count, app_tx_gas, app_block_process_duration, app_build_info, app_pending_nonce, app_lightinvariance_supply_*) that operators can scrape for observability. (sei-protocol/sei-chain#3396) --- node/advanced-config-monitoring.mdx | 64 +++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/node/advanced-config-monitoring.mdx b/node/advanced-config-monitoring.mdx index 8c65e78..0177ddd 100644 --- a/node/advanced-config-monitoring.mdx +++ b/node/advanced-config-monitoring.mdx @@ -574,6 +574,70 @@ The `db` label identifies the underlying data DB (for example, the account, stor + +## App (ABCI) Metrics + +Sei nodes emit OpenTelemetry-based metrics for the application (ABCI) layer through the process-wide `MeterProvider` (for example, a Prometheus exporter). These `app_*` metrics let operators observe ABCI phase durations, transaction throughput and gas usage, block processing, and light invariance checks. They are the recommended source for application-level observability. + + + A set of legacy telemetry metrics (for example, the `abci`/`tx`/`sei_lightinvariance_supply` series) are still emitted alongside the new `app_*` metrics for backward compatibility, but they are deprecated and scheduled for removal (PLT-327) once dashboards migrate to the OpenTelemetry `app_*` metrics. When building or updating dashboards and alerts, prefer the `app_*` metrics over their legacy counterparts. + + +### ABCI phase duration metrics + +Each of these is a histogram reported in seconds (unit `s`), measuring the duration of the corresponding ABCI phase. + +| Metric | Type | Description | +| --- | --- | --- | +| `app_abci_begin_block_duration_seconds` | histogram | Duration of ABCI `BeginBlock`. | +| `app_abci_end_block_duration_seconds` | histogram | Duration of ABCI `EndBlock`. | +| `app_abci_module_end_block_duration_seconds` | histogram | Duration of module `EndBlock` calls within ABCI `EndBlock`. | +| `app_abci_check_tx_duration_seconds` | histogram | Duration of ABCI `CheckTx`. | +| `app_abci_deliver_tx_duration_seconds` | histogram | Duration of ABCI `DeliverTx`. | +| `app_abci_deliver_batch_tx_duration_seconds` | histogram | Duration of ABCI `DeliverTxBatch`. | +| `app_abci_commit_duration_seconds` | histogram | Duration of ABCI `Commit` (state write to disk). | + +### Block processing metric + +| Metric | Type | Attributes | Description | +| --- | --- | --- | --- | +| `app_block_process_duration_seconds` | histogram | `type` | Duration of block transaction processing by execution type. | + +The `type` attribute identifies the execution path: `synchronous`, `synchronous_giga`, `optimistic_concurrency`, or `occ_giga`. + +### Transaction counter metrics + +| Metric | Type | Attributes | Description | +| --- | --- | --- | --- | +| `app_tx_count_total` | counter | `result` | Number of transactions delivered, labeled by result (for example, `successful`). | +| `app_tx_process_type_total` | counter | `type` | Transactions processed by execution type (`synchronous`, `synchronous_giga`, `optimistic_concurrency`, `occ_giga`). | +| `app_tx_gas_total` | counter | `type` | Cumulative transaction gas, where `type` is `gas_used` or `gas_wanted`. | + +### App flow counter metrics + +| Metric | Type | Attributes | Description | +| --- | --- | --- | --- | +| `app_optimistic_processing_total` | counter | `enabled` | Optimistic processing attempts; `enabled:true` means the optimistic result was used, `false` means it was discarded. | +| `app_failed_total_gas_wanted_check_total` | counter | `proposer` | Proposals rejected because total block gas wanted exceeded the maximum; `proposer` is the hex-encoded proposer address. | +| `app_giga_fallback_to_v2_total` | counter | — | Number of times the giga executor fell back to V2 processing. | +| `app_pending_nonce_total` | counter | `event` | Pending nonce events, where `event` is `added`, `expired`, `rejected`, or `accepted`. | + +### Light invariance metrics + +| Metric | Type | Attributes | Description | +| --- | --- | --- | --- | +| `app_lightinvariance_supply_duration_seconds` | histogram | — | Duration of the light invariance total supply check. | +| `app_lightinvariance_supply_invalid_key_total` | counter | `type` | Invalid changed-pair keys detected during the invariance check (`type` is `sei` or `wei`). | +| `app_lightinvariance_supply_unmarshal_failure_total` | counter | `type`, `step` | Unmarshal failures during the invariance supply check (`type` is `usei`, `wei`, or `total_supply`; `step` is `pre_block` or `post_block`). | + +### Build info metric + +| Metric | Type | Attributes | Description | +| --- | --- | --- | --- | +| `app_build_info` | gauge | `seid_version`, `commit` | Running binary build info; the value is always `1`, with the running version and commit exposed as attributes. This observable gauge is populated by a scrape callback, so it reflects the currently running binary on every scrape. | + + + ## Backup Management From 4079ea8a27237eb7f8b8dade594b2be69f98659f Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:11:31 +0000 Subject: [PATCH 47/81] docs: Adds two new seidb subcommands (import-flatkv-from-memiavl and memiavl-latest-version) plus supporting FlatKV import/migration tooling for moving the EVM module from memiavl to FlatKV storage. (sei-protocol/sei-chain#3417) --- learn/seidb.mdx | 61 +++++++++++++++++++++ node/giga-storage-migration.mdx | 95 +++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) diff --git a/learn/seidb.mdx b/learn/seidb.mdx index 6cb8f99..be0b15c 100644 --- a/learn/seidb.mdx +++ b/learn/seidb.mdx @@ -319,3 +319,64 @@ FlatKV analysis is strictly additive: if the FlatKV directory is missing or the | `--db-dir` | `-d` | | memIAVL database directory. | | `--flatkv-dir` | | auto-detect `/../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. + +Run this command against a stopped node. It reads the on-disk memIAVL state directly and is intended for offline use. + +### Usage + +```bash +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. + +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. + +**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 +seidb import-flatkv-from-memiavl \ + --modules evm \ + --data-dir /path/to/.sei/data \ + --height \ + [--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. + +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`. + +### Migration configuration constraints + +When restarting a node after the import, keep `evm-ss-split = false` and `sc-enable-lattice-hash = 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. Turning `sc-enable-lattice-hash` on would fold the FlatKV LtHash into the AppHash for blocks that were committed before the import (whose persisted AppHash was memiavl-only), causing the replay check at startup to fail with an AppHash mismatch. + diff --git a/node/giga-storage-migration.mdx b/node/giga-storage-migration.mdx index 19f8dc4..f13029f 100644 --- a/node/giga-storage-migration.mdx +++ b/node/giga-storage-migration.mdx @@ -76,6 +76,101 @@ requires a non-`nil` `memiavl` handle for every mode except `FlatKVOnly`, and a non-`nil` `flatKV` handle for every mode except `MemiavlOnly`. + +## Offline FlatKV EVM import (MigrateEVM) + +The `seidb` tool ships an offline import path that moves the `evm/` module's +SC-layer data out of `memiavl` and into FlatKV without running the in-process +migration state machine. This is the operational entrypoint for the +`MigrateEVM` (V0 → V1) transition on a stopped node. + + +This is an **offline** operation. The node must be fully stopped before +running the import — the tool opens both the `memiavl` and FlatKV directories +directly and will conflict with a running `seid`. + + +### Reading the latest memiavl version + +Before importing, read the latest committed `memiavl` version from a stopped +node's data directory. In a multi-validator cluster, run this on every node +and pick the minimum so the import height is uniform across the cluster: + +```bash copy +seidb memiavl-latest-version --data-dir +``` + +`--data-dir` may point at either the `data/` directory or the Sei home +directory; if the basename is `data`, its parent is treated as home. You can +also pass `--home ` instead. + +### Running the import + +```bash copy +seidb import-flatkv-from-memiavl \ + --modules=evm \ + --data-dir \ + --height \ + [--force] +``` + +| Flag | Meaning | +|---|---| +| `--home` | Sei home directory. Defaults to `$HOME/.sei`. | +| `--data-dir` | Sei data directory or home directory. If the basename is `data`, its parent is used as home. | +| `--modules` | Comma-separated module names to import. Initial production scope is **evm-only**; any other module name is rejected. | +| `--height` | The `memiavl` version to import. `0` means latest. | +| `--force` | Overwrite existing committed FlatKV data. | + +The import resets FlatKV before loading the selected `memiavl` rows and +**refuses to overwrite committed FlatKV data unless `--force` is supplied**. If +an external error interrupts the import (context cancellation, exporter or +translator failure), the import is aborted rather than finalized — FlatKV is +left at its pre-import committed version, so the operation can be retried +without `--force`. + + +The import **must run at the memiavl latest version**. Importing FlatKV at a +height `H` lower than the latest `memiavl` version is rejected: on the next +`GIGA_STORAGE` startup the composite commit store's `reconcileVersions` step +would silently roll `memiavl` back to `H`, truncating every cosmos block in +`(H, latest]`. If you genuinely need a non-latest height, roll `memiavl` back +to that height yourself first (for example with `seid rollback`), then re-run +the import. The CLI deliberately does **not** roll `memiavl` back on your +behalf. A height ahead of the latest `memiavl` version is likewise rejected. + + +### Configuration constraints across the import boundary + +The import moves only the SC-layer EVM data into FlatKV. When restarting the +node after the import, two settings **must stay off** across the import +boundary or the node will panic on startup: + +- **`evm-ss-split = false`.** SS history for EVM remains in the existing + combined cosmos SS database; the import does not populate a separate EVM SS + directory. Flipping `evm-ss-split` to `true` triggers the rootmulti startup + panic *"EVM SS directory ... does not exist but Cosmos SS already has + history"*. Moving the SS layer to split mode is a separate state-sync + workflow (see [Step 2](#step-2%3A-state-sync-into-the-new-layout)) and is out + of scope for the offline SC import. +- **`sc-enable-lattice-hash = false`.** Before the import the chain ran without + FlatKV, so tendermint persisted app hashes computed from `memiavl` alone for + every block up to the import height. Enabling the lattice hash now would fold + the FlatKV LtHash into the app hash, and the replay check at startup would + fail with *"state.AppHash does not match AppHash after replay"*. Note that + `dual_write` does not require the lattice hash — only `split_write` does. + +A production rollout coordinates these transitions via a chain upgrade at an +agreed height rather than flipping them mid-life. + + +For the full operational failure-mode catalog and recovery/tooling roadmap for +MigrateEVM, see +[`sei-db/state_db/sc/migration/OPERATIONS.md`](https://github.com/sei-protocol/sei-chain/blob/main/sei-db/state_db/sc/migration/OPERATIONS.md) +in `sei-chain`. + + + This guide tracks the canonical procedure in [`docs/migration/giga_store_migration.md`](https://github.com/sei-protocol/sei-chain/blob/main/docs/migration/giga_store_migration.md) inside `sei-chain`. Open an issue there if anything here drifts. ## Prerequisites From 8dfaa3d79d50390444b01090fdf1747fd0ed540c Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:14:05 +0000 Subject: [PATCH 48/81] docs: Out-of-process ABCI support was removed: the 'proxy-app' and 'abci' config fields and the '--address'/'--transport' start flags are deprecated/ignored, and the node now always runs Tendermint in-process. (sei-protocol/sei-chain#3410) --- node/seictl.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/seictl.mdx b/node/seictl.mdx index 3b57536..f90adc4 100644 --- a/node/seictl.mdx +++ b/node/seictl.mdx @@ -264,7 +264,7 @@ Client-level configuration including: Node-level configuration including: -- Proxy app and database settings +- Database settings - Logging configuration - RPC and P2P settings - Mempool and consensus parameters From 2d6ef745774c1f26aca2e677bbeda687f20b3fd8 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:15:10 +0000 Subject: [PATCH 49/81] docs: The sei_getTransactionReceiptExcludeTraceFail (and *ExcludeTraceFail) endpoints changed their filtering logic so that reverted/OOG transactions are now included (they ran in the VM and have traces), while only ante-rejected and synthetic txs are excluded. (sei-protocol/sei-chain#3450) --- evm/reference.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/evm/reference.mdx b/evm/reference.mdx index 16961c9..7c4d8d8 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -1343,11 +1343,11 @@ To enable additional legacy methods, add them to this array. All other `sei_*` a | `sei_newFilter` | Create a new log filter | | `sei_newBlockFilter` | Create a new block filter | | `sei_uninstallFilter` | Remove a filter | -| `sei_getBlockByHashExcludeTraceFail` | Get block by hash excluding failed traces | -| `sei_getBlockByNumberExcludeTraceFail` | Get block by number excluding failed traces | -| `sei_getTransactionReceiptExcludeTraceFail` | Get receipt excluding failed traces | -| `sei_traceBlockByHashExcludeTraceFail` | Trace block by hash excluding failed traces | -| `sei_traceBlockByNumberExcludeTraceFail` | Trace block by number excluding failed traces | +| `sei_getBlockByHashExcludeTraceFail` | Get block by hash, excluding only untraceable txs (ante-rejected and synthetic); reverts/OOG are included | +| `sei_getBlockByNumberExcludeTraceFail` | Get block by number, excluding only untraceable txs (ante-rejected and synthetic); reverts/OOG are included | +| `sei_getTransactionReceiptExcludeTraceFail` | Get receipt, excluding only untraceable txs (ante-rejected and synthetic); reverts/OOG are included | +| `sei_traceBlockByHashExcludeTraceFail` | Trace block by hash, excluding only untraceable txs (ante-rejected and synthetic); reverts/OOG are included | +| `sei_traceBlockByNumberExcludeTraceFail` | Trace block by number, excluding only untraceable txs (ante-rejected and synthetic); reverts/OOG are included | **`sei2_*` methods** (block queries with bank transfers included): From 66a71a90f1e3ec9e5d978bdb1ff0338c70b8b615 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:16:01 +0000 Subject: [PATCH 50/81] docs: Under Autobahn consensus mode, eth_subscribe("newHeads") is now fed by an in-process notifier that publishes committed-block headers, but the resulting headers omit parentHash, receiptsRoot, and transactionsRoot (returned as zero hashes) and source stateRoot/hash differently than the legacy path. (sei-protocol/sei-chain#3419) --- evm/evm-parity/websocket.mdx | 17 +++++++++++++++++ evm/reference.mdx | 2 ++ 2 files changed, 19 insertions(+) diff --git a/evm/evm-parity/websocket.mdx b/evm/evm-parity/websocket.mdx index a1315a6..be7d876 100644 --- a/evm/evm-parity/websocket.mdx +++ b/evm/evm-parity/websocket.mdx @@ -114,3 +114,20 @@ const unwatch = client.watchEvent({ - Sei's instant finality means every block emitted over WebSocket is already final — no need to wait for additional confirmations before acting on an event. - Pending transaction subscriptions (`newPendingTransactions`) are supported at the RPC level but Sei does not guarantee Ethereum-style pending state visibility. + + + +## `newHeads` Under Autobahn Consensus + +When a node runs under Autobahn consensus, `eth_subscribe("newHeads")` notifications are delivered from an in-process notifier that publishes committed-block headers directly, rather than from the legacy consensus event bus. Subscribers still only observe headers for fully committed blocks, but the header payload differs from the legacy path in a few ways: + +- **`parentHash`, `receiptsRoot`, and `transactionsRoot` are returned as zero hashes** (`0x0000…0000`). The Autobahn block-execution path does not build a Tendermint-style hash chain, so there is no meaningful value to surface for these fields. +- **`stateRoot`** is sourced from the finalized block's `AppHash` (the post-execution application hash), rather than from a pre-execution header field. +- **`hash`** is the Autobahn block-header hash — the same value reported as `blockHash` by `eth_getBlockByNumber` and the receipt APIs, keeping `newHeads` consistent with the rest of the EVM RPC surface. +- **`gasUsed`** is an approximation (summed from per-transaction results) to keep the notification cheap. + +Because of these differences: + +- Subscribers that chain-validate the head stream by linking `parentHash` values cannot rely on `newHeads` under Autobahn and need a different mechanism. +- If you need exact `gasUsed` or the omitted hash fields, fetch the block explicitly with `eth_getBlockByNumber`. + diff --git a/evm/reference.mdx b/evm/reference.mdx index 7c4d8d8..f64de26 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -916,6 +916,8 @@ EVM endpoints that walk through these (e.g. `eth_getBlockByNumber`) therefore wo **Sei-specific behavior:** WebSocket-only (SubscriptionAPI is not registered on the HTTP server; returns rpc.ErrNotificationsUnsupported over HTTP). Only 'newHeads' and 'logs' are implemented in source; there is no 'newPendingTransactions' subscription despite some client docs implying otherwise. newHeads subscriptions are capped by MaxSubscriptionsNewHead. +Under Autobahn consensus (i.e. when `AutobahnConfigFile` is set), `newHeads` notifications are delivered by an in-process notifier that publishes committed-block headers after a successful `Commit`, rather than through the CometBFT event bus used by the legacy path. Subscribers therefore observe only committed state, but the header payloads differ from the legacy encoding: `parentHash`, `receiptsRoot`, and `transactionsRoot` are returned as the zero hash (Autobahn does not compute a Tendermint-style hash chain), `stateRoot` is sourced from the finalized block's post-execution `AppHash`, and `hash` is the Autobahn block-header hash. `gasUsed` is an approximation (summed over transaction results); subscribers needing exact gas or the omitted header fields should query `eth_getBlockByNumber`. Under Autobahn, on consumer lag the latest head wins (overwrite-on-full) and intermediate heads may be dropped, and subscribers that chain-validate the head stream will need a different mechanism. + **Parameters:** | # | Name | Type | Description | From 171256364ecae7df5a509293128e099dfef2919b Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:16:56 +0000 Subject: [PATCH 51/81] docs: The *ExcludeTraceFail EVM RPC endpoints (sei_getBlockBy{Number,Hash}ExcludeTraceFail and debug traceBlockBy{Number,Hash}ExcludeTraceFail) now consistently drop ante-deferred stub txs (e.g. insufficient funds) that bumped their nonce but never reached the VM, while regular eth_getBlockBy* endpoints continue to surface them. (sei-protocol/sei-chain#3459) --- evm/reference.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/evm/reference.mdx b/evm/reference.mdx index f64de26..cf9f81a 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -1331,6 +1331,8 @@ To enable additional legacy methods, add them to this array. All other `sei_*` a | `sei_getVMError` | Get VM error details for a transaction | | `sei_getBlockByHash` | Get block by hash (includes synthetic txs) | | `sei_getBlockByNumber` | Get block by number (includes synthetic txs) | +| `sei_getBlockByHashExcludeTraceFail` | Get block by hash, excluding untraceable txs — synthetic txs and ante-deferred stub txs (those that bumped their nonce in ante but never reached the VM, e.g. insufficient funds/fee, identified by `EffectiveGasPrice == 0 && GasUsed == 0`). Note that the regular `eth_getBlockBy*`/`sei_getBlockBy*` endpoints still surface these stub txs; only the `ExcludeTraceFail` variants drop them. | +| `sei_getBlockByNumberExcludeTraceFail` | Get block by number, excluding untraceable txs — synthetic txs and ante-deferred stub txs (those that bumped their nonce in ante but never reached the VM, e.g. insufficient funds/fee, identified by `EffectiveGasPrice == 0 && GasUsed == 0`). Note that the regular `eth_getBlockBy*`/`sei_getBlockBy*` endpoints still surface these stub txs; only the `ExcludeTraceFail` variants drop them. | | `sei_getBlockReceipts` | Get block receipts (includes synthetic txs) | | `sei_getBlockTransactionCountByHash` | Get tx count by block hash (includes synthetic txs) | | `sei_getBlockTransactionCountByNumber` | Get tx count by block number (includes synthetic txs) | From b2c88459ced68055cb557af422b78fda1ede06fb Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:18:35 +0000 Subject: [PATCH 52/81] docs: Added EVM RPC request proxying (sharding) so validators forward eth_sendRawTransaction and pending eth_getTransactionCount requests to the validator owning the sender's shard, requiring a new evmrpc_url.txt per-node file and an evmrpc field in the autobahn config. (sei-protocol/sei-chain#3438) --- learn/sei-giga.mdx | 3 ++- node/advanced-config-monitoring.mdx | 8 ++++++++ node/node-operators.mdx | 24 ++++++++++++++++++++---- node/technical-reference.mdx | 2 +- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/learn/sei-giga.mdx b/learn/sei-giga.mdx index 46b212e..ca63c12 100644 --- a/learn/sei-giga.mdx +++ b/learn/sei-giga.mdx @@ -219,11 +219,12 @@ Rather than hand-authoring the JSON file, you can generate it from per-node pubk seid tendermint gen-autobahn-config [node-dirs...] --output ``` -The command reads three files from each node directory passed as an argument and assembles one `validators` entry per directory: +The command reads four files from each node directory passed as an argument and assembles one `validators` entry per directory: - `validator_pubkey.txt` — the Autobahn validator public key, in `validator:` format - `node_pubkey.txt` — the p2p node public key, in `node:ed25519:public:` format - `autobahn_address.txt` — the node's network address in `host:port` format +- `evmrpc_url.txt` — the node's EVM RPC HTTP URL (for example `http://:8545`), used to proxy EVM requests to the validator that owns the sender's shard The `--output` (or `-o`) flag is required and specifies where the generated JSON config is written. The generated file uses default consensus parameters (for example, a 400ms block interval and a 1.5s view timeout), which you can adjust afterward if needed. diff --git a/node/advanced-config-monitoring.mdx b/node/advanced-config-monitoring.mdx index 0177ddd..30469ac 100644 --- a/node/advanced-config-monitoring.mdx +++ b/node/advanced-config-monitoring.mdx @@ -500,6 +500,14 @@ Sei nodes emit OpenTelemetry-based metrics for the EVM JSON-RPC layer through th | --- | --- | --- | | `evmrpc_request_latency_seconds` | histogram | RPC request latency in seconds, labeled by endpoint, connection, success, error class, and JSON-RPC code bucket. | | `evmrpc_websocket_connects_total` | counter | Number of new websocket connections. | +| `evmrpc_redirected_requests_total` | counter | Number of EVM RPC requests forwarded (proxied) to another validator, labeled by endpoint and connection. Emitted when a request such as `eth_sendRawTransaction` or a pending `eth_getTransactionCount` is redirected to the validator that owns the sender's EVM address shard. | + +### `evmrpc_redirected_requests_total` labels + +| Label | Description | +| --- | --- | +| `endpoint` | The RPC method being forwarded (e.g. `eth_sendRawTransaction`, `eth_getTransactionCount`). | +| `connection` | The connection type that received the original request (e.g. `http`, `websocket`). | ### `evmrpc_request_latency_seconds` labels diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 644edd1..626b98e 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -274,7 +274,7 @@ gen-autobahn-config` command: seid tendermint gen-autobahn-config [node-dirs...] --output ``` -Each `node-dir` argument must contain three files describing that committee +Each `node-dir` argument must contain four files describing that committee member: - `validator_pubkey.txt` — the validator public key in `validator:` @@ -282,6 +282,10 @@ member: - `node_pubkey.txt` — the p2p node public key in `node:ed25519:public:` format - `autobahn_address.txt` — the node's network address in `host:port` format +- `evmrpc_url.txt` — the node's EVM RPC HTTP URL (for example + `http://:8545`, using the EVM RPC HTTP port from the `[evm]` + section of `app.toml`). This is used to proxy EVM RPC requests to the + validator that owns the sender's EVM address shard. The command reads these files from each directory, assembles the `validators` list, and writes a complete Autobahn JSON config (with default consensus and @@ -292,9 +296,21 @@ The `validator_pubkey.txt` and `node_pubkey.txt` files are produced automatically: whenever `seid` saves the validator private key (`priv_validator_key.json`) it also writes `validator_pubkey.txt`, and whenever it saves the node key (`node_key.json`) it also writes `node_pubkey.txt`, both -in the same directory as the key file. You only need to supply -`autobahn_address.txt` yourself. Point `autobahn-config-file` at the generated -file to enable Autobahn. +in the same directory as the key file. You need to supply +`autobahn_address.txt` and `evmrpc_url.txt` yourself. Point +`autobahn-config-file` at the generated file to enable Autobahn. + +#### EVM RPC request proxying + +Each validator is assigned a shard of the EVM address space. When a node +receives an `eth_sendRawTransaction` request, or an `eth_getTransactionCount` +request for the pending block, it forwards (proxies) the request to the EVM +RPC endpoint of the validator that owns the sender's shard, using the `evmrpc` +URL from that validator's config entry. Requests whose sender maps to the +local validator are handled locally. Proxied requests are counted by the +`evmrpc_redirected_requests_total` telemetry metric (labeled with the +endpoint and connection type). This is why every committee member must publish +an `evmrpc` URL via `evmrpc_url.txt`. diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index cd69d91..334511f 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -40,7 +40,7 @@ seid query node info ### Autobahn Config Generation -Generate an Autobahn (GigaRouter) JSON config from a set of node directories. Each node directory must contain `validator_pubkey.txt`, `node_pubkey.txt`, and `autobahn_address.txt`. These pubkey files are written automatically alongside the key files when the validator key and node key are saved (in `validator:` and `node:ed25519:public:` formats, respectively). +Generate an Autobahn (GigaRouter) JSON config from a set of node directories. Each node directory must contain `validator_pubkey.txt`, `node_pubkey.txt`, `autobahn_address.txt`, and `evmrpc_url.txt`. These pubkey files are written automatically alongside the key files when the validator key and node key are saved (in `validator:` and `node:ed25519:public:` formats, respectively). The `evmrpc_url.txt` file must contain the node's EVM RPC HTTP URL (e.g. `http://:8545`), which is used to proxy EVM RPC requests to the validator that owns the sender's EVM address shard. ```bash # Generate an autobahn config from one or more node directories From 548fe9e04917469cd245f032bf35fd86b596fb0d Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:20:42 +0000 Subject: [PATCH 53/81] docs: The SeiDB state-commit config was overhauled: the sc-read-mode and sc-enable-lattice-hash fields were removed, and sc-write-mode's valid values changed to a new migration-based set (memiavl_only, migrate_evm, evm_migrated, migrate_all_but_bank, all_migrated_but_bank, migrate_bank, flatkv_only, test_only_dual_write) with a new keys-to-migrate-per-block field. (sei-protocol/sei-chain#3420) --- learn/seidb.mdx | 4 +++- node/giga-storage-migration.mdx | 31 +++++++++++++++---------------- node/node-operators.mdx | 26 +++++++++++++------------- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/learn/seidb.mdx b/learn/seidb.mdx index be0b15c..346cd0b 100644 --- a/learn/seidb.mdx +++ b/learn/seidb.mdx @@ -378,5 +378,7 @@ The import must be run at the memIAVL **latest** height. The command refuses to ### Migration configuration constraints -When restarting a node after the import, keep `evm-ss-split = false` and `sc-enable-lattice-hash = 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. Turning `sc-enable-lattice-hash` on would fold the FlatKV LtHash into the AppHash for blocks that were committed before the import (whose persisted AppHash was memiavl-only), causing the replay check at startup to fail with an AppHash mismatch. +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. + +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. diff --git a/node/giga-storage-migration.mdx b/node/giga-storage-migration.mdx index f13029f..1c89d23 100644 --- a/node/giga-storage-migration.mdx +++ b/node/giga-storage-migration.mdx @@ -22,24 +22,23 @@ and `memiavl` remains the authoritative source for the app hash, so this is invisible to the network. -The SC-layer routing fields `sc-write-mode`, `sc-read-mode`, and -`sc-enable-lattice-hash` are emitted in the generated `app.toml` template under -the `[state-store]` section. They default to `cosmos_only` / `cosmos_only` / -`false`, so leaving them at their defaults keeps the SC layer untouched for this -migration. +The SC-layer routing field `sc-write-mode` is emitted in the generated +`app.toml` template under the `[state-store]` section. It defaults to +`memiavl_only`, so leaving it at the default keeps the SC layer untouched for +this migration. - `sc-write-mode` — write routing mode for EVM data in the SC layer. Valid - values: `cosmos_only`, `dual_write`, `split_write`. -- `sc-read-mode` — read routing mode for EVM data in the SC layer. Valid - values: `cosmos_only`, `evm_first`, `split_read`. -- `sc-enable-lattice-hash` — whether the lattice hash participates in the final - app hash. - -If you configure the SC layer to use `split_write` mode -(`sc-write-mode = "split_write"`), the lattice hash must be enabled -(`sc-enable-lattice-hash = true`). State-commit config validation rejects -`split_write` with the lattice hash disabled — the composite commit store -panics on creation with `lattice hash must be enabled when using split_write mode`. + values: `memiavl_only`, `migrate_evm`, `evm_migrated`, `migrate_all_but_bank`, + `all_migrated_but_bank`, `migrate_bank`, `flatkv_only`, `test_only_dual_write`. + An invalid value fails at config parse time with a clear error. +- `keys-to-migrate-per-block` — the number of keys migrated from `memiavl` to + `flatKV` per block while in a migration mode. Defaults to `1024` and must be + greater than `0`; ignored outside of a migration mode. + +The legacy `sc-read-mode` and `sc-enable-lattice-hash` fields have been +**removed**. Read routing and lattice-hash participation are now derived +automatically from the write mode and the on-disk migration state — an +`app.toml` that still references either field is no longer valid. diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 626b98e..e79d85a 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -447,23 +447,23 @@ sc-snapshot-prefetch-threshold = 0.8 # Maximum snapshot write rate in MB/s (global across all trees). 0 = unlimited. Default 100. sc-snapshot-write-rate-mbps = 100 -# EVMSSMode consolidates the previous separate SC-layer EVM write/read routing -# modes (sc-write-mode / sc-read-mode) into a single setting. It controls how -# EVM state store data is written and read. -# Valid values: cosmos_only, dual_write, split_write -evm-ss-mode = "cosmos_only" - -# EnableLatticeHash controls whether lattice hash participates in the final app hash. -# Must be enabled when using split_write mode. -sc-enable-lattice-hash = false - -# KeysToMigratePerBlock controls how many EVM keys the in-flight migration -# (sc-write-mode = migrate_evm / migrate_bank / migrate_all_but_bank) drains +# WriteMode defines the write routing mode for EVM data in the SC layer. +# Valid values: memiavl_only, migrate_evm, evm_migrated, migrate_all_but_bank, +# all_migrated_but_bank, migrate_bank, flatkv_only, test_only_dual_write +# Defaults to memiavl_only. An invalid value fails at config parse time with a +# clear error. The memiavl_only, evm_migrated, all_migrated_but_bank, and +# flatkv_only values are steady states; the migrate_* values drive an in-flight +# migration from memiavl to flatkv. test_only_dual_write is for test clusters +# only and must never be deployed to testnet/mainnet. +sc-write-mode = "memiavl_only" + +# KeysToMigratePerBlock controls how many keys the in-flight migration +# (sc-write-mode = migrate_evm / migrate_all_but_bank / migrate_bank) drains # from memiavl into flatkv per block. Default 1024 is appropriate for # production drains; lower it (e.g. 256) to spread the migration across more # blocks for test runs that need to observe the resume / hybrid-read path. # Must be > 0; ignored entirely when not in a migration mode. -sc-keys-to-migrate-per-block = 1024 +keys-to-migrate-per-block = 1024 ############################################################################### ### FlatKV (EVM) Configuration ### From b58e981a48d1d06b496baba9eb229f0fcbc46f6b Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:21:38 +0000 Subject: [PATCH 54/81] docs: Distribution module now validates withdraw addresses against bank's CanSendTo check, rejecting SetWithdrawAddr for recipients not allowed to receive external funds and falling back to the delegator address when a stored withdraw address becomes invalid. (sei-protocol/sei-chain#3463) --- evm/precompiles/distribution.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/evm/precompiles/distribution.mdx b/evm/precompiles/distribution.mdx index 877bd1f..ecd1184 100644 --- a/evm/precompiles/distribution.mdx +++ b/evm/precompiles/distribution.mdx @@ -156,6 +156,10 @@ function setWithdrawAddress(address withdrawAddr) external returns (bool success **Gas Cost**: ~30,000 gas +**Recipient Validation**: The withdraw address must be allowed to receive external funds. The distribution module validates the recipient against the bank module's `CanSendTo` check, and the call reverts with `ErrInvalidRecipient` if it fails. In particular, an unassociated EVM-cast address (an EVM address that has no associated Sei account) is rejected, as are blocked module addresses. Ensure the target address is associated before setting it as a withdraw address. + +**Fallback on Invalid Stored Address**: If a previously set withdraw address later becomes unable to receive funds (for example, it becomes blocked or otherwise fails the `CanSendTo` check), the distribution module falls back to sending rewards to the delegator's own address rather than failing. Reward and commission withdrawals therefore always succeed even if the stored withdraw address is no longer valid. + **Example:** ```solidity From 7de3bf3d7147df1a613e54ce6ac9609356f26aea Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:22:36 +0000 Subject: [PATCH 55/81] docs: A new --persistent-state-dir flag was added to the tendermint gen-autobahn-config command, defaulting to 'data/autobahn' to persist consensus and data WALs across restarts, with empty value disabling persistence for in-memory-only mode. (sei-protocol/sei-chain#3483) --- learn/sei-giga.mdx | 2 +- node/node-operators.mdx | 2 +- node/technical-reference.mdx | 7 +++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/learn/sei-giga.mdx b/learn/sei-giga.mdx index ca63c12..7fb349a 100644 --- a/learn/sei-giga.mdx +++ b/learn/sei-giga.mdx @@ -181,7 +181,7 @@ The file referenced by `autobahn-config-file` is a JSON document with the follow | `block_interval` | duration | Target interval between blocks. Must be greater than 0. | | `allow_empty_blocks` | boolean | Whether empty blocks may be produced. | | `view_timeout` | duration | Consensus view timeout. Must be greater than 0. | -| `persistent_state_dir` | string \| null | Optional directory for persisting consensus state. | +| `persistent_state_dir` | string \| null | Directory for persisting the Autobahn consensus and data-layer WALs across restarts, so both layers survive process restarts (they share this on-disk root and write to distinct subdirectories under it). Relative paths are resolved against the node's `--home` directory at load time; absolute paths are used as-is. Set to `null` (or generate with an empty `--persistent-state-dir`) to disable persistence and run in-memory only. | | `dial_interval` | duration | Interval at which peers are dialed. Must be greater than 0. | Example configuration file: diff --git a/node/node-operators.mdx b/node/node-operators.mdx index e79d85a..e93a76b 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -260,7 +260,7 @@ Be aware of the following Autobahn-specific limitations: | `block_interval` | Target interval between blocks. Must be `> 0`. | | `allow_empty_blocks` | Whether to produce blocks when there are no transactions. | | `view_timeout` | Consensus view timeout. Must be `> 0`. | -| `persistent_state_dir` | Optional directory for persistent consensus state. | +| `persistent_state_dir` | Directory used to persist the Autobahn consensus and data-layer write-ahead logs (WALs) across restarts. Both layers share this on-disk root and write to distinct subdirectories under it. Relative paths are resolved against the node's `--home` directory at load time; absolute paths are used as-is. When generated via `gen-autobahn-config` this defaults to `data/autobahn`, so persistence is on by default. Set it to an empty value (or omit it entirely) to disable persistence and run both the consensus and data layers in-memory only. | | `dial_interval` | Interval between dial attempts to committee peers. Must be `> 0`. | diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 334511f..fec42df 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -57,6 +57,13 @@ The `--output` / `-o` flag is required and specifies the destination file path f | `validator_pubkey.txt` | Autobahn validator public key in `validator:` format. | | `node_pubkey.txt` | p2p node public key in `node:ed25519:public:` format. | | `autobahn_address.txt` | Network address (`host:port`) for the node. | +| `evmrpc_url.txt` | The node's EVM RPC HTTP URL (e.g. `http://:8545`). | + +The command also accepts an optional `--persistent-state-dir` flag: + +| Flag | Description | +| --- | --- | +| `--persistent-state-dir` | Directory to persist the Autobahn consensus and data-layer WALs across restarts. Defaults to `data/autobahn`, so persistence is enabled by default without operator action. Relative paths are resolved against the node's `--home` directory at load time; absolute paths are used unchanged. Pass `--persistent-state-dir=` (empty) to disable persistence and run both the consensus and data layers in-memory only. | The resulting JSON file can then be referenced from `config.toml` via the `autobahn-config-file` field to enable Autobahn wiring at node startup. From f31a55cca908751e6e697a35aa24f9e7d9e5e5c8 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:24:45 +0000 Subject: [PATCH 56/81] docs: eth_getTransactionReceipt now returns JSON null (instead of an error) when the receipt's block is above the safe-latest watermark, matching Ethereum JSON-RPC 'not yet mined' semantics. (sei-protocol/sei-chain#3501) --- evm/reference.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/reference.mdx b/evm/reference.mdx index cf9f81a..941d67d 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -220,7 +220,7 @@ Every method below is also browsable interactively in the explorer above; this s **Supported.** Returns the receipt of a transaction by hash, or null if not found. -**Sei-specific behavior:** Receipt is reconstructed from keeper.GetReceipt + CometBFT block data rather than from a native MPT receipt trie; status/logs are standard Ethereum format. +**Sei-specific behavior:** Receipt is reconstructed from keeper.GetReceipt + CometBFT block data rather than from a native MPT receipt trie; status/logs are standard Ethereum format. If a receipt exists but its block height is above the safe-latest watermark (e.g. the CometBFT status momentarily lags the receipt store by a block), the method returns JSON `null` — the Ethereum JSON-RPC 'not yet mined' signal — rather than an error, so clients simply poll again. This matches the behavior of `eth_getBlockByNumber` for blocks above the watermark. **Parameters:** From 8d86f9cba27ecd438bd7f6b82cb2fbadb440e8d2 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:25:28 +0000 Subject: [PATCH 57/81] docs: The Tendermint mempool config changed TTLDuration/TTLNumBlocks handling (now optional, zero disables) and the mempool was refactored, changing behavior of expired READY vs PENDING tx pruning and removing peer-based no-broadcast-to-sender behavior. (sei-protocol/sei-chain#3476) --- node/index.mdx | 8 ++++++-- node/node-operators.mdx | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/node/index.mdx b/node/index.mdx index c6eedb0..634afe7 100644 --- a/node/index.mdx +++ b/node/index.mdx @@ -247,10 +247,14 @@ max-tx-bytes = 2048576 # Maximum size of a batch of transactions to send to a peer max-batch-bytes = 0 -# Maximum length of time a transaction can remain in the mempool +# Maximum length of time a transaction can remain in the mempool. +# Set to "0s" to explicitly disable time-based TTL purging. +# The default is "5s". ttl-duration = "3s" -# Maximum number of blocks a transaction can remain in the mempool +# Maximum number of blocks a transaction can remain in the mempool. +# Set to 0 to explicitly disable block-based TTL purging. +# The default is 10 blocks. ttl-num-blocks = 5 tx-notify-threshold = 0 diff --git a/node/node-operators.mdx b/node/node-operators.mdx index e93a76b..2684c8e 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -178,6 +178,34 @@ The referenced JSON file supports the following fields: | `max_txs_per_second` | Optional cap on transactions per second (omit to leave unset). | | `mempool_size` | Retained for compatibility. Must be `> 0`. Note that the Autobahn producer no longer maintains a separate producer mempool channel — blocks are now built by reaping transactions directly from the shared node `TxMempool` (configured under the `[mempool]` section of `config.toml`). | +#### Mempool transaction TTL (config.toml) + +Under the `[mempool]` section of `config.toml`, the transaction TTL settings +control how long a transaction is allowed to remain in the mempool before it is +purged. Both settings are now optional, and a value of `0` explicitly disables +the corresponding TTL. + +```toml +[mempool] +# Maximum amount of time a transaction may remain in the mempool before it is +# purged. Set to "0s" to disable time-based TTL purging. Default: 5s. +ttl-duration = "5s" +# Maximum number of blocks a transaction may remain in the mempool before it is +# purged. Set to 0 to disable block-based TTL purging. Default: 10. +ttl-num-blocks = 10 +``` + +Previously a non-zero value enabled the corresponding TTL; now `ttl-duration = 0` +and `ttl-num-blocks = 0` explicitly disable time-based and block-based TTL +purging respectively. The defaults remain `5s` and `10` blocks. + + + Expiration behavior differs between READY and PENDING transactions. + `remove-expired-txs-from-queue` now governs whether expired **READY** + transactions are pruned from the mempool queue. Expired **PENDING** + transactions are always removed regardless of this setting. + + When Autobahn is enabled, the node builds blocks directly from the shared `TxMempool` and disables the mempool gossip reactor, the consensus reactor, From e59bf32cf8ee61c3df0669042c37e3064d920bd6 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:26:54 +0000 Subject: [PATCH 58/81] docs: Adds a new seidb `migrate-evm-status` CLI subcommand, a new `sc-keys-to-migrate-per-block` app.toml config field for the in-flight FlatKV EVM migration, a new `-mode` flag on the evm_stress workload tool, and a `GIGA_MIGRATE_FROM_MEMIAVL` cluster env var, along with behavior changes to EVM migration read/iteration during in-flight migration. (sei-protocol/sei-chain#3473) --- learn/seidb.mdx | 53 +++++++++++++++++++++++++++++++++ node/giga-storage-migration.mdx | 4 +-- node/node-operators.mdx | 2 +- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/learn/seidb.mdx b/learn/seidb.mdx index 346cd0b..4a5e58e 100644 --- a/learn/seidb.mdx +++ b/learn/seidb.mdx @@ -382,3 +382,56 @@ When restarting a node after the import, keep `evm-ss-split = false` across the 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. + + +## 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 +seidb migrate-evm-status \ + --db-dir /path/to/flatkv \ + [--height ] +``` + +### 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 +{ + "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. | + +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`. + diff --git a/node/giga-storage-migration.mdx b/node/giga-storage-migration.mdx index 1c89d23..4ff744d 100644 --- a/node/giga-storage-migration.mdx +++ b/node/giga-storage-migration.mdx @@ -31,7 +31,7 @@ this migration. values: `memiavl_only`, `migrate_evm`, `evm_migrated`, `migrate_all_but_bank`, `all_migrated_but_bank`, `migrate_bank`, `flatkv_only`, `test_only_dual_write`. An invalid value fails at config parse time with a clear error. -- `keys-to-migrate-per-block` — the number of keys migrated from `memiavl` to +- `sc-keys-to-migrate-per-block` — the number of keys migrated from `memiavl` to `flatKV` per block while in a migration mode. Defaults to `1024` and must be greater than `0`; ignored outside of a migration mode. @@ -54,7 +54,7 @@ progresses through a linear sequence of on-disk **migration versions**: | WriteMode | Migration version | Behavior | |---|---|---| | `MemiavlOnly` (`memiavl_only`) | 0 | Pre-migration baseline: every module routes to `memiavl`; `flatKV` is not in the data path (bootstrap passes `nil` for `flatKV`). | -| `MigrateEVM` (`migrate_evm`) | 0 → 1 | Migrates the `evm/` module from `memiavl` to `flatKV` in batches; un-migrated EVM keys still read from `memiavl`. | +| `MigrateEVM` (`migrate_evm`) | 0 → 1 | Migrates the `evm/` module from `memiavl` to `flatKV` in batches. Reads for un-migrated keys are served from `memiavl` first and fall back to `flatKV` for brand-new keys created after the migration started; brand-new writes are routed to `flatKV` so the migration boundary can reach completion instead of chasing an ever-growing key tail. Iteration is forwarded to the `memiavl` iterator while the migration is `NotStarted`/`InProgress` (with the caveat that already-migrated keys are no longer visible there, so results may be incomplete mid-flight) and is refused once the migration is `Complete`. | | `EVMMigrated` (`evm_migrated`) | 1 | Steady state: `evm/` lives in `flatKV`, every other module in `memiavl`; no migration manager in the path. | | `MigrateAllButBank` (`migrate_all_but_bank`) | 1 → 2 | Migrates every module except `bank/` (and the already-migrated `evm/`) from `memiavl` to `flatKV`. | | `AllMigratedButBank` (`all_migrated_but_bank`) | 2 | Steady state: everything except `bank/` lives in `flatKV`; `bank/` remains in `memiavl`. | diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 2684c8e..a697e18 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -491,7 +491,7 @@ sc-write-mode = "memiavl_only" # production drains; lower it (e.g. 256) to spread the migration across more # blocks for test runs that need to observe the resume / hybrid-read path. # Must be > 0; ignored entirely when not in a migration mode. -keys-to-migrate-per-block = 1024 +sc-keys-to-migrate-per-block = 1024 ############################################################################### ### FlatKV (EVM) Configuration ### From 2cb5a766152685f66b80d634b1e4b24639d9f1a3 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:29:44 +0000 Subject: [PATCH 59/81] docs: Adds new OpenTelemetry metrics (histograms/counters) for module mid-block and per-module begin/end-blocker durations and validator slash events, and renames existing staking keeper metrics to a prefixed convention. (sei-protocol/sei-chain#3512) --- node/advanced-config-monitoring.mdx | 66 +++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/node/advanced-config-monitoring.mdx b/node/advanced-config-monitoring.mdx index 30469ac..3f7c20f 100644 --- a/node/advanced-config-monitoring.mdx +++ b/node/advanced-config-monitoring.mdx @@ -646,6 +646,72 @@ The `type` attribute identifies the execution path: `synchronous`, `synchronous_ + +## Module & Governance Metrics + +Sei nodes emit OpenTelemetry-based metrics for the SDK module lifecycle (mid-block, begin-blocker, and end-blocker execution) and for validator slash events through the process-wide `MeterProvider` (for example, a Prometheus exporter). These `module_*`, per-module `*_blocker_duration`, and `validator_slashed` metrics let operators observe where per-block module execution time is spent and track slashing activity. + + + These OpenTelemetry metrics are emitted alongside the existing legacy telemetry counterparts, which are retained pending verification (PLT-414). When building or updating dashboards and alerts, prefer these OpenTelemetry metrics over their legacy counterparts. + + +### Mid-block duration metrics + +Each of these is a histogram reported in seconds (unit `s`), measuring the duration of module mid-block execution. + +| Metric | Type | Attributes | Description | +| --- | --- | --- | --- | +| `module_total_mid_block_duration` | histogram | — | Total duration of all modules' mid-block execution in seconds. | +| `module_mid_block_duration` | histogram | `module` | Duration of per-module mid-block execution in seconds, labeled by module name. | + +### Per-module begin/end-blocker duration metrics + +Each of these is a histogram reported in seconds (unit `s`), measuring the duration of the corresponding module's begin-blocker or end-blocker execution. + +| Metric | Type | Description | +| --- | --- | --- | +| `capability_begin_blocker_duration` | histogram | Duration of capability begin-blocker execution in seconds. | +| `crisis_end_blocker_duration` | histogram | Duration of crisis end-blocker execution in seconds. | +| `crisis_init_genesis_unmarshal_duration` | histogram | Duration of crisis `InitGenesis` JSON unmarshal in seconds. | +| `distribution_begin_blocker_duration` | histogram | Duration of distribution begin-blocker execution in seconds. | +| `evidence_begin_blocker_duration` | histogram | Duration of evidence begin-blocker execution in seconds. | +| `gov_end_blocker_duration` | histogram | Duration of gov end-blocker execution in seconds. | +| `slashing_begin_blocker_duration` | histogram | Duration of slashing begin-blocker execution in seconds. | +| `staking_begin_blocker_duration` | histogram | Duration of staking begin-blocker execution in seconds. | +| `staking_end_blocker_duration` | histogram | Duration of staking end-blocker execution in seconds. | + +### Validator slash counter + +| Metric | Type | Attributes | Description | +| --- | --- | --- | --- | +| `validator_slashed` | counter | `type`, `validator` | Number of validator slash events, labeled by slash reason (`type` is `missing_signature` or `double_sign`) and the consensus address of the slashed validator. | + +### Staking keeper metrics + +The staking keeper delegation metrics are emitted with a `staking_keeper_` prefix to avoid collisions with other metric namespaces. + +| Metric | Type | Description | +| --- | --- | --- | +| `staking_keeper_delegate` | counter | Number of delegation transactions. | +| `staking_keeper_last_delegate_amount` | gauge | Amount delegated in the last delegation transaction (in `usei`). | +| `staking_keeper_redelegate` | counter | Number of redelegation transactions. | +| `staking_keeper_last_redelegate_amount` | gauge | Amount redelegated in the last redelegation transaction (in `usei`). | +| `staking_keeper_undelegate` | counter | Number of undelegation transactions. | +| `staking_keeper_last_undelegate_amount` | gauge | Amount undelegated in the last undelegation transaction (in `usei`). | + + + The staking keeper metrics were previously emitted without the `staking_keeper_` prefix (for example, `delegate`, `last_delegate_amount`). Update any dashboards or alerts that reference the old unprefixed names. + + +The duration histograms use the following explicit bucket boundaries (in seconds): + +``` +0.000025, 0.000050, 0.0001, 0.0005, 0.001, 0.0025, 0.005, 0.010, 0.020, 0.050, 0.075, 0.1, 0.25, 0.5, 1, 10 +``` + + + + ## Backup Management From cc78e02610ae670738a16817f17bca0f4422112c Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:30:33 +0000 Subject: [PATCH 60/81] docs: The max block lookback guard now applies to all debug_trace* RPC methods (traceTransaction, traceTransactionProfile, traceBlockByHash, traceCall, traceStateAccess) in addition to traceBlockByNumber, so requests targeting historical blocks beyond the configured lookback are now rejected with an error. (sei-protocol/sei-chain#3515) --- evm/reference.mdx | 2 +- node/advanced-config-monitoring.mdx | 10 ++++++++++ node/node-operators.mdx | 10 +++++++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/evm/reference.mdx b/evm/reference.mdx index 941d67d..74ab933 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -1116,7 +1116,7 @@ The `filter` object applies only to `logs` subscriptions. For `newHeads`, pass t **Supported.** Replays a transaction by hash and returns an execution trace using the configured tracer. -**Sei-specific behavior:** HTTP-only (the debug namespace is not registered on the WebSocket server). Supports geth tracers (callTracer, prestateTracer, flatCallTracer, struct/opcode logger); callTracer/prestateTracer/flatCallTracer results are pre-baked/cached via TraceBaker. Requires trace-enabled/archive state for the target height. +**Sei-specific behavior:** HTTP-only (the debug namespace is not registered on the WebSocket server). Supports geth tracers (callTracer, prestateTracer, flatCallTracer, struct/opcode logger); callTracer/prestateTracer/flatCallTracer results are pre-baked/cached via TraceBaker. Requires trace-enabled/archive state for the target height. Subject to the max block lookback guard: requests targeting a block older than the node's configured `maxBlockLookback` (resolved from the transaction's receipt block number) are rejected with `block number N is beyond max lookback of M`. **Parameters:** diff --git a/node/advanced-config-monitoring.mdx b/node/advanced-config-monitoring.mdx index 3f7c20f..5378780 100644 --- a/node/advanced-config-monitoring.mdx +++ b/node/advanced-config-monitoring.mdx @@ -502,6 +502,16 @@ Sei nodes emit OpenTelemetry-based metrics for the EVM JSON-RPC layer through th | `evmrpc_websocket_connects_total` | counter | Number of new websocket connections. | | `evmrpc_redirected_requests_total` | counter | Number of EVM RPC requests forwarded (proxied) to another validator, labeled by endpoint and connection. Emitted when a request such as `eth_sendRawTransaction` or a pending `eth_getTransactionCount` is redirected to the validator that owns the sender's EVM address shard. | + +| `evmrpc_historical_debug_trace_attempts_total` | counter | Number of `debug_trace*` requests targeting historical blocks, labeled by endpoint and connection. Incremented whenever a `debug_trace*` request (`debug_traceTransaction`, `debug_traceTransactionProfile`, `debug_traceBlockByNumber`, `debug_traceBlockByHash`, `debug_traceCall`, or `debug_traceStateAccess`) targets a block older than the configured `maxBlockLookback`. Such requests are rejected with an error like `block number N is beyond max lookback of M`. | + +### `evmrpc_historical_debug_trace_attempts_total` labels + +| Label | Description | +| --- | --- | +| `endpoint` | The `debug_trace*` method that attempted the historical block (e.g. `debug_traceTransaction`, `debug_traceBlockByNumber`, `debug_traceCall`). | +| `connection` | The connection type that received the request (e.g. `http`, `websocket`). | + ### `evmrpc_redirected_requests_total` labels | Label | Description | diff --git a/node/node-operators.mdx b/node/node-operators.mdx index a697e18..82fe631 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -770,7 +770,15 @@ max_subscriptions_new_head = 10000 # Set to 0 for unlimited. max_concurrent_trace_calls = 10 -# Max number of blocks allowed to look back for tracing +# Max number of blocks allowed to look back for tracing. +# This lookback guard applies to all debug_trace* methods +# (debug_traceTransaction, debug_traceTransactionProfile, +# debug_traceBlockByNumber, debug_traceBlockByHash, debug_traceCall, and +# debug_traceStateAccess). Any request targeting a block older than +# (latest - max_trace_lookback_blocks) is rejected with +# "block number N is beyond max lookback of M", and the attempt is counted +# by the evmrpc_historical_debug_trace_attempts_total telemetry metric +# (labeled by endpoint and connection type). # Set to -1 for unlimited lookback, which is useful for archive nodes. max_trace_lookback_blocks = 10000 From 865ef13d8942148fb10f032a395128a4879d4014 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:32:20 +0000 Subject: [PATCH 61/81] docs: The eth_getTransactionByHash RPC now looks up pending transactions via a direct mempool EVM-hash index instead of paginating unconfirmed txs, and the UnconfirmedTxs RPC now returns results from a recent mempool snapshot with byte totals computed over that snapshot rather than the full mempool size. (sei-protocol/sei-chain#3546) --- evm/reference.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/reference.mdx b/evm/reference.mdx index 74ab933..0e59581 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -195,7 +195,7 @@ Every method below is also browsable interactively in the explorer above; this s **Supported.** Returns the EVM transaction matching the given hash, or null if not found. -**Sei-specific behavior:** Sees EVM transactions only; if the hash resolves to a non-EVM Cosmos tx it errors. Pending lookups read from the CometBFT mempool, not a geth txpool. Use the legacy sei_getTransactionByHash to also surface Cosmos txs with synthetic representations. +**Sei-specific behavior:** Sees EVM transactions only; if the hash resolves to a non-EVM Cosmos tx it errors. Pending lookups read from the CometBFT mempool (not a geth txpool) via a direct EVM-hash index lookup rather than scanning paginated unconfirmed-tx pages, so pending transactions are resolved efficiently by hash. Use the legacy sei_getTransactionByHash to also surface Cosmos txs with synthetic representations. **Parameters:** From b117a5df5da74e2f6b667059e2b8789497ac196f Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:34:08 +0000 Subject: [PATCH 62/81] docs: The Autobahn (giga) autobahn config file drops the mempool_size field and the block payload/producer config are restructured (total_gas split into wanted/estimated), plus some RPC behaviors change under the Autobahn mempool. (sei-protocol/sei-chain#3522) --- learn/sei-giga-specs.mdx | 11 ++++++++--- learn/sei-giga.mdx | 1 - node/node-operators.mdx | 5 ++--- node/technical-reference.mdx | 6 ++++-- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/learn/sei-giga-specs.mdx b/learn/sei-giga-specs.mdx index 0e8785b..026b4f0 100644 --- a/learn/sei-giga-specs.mdx +++ b/learn/sei-giga-specs.mdx @@ -70,7 +70,9 @@ The specifications are organized to clearly distinguish between what is currentl When a node runs with Autobahn (Sei Giga) consensus enabled, the block producer builds payloads by reaping transactions directly from the shared mempool, subject to hard on-chain block size constraints that are enforced during payload construction. -The block gas limit is no longer a configurable Autobahn field. The producer's `MaxGasPerBlock` is derived directly from the genesis `consensus_params.block.max_gas` value — the same gas limit the EVM runtime reads via `ctx.ConsensusParams().Block.MaxGas`. This ensures `eth_getBlockByNumber`'s reported `gasLimit` matches the `GASLIMIT` opcode value seen during execution. The `max_gas_per_block` field has been removed from the Autobahn config file, so it should be omitted from existing configs. +The block gas limit is no longer a single configurable Autobahn field. The producer now tracks two separate per-block gas dimensions: gas wanted and gas estimated. Each block payload records `total_gas_wanted` and `total_gas_estimated` (replacing the previous single `total_gas` field), and both are enforced against `MaxGasWantedPerBlock` and `MaxGasEstimatedPerBlock` limits during payload construction. + +These limits are derived from the genesis `consensus_params.block` values: `MaxGasWantedPerBlock` comes from `max_gas_wanted` and `MaxGasEstimatedPerBlock` comes from `max_gas` — the same gas limit the EVM runtime reads via `ctx.ConsensusParams().Block.MaxGas`. Under Autobahn, `BlockResults`'s `ConsensusParamUpdates.Block.MaxGas` reflects `MaxGasEstimatedPerBlock`. The `max_gas_per_block` field has been removed from the Autobahn config file, so it should be omitted from existing configs. Genesis `consensus_params.block.max_gas` must be a positive value. If it is missing or non-positive, node startup fails with `ErrGenesisMaxGasInvalid` (`genesis consensus_params.block.max_gas must be > 0`). @@ -81,12 +83,15 @@ The block gas limit is no longer a configurable Autobahn field. The producer's ` | --- | --- | | Max transactions per block | 2000 (`MaxTxsPerBlock`) | | Max total tx bytes per block | ~2 MB (`MaxTxsBytesPerBlock` = 2000 × 1024) | - | Max gas per block | Derived from genesis `consensus_params.block.max_gas` (`MaxGasPerBlock`) | + | Max gas wanted per block | Derived from genesis `consensus_params.block.max_gas_wanted` (`MaxGasWantedPerBlock`) | + | Max gas estimated per block | Derived from genesis `consensus_params.block.max_gas` (`MaxGasEstimatedPerBlock`) | | Block proto size bound | Derived from `MaxTxsPerBlock` and `MaxTxsBytesPerBlock` (`MaxBlockProtoSize`) | - Total tx bytes may be split arbitrarily across transactions (one large tx or many small ones), up to the `MaxTxsPerBlock` limit. - - The block gas limit is sourced from genesis `consensus_params.block.max_gas`; genesis must set this to a value greater than zero or the node will refuse to start. + - Each block payload tracks `total_gas_wanted` and `total_gas_estimated`; a transaction is rejected if adding it would push either total past `MaxGasWantedPerBlock` or `MaxGasEstimatedPerBlock`. + - The gas limits are sourced from genesis `consensus_params.block`; `max_gas` (used for gas estimated) must be greater than zero or the node will refuse to start. + - Under Autobahn, `BlockResults` reports `ConsensusParamUpdates.Block.MaxGas` as `MaxGasEstimatedPerBlock`. - Limits are validated when the payload is built; payloads exceeding the transaction count or total byte limit are rejected. - The block proto size bound derives an upper limit on the encoded block used to size networking message windows. diff --git a/learn/sei-giga.mdx b/learn/sei-giga.mdx index 7fb349a..b129df4 100644 --- a/learn/sei-giga.mdx +++ b/learn/sei-giga.mdx @@ -177,7 +177,6 @@ The file referenced by `autobahn-config-file` is a JSON document with the follow | `max_gas_per_block` | number | Maximum gas allowed per block. Must be greater than 0. | | `max_txs_per_block` | number | Maximum transactions per block. Must be greater than 0. | | `max_txs_per_second` | number \| null | Optional cap on transactions per second. Omit or set null for no limit. | -| `mempool_size` | number | Maximum mempool size. Must be greater than 0. | | `block_interval` | duration | Target interval between blocks. Must be greater than 0. | | `allow_empty_blocks` | boolean | Whether empty blocks may be produced. | | `view_timeout` | duration | Consensus view timeout. Must be greater than 0. | diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 82fe631..e9f4f15 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -161,7 +161,6 @@ The referenced JSON file supports the following fields: ], "max_txs_per_block": 5000, "max_txs_per_second": 1000, - "mempool_size": 20000, "block_interval": "400ms", "allow_empty_blocks": true, "view_timeout": "1500ms", @@ -173,10 +172,10 @@ The referenced JSON file supports the following fields: | Field | Description | | --- | --- | | `validators` | Committee membership. Each entry is `{ validator_key, node_key, address }`. Validator keys and node keys must be unique across the list, and the node's own keys must be present. | -| `max_gas_per_block` | Maximum gas per produced block. Must be `> 0`. | | `max_txs_per_block` | Maximum transactions per produced block. Must be `> 0`. Note that Autobahn also enforces hard on-chain per-block caps of **2000 transactions** and roughly **2 MB** of total transaction bytes; `max_txs_per_block` is effectively clamped to the 2000-tx limit, so setting it higher has no effect. | | `max_txs_per_second` | Optional cap on transactions per second (omit to leave unset). | -| `mempool_size` | Retained for compatibility. Must be `> 0`. Note that the Autobahn producer no longer maintains a separate producer mempool channel — blocks are now built by reaping transactions directly from the shared node `TxMempool` (configured under the `[mempool]` section of `config.toml`). | + +The `mempool_size` field has been removed from the Autobahn config and is no longer required by validation. Autobahn no longer reaps transactions from the shared CometBFT `TxMempool`; instead the block producer maintains its own mempool whose capacity is derived from the per-lane block budget (`BlocksPerLane`). This producer-backed mempool inserts EVM transactions in strict per-account nonce order and enforces the per-block gas-wanted and gas-estimated limits, so transactions with unexpected nonces or exceeding the size/gas limits are rejected at insertion time. The maximum gas per block is now derived from the genesis `ConsensusParams.Block` (`MaxGas` and `MaxGasWanted`) rather than a `max_gas_per_block` config field. #### Mempool transaction TTL (config.toml) diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index fec42df..3d3b07a 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -286,7 +286,6 @@ When Autobahn is enabled, the referenced JSON file supports the following fields ], "max_txs_per_block": 5000, "max_txs_per_second": 1000, - "mempool_size": 20000, "block_interval": "400ms", "allow_empty_blocks": false, "view_timeout": "1500ms", @@ -299,12 +298,15 @@ When Autobahn is enabled, the referenced JSON file supports the following fields The `max_gas_per_block` field has been removed from the Autobahn config file. The producer's max-gas-per-block is now derived from the chain's genesis `consensus_params.block.max_gas` — the same gas-limit consensus rule the EVM runtime reads. This value must be greater than 0, otherwise the node fails to start with an `ErrGenesisMaxGasInvalid` error (`genesis consensus_params.block.max_gas must be > 0`). Node operators upgrading from an earlier release must remove any `max_gas_per_block` line from their Autobahn config file. + + The `mempool_size` field has been removed from the Autobahn config file. The mempool capacity is now derived automatically from the number of unexecuted blocks the local lane may hold (`BlocksPerLane`), so it no longer needs to be configured. Node operators upgrading from an earlier release must remove any `mempool_size` line from their Autobahn config file. + + | Field | Description | | --- | --- | | `validators` | List of committee members, each with a `validator_key`, `node_key`, and `address`. Must not be empty. | | `max_txs_per_block` | Maximum number of transactions per block. Must be greater than 0. | | `max_txs_per_second` | Optional cap on transactions per second. | -| `mempool_size` | Maximum mempool size. Must be greater than 0. | | `block_interval` | Target interval between blocks (e.g. `400ms`). Must be greater than 0. | | `allow_empty_blocks` | Whether to produce empty blocks. | | `view_timeout` | Consensus view timeout. Must be greater than 0. | From 0fa678b4dccecceca06a1148e727a91df78e5c27 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:34:34 +0000 Subject: [PATCH 63/81] docs: String length limits were added to numeric parsing functions (Dec, Int, Uint) and the JSON precompile's ExtractAsUint256, causing overly long numeric strings to now be rejected with an error. (sei-protocol/sei-chain#3532) --- evm/precompiles/json.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/evm/precompiles/json.mdx b/evm/precompiles/json.mdx index fdcd386..6541c0d 100644 --- a/evm/precompiles/json.mdx +++ b/evm/precompiles/json.mdx @@ -131,6 +131,10 @@ The JSON precompile has specific limitations for different data types: | extractAsBytesList | Arrays of strings/objects | Each element returned as bytes | + +**Value Length Limit:** `extractAsUint256` rejects value strings longer than 100 characters. If the numeric string extracted for the given key exceeds 100 characters, the call fails with `value string too long`. Ensure the numeric values you pass stay within this limit. + + ### Data Type Conversion Strategies ```typescript From 9b7d0961da01d8e7433d5a1d7d2bb8cc881f127d Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:36:10 +0000 Subject: [PATCH 64/81] docs: Adds a new mock_chain_validation build tag (and Docker images) that swallows most halting consensus validation failures, plus a new sei_unsafe_validation_skipped_total metric emitted by non-default build variants. (sei-protocol/sei-chain#3429) --- node/advanced-config-monitoring.mdx | 39 +++++++++++++++++++++++++++++ node/index.mdx | 19 +++++++++++--- node/technical-reference.mdx | 27 +++++++++++++++++++- 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/node/advanced-config-monitoring.mdx b/node/advanced-config-monitoring.mdx index 5378780..ef16a2d 100644 --- a/node/advanced-config-monitoring.mdx +++ b/node/advanced-config-monitoring.mdx @@ -722,6 +722,45 @@ The duration histograms use the following explicit bucket boundaries (in seconds +## Consensus Validation Metrics + +Sei nodes emit an OpenTelemetry-based counter through the process-wide `MeterProvider` (for example, a Prometheus exporter) that tracks halting consensus validation failures swallowed by non-default `ConsensusPolicy` builds. + +| Metric | Type | Attributes | Description | +| --- | --- | --- | --- | +| `sei_unsafe_validation_skipped_total` | counter | `kind` | Number of halting consensus validation failures that were swallowed (counted and continued instead of halting the chain) by a non-default `ConsensusPolicy`. The `kind` attribute identifies the specific validation failure that was skipped. | + + + In production (default) builds this counter is **always zero** — every validation failure halts the node as expected. A non-zero value is only ever emitted by special-purpose binaries built with the `mock_block_validation` or `mock_chain_validation` build tags (published as `sei-chain:mock_chain_validation-*` and `sei-chain:mock_chain_validation-nightly-*` Docker images). These binaries intentionally bypass halting validation and must never be run on mainnet or any node whose state you trust; they exist for forked-state replays and similar diagnostic scenarios. + + +Build-tag behavior: + +- **default (production)** — no failures are swallowed; the counter stays at zero and every validation failure halts. +- **`mock_block_validation`** — swallows only `app_hash` and `data_hash` failures, preserving that tag's long-standing behavior; all other failures still halt. +- **`mock_chain_validation`** — swallows every swallow-eligible failure except `last_commit_verify` (which is excluded to avoid a downstream panic and therefore still halts). Intended for forked-state replays. + +### `sei_unsafe_validation_skipped_total` `kind` values + +| `kind` | Swallowed validation failure | +| --- | --- | +| `app_hash` | Block `AppHash` did not match the expected application hash. | +| `data_hash` | Block `DataHash` did not match the hash of the block data. | +| `last_results_hash` | Block `LastResultsHash` did not match the expected value. | +| `last_block_id` | Block `LastBlockID` did not match the expected previous block ID. | +| `consensus_hash` | Block `ConsensusHash` did not match the hash of the consensus params. | +| `validators_hash` | Block `ValidatorsHash` did not match the current validator set hash. | +| `next_validators_hash` | Block `NextValidatorsHash` did not match the next validator set hash. | +| `last_commit_verify` | `LastCommit` verification failed. Never swallowed by `mock_chain_validation` (excluded from the swallow set) — always halts. | +| `proposer_not_in_validator_set` | Block proposer address is not a member of the validator set. | +| `evidence_overflow` | Block evidence exceeded the maximum allowed byte size. | +| `last_commit_hash` | Block `LastCommitHash` did not match the expected value. | +| `evidence_hash` | Block `EvidenceHash` did not match the hash of the block evidence. | +| `per_evidence_validate_basic` | An individual evidence item failed `ValidateBasic`. | + + + + ## Backup Management diff --git a/node/index.mdx b/node/index.mdx index 634afe7..227792d 100644 --- a/node/index.mdx +++ b/node/index.mdx @@ -103,14 +103,27 @@ See Network Versions table above for current recommended version. - **Mock block validation builds are for testing/mock environments only — never run them in production.** Building with the `mock_block_validation` Go build tag produces a `seid` binary that bypasses `AppHash` and `DataHash` validation during block execution and validation. Default (production) builds always enforce every consensus check. + **Mock validation builds are for testing/mock environments only — never run them in production.** These builds use a build-tag-selected `ConsensusPolicy` whose `HandleError` mechanism swallows specific halting validation failures (incrementing the `sei_unsafe_validation_skipped_total{kind=...}` counter instead of halting) rather than enforcing them. Default (production) builds always enforce every consensus check, and this counter is always zero. + + **`mock_block_validation`** — swallows only `AppHash` and `DataHash` validation failures during block execution and validation; every other consensus check still halts. ```bash - # Build a seid binary that skips AppHash/DataHash validation (testing only) + # Build a seid binary that swallows AppHash/DataHash validation failures (testing only) GO_BUILD_TAGS=mock_block_validation make install ``` - A dedicated Docker image is published for this build in ECR, tagged `sei/sei-chain:mock_block_validation-` (built with `GO_BUILD_TAGS=mock_block_validation`). Because these binaries skip integrity checks that guard against divergent or malformed state, they must not be used on mainnet, testnets, or any network carrying real value. + A dedicated Docker image is published for this build in ECR, tagged `sei/sei-chain:mock_block_validation-` (built with `GO_BUILD_TAGS=mock_block_validation`). + + **`mock_chain_validation`** — intended for forked-state replays; swallows every swallow-eligible halting validation failure except `ErrLastCommitVerify` (which still halts to avoid a downstream panic). It is built together with `mock_balances`. + + ```bash + # Build a seid binary for forked-state replays (testing only) + GO_BUILD_TAGS="mock_balances mock_chain_validation" make install + ``` + + A dedicated Docker image is published for this build in ECR, tagged `sei/sei-chain:mock_chain_validation-` (and `sei/sei-chain:mock_chain_validation-nightly-*` for nightly builds). + + Because these binaries skip integrity checks that guard against divergent or malformed state, they must not be used on mainnet, testnets, or any network carrying real value. diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 3d3b07a..eb65427 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -362,9 +362,17 @@ In addition to the configurable `max_gas_per_block` and `max_txs_per_block` fiel The `seid` binary can be compiled with optional Go build tags that alter consensus behavior. Build tags are passed via the `GO_BUILD_TAGS` build argument. +The `seid` binary decides how to react to a halting validation failure at compile time via the `ConsensusPolicy` type. Each build variant compiles in exactly one policy through its `ConsensusPolicy.HandleError(err)` method, so there is no runtime branch: + +- **Default (production):** `HandleError` returns the error for every validation-failure kind, so production halting semantics are unchanged. +- **`mock_block_validation`:** `HandleError` swallows only `ErrAppHash` and `ErrDataHash` failures (the same effective set the tag has always relaxed) and halts on everything else. +- **`mock_chain_validation`:** `HandleError` swallows every swallow-eligible halting validation failure except `ErrLastCommitVerify` (excluded to avoid a downstream panic in `buildLastCommitInfo`). + +When a non-default policy swallows a failure, it increments the `sei_unsafe_validation_skipped_total` counter (labeled with the failure `kind`) instead of halting. This metric is always zero in production builds. + #### `mock_block_validation` -Building with `GO_BUILD_TAGS=mock_block_validation` produces a `seid` binary that bypasses `AppHash` and `DataHash` block validation checks during block execution and validation. This is controlled at compile time by the `ConsensusPolicy` type: production (default) builds enforce every check, while `mock_block_validation` builds have `ConsensusPolicy.SkipAppHashValidation()` and `ConsensusPolicy.SkipDataHashValidation()` return `true` unconditionally. +Building with `GO_BUILD_TAGS=mock_block_validation` produces a `seid` binary whose `ConsensusPolicy.HandleError` swallows `AppHash` and `DataHash` block validation failures during block execution and validation, incrementing `sei_unsafe_validation_skipped_total` for each swallowed failure instead of halting. All other validation-failure kinds halt as in production. The `mock_block_validation` build is intended for testing and mock environments only. It disables cryptographic block-content validation and must never be used for a production or mainnet node. @@ -378,6 +386,23 @@ sei/sei-chain:mock_block_validation- This image is built with `GO_BUILD_TAGS=mock_block_validation` and is distinct from the standard `sei/sei-chain` image tags. +#### `mock_chain_validation` + +Building with `GO_BUILD_TAGS=mock_balances mock_chain_validation` produces a `seid` binary whose `ConsensusPolicy.HandleError` swallows every swallow-eligible halting validation failure except `ErrLastCommitVerify`. The chain still computes every check authentically; a swallowed failure increments `sei_unsafe_validation_skipped_total{kind=...}` and continues instead of halting. `ErrLastCommitVerify` is the exception — it always halts and is not counted, because swallowing it would trigger a downstream panic in `buildLastCommitInfo`. This variant is intended for forked-state replays. + + + The `mock_chain_validation` build is intended for testing and forked-state replay environments only. It swallows nearly all halting consensus validation failures and must never be used for a production or mainnet node. + + +Corresponding Docker images are published to ECR for this build: + +```text +sei/sei-chain:mock_chain_validation- +sei/sei-chain:mock_chain_validation-nightly-- +``` + +These images are built with `GO_BUILD_TAGS=mock_balances mock_chain_validation` and are distinct from the standard `sei/sei-chain` image tags. + Understanding network parameters helps you operate your node effectively. From 7cded5e33b9e0a3a6bf0edf7fc7979f04c1c2285 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:36:37 +0000 Subject: [PATCH 65/81] docs: The Prometheus metrics namespace changed from 'sei-chain' to 'sei_chain', which alters exported metric names that operators query in monitoring dashboards. (sei-protocol/sei-chain#3554) --- node/advanced-config-monitoring.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/node/advanced-config-monitoring.mdx b/node/advanced-config-monitoring.mdx index ef16a2d..e4b5930 100644 --- a/node/advanced-config-monitoring.mdx +++ b/node/advanced-config-monitoring.mdx @@ -496,6 +496,12 @@ Each checkpoint also writes a `proposer priority hash checkpoint` log line conta Sei nodes emit OpenTelemetry-based metrics for the EVM JSON-RPC layer through the process-wide `MeterProvider` (for example, a Prometheus exporter). These `evmrpc_*` metrics are the recommended source for monitoring RPC performance and websocket activity. + + + + The OpenTelemetry Prometheus exporter namespace is `sei_chain` (underscore). When these metrics are scraped through the Prometheus exporter, exported series are prefixed accordingly (for example, `sei_chain_evmrpc_request_latency_seconds`, `sei_chain_flatkv_commit_latency`, `sei_chain_app_abci_commit_duration_seconds`, `sei_chain_module_mid_block_duration`). The metric names documented on this page are the unprefixed instrument names; prepend the `sei_chain_` namespace when querying them in Prometheus/Grafana. This namespace was previously `sei-chain` (hyphen); because Prometheus normalizes the hyphen to an underscore anyway, existing dashboards and alert queries should continue to match, but confirm your PromQL uses the `sei_chain_` prefix after upgrading. + + | Metric | Type | Description | | --- | --- | --- | | `evmrpc_request_latency_seconds` | histogram | RPC request latency in seconds, labeled by endpoint, connection, success, error class, and JSON-RPC code bucket. | From f1a9f10d296558817fe8173031f8993625b71011 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:37:03 +0000 Subject: [PATCH 66/81] docs: Adds support for booting a node directly in flatkv_only state-commit mode (sc-write-mode = "flatkv_only") and fixes snapshot/state-sync and empty-value WAL-replay correctness for FlatKV-only nodes. (sei-protocol/sei-chain#3545) --- node/giga-storage-migration.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/giga-storage-migration.mdx b/node/giga-storage-migration.mdx index 4ff744d..b7c2a69 100644 --- a/node/giga-storage-migration.mdx +++ b/node/giga-storage-migration.mdx @@ -59,7 +59,7 @@ progresses through a linear sequence of on-disk **migration versions**: | `MigrateAllButBank` (`migrate_all_but_bank`) | 1 → 2 | Migrates every module except `bank/` (and the already-migrated `evm/`) from `memiavl` to `flatKV`. | | `AllMigratedButBank` (`all_migrated_but_bank`) | 2 | Steady state: everything except `bank/` lives in `flatKV`; `bank/` remains in `memiavl`. | | `MigrateBank` (`migrate_bank`) | 2 → 3 | Migrates the final `bank/` module from `memiavl` to `flatKV`. | -| `FlatKVOnly` (`flatkv_only`) | 3 | Terminal state: every module routes to `flatKV`; `memiavl` is not in the data path (bootstrap passes `nil` for `memiavl`). | +| `FlatKVOnly` (`flatkv_only`) | 3 | Terminal state: every module routes to `flatKV`; `memiavl` is not in the data path (bootstrap passes `nil` for `memiavl`). A node can be booted **directly** into this steady state by setting `sc-write-mode = "flatkv_only"` in `app.toml` — `memiavl` is never allocated. Snapshot export and state-sync restore work correctly in this mode: the State Store is fully repopulated and the restored AppHash matches the snapshot source (the FlatKV exporter now emits its own module header, and empty-value writes are preserved rather than dropped on WAL replay). | | `TestOnlyDualWrite` (`test_only_dual_write`) | — | Test-only mode that dual-writes `evm/` traffic to both `memiavl` and `flatKV` while routing all other modules to `memiavl`; reads, proofs, and iteration are served exclusively by `memiavl`. | From 05bf7810334894b83510ddeacf1b866d9fed1259 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:37:37 +0000 Subject: [PATCH 67/81] docs: A new RPC config field `timeout-write` was added to control the HTTP write timeout, defaulting to 30s, replacing the previous auto-adjustment logic tied to timeout-broadcast-tx-commit. (sei-protocol/sei-chain#3558) --- node/node-operators.mdx | 6 ++++++ node/technical-reference.mdx | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/node/node-operators.mdx b/node/node-operators.mdx index e9f4f15..2edf350 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -57,6 +57,12 @@ laddr = "tcp://0.0.0.0:26657" max-open-connections = 900 # Transaction confirmation timeout for /broadcast_tx_commit timeout-broadcast-tx-commit = "10s" + + +# HTTP write timeout; acts as a hard backstop for all handlers. Default 30s. +# Must be greater than timeout-broadcast-tx-commit when non-zero. +# Set to "0s" to disable the write timeout (not recommended). +timeout-write = "30s" ``` #### Application Settings (app.toml) diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index eb65427..78a9a7b 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -228,6 +228,10 @@ cors_allowed_methods = ["HEAD", "GET", "POST"] cors_allowed_headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time"] max_open_connections = 900 timeout_broadcast_tx_commit = "10s" +# HTTP write timeout; acts as a hard backstop for all handlers. Must be greater +# than timeout_broadcast_tx_commit when non-zero. Set to "0s" to disable (not +# recommended). Defaults to 30s. +timeout-write = "30s" # Consensus Configuration [consensus] From 12ad528097c57c6afc3ea47986e455e0725050bb Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:38:18 +0000 Subject: [PATCH 68/81] docs: Two mempool config fields (pending-ttl-duration and pending-ttl-num-blocks) are now deprecated with no effect, and BroadcastTxCommit now honors the configured timeout-broadcast-tx-commit setting. (sei-protocol/sei-chain#3567) --- node/index.mdx | 2 ++ node/node-operators.mdx | 9 +++++++++ node/technical-reference.mdx | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/node/index.mdx b/node/index.mdx index 227792d..dc6a939 100644 --- a/node/index.mdx +++ b/node/index.mdx @@ -280,8 +280,10 @@ pending-size = 5000 max-pending-txs-bytes = 1073741824 +# Deprecated: pending TTL is not used and this field has no effect. pending-ttl-duration = "3s" +# Deprecated: pending TTL is not used and this field has no effect. pending-ttl-num-blocks = 5 ``` diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 2edf350..e467dea 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -204,6 +204,15 @@ Previously a non-zero value enabled the corresponding TTL; now `ttl-duration = 0 and `ttl-num-blocks = 0` explicitly disable time-based and block-based TTL purging respectively. The defaults remain `5s` and `10` blocks. + + The separate **pending** TTL fields `pending-ttl-duration` and + `pending-ttl-num-blocks` under `[mempool]` are now **deprecated and have no + effect**. Pending TTL is no longer used by the mempool, so setting these + fields does nothing. They are retained only for backward compatibility and + may be removed in a future release; do not rely on them to expire pending + transactions. + + Expiration behavior differs between READY and PENDING transactions. `remove-expired-txs-from-queue` now governs whether expired **READY** diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 78a9a7b..d8ed90f 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -227,6 +227,11 @@ cors_allowed_origins = [] cors_allowed_methods = ["HEAD", "GET", "POST"] cors_allowed_headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time"] max_open_connections = 900 +# Maximum time to wait for a BroadcastTxCommit request to complete. When set to +# a value greater than 0, the BroadcastTxCommit RPC now enforces this as a +# context deadline on the request: if CheckTx and DeliverTx do not complete +# within this duration, the request context is cancelled and the call returns a +# timeout error. Set to "0s" to disable the timeout. timeout_broadcast_tx_commit = "10s" # HTTP write timeout; acts as a hard backstop for all handlers. Must be greater # than timeout_broadcast_tx_commit when non-zero. Set to "0s" to disable (not From d5945d925ee5114a04c0553d60089e7f7491835f Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:40:15 +0000 Subject: [PATCH 69/81] docs: The eth_getProof JSON-RPC endpoint now requires hex-encoded storage keys, rejects malformed keys, and enforces a maximum of 1024 storage keys per request. (sei-protocol/sei-chain#3556) --- evm/evm-parity/state-proofs.mdx | 7 +++++++ evm/reference.mdx | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/evm/evm-parity/state-proofs.mdx b/evm/evm-parity/state-proofs.mdx index dbe256a..8fa8462 100644 --- a/evm/evm-parity/state-proofs.mdx +++ b/evm/evm-parity/state-proofs.mdx @@ -25,6 +25,13 @@ If you are doing standard contract reads, event queries, or transaction lookups, ## Calling eth_getProof +### Storage key requirements + +Before calling `eth_getProof`, note two requirements Sei enforces on the `storageKeys` argument: + +- **Keys must be hex-encoded.** Each storage key must be a valid hex-encoded value (for example `0x0000000000000000000000000000000000000000000000000000000000000001`). Keys are decoded and left-padded to 32 bytes. A malformed, non-hex key is rejected with an `invalid storage key` error. Raw byte strings, which were previously accepted, no longer work. +- **At most 1024 keys per request.** A single proof request may include a maximum of 1024 storage keys. Requesting more returns a `too many storage keys` error. Split larger sets across multiple requests. + The call works through standard libraries: diff --git a/evm/reference.mdx b/evm/reference.mdx index 0e59581..098af58 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -487,12 +487,14 @@ Every method below is also browsable interactively in the explorer above; this s **Sei-specific behavior:** Sei stores state in an IAVL tree, not an Ethereum Merkle-Patricia trie. The result is a Sei-specific ProofResult{address, hexValues, storageProof} where storageProof entries are CometBFT/IAVL crypto.ProofOps, NOT eth-style MPT proof nodes. There is no accountProof, balance, codeHash, nonce, or storageHash field (Sei has no per-account state root); standard eth_getProof verifiers will not work. The EVM store is resolved by unwrapping any wrapping KVStore layers (cachekv, Giga cache, tracekv, and prefix stores) to reach the underlying proof-capable queryable store, so proofs succeed across more node/store configurations (classic IAVL, store/v2 memiavl, and future proof-capable roots) rather than only the classic IAVL store. +**Storage key validation:** Each entry in `storageKeys` must be a valid hex-encoded value (0x-prefixed); it is decoded and left-padded to 32 bytes. Raw non-hex byte strings are no longer accepted — a malformed key is rejected with an `invalid storage key` error. A request may include at most 1024 storage keys (`MaxStorageKeysPerProof`); exceeding this returns a `too many storage keys` error. + **Parameters:** | # | Name | Type | Description | | :- | :- | :- | :- | | 1 | `address` | DATA, 20 bytes | Account address. | -| 2 | `storageKeys` | array of DATA, 32 bytes | Storage slot keys to prove (bounded by MaxStorageKeysPerProof). | +| 2 | `storageKeys` | array of DATA, 32 bytes | Hex-encoded storage slot keys to prove; each is decoded and left-padded to 32 bytes. Malformed (non-hex) keys are rejected with `invalid storage key`. At most 1024 keys per request (`MaxStorageKeysPerProof`); exceeding returns `too many storage keys`. | | 3 | `blockNrOrHash` | BLOCKNUMBER or DATA | Block number, tag, or hash. | **Example request:** From e4b52b305d3d0f1bf826d24488492271215bcbe7 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:41:49 +0000 Subject: [PATCH 70/81] docs: The consensus validation metric label changed from `kind` to `validation_error` (and the `evidence_overflow` value became `too_much_evidence`) on the sei_unsafe_validation_skipped_total counter emitted by non-default (mock) build tags. (sei-protocol/sei-chain#3565) --- node/advanced-config-monitoring.mdx | 2 +- node/index.mdx | 2 +- node/technical-reference.mdx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/node/advanced-config-monitoring.mdx b/node/advanced-config-monitoring.mdx index e4b5930..b4232af 100644 --- a/node/advanced-config-monitoring.mdx +++ b/node/advanced-config-monitoring.mdx @@ -734,7 +734,7 @@ Sei nodes emit an OpenTelemetry-based counter through the process-wide `MeterPro | Metric | Type | Attributes | Description | | --- | --- | --- | --- | -| `sei_unsafe_validation_skipped_total` | counter | `kind` | Number of halting consensus validation failures that were swallowed (counted and continued instead of halting the chain) by a non-default `ConsensusPolicy`. The `kind` attribute identifies the specific validation failure that was skipped. | +| `sei_unsafe_validation_skipped_total` | counter | `validation_error` | Number of halting consensus validation failures that were swallowed (counted and continued instead of halting the chain) by a non-default `ConsensusPolicy`. The `validation_error` attribute identifies the specific validation failure that was skipped. | In production (default) builds this counter is **always zero** — every validation failure halts the node as expected. A non-zero value is only ever emitted by special-purpose binaries built with the `mock_block_validation` or `mock_chain_validation` build tags (published as `sei-chain:mock_chain_validation-*` and `sei-chain:mock_chain_validation-nightly-*` Docker images). These binaries intentionally bypass halting validation and must never be run on mainnet or any node whose state you trust; they exist for forked-state replays and similar diagnostic scenarios. diff --git a/node/index.mdx b/node/index.mdx index dc6a939..e9a98ba 100644 --- a/node/index.mdx +++ b/node/index.mdx @@ -103,7 +103,7 @@ See Network Versions table above for current recommended version. - **Mock validation builds are for testing/mock environments only — never run them in production.** These builds use a build-tag-selected `ConsensusPolicy` whose `HandleError` mechanism swallows specific halting validation failures (incrementing the `sei_unsafe_validation_skipped_total{kind=...}` counter instead of halting) rather than enforcing them. Default (production) builds always enforce every consensus check, and this counter is always zero. + **Mock validation builds are for testing/mock environments only — never run them in production.** These builds use a build-tag-selected `ConsensusPolicy` whose `HandleError` mechanism swallows specific halting validation failures (incrementing the `sei_unsafe_validation_skipped_total{validation_error=...}` counter instead of halting) rather than enforcing them. Default (production) builds always enforce every consensus check, and this counter is always zero. **`mock_block_validation`** — swallows only `AppHash` and `DataHash` validation failures during block execution and validation; every other consensus check still halts. diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index d8ed90f..346045b 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -377,7 +377,7 @@ The `seid` binary decides how to react to a halting validation failure at compil - **`mock_block_validation`:** `HandleError` swallows only `ErrAppHash` and `ErrDataHash` failures (the same effective set the tag has always relaxed) and halts on everything else. - **`mock_chain_validation`:** `HandleError` swallows every swallow-eligible halting validation failure except `ErrLastCommitVerify` (excluded to avoid a downstream panic in `buildLastCommitInfo`). -When a non-default policy swallows a failure, it increments the `sei_unsafe_validation_skipped_total` counter (labeled with the failure `kind`) instead of halting. This metric is always zero in production builds. +When a non-default policy swallows a failure, it increments the `sei_unsafe_validation_skipped_total` counter (labeled with the failure via the `validation_error` attribute) instead of halting. This metric is only emitted by the non-default (mock) build variants. #### `mock_block_validation` From dc77bfcdb80b613486a7594845cc8bddd6c218eb Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:43:51 +0000 Subject: [PATCH 71/81] docs: The parquet/DuckDB receipt store backend and its associated config fields have been removed; pebbledb is now the only supported receipt-store backend. (sei-protocol/sei-chain#3580) --- node/giga-storage-migration.mdx | 10 +++++----- node/node-operators.mdx | 11 ++++++----- node/technical-reference.mdx | 26 ++++++++++++++------------ 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/node/giga-storage-migration.mdx b/node/giga-storage-migration.mdx index b7c2a69..2b81844 100644 --- a/node/giga-storage-migration.mdx +++ b/node/giga-storage-migration.mdx @@ -346,20 +346,20 @@ described above, or (b) set `evm-ss-split = false` and restart. If ## Receipt backend default When Giga Storage is enabled (`GIGA_STORAGE=true`), the receipt backend now -defaults to `parquet`. Previously the receipt backend was left unchanged and +defaults to `pebble`. Previously the receipt backend was left unchanged and had to be set explicitly through the `RECEIPT_BACKEND` environment variable. This default is applied implicitly: enabling Giga Storage sets -`RECEIPT_BACKEND=parquet` unless you have already provided an explicit value. +`RECEIPT_BACKEND=pebble` unless you have already provided an explicit value. To use a different receipt backend, set `RECEIPT_BACKEND` explicitly before starting the node — an explicit value always takes precedence over the -parquet default. +pebble default. ```bash copy -# Giga Storage on, receipt backend defaults to parquet +# Giga Storage on, receipt backend defaults to pebble export GIGA_STORAGE=true -# Override the parquet default with an explicit backend +# Override the pebble default with an explicit backend export GIGA_STORAGE=true export RECEIPT_BACKEND= ``` diff --git a/node/node-operators.mdx b/node/node-operators.mdx index e467dea..7d176fc 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -119,11 +119,12 @@ ss-enable = true ss-keep-recent = 100000 [receipt-store] -# Storage backend for EVM transaction receipts (pebbledb or parquet). -# Defaults to pebbledb, but when Giga Storage is enabled (GIGA_STORAGE=true) -# the receipt backend defaults to parquet instead. You can still force a -# specific backend by setting rs-backend explicitly (or the RECEIPT_BACKEND -# env var in the containerized node scripts), which always takes precedence. +# Storage backend for EVM transaction receipts. pebbledb is the only +# supported backend (aka pebble); setting rs-backend to any other value +# returns an error. When Giga Storage is enabled (GIGA_STORAGE=true) the +# receipt backend still defaults to pebble. You can force the backend +# explicitly with rs-backend (or the RECEIPT_BACKEND env var in the +# containerized node scripts), which always takes precedence. rs-backend = "pebbledb" ``` diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 346045b..d8d8ca7 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -173,18 +173,20 @@ ss-prune-interval = 600 # Receipt store configuration [state-store.receipt-store] -# TxIndexBackend selects the tx-hash index implementation for the parquet -# receipt store. Set to "pebbledb" (the default) to maintain a Pebble-backed -# tx_hash -> block_number index alongside the parquet files so receipt-by-hash -# lookups can target a single file instead of scanning all files. The index is -# kept in sync on writes, rebuilt during WAL replay, and pruned alongside the -# parquet files. Set to "" to disable the index. When the index is disabled, a -# receipt-by-tx-hash lookup that misses the in-memory cache fails fast and -# returns not-found instead of performing a full parquet scan (which would be -# prohibitively expensive at production scale). Operators who rely on tx-hash -# receipt lookups for historical receipts that are no longer cached must keep -# the index enabled. This field is ignored unless rs-backend = "parquet". -tx-index-backend = "pebbledb" +# Backend defines the receipt store backend. +# The only supported backend is pebbledb (aka pebble), which is also the +# default. The parquet/DuckDB backend has been removed; setting rs-backend to +# "parquet" now returns an error. +rs-backend = "pebbledb" + +# AsyncWriteBuffer defines the async queue length for commits applied to the +# receipt store. Applies only when rs-backend = "pebbledb". Set <= 0 for +# synchronous writes. Defaults to 100. +async-write-buffer = 100 + +# Interval in seconds to trigger pruning. Receipt retention is controlled by +# the global min-retain-blocks flag. Defaults to 600 seconds. +prune-interval-seconds = 600 ``` From afa4f3d5024a709ebd3bf24d8e7ab0869c92d5cf Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:44:42 +0000 Subject: [PATCH 72/81] =?UTF-8?q?docs:=20Pagination=20now=20enforces=20har?= =?UTF-8?q?d=20caps=20on=20limit=20(MaxLimit=3D1000),=20offset=20(MaxOffse?= =?UTF-8?q?t=3D10000),=20and=20scan=20iterations=20(MaxScanLimit=3D10000),?= =?UTF-8?q?=20and=20no=20longer=20auto-enables=20count=5Ftotal=20when=20li?= =?UTF-8?q?mit=20is=20omitted=20=E2=80=94=20requests=20exceeding=20these?= =?UTF-8?q?=20bounds=20return=20InvalidArgument=20errors.=20(sei-protocol/?= =?UTF-8?q?sei-chain#3494)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node/technical-reference.mdx | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index d8d8ca7..774f556 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -369,6 +369,26 @@ In addition to the configurable `max_gas_per_block` and `max_txs_per_block` fiel +### Query Pagination Limits + +Queries that support pagination now enforce hard caps to protect nodes from unbounded store walks. Requests that exceed any of these bounds are rejected with an `InvalidArgument` gRPC error. + +| Parameter | Value | Description | +| --- | --- | --- | +| `MaxLimit` | 1000 | Maximum page size. A `limit` above this returns an `exceeds maximum allowed limit` error. | +| `MaxOffset` | 10000 | Maximum offset allowed in a `PageRequest`. An `offset` above this returns an `exceeds maximum allowed offset` error. | +| `MaxScanLimit` | 10000 | Maximum number of store entries offset-based (lazy) pagination will scan past the page end. Exceeding it returns a `scanned more than 10000 entries` error suggesting key-based pagination. | + + + For datasets larger than a single page, use **key-based pagination** (`pagination.key`) rather than offset-based pagination. With offset-based pagination over a sparse filter, the scan limit may be reached before the page fills, in which case the returned `next_key` can be `nil` even when more results exist. + + + + `count_total` is no longer automatically enabled when `limit` is omitted or set to zero. Previously an empty or zero-limit page request would populate the `total` field; now `total` is `0` unless you explicitly set `pagination.count_total = true`. Requesting `count_total` on a large dataset can also hit the `MaxScanLimit` and fail — prefer key-based pagination for full traversals. + + + + ### Build Tags The `seid` binary can be compiled with optional Go build tags that alter consensus behavior. Build tags are passed via the `GO_BUILD_TAGS` build argument. From 54f21cda3706b3b496ed948f3d5fb46f369a0d5c Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:46:40 +0000 Subject: [PATCH 73/81] docs: EVM SetCode transactions (EIP-7702) with an empty authorization list are now rejected with an 'auth list cannot be empty' validation error. (sei-protocol/sei-chain#3528) --- evm/evm-parity/transaction-types.mdx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/evm/evm-parity/transaction-types.mdx b/evm/evm-parity/transaction-types.mdx index 7f11981..badc49d 100644 --- a/evm/evm-parity/transaction-types.mdx +++ b/evm/evm-parity/transaction-types.mdx @@ -16,6 +16,13 @@ Sei supports most Ethereum transaction types. The one notable exception is blob | 2 | EIP-1559 | Fee market | Supported — base fee is not burned | | 4 | EIP-7702 | Set code | Supported | + +### Set Code (EIP-7702) Auth List Requirement + +Type 4 (EIP-7702) SetCode transactions must include a non-empty authorization list. A transaction with an empty or nil auth list is rejected during validation with the error `auth list cannot be empty`. + +Each authorization entry must also carry a valid (non-nil) chain ID. If you are constructing SetCode transactions directly, ensure at least one authorization is present before submitting. + ## Not Supported | Type | EIP | Name | Notes | From 464a22f90653f3533a3df2b69548d85007c70a5a Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:47:09 +0000 Subject: [PATCH 74/81] docs: The EVM RPC methods eth_getBlockTransactionCountByNumber and eth_getBlockTransactionCountByHash now return a 'receipts have been pruned' error when the requested block height is below the receipt store's earliest available version. (sei-protocol/sei-chain#3216) --- evm/reference.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/reference.mdx b/evm/reference.mdx index 098af58..d97649a 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -608,7 +608,7 @@ Every method below is also browsable interactively in the explorer above; this s **Supported.** Returns the number of EVM transactions in a block by hash, as a hex quantity. -**Sei-specific behavior:** Counts EVM transactions only; synthetic/bank-transfer txs are excluded. Genesis hash returns 0x0; unknown hash returns null. +**Sei-specific behavior:** Counts EVM transactions only; synthetic/bank-transfer txs are excluded. Genesis hash returns 0x0; unknown hash returns null. If the block's receipts have been pruned from the receipt store — which can happen when the receipt store is configured with a smaller `KeepRecent` than the block/state stores — the method returns an error of the form `requested height X receipts have been pruned; earliest available is Y` instead of a count. **Parameters:** From d0680db7a95a6b806805049207cfea183202bb0e Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:50:04 +0000 Subject: [PATCH 75/81] docs: The Autobahn consensus protocol now enforces a maximum of 100 validators and adds wire-format size/count limits on protobuf message fields, which affects network compatibility and validator set sizing. (sei-protocol/sei-chain#3609) --- learn/sei-giga-specs.mdx | 4 +++- node/node-operators.mdx | 2 +- node/technical-reference.mdx | 29 +++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/learn/sei-giga-specs.mdx b/learn/sei-giga-specs.mdx index 026b4f0..80518f0 100644 --- a/learn/sei-giga-specs.mdx +++ b/learn/sei-giga-specs.mdx @@ -160,10 +160,12 @@ These limits are derived from the genesis `consensus_params.block` values: `MaxG | Property | Value | | --- | --- | - | Max Validators | 100 | + | Max Validators | 100 (hard limit, enforced by Autobahn) | | Voting Power | Stake-weighted | | Unbonding Period | 21 days | | Slashing | Byzantine behavior | + + Under Autobahn consensus, the validator set size is a hard protocol limit rather than just a configurable network parameter. Committee creation (`NewCommittee`) enforces `MaxValidators = 100` and rejects any committee containing more than 100 validators with an error. | Property | Value | diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 7d176fc..207f041 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -178,7 +178,7 @@ The referenced JSON file supports the following fields: | Field | Description | | --- | --- | -| `validators` | Committee membership. Each entry is `{ validator_key, node_key, address }`. Validator keys and node keys must be unique across the list, and the node's own keys must be present. | +| `validators` | Committee membership. Each entry is `{ validator_key, node_key, address }`. Validator keys and node keys must be unique across the list, and the node's own keys must be present. The committee is capped at **100 validators** (`MaxValidators = 100`): a `validators` list with more than 100 entries is rejected at startup and Autobahn refuses to build the committee. | | `max_txs_per_block` | Maximum transactions per produced block. Must be `> 0`. Note that Autobahn also enforces hard on-chain per-block caps of **2000 transactions** and roughly **2 MB** of total transaction bytes; `max_txs_per_block` is effectively clamped to the 2000-tx limit, so setting it higher has no effect. | | `max_txs_per_second` | Optional cap on transactions per second (omit to leave unset). | diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 774f556..fc14ce1 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -365,6 +365,35 @@ In addition to the configurable `max_gas_per_block` and `max_txs_per_block` fiel The effective per-block transaction count is the smaller of the configured `max_txs_per_block` and the hard limit of 2000. If you configure a larger value, the 2000-tx cap still applies. The block proto size upper bound used for p2p message sizing is derived from these limits. + +#### Committee Size Ceiling + +Autobahn enforces a hard upper bound of **100 validators** per committee. Committee construction (`NewCommittee`) rejects any validator set larger than this ceiling, returning an error rather than starting consensus. This `MaxValidators = 100` limit is a protocol-level invariant and applies regardless of how many entries appear in the `validators` list of the Autobahn config file. + + + A validator set exceeding 100 members will cause committee creation to fail. Ensure the `validators` list in your Autobahn config file contains no more than 100 members. + + +#### Wire-Format Message Limits + +Autobahn also enforces structural size and count limits on its protobuf messages during deserialization. These bounds are checked while scanning the raw wire bytes — *before* a message is fully decoded — so that oversized or malformed payloads are rejected without allocating unbounded memory. A message that violates any of these limits is dropped and the sending peer is disconnected. + +The enforced field limits include: + +| Field | Limit | Description | +| --- | --- | --- | +| ed25519 public key | 32 bytes | `PublicKey.ed25519` is bounded to a fixed 32-byte length. | +| Signature bytes | 64 bytes | `Signature.sig` is bounded to a fixed 64-byte length. | +| Block / payload / parent / app hashes | 32 bytes | Hash fields (e.g. `parent_hash`, `payload_hash`, `last_hash`, `app_hash`) are bounded to 32 bytes each. | +| Payload transaction count | 2000 | `Payload.txs` may contain at most 2000 transactions. | +| Payload total transaction size | ~2 MB (2,048,000 bytes) | The combined byte size of all transactions in a payload may not exceed 2,048,000 bytes. | +| QC signature lists | 100 | Signature lists on quorum certificates (`PrepareQC`, `CommitQC`, `AppQC`, `LaneQC`) and vote lists on `TimeoutQC` and `FullProposal.lane_qcs` are each capped at 100 entries, matching the 100-validator committee ceiling. | + + + These wire-format bounds are applied to every Autobahn consensus and data-layer message on receipt. They are protocol-level invariants and are not configurable. Because they are enforced during message scanning rather than after decoding, they protect nodes from resource-exhaustion attacks that rely on the decoded representation being far larger than the encoded bytes. + + + ## Network Parameters From 3287f49ff87b32fbed6ee79f8678251d7d2bcc36 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:55:22 +0000 Subject: [PATCH 76/81] docs: A new consensus config field `unsafe-overrides-enabled` gates whether the Unsafe*TimeoutOverride fields are applied, changing when timeout overrides take effect on nodes. (sei-protocol/sei-chain#3601) --- learn/twin-turbo-consensus.mdx | 2 +- node/technical-reference.mdx | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/learn/twin-turbo-consensus.mdx b/learn/twin-turbo-consensus.mdx index 919547f..6490542 100644 --- a/learn/twin-turbo-consensus.mdx +++ b/learn/twin-turbo-consensus.mdx @@ -14,7 +14,7 @@ The key to achieving sub-second finality lies in aggressively optimizing and par This optimized flow involves several key enhancements: -1. **Aggressive Timeout Configuration:** Sei utilizes heavily tuned Tendermint consensus parameters. Configuration settings (e.g., `UnsafeProposeTimeoutOverride`, `UnsafeCommitTimeoutOverride`) enforce much shorter durations for block proposal, voting, and commit rounds compared to standard Tendermint configurations, directly contributing to the sub-second target block time. Faster gossip propagation for consensus messages further reduces communication latency between validators. +1. **Aggressive Timeout Configuration:** Sei utilizes heavily tuned Tendermint consensus parameters. Configuration settings (e.g., `UnsafeProposeTimeoutOverride`, `UnsafeCommitTimeoutOverride`) can enforce much shorter durations for block proposal, voting, and commit rounds compared to standard Tendermint configurations, directly contributing to the sub-second target block time. These `Unsafe*TimeoutOverride` fields are gated by the `unsafe-overrides-enabled` flag under the `[consensus]` section of the node config. This flag defaults to `false`, meaning the overrides are ignored and the on-chain timeout consensus parameters are used instead. The overrides are only applied when `unsafe-overrides-enabled` is set to `true` (or, during the transition period, while the on-chain timeout params still match the legacy values). In practice, timeout tuning should be governed by the on-chain consensus parameters rather than these unsafe per-node overrides. Faster gossip propagation for consensus messages further reduces communication latency between validators. 2. **Intelligent Mempool Management & Transaction Preparation:** Even before a block proposal is formally initiated for height `H`, validators can begin processing transactions intended for that block. This involves collecting transactions from the network, decoding them concurrently (`DecodeTransactionsConcurrently`), analyzing potential state dependencies (`GenerateEstimatedWritesets`), and potentially pre-fetching required state data from SeiDB. This "pre-consensus" preparation minimizes the work needed once the actual proposal for height `H` arrives. 3. **Optimized BFT Rounds with Parallel Execution Integration:** The critical optimization is the deep integration with Sei's parallelization engine. When a validator receives a block proposal for height `H`, it doesn't necessarily wait for the prevote/precommit rounds to complete before starting execution. Instead: - The block's transactions are dispatched to the parallel execution engine (`ProcessTXsWithOCC`, `DeliverTxBatch`). diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index fc14ce1..22a3eb0 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -254,6 +254,22 @@ double_sign_check_height = 0 ``` + + + The `[consensus]` section also accepts an `unsafe-overrides-enabled` field (defaults to `false`). This flag gates whether the `Unsafe*TimeoutOverride` fields (`UnsafeProposeTimeoutOverride`, `UnsafeProposeTimeoutDeltaOverride`, `UnsafeVoteTimeoutOverride`, `UnsafeVoteTimeoutDeltaOverride`, `UnsafeCommitTimeoutOverride`, and `UnsafeBypassCommitTimeoutOverride`) are actually applied to the resolved consensus timeouts. + + When `unsafe-overrides-enabled = false`, the unsafe timeout overrides are ignored and the node uses the on-chain timeout parameters (falling back to Tendermint defaults for any unset field). As a transitional exception, the overrides are still applied while the on-chain timeout params remain equal to the legacy "bad params" values — this preserves prior behavior until those params are corrected via a governance proposal. + + When `unsafe-overrides-enabled = true`, the unsafe overrides are applied on top of the resolved timeouts. In this mode `UnsafeBypassCommitTimeoutOverride` can also override `BypassCommitTimeout` to `false` (a nil override leaves the resolved value untouched). + + ```toml + [consensus] + # Gates whether the Unsafe*TimeoutOverride fields are applied. Defaults to false. + unsafe-overrides-enabled = false + ``` + + + The `[consensus]` section still parses a `stateless-leader-election` field, but it is now **deprecated and ignored**. Stateless leader election is always enabled: the consensus engine always selects each round's leader via a deterministic seeded stateless computation. The former stateful proposer-priority leader-election mode is no longer supported. From 090096cc39f478c1fa0f7aff9e204d37d8327efb Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:56:53 +0000 Subject: [PATCH 77/81] docs: Adds a new RPC config field `timeout-read-header` to Tendermint that limits the time allowed to read HTTP request headers (mitigating slowloris attacks), defaulting to 10 seconds. (sei-protocol/sei-chain#3607) --- node/node-operators.mdx | 4 ++++ node/technical-reference.mdx | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 207f041..8c3ed31 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -59,6 +59,10 @@ max-open-connections = 900 timeout-broadcast-tx-commit = "10s" +# Timeout to read HTTP request headers; mitigates slowloris attacks. Default 10s. +# Set to "0s" to disable (not recommended). +timeout-read-header = "10s" + # HTTP write timeout; acts as a hard backstop for all handlers. Default 30s. # Must be greater than timeout-broadcast-tx-commit when non-zero. # Set to "0s" to disable the write timeout (not recommended). diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index 22a3eb0..c2f4fff 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -235,6 +235,10 @@ max_open_connections = 900 # within this duration, the request context is cancelled and the call returns a # timeout error. Set to "0s" to disable the timeout. timeout_broadcast_tx_commit = "10s" +# Timeout to read HTTP request headers; mitigates slowloris attacks by limiting +# the time allowed to read request headers. Set to "0s" to disable (not +# recommended). Defaults to 10s. +timeout-read-header = "10s" # HTTP write timeout; acts as a hard backstop for all handlers. Must be greater # than timeout_broadcast_tx_commit when non-zero. Set to "0s" to disable (not # recommended). Defaults to 30s. From a0070a7b1aa0c549848c840ceb3281ed20d46b20 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:57:23 +0000 Subject: [PATCH 78/81] docs: A new RPC config field `max-tx-search-results` caps the number of results returned by the `tx_search` and `block_search` endpoints (default 10,000), which changes their behavior on nodes. (sei-protocol/sei-chain#3608) --- node/node-operators.mdx | 18 ++++++++++++++++++ node/technical-reference.mdx | 8 ++++++++ 2 files changed, 26 insertions(+) diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 8c3ed31..3b820ca 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -69,6 +69,24 @@ timeout-read-header = "10s" timeout-write = "30s" ``` + + + The `[rpc]` section also supports `max-tx-search-results`, which caps the + number of results returned by the `tx_search` and `block_search` RPC + endpoints. The cap is applied *after* results are sorted by `order_by`, and + the reported `TotalCount` reflects the post-cap count. The default is + `10000`. Set it to `0` to disable the cap entirely (not recommended on + public nodes, since unbounded searches can be used to exhaust node + resources). The value must not be negative. + + ```toml + [rpc] + # Maximum number of results returned by tx_search and block_search. + # Set to 0 to disable the cap (not recommended on public nodes). + max-tx-search-results = 10000 + ``` + + #### Application Settings (app.toml) ```toml diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index c2f4fff..c8c1372 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -244,6 +244,14 @@ timeout-read-header = "10s" # recommended). Defaults to 30s. timeout-write = "30s" + +# Maximum number of results returned by the tx_search and block_search RPC +# endpoints. The cap is applied after results are sorted, so the top matches +# (per order_by) are preserved, and TotalCount reflects the post-cap count. +# Must not be negative. Set to 0 to disable the cap (not recommended on public +# nodes). Defaults to 10000. +max-tx-search-results = 10000 + # Consensus Configuration [consensus] wal_file = "data/cs.wal/wal" From 1d3a6dda44d65dd064cbeb7be000a6cad6948117 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:58:11 +0000 Subject: [PATCH 79/81] docs: A new `seidb evm-logical-digest` CLI subcommand was added to compute a backend-independent digest of EVM logical state, letting operators compare memIAVL and FlatKV nodes at the same height. (sei-protocol/sei-chain#3611) --- learn/seidb.mdx | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/learn/seidb.mdx b/learn/seidb.mdx index 4a5e58e..ba832e2 100644 --- a/learn/seidb.mdx +++ b/learn/seidb.mdx @@ -435,3 +435,68 @@ The command prints a single JSON object to standard output: 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`. + + + +## 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-/evm`, or `current/evm` when `--height` is `0`. + +### Usage + +```bash +# 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-/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. | + +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. + From 5f2297675900c9a32d2eb4c120a3624d30f302c4 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:59:49 +0000 Subject: [PATCH 80/81] docs: The Giga executor now loads the evmone shared library from a trusted absolute path with SHA-256 verification, and a new SEI_EVMONE_LIB_DIR environment variable lets operators override the library directory. (sei-protocol/sei-chain#3624) --- node/node-operators.mdx | 27 +++++++++++++++++++++++++++ node/technical-reference.mdx | 23 +++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/node/node-operators.mdx b/node/node-operators.mdx index 3b820ca..ea8347c 100644 --- a/node/node-operators.mdx +++ b/node/node-operators.mdx @@ -892,6 +892,33 @@ enabled = true # Default: true occ_enabled = true + + + + **evmone library loading (Giga executor).** The Giga executor loads its + platform-specific `evmone` shared library from a fixed, trusted absolute path + and verifies the file's SHA-256 digest against the digest pinned for the + running platform before handing it to the dynamic linker. Passing an absolute + path avoids the dynamic linker's search path (`LD_LIBRARY_PATH`, + `ld.so.cache`, default directories), so the library cannot be substituted by + planting a file earlier in the loader's search order. + + The library directory is resolved in the following order, and the first + directory that actually contains the library wins: + + 1. `$SEI_EVMONE_LIB_DIR` — optional operator override. Set it to an absolute + path to a root-owned, non-writable directory that holds the trusted, + integrity-verified `evmone` library. + 2. `/usr/lib` — the canonical install location used by release images. + 3. The source-tree directory — used for local development and tests. + + Release Docker images install the `evmone` library to `/usr/lib` (alongside + the other native libraries) and add the `libstdc++6` runtime dependency, so + no additional configuration is required when running the official images. If + the resolved library is missing or its digest does not match the expected + value, node startup fails with an explicit error. + + ############################################################################### ### Admin Configuration (Auto-managed) ### ############################################################################### diff --git a/node/technical-reference.mdx b/node/technical-reference.mdx index c8c1372..0386b73 100644 --- a/node/technical-reference.mdx +++ b/node/technical-reference.mdx @@ -312,6 +312,29 @@ The `autobahn-config-file` field in `config.toml` enables the Autobahn (GigaRout autobahn-config-file = "" ``` + +#### Giga Executor EVM Library (`SEI_EVMONE_LIB_DIR`) + +The Giga executor loads the platform-specific `evmone` shared library from a fixed, trusted absolute path and verifies its SHA-256 digest against the value pinned for the current platform before handing it to the dynamic linker. Loading from an absolute path (rather than relying on the dynamic linker's search path) prevents the library from being substituted by planting a file earlier in the loader's search order. + +The optional `SEI_EVMONE_LIB_DIR` environment variable lets operators override the directory the library is loaded from. It must be an absolute path to a root-owned, non-writable directory containing the trusted, integrity-verified `evmone` library. + +The library directory is resolved in the following order — the first directory that actually contains the library wins: + +1. `$SEI_EVMONE_LIB_DIR` — operator override, when set. +2. `/usr/lib` — the canonical install location used by release Docker images. +3. The source-tree directory — used for local development and tests. + +```bash +# Point the Giga executor at a custom directory holding the trusted evmone library +export SEI_EVMONE_LIB_DIR=/opt/sei/lib +``` + + + Release Docker images install the `evmone` library to `/usr/lib` and add the `libstdc++6` runtime dependency, so no additional configuration is required for standard deployments. If the resolved library's SHA-256 digest does not match the pinned value, the node fails to start with a digest-mismatch error. + + + When Autobahn is enabled, the referenced JSON file supports the following fields: ```json From d67b006ff4e35dec35f337019f472a3fbcaa55d0 Mon Sep 17 00:00:00 2001 From: "seidroid[bot]" <257742136+seidroid[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 05:00:29 +0000 Subject: [PATCH 81/81] docs: A new v6.6 upgrade version is registered across all EVM precompiles (addr, bank, distribution, gov, ibc, json, oracle, p256, pointer, pointerview, solo, staking), and the oracle precompile is now retired so getExchangeRates and getOracleTwaps revert with an error. (sei-protocol/sei-chain#3625) --- evm/precompiles/oracle.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/precompiles/oracle.mdx b/evm/precompiles/oracle.mdx index efcffed..00e6082 100644 --- a/evm/precompiles/oracle.mdx +++ b/evm/precompiles/oracle.mdx @@ -6,4 +6,4 @@ keywords: ['oracle precompile', 'ethers.js', 'price feeds', 'exchange rates', 't --- **Address:** `0x0000000000000000000000000000000000001008` -**Retired as of v6.5:** The native Sei Oracle precompile has been retired. As of the v6.5 chain upgrade, both `getExchangeRates` and `getOracleTwaps` now revert with the error `oracle precompile is retired; oracle data queries are disabled` instead of returning data. Any contract that relies on on-chain oracle exchange rate or TWAP queries via this precompile will break after the upgrade. Migrate to one of the third-party oracle providers, such as [Chainlink](/evm/oracles/chainlink), [Pyth](/evm/oracles/pyth-network), [Redstone](/evm/oracles/redstone), or [API3](/evm/oracles/api3). +**Retired as of v6.6:** The native Sei Oracle precompile has been retired. As of the v6.6 chain upgrade, both `getExchangeRates` and `getOracleTwaps` now revert with the error `oracle precompile is retired; oracle data queries are disabled` instead of returning data. Any contract that relies on on-chain oracle exchange rate or TWAP queries via this precompile will break after the upgrade. Migrate to one of the third-party oracle providers, such as [Chainlink](/evm/oracles/chainlink), [Pyth](/evm/oracles/pyth-network), [Redstone](/evm/oracles/redstone), or [API3](/evm/oracles/api3).