Skip to content

Port sei-v3 PR #510: crash-safe consensus state persistence#2893

Open
wen-coding wants to merge 2 commits intomainfrom
wen/port_v3_pr_510
Open

Port sei-v3 PR #510: crash-safe consensus state persistence#2893
wen-coding wants to merge 2 commits intomainfrom
wen/port_v3_pr_510

Conversation

@wen-coding
Copy link
Contributor

Summary

This is a port of sei-protocol/sei-v3#510 to sei-chain.

Adds crash-safe A/B file persistence for the autobahn consensus inner state (votes and QCs). This prevents double-voting on restart (a slashable offense) and enables fast view synchronization after cluster-wide outages by persisting QC justifications.

Key changes

  • Crash-safe A/B file persistence (persist.go): Alternates writes between two files (_a.pb/_b.pb) with sequence numbering. On load, picks the file with the higher seq; tolerates one corrupt file (crash mid-write recovery). Only needs one fsync per write (no directory sync after initial setup).
  • Persisted consensus state (persisted_inner.go): Defines the persistedInner struct holding CommitQC, PrepareQC, TimeoutQC, and current-view votes. Includes validation logic that checks internal consistency and cryptographic signatures on load.
  • Inner refactor (inner.go): inner now embeds persistedInner so persisted fields are promoted. Added newInner constructor that loads and validates persisted state.
  • State integration (state.go): NewState now returns (*State, error). Added PersistentStateDir config option. Persistence is called in runOutputs before broadcasting votes.
  • Protobuf (autobahn.proto, autobahn.pb.go): Added PersistedInner and PersistedWrapper message definitions. Regenerated via buf generate.
  • Test helper (types/testonly.go): Added GenProposalAt for generating proposals at a specific view.
  • Caller updates (giga/avail_test.go, giga/data_test.go): Adapted for NewState returning an error.

Adaptation notes (sei-v3 → sei-chain)

  • Import paths: sei-stream/stream/consensussei-tendermint/internal/autobahn/consensus
  • Package name: protocolpb (protobuf package)
  • Concurrency model: utils.AtomicWatch[inner].Update()utils.Mutex[*utils.AtomicSend[inner]].Lock()/Store()
  • Random type: *rand.Randutils.Rng in test helpers
  • Protobuf test: innerProtoConv.Test() replaced with manual roundtrip using google.golang.org/protobuf/proto (gogo/protobuf incompatibility with protoc-gen-go generated types)

New files (5)

  • sei-tendermint/internal/autobahn/consensus/persisted_inner.go
  • sei-tendermint/internal/autobahn/consensus/persist.go
  • sei-tendermint/internal/autobahn/consensus/inner_test.go
  • sei-tendermint/internal/autobahn/consensus/persist_test.go
  • sei-tendermint/internal/autobahn/consensus/persisted_inner_test.go

Modified files (7)

  • sei-tendermint/internal/autobahn/autobahn.proto
  • sei-tendermint/internal/autobahn/pb/autobahn.pb.go
  • sei-tendermint/internal/autobahn/consensus/inner.go
  • sei-tendermint/internal/autobahn/consensus/state.go
  • sei-tendermint/internal/autobahn/types/testonly.go
  • sei-tendermint/internal/p2p/giga/avail_test.go
  • sei-tendermint/internal/p2p/giga/data_test.go

Test plan

  • All autobahn package tests pass (go test ./sei-tendermint/internal/autobahn/...)
  • All giga package tests pass (go test ./sei-tendermint/internal/p2p/giga/...)
  • gofmt -s clean on all modified files
  • Protobuf regenerated via buf generate (matching protoc-gen-go v1.36.10, protoc (unknown))
  • Full content comparison against sei-v3 source confirms no lost comments or code

Made with Cursor

Port of sei-protocol/sei-v3#510 to sei-chain.

Adds crash-safe A/B file persistence for the autobahn consensus inner
state (votes and QCs), preventing double-voting on restart and enabling
fast view synchronization after cluster-wide outages.

New files:
- persisted_inner.go: persistedInner struct, validation, protobuf conversion
- persist.go: crash-safe A/B file persistence with seq numbering
- inner_test.go: tests for newInner and persisted state loading
- persist_test.go: tests for A/B file persistence logic
- persisted_inner_test.go: protobuf roundtrip tests

Modified files:
- autobahn.proto: added PersistedInner and PersistedWrapper messages
- autobahn.pb.go: regenerated via buf generate
- inner.go: refactored to embed persistedInner, added newInner constructor
- state.go: NewState returns error, added PersistentStateDir config,
  integrated persistence into runOutputs
- types/testonly.go: added GenProposalAt helper
- giga/avail_test.go, data_test.go: adapted for NewState error return

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions
Copy link

github-actions bot commented Feb 13, 2026

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

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedFeb 13, 2026, 11:45 PM

@codecov
Copy link

codecov bot commented Feb 13, 2026

Codecov Report

❌ Patch coverage is 77.09924% with 60 lines in your changes missing coverage. Please review.
✅ Project coverage is 57.21%. Comparing base (7407960) to head (7f986d9).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...-tendermint/internal/autobahn/consensus/persist.go 76.36% 16 Missing and 10 partials ⚠️
...int/internal/autobahn/consensus/persisted_inner.go 83.72% 7 Missing and 7 partials ⚠️
...ei-tendermint/internal/autobahn/consensus/inner.go 68.75% 2 Missing and 8 partials ⚠️
...ei-tendermint/internal/autobahn/consensus/state.go 68.75% 7 Missing and 3 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2893      +/-   ##
==========================================
+ Coverage   57.15%   57.21%   +0.06%     
==========================================
  Files        2091     2093       +2     
  Lines      171524   171755     +231     
==========================================
+ Hits        98033    98271     +238     
+ Misses      64751    64727      -24     
- Partials     8740     8757      +17     
Flag Coverage Δ
sei-chain 52.69% <77.09%> (+0.07%) ⬆️
sei-cosmos 48.16% <ø> (+<0.01%) ⬆️
sei-db 68.72% <ø> (ø)

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

Files with missing lines Coverage Δ
sei-tendermint/internal/autobahn/types/testonly.go 94.44% <100.00%> (+0.08%) ⬆️
...ei-tendermint/internal/autobahn/consensus/inner.go 62.22% <68.75%> (+0.68%) ⬆️
...ei-tendermint/internal/autobahn/consensus/state.go 82.92% <68.75%> (-4.49%) ⬇️
...int/internal/autobahn/consensus/persisted_inner.go 83.72% <83.72%> (ø)
...-tendermint/internal/autobahn/consensus/persist.go 76.36% <76.36%> (ø)

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

- Add nolint:gosec for os.ReadFile, os.OpenFile, and os.Open where
  paths are built from operator-configured stateDir + hardcoded
  filename suffixes (G304 false positives — no user-controlled input).
- Explicitly ignore return values of probe.Close(), os.Remove(),
  f.Close(), and d.Close() with _ = to satisfy errcheck. All are
  safe to ignore: probe and dir handles have no data to flush.

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.

1 participant