Skip to content

integrate hashvault#3602

Open
cody-littley wants to merge 6 commits into
mainfrom
cjl/hashvault-integration
Open

integrate hashvault#3602
cody-littley wants to merge 6 commits into
mainfrom
cjl/hashvault-integration

Conversation

@cody-littley

Copy link
Copy Markdown
Contributor

Describe your changes and provide context

Wire in the hash vault. This prevents the app hash from changing for a particular block without human intervention.

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown

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

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedJun 18, 2026, 1:11 PM

@codecov

codecov Bot commented Jun 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 69.76744% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 58.19%. Comparing base (c1eab8e) to head (28bd8ef).

Files with missing lines Patch % Lines
sei-tendermint/node/node.go 47.36% 8 Missing and 2 partials ⚠️
sei-db/state_db/sc/hashvault/noop_hashvault.go 0.00% 8 Missing ⚠️
sei-tendermint/internal/state/execution.go 68.00% 5 Missing and 3 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3602      +/-   ##
==========================================
- Coverage   59.02%   58.19%   -0.84%     
==========================================
  Files        2215     2146      -69     
  Lines      182530   174295    -8235     
==========================================
- Hits       107741   101423    -6318     
+ Misses      65092    63853    -1239     
+ Partials     9697     9019     -678     
Flag Coverage Δ
sei-chain-pr 68.61% <76.92%> (?)
sei-db 70.62% <ø> (+0.21%) ⬆️
sei-db-state-db ?
sei-db-state-db-pr 79.51% <0.00%> (?)

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

Files with missing lines Coverage Δ
sei-tendermint/config/config.go 73.57% <100.00%> (+0.05%) ⬆️
sei-tendermint/config/toml.go 55.00% <ø> (ø)
sei-tendermint/internal/consensus/replay.go 70.47% <100.00%> (+2.38%) ⬆️
sei-db/state_db/sc/hashvault/noop_hashvault.go 0.00% <0.00%> (ø)
sei-tendermint/internal/state/execution.go 81.10% <68.00%> (+0.17%) ⬆️
sei-tendermint/node/node.go 63.37% <47.36%> (-0.86%) ⬇️

... and 74 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.

@cody-littley cody-littley marked this pull request as ready for review June 17, 2026 13:18
@cody-littley cody-littley requested a review from wen-coding June 17, 2026 13:19
@cursor

cursor Bot commented Jun 17, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Changes core commit/replay paths and can halt the node on HashVault errors; the unsafe disable flag removes equivocation protection if enabled.

Overview
This PR wires HashVault into block execution and node startup so every applied block’s hash is recorded and checked before state is saved, with fail-closed halting on mismatch or operational commit failure (context cancel during shutdown returns an error instead of panicking).

Node wiring: makeHashVault creates a Pebble vault under <db-dir>/hashvault by default, or NoopHashVault when hash-vault-disabled-unsafe is set (with loud error logs). Config and config.toml expose that flag; NewBlockExecutor, ExecCommitBlock, and Handshaker now take a HashVault. After block pruning, the vault is pruned to the blockstore base (not only the requested retain height) so replayed heights are not rejected with ErrBelowPruneBoundary.

Tests use NewNoopHashVault(); new tests cover panic on ErrHashMismatch and clean unwind on context cancellation.

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

@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 2 potential issues.

Fix All in Cursor

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

Reviewed by Cursor Bugbot for commit 203fb1f. Configure here.

Comment thread sei-tendermint/internal/consensus/replay.go
Comment thread sei-tendermint/internal/state/execution.go

// Commit this block's hash to the equivocation guard before saving state. See commitHashToVault.
// A returned error is a benign shutdown cancellation; genuine faults panic inside the call.
if err := commitHashToVault(ctx, blockExec.hashVault, block.Height, block.Hash()); err != nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think the intent is to vault AppHash? block.Hash() is the Tendermint block header hash.

I think you should do:

if err := commitHashToVault(ctx, blockExec.hashVault, block.Height, state.AppHash); err != nil {
    return state, err
}

instead.

h.eventBus,
sm.NopMetrics(),
h.consensusPolicy,
h.hashVault)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This only covers non-Autobahn part. Is the intent to do Autobahn part later? I think you would need to:

  1. GigaRouter struct — add the vault field:
type GigaRouter struct {
    // ... existing fields ...
    hashVault hashvault.HashVault
}
  1. NewGigaRouter — accept it as a parameter and set the field.

  2. executeBlock — vault resp.AppHash (the FinalizeBlock output, not the Autobahn header hash) right after FinalizeBlock succeeds, before Commit:

resp, err := app.FinalizeBlock(ctx, ...)
if err != nil { ... }

// Seal the computed AppHash before commit — same equivocation guard as the Cosmos path.
if err := commitHashToVault(ctx, r.hashVault, int64(b.GlobalNumber), resp.AppHash); err != nil {
    return nil, err
}

commitResp, err := app.Commit(ctx)
  1. buildGigaRouter in setup.go — thread the vault from makeNode through to NewGigaRouter.

return fmt.Errorf("hashvault CommitToHash aborted at height %d: %w", height, err)
}
if errors.Is(err, hashvault.ErrHashMismatch) {
logger.Error("FATAL: HashVault detected a block-hash mismatch — the node has equivocated. "+

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Chatted with Greg today, since re-execution of a block should only happen during restart, it's fine to just panic here. I think you can print previous and current hash, then hint if the human is really really sure, he can remove directory to proceed, but warn that this may lead to slashing etc

"Halting. DO NOT RESTART WITHOUT HUMAN INTERVENTION.",
"height", height, "hash", fmt.Sprintf("%X", hash), "err", err)
} else {
logger.Error("FATAL: HashVault could not commit the block hash (operational error, not a "+

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could a transient I/O error land here?

What's the behavior if the on-disk file is corrupted? If the on-disk file is corrupted maybe we should just ask human to remove or just proceed? I just don't want one corrupted bit on disk to take down the whole validator. What do you feel, log an error and proceed, but don't overwrite the corrupted entry?

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.

2 participants