Skip to content

Backport release/v6.7: feat(seidb): Add JSON output to evm-logical-digest and inspect a FlatKV migration in flight - #4255

Merged
blindchaser merged 3 commits into
release/v6.7from
backport-4166-to-release/v6.7
Sep 21, 2026
Merged

blindchaser merged 3 commits into
release/v6.7from
backport-4166-to-release/v6.7

Conversation

@seidroid

@seidroid seidroid Bot commented Sep 18, 2026

Copy link
Copy Markdown

Backport of #4166 to release/v6.7.

@seidroid

seidroid Bot commented Sep 18, 2026

Copy link
Copy Markdown
Author

Please cherry-pick the changes locally and resolve any conflicts.

git fetch origin backport-4166-to-release/v6.7
git worktree add --checkout .worktree/backport-4166-to-release/v6.7 backport-4166-to-release/v6.7
cd .worktree/backport-4166-to-release/v6.7
git reset --hard HEAD^
git cherry-pick -x 29139f27297d719a0732d413eae2ca727d52b8e0
git push --force-with-lease

@github-actions

github-actions Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedSep 21, 2026, 4:35 PM

@codecov

codecov Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 38.59649% with 245 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.33%. Comparing base (e97fdc7) to head (34fd677).

Files with missing lines Patch % Lines
...b/tools/cmd/seidb/operations/evm_logical_digest.go 38.69% 232 Missing and 12 partials ⚠️
sei-db/tools/cmd/seidb/main.go 0.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@               Coverage Diff                @@
##           release/v6.7    #4255      +/-   ##
================================================
- Coverage         61.34%   60.33%   -1.02%     
================================================
  Files              2163     2064      -99     
  Lines            188780   177335   -11445     
================================================
- Hits             115812   106993    -8819     
+ Misses            62250    60554    -1696     
+ Partials          10718     9788     -930     
Flag Coverage Δ
sei-chain-pr 32.89% <38.59%> (?)
sei-db 69.80% <ø> (ø)
sei-db-state-db ?

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
sei-db/tools/cmd/seidb/main.go 0.00% <0.00%> (ø)
...b/tools/cmd/seidb/operations/evm_logical_digest.go 34.44% <38.69%> (+11.45%) ⬆️

... and 99 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…KV migration in flight (#4166)

Adds a `--json` flag to `seidb evm-logical-digest`, and extends inspect
mode to
work during a FlatKV migration.

Getting JSON out required splitting rendering from accumulating: both
forms now
render from one report struct per run (`evmDigestJSON` /
`evmInspectJSON`), so
no number is computed twice and the prose and the JSON cannot drift. A
package-level `digestSink` holds the two destinations, so one assignment
redirects every line the scan helpers emit.

- `sei-db/tools/cmd/seidb/operations/evm_logical_digest.go`:
- `--json` emits the report as one JSON line on stdout and moves the
narration
to stderr. Storage-layer logging is raised to error level, because
`seilog`
writes to stdout and fixes its destination at process start. A warning
fires
when `SEI_LOG_OUTPUT` still points at stdout; it goes to the narration,
    never into the report.
- `marker_adjustments` names the migration marker rows XORed out of the
misc
bucket. That list is the only thing distinguishing a mid-migration
reading
    from a completed one, since the misc digest is adjusted in both.
- A new zero-value census counts the populations FlatKV normalization
can
change. It is one nullable field shared by the row-level and
account-level
counters, so a half-counted census is unreachable. `nil` reads as "not
    measured" in both forms, not as all-zero.
- `semanticAccountDigestState` records whether a code-hash row was
present, so
    a stored all-zero row is distinguished from an absent one.
- Inspect mode accepts `--backend composite` (FlatKV rows plus memiavl
rows
past the migration boundary) and `--memiavl-open-mode=replay`, reusing
the
existing no-repair read-only open. Translator normalization and
`--details`
storage inspect still require snapshot mode and now reject replay with
their
    own messages.
- The composite and semantic scans take a consumer, an optional
account-key
filter, and an optional progress callback, so digest and inspect share
one
scan. The filter drops out-of-shard account fragments before buffering.
- The composite digest takes no census: its accounts are partly rebuilt
from
FlatKV rows, which cannot observe whether memiavl held a code-hash row.

`sei-db/tools/cmd/seidb/operations/evm_logical_digest_test.go`

- Output-form agreement: every bucket count and digest, the final
digest, and
the run context match between prose and JSON, for both digest and
inspect
  reports. JSON output is one line and carries no prose.
- Census: all six counters over a crafted leaf set; all-or-nothing
across both
counter levels (table over nil and non-nil); an untaken census omitted
from
  both forms.
- Marker adjustments: empty for a clean digest, named for one that
consumed a
boundary row, misc bucket equal in both, and empty encodes as `[]` not
`null`.
- JSON-mode warning: present when `SEI_LOG_OUTPUT` is unset, absent when
it is
  redirected, and never in the report buffer.
- Composite and filtered inspect: the memiavl tail counts only
unmigrated rows,
matching a reference accumulator; an account prefix filter skips
out-of-range
  addresses.

Existing tests take the new census argument and otherwise assert
unchanged
behavior.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 29139f2)
@blindchaser

Copy link
Copy Markdown
Contributor

Rebuilt this branch: re-ran the cherry-pick of 29139f2 and resolved the two conflicts by hand. Force-pushed 8d333aba9.

evm_logical_digest.go — the conflict bundled two unrelated things on the incoming side. Kept account.codeHashRow = true; dropped case keys.EVMKeyBalance:, since release/v6.7 has no keys.EVMKeyBalance. Taking the HEAD side wholesale is the tempting resolution and it is wrong: it also drops codeHashRow, which the new zero-value census reads, and TestSemanticMemiavlDigestReportsZeroCensus then fails with LiveAccountsWithZeroCodeHashRow: 1 -> 0.

CHANGELOG.md — resolved to no change. Every backport onto this branch since the v6.7 changelog cut (#4113) drops its CHANGELOG hunk, including #4035, #4049, #4051, #4054, #4074 and #4095, all of which do carry entries on main.

Verified locally: go build ./sei-db/tools/..., go vet, go test -race ./sei-db/tools/cmd/seidb/operations/, gofmt -s -l and goimports -l all clean.

⚠️ Depends on #4282. NoChangelogRepair comes from #3983, which is on main but was never backported here, so it is absent from this branch and the diff against main still shows that gap. This PR widens who reaches replay mode (inspect and composite now accept --memiavl-open-mode replay) while that path still repairs — truncates — a changelog it cannot read. #4282 backports #3983 and should land first.

@blindchaser

Copy link
Copy Markdown
Contributor

Correction on the dependency note above: the prerequisite is now #4285, not #4282. #4282 was created by hand and is closed; #4285 is the seidroid backport of #3983 and is the one to land first.

… release/v6.7

goconst is enabled on this branch and disabled on main, so the third
"composite" literal this backport adds fails lint here only.
@blindchaser

Copy link
Copy Markdown
Contributor

Pushed 2bdf15e83 for the lint failure. It was real and branch-specific: goconst is enabled in .golangci.yml on release/v6.7 and deliberately disabled on main ("more noise than it is worth"), so the third "composite" literal this backport adds only fails here.

Fixed the way this file already handles the same linter — it has a const block for the --memiavl-open-mode / --memiavl-normalization flag values with the comment "named so they are not repeated as bare string literals (goconst)". Added the --backend values alongside them and used them at the selector sites. The two remaining literals are output labels rather than backend selectors (srcLabel and the caller tag), so they stay as strings.

Reproduced and verified with the same linter version CI uses (v2.8.0): fails on the parent commit with string composite has 3 occurrences, clean after. go build, go test -race, gofmt -s -l and goimports -l all pass.

@blindchaser
blindchaser marked this pull request as ready for review September 21, 2026 15:22
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-21T15:28:50.989236Z 2bdf15e Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@cursor

cursor Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

PR Summary

Low Risk
Changes are limited to the offline seidb CLI tool (output routing and reporting); no on-chain or node runtime behavior is modified.

Overview
Adds --json to evm-logical-digest so digest and inspect results are a single JSON line on stdout, with progress and banners on stderr. Text and JSON share one report() path so numbers cannot drift. seidb root errors also go to stderr so they do not break JSON parsing.

Inspect during FlatKV migration is expanded: --backend composite works with --inspect-bucket, memiavl replay open mode, and key-prefix filtering on account rows (shared composite open/scan helpers).

Memiavl semantic digests gain an optional zero-value census (zero accounts, all-zero code-hash rows, empty code, zero storage) to debug FlatKV vs memiavl normalization differences; composite digest paths intentionally skip census.

JSON mode raises default log level to error and warns when SEI_LOG_OUTPUT still targets stdout.

Reviewed by Cursor Bugbot for commit 34fd677. Bugbot is set up for automated code reviews on this repo. Configure here.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2bdf15e830

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +568 to +570
// enterJSONMode redirects this command's narration to stderr so stdout carries
// only the encoded report, and raises the storage layer's log level, which
// writes to stdout and would otherwise put several lines in front of the object.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Rewrite the enterJSONMode Godoc as what-only

Rewrite this Godoc to state only what enterJSONMode does; its multi-paragraph discussion of logger limitations, implementation choices, and operational rationale is exactly the mechanism-heavy form the repository guide prohibits, so the rationale should be moved to the specific lines that require it or omitted.

AGENTS.md reference: AGENTS.md:L61-L68

Useful? React with 👍 / 👎.

Comment on lines 1110 to +1113
if meta != "" {
fmt.Printf("key=%X logical=%X %s\n", physKey, logical, meta)
} else {
fmt.Printf("key=%X logical=%X\n", physKey, logical)
entry.Meta = meta
}
a.entries = append(a.entries, entry)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid retaining text-mode list entries

When inspect mode runs with --list --list-limit <=0 (or a large limit) without --json, every matching row is now both printed immediately and appended to a.entries, even though the text report never reads that slice. Large storage inspections can therefore retain hex-encoded copies of the entire result set and exhaust memory, whereas the previous text path streamed entries with bounded memory; only accumulate entries when generating JSON.

Useful? React with 👍 / 👎.

if acc.inspectBucket == flatkvBucketAccount {
accounts = make(map[string]*semanticAccountDigestState)
}
if err := consumeCompositeFlatKV(source.opened, acc.addLogical, accounts, acc.matchesAccountPhysicalKey, nil); err != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor details for composite storage inspection

For --backend composite --inspect-bucket storage --list --details, this path routes FlatKV rows through acc.addLogical, which discards the raw value and always supplies an empty metadata string; the memiavl half does the same below. The accepted --details flag consequently produces no block_height or leaf_version metadata, unlike the existing backend-specific storage paths, so composite mode should preserve that metadata or explicitly reject this unsupported combination.

Useful? React with 👍 / 👎.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2bdf15e. Configure here.

digestOut.sayf("key=%X logical=%X %s\n", physKey, logical, meta)
} else {
digestOut.sayf("key=%X logical=%X\n", physKey, logical)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inspect list buffers all matching entries

Medium Severity

--list now appends every matching pair onto entries before the report is emitted, including in text mode where those rows are already printed and then ignored. With --list-limit at 0 (unlimited), a full-bucket inspect holds every key and logical value as hex in memory instead of streaming them.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 2bdf15e. Configure here.

@seidroid seidroid Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean backport of #4166 — the code hunks match the merged original, the text/JSON reports are rendered from one report() so they cannot drift, and isZeroAccount is refactored without changing semantics. Two small behavioural gaps (unbounded entry buffering in text list mode, --details silently ignored on the new composite inspect) and a missing CHANGELOG entry for the backport.

Findings: 0 blocking | 4 non-blocking | 2 posted inline

Blockers

  • None at the file/PR level.

Non-blocking

  • [suggestion] The original PR #4166 added a CHANGELOG.md entry under ## Unreleased / ### Improvements; this backport carries no CHANGELOG change. The base branch records backports explicitly (CHANGELOG.md:49-56, e.g. "#4095 Backport release/v6.7: ..."), so v6.7's changelog will not mention this tool change.
  • [suggestion] The EvmLogicalDigestCmd godoc's Usage block documents every other mode with an example but says nothing about --json, nor about the two new inspect capabilities this PR adds (--backend composite inspect and --memiavl-open-mode replay inspect). A line in Usage for each would keep the block a complete map of the command's modes.
  • 2 suggestion(s)/nit(s) flagged inline on specific lines.

Inline comments (could not post inline; listed here)

  • sei-db/tools/cmd/seidb/operations/evm_logical_digest.go:1113 (RIGHT) -- [suggestion] a.entries is appended unconditionally, including in text mode where the entry is printed and immediately discarded. Before this PR the text --list path streamed; now it retains every listed key/value as two hex strings. With --list-limit <=0 (documented as unlimited) on a large storage or code bucket that is unbounded growth — roughly 200 B per row, so tens of GB on a full EVM storage scan — where the old code used constant memory.

Since report() only reads a.entries when a JSON report is being written, gating the append on digestOut.jsonReport != nil keeps text mode streaming:

if digestOut.jsonReport != nil {
	a.entries = append(a.entries, entry)
} else if meta != "" {
	digestOut.sayf("key=%X logical=%X %s\n", physKey, logical, meta)
} else {
	digestOut.sayf("key=%X logical=%X\n", physKey, logical)
}
  • sei-db/tools/cmd/seidb/operations/evm_logical_digest.go:1248 (RIGHT) -- [suggestion] inspectCompositeMigrateEVM never reads acc.details: both the FlatKV side (consumeCompositeFlatKV → acc.addLogical) and the memiavl side pass meta as "", so --inspect-bucket storage --list --details --backend composite silently produces listings with no leaf_version/version metadata rather than failing. That is inconsistent with the other unsupported combinations this PR guards explicitly (inspectMemIAVL rejects translator+replay, inspectMemIAVLSemantic rejects details+storage+replay). Either wire the meta through or return an error naming the unsupported combination, so an operator does not read a detail-less listing as "no version metadata exists".

@blindchaser
blindchaser merged commit 2cf6111 into release/v6.7 Sep 21, 2026
72 checks passed
@blindchaser
blindchaser deleted the backport-4166-to-release/v6.7 branch September 21, 2026 17:16
masih pushed a commit that referenced this pull request Sep 22, 2026
Adds the `release/v6.7` entries merged since the rc1 changelog (#4110),
in prep to cut **v6.7.0-rc2**:

- [#4292](#4292) — Flush
MemIAVL changelog before exiting on an upgrade panic
- [#4285](#4285) —
fix(seidb): refuse a corrupted changelog in digest replay instead of
repairing it
- [#4255](#4255) —
feat(seidb): Add JSON output to evm-logical-digest and inspect a FlatKV
migration in flight
- [#4116](#4116) — rc1
version bump
- [#4113](#4113) — rc1
changelog backport

Regenerated with `./scripts/generate-changelog.sh release/v6.6
release/v6.7`; only the `## v6.7` PR list changes, so the `backport
release/v6.7` cherry-pick applies cleanly (verified with `git apply
--check` against `origin/release/v6.7`). Docs-only; no code change.

Made with [Cursor](https://cursor.com)

Co-authored-by: Cursor <cursoragent@cursor.com>
alexander-sei added a commit that referenced this pull request Sep 22, 2026
## Summary
- Bump `version.json` from `v6.7.0-rc1` to `v6.7.0-rc2` to cut the
second `v6.7` release candidate.

Contents since rc1: #4285, #4255, #4292 (all `sei-db` fixes/tooling),
plus the rc2 changelog update (#4294). Merge after #4294 so the tag cut
by `uci-release-publish` on this `version.json` change includes the
updated changelog.

## Test plan
- [x] `git diff --check`

Made with [Cursor](https://cursor.com)

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants