Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
5e5a6f9
feat(autobahn): complete multi-epoch ownership across layers (CON-358)
wen-coding Aug 16, 2026
8f2747d
fix(autobahn): verify outside lock and derive Joined from activate tip
wen-coding Aug 17, 2026
296a5bd
refactor(utils): move ReadOnly out of testonly.go
wen-coding Aug 18, 2026
5a2107a
fix(autobahn): shard EVM txs with NextCommitEpoch, not tip verify-epoch
wen-coding Aug 18, 2026
b4b97ee
fix(autobahn): optional ConsensusSpec tip and hard-error missing catc…
wen-coding Aug 18, 2026
f671105
refactor(autobahn): split Verify integrity from committee membership
wen-coding Aug 18, 2026
493ffc3
refactor(autobahn): replace consensus WAL CommitQC with CommitQCIndex
wen-coding Aug 19, 2026
64a83a6
refactor(autobahn): reweightVotes from applied i.epoch
wen-coding Aug 19, 2026
11282a3
docs(autobahn): RoadIndex wording and Anchor epoch docs
wen-coding Aug 19, 2026
b2dd476
refactor(autobahn): use advance consistently for epoch transitions
wen-coding Aug 19, 2026
6ad8d3b
refactor(autobahn): match blocks by header, votes by epoch then Verify
wen-coding Aug 19, 2026
7c1e0c5
refactor(autobahn): inline epochForRoad; note AvailSpec follow-up
wen-coding Aug 19, 2026
fa8599e
feat(autobahn): prune registry epochs behind the data Anchor
wen-coding Aug 20, 2026
6872569
docs(autobahn): laneQC is weighted under the applied epoch
wen-coding Aug 20, 2026
b85bad3
test(autobahn): fold duplicate multi-epoch tests into tables
wen-coding Aug 20, 2026
23d2e88
docs(autobahn): LaneProposal.Verify is integrity, not mechanism
wen-coding Aug 20, 2026
3f33d05
refactor(autobahn): apply epochs via ConsensusSpec.Epoch
wen-coding Aug 20, 2026
c332a41
docs(autobahn): blockVotes stay weighted under applied epoch
wen-coding Aug 20, 2026
1990816
docs(autobahn): Anchor.Epoch is the epoch of CommitQC
wen-coding Aug 20, 2026
5779b95
refactor(autobahn): tryAdvanceEpoch is a single restart step
wen-coding Aug 20, 2026
ab6707c
refactor(autobahn): admit CommitQCs and blocks under applied epoch
wen-coding Aug 20, 2026
3594449
refactor(autobahn): plan avail applied epoch before newInner
wen-coding Aug 20, 2026
eacea27
refactor(autobahn): WAL Index is the current view
wen-coding Aug 21, 2026
2224f36
refactor(autobahn): live epoch window and PushQC wait order
wen-coding Aug 21, 2026
26de868
fix(autobahn): regenerate PersistedInner Index comment in pb.go
wen-coding Aug 21, 2026
e00b3db
fix(autobahn): jump applied on data catch-up instead of killing Run
wen-coding Aug 21, 2026
e69dfad
test(autobahn): collapse duplicate epoch-boundary coverage
wen-coding Aug 21, 2026
bd65c6e
fix(autobahn): install catch-up epochs in runEpochAdvance, not prune
wen-coding Aug 21, 2026
bd39e39
refactor(autobahn): one wait/jump in runEpochAdvance
wen-coding Aug 21, 2026
3b9d354
refactor(autobahn): restore tip as Option[restoredQC]; nextViewEpoch …
wen-coding Aug 21, 2026
5c7dd4e
refactor(autobahn): derive epoch-advance target from the durable tip
wen-coding Aug 21, 2026
2e96353
fix(avail): do not rewind the durable tip after prune
wen-coding Aug 21, 2026
b69f855
fix(autobahn): wrap leftover tests with blockstore after rebase
wen-coding Aug 21, 2026
5591c9c
test(autobahn): route remaining tests through BlockStore helpers
wen-coding Aug 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions sei-tendermint/autobahn/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,9 @@ func (b *Block) Header() *BlockHeader { return b.header }
// Payload .
func (b *Block) Payload() *Payload { return b.payload }

// Verify validates the Block.
Comment thread
pompon0 marked this conversation as resolved.
func (b *Block) Verify(c *Committee) error {
if err := b.Header().Verify(c); err != nil {
return fmt.Errorf("header.Verify(): %w", err)
}
if got, want := b.Payload().Hash(), b.Header().PayloadHash(); got != want {
// Verify checks the block's internal integrity.
func (b *Block) Verify() error {
if got, want := b.payload.Hash(), b.header.payloadHash; got != want {
return fmt.Errorf("payload.Hash() = %v, want %v", got, want)
}
return nil
Expand Down
10 changes: 5 additions & 5 deletions sei-tendermint/autobahn/types/committee_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func TestLaneQCVerifyChecksWeight(t *testing.T) {
func TestPrepareQCVerifyChecksWeight(t *testing.T) {
rng := utils.TestRng()
ep, keys := makeEpoch(rng)
vote := NewPrepareVote(ProposalAt(ep, View{EpochIndex: ep.EpochIndex(), Index: ep.RoadRange().First}))
vote := NewPrepareVote(ProposalAt(ep, View{EpochIndex: ep.EpochIndex(), Index: ep.RoadRange().First}, ep.FirstBlock()))

heavyOnly := NewPrepareQC([]*Signed[*PrepareVote]{
Sign(keys[0], vote),
Expand All @@ -128,7 +128,7 @@ func TestPrepareQCVerifyChecksEpochBinding(t *testing.T) {
return NewPrepareQC([]*Signed[*PrepareVote]{Sign(keys[0], NewPrepareVote(p))})
}

require.NoError(t, sign(ProposalAt(ep, View{Index: ep.RoadRange().First})).Verify(ep))
require.NoError(t, sign(ProposalAt(ep, View{Index: ep.RoadRange().First}, ep.FirstBlock())).Verify(ep))

wrongEpoch := newProposal(View{Index: ep.RoadRange().First, EpochIndex: ep.EpochIndex() + 1}, time.Time{}, nil, ep.FirstBlock())
require.Error(t, sign(wrongEpoch).Verify(ep))
Expand All @@ -144,7 +144,7 @@ func TestCommitQCVerifyChecksEpochBinding(t *testing.T) {
return NewCommitQC([]*Signed[*CommitVote]{Sign(keys[0], NewCommitVote(p))})
}

require.NoError(t, sign(ProposalAt(ep, View{Index: ep.RoadRange().First})).Verify(ep))
require.NoError(t, sign(ProposalAt(ep, View{Index: ep.RoadRange().First}, ep.FirstBlock())).Verify(ep))

wrongEpoch := newProposal(View{Index: ep.RoadRange().First, EpochIndex: ep.EpochIndex() + 1}, time.Time{}, nil, ep.FirstBlock())
require.Error(t, sign(wrongEpoch).Verify(ep))
Expand All @@ -156,7 +156,7 @@ func TestCommitQCVerifyChecksEpochBinding(t *testing.T) {
func TestCommitQCVerifyChecksWeight(t *testing.T) {
rng := utils.TestRng()
ep, keys := makeEpoch(rng)
vote := NewCommitVote(ProposalAt(ep, View{EpochIndex: ep.EpochIndex(), Index: ep.RoadRange().First}))
vote := NewCommitVote(ProposalAt(ep, View{EpochIndex: ep.EpochIndex(), Index: ep.RoadRange().First}, ep.FirstBlock()))

heavyOnly := NewCommitQC([]*Signed[*CommitVote]{
Sign(keys[0], vote),
Expand All @@ -172,7 +172,7 @@ func TestCommitQCVerifyChecksWeight(t *testing.T) {
func TestAppQCVerifyChecksWeight(t *testing.T) {
rng := utils.TestRng()
ep, keys := makeEpoch(rng)
vote := NewAppVote(NewAppProposal(ProposalAt(ep, View{EpochIndex: ep.EpochIndex(), Index: ep.RoadRange().First}), GenAppHash(rng)))
vote := NewAppVote(NewAppProposal(ProposalAt(ep, View{EpochIndex: ep.EpochIndex(), Index: ep.RoadRange().First}, ep.FirstBlock()), GenAppHash(rng)))

heavyOnly := NewAppQC([]*Signed[*AppVote]{
Sign(keys[0], vote),
Expand Down
12 changes: 9 additions & 3 deletions sei-tendermint/autobahn/types/epoch.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,25 @@ import (
// EpochIndex is the epoch number.
type EpochIndex uint64

// RoadRange is an inclusive range of RoadIndex values [First, Last].
// RoadRange is a half-open road range [First, Next).
type RoadRange struct {
First RoadIndex
Next RoadIndex
}

// EpochRange is a half-open epoch-index range [First, Next).
type EpochRange struct {
First EpochIndex
Next EpochIndex
}

// OpenRoadRange returns a RoadRange covering all road indices from 0.
// Use in tests and genesis epochs where no upper bound is known yet.
func OpenRoadRange() RoadRange { return RoadRange{First: 0, Next: utils.Max[RoadIndex]()} }

// Has reports whether idx falls within this range.
func (r RoadRange) Has(idx RoadIndex) bool { return r.First <= idx && idx < r.Next }

func (r EpochRange) Has(idx EpochIndex) bool { return r.First <= idx && idx < r.Next }

// Epoch holds the complete context for a single epoch.
// Retrieved from the local Registry; never transmitted on the wire.
type Epoch struct {
Expand Down
8 changes: 8 additions & 0 deletions sei-tendermint/autobahn/types/epoch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ import (
"github.com/sei-protocol/sei-chain/sei-tendermint/libs/utils/require"
)

func TestRoadRange_Has(t *testing.T) {
r := RoadRange{First: 10, Next: 13}
require.False(t, r.Has(9))
require.True(t, r.Has(10))
require.True(t, r.Has(12))
require.False(t, r.Has(13))
}

func TestEpochIsClosed(t *testing.T) {
rng := utils.TestRng()
a := GenSecretKey(rng).Public()
Expand Down
6 changes: 3 additions & 3 deletions sei-tendermint/autobahn/types/lane_proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ func NewLaneProposal(block *Block) *LaneProposal {
// Block .
func (m *LaneProposal) Block() *Block { return m.block }

// Verify verifies that the LaneProposal is consistent with the Committee.
func (m *LaneProposal) Verify(c *Committee) error {
return m.block.Verify(c)
// Verify checks the proposal's internal integrity.
func (m *LaneProposal) Verify() error {
return m.block.Verify()
}

// LaneProposalConv is a protobuf converter for LaneProposal.
Expand Down
12 changes: 6 additions & 6 deletions sei-tendermint/autobahn/types/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,8 @@ func (m *Signed[T]) Sig() *Signature { return m.sig }
// Key returns the key whish signed the message.
func (m *Signed[T]) Key() PublicKey { return m.sig.key }

// VerifySig verifies the signature of the message.

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.

having both "VerifySig" vs "VerifySignature" is a poor naming scheme.
You can remove membership check from VerifySig.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

func (m *Signed[T]) VerifySig(c *Committee) error {
if !c.HasReplica(m.sig.key) {
return fmt.Errorf("%q is not a replica", m.sig.key)
}
// VerifySig verifies the cryptographic signature.
func (m *Signed[T]) VerifySig() error {
return m.sig.key.key.VerifyWithTag(autobahnTag, m.hashed.hash[:], m.sig.sig)
}

Expand All @@ -207,7 +204,10 @@ func (m *Hashed[T]) verifyQC(c *Committee, quorumWeight uint64, sigs []*Signatur
done[sig.key] = struct{}{}
weight += c.Weight(sig.key)
sm := &Signed[T]{hashed: m, sig: sig}
if err := sm.VerifySig(c); err != nil {
if !c.HasReplica(sm.Key()) {
return fmt.Errorf("%q is not a replica", sm.Key())
}
if err := sm.VerifySig(); err != nil {
return err
}
}
Expand Down
26 changes: 19 additions & 7 deletions sei-tendermint/autobahn/types/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,16 +125,28 @@ func (v View) Next() View {
return v
}

// ViewSpec is the full local context for starting a view: justification QCs plus
// the epoch active at that view. Epoch is required; View(), NextGlobalBlock(), and
// NextTimestamp() panic if it is nil.
// ConsensusSpec is the durable CommitQC tip paired with the epoch of the
// RoadIndex that follows it. CommitQC is None before the first tip; until then
// Epoch is genesis epoch 0 (and FirstBlock is the next global block). Consensus
// advances with a spec verbatim.
type ConsensusSpec struct {
CommitQC utils.Option[*CommitQC]
Epoch *Epoch
}

// Index is the RoadIndex of the next view: CommitQC.Index()+1, or 0 if there is no tip.
func (s ConsensusSpec) Index() RoadIndex {
return NextIndexOpt(s.CommitQC)
}

// ViewSpec is ConsensusSpec plus the TimeoutQC for the current view number.
// Epoch is required; View(), NextGlobalBlock(), and NextTimestamp() panic if it is nil.
type ViewSpec struct {
ConsensusSpec
// WARNING: currently we have implicit assumption that
// TimeoutQC.View().Index == CommitQC.Index.Next(),
// I.e. that TimeoutQC comes from the expected consensus instance.
CommitQC utils.Option[*CommitQC]
TimeoutQC utils.Option[*TimeoutQC]
Epoch *Epoch
}

// NextGlobalBlock returns the first global block number expected in the next proposal.
Expand All @@ -149,7 +161,7 @@ func (vs *ViewSpec) NextGlobalBlock() GlobalBlockNumber {

// View is the view justified by vs.
func (vs *ViewSpec) View() View {
idx := NextIndexOpt(vs.CommitQC)
idx := vs.Index()
if view := NextViewOpt(vs.TimeoutQC); view.Index == idx {
view.EpochIndex = vs.Epoch.EpochIndex()
return view
Expand Down Expand Up @@ -411,7 +423,7 @@ func (m *FullProposal) Verify(vs ViewSpec) error {
return fmt.Errorf("proposer %q, want %q", got, want)
}
// Verify the proposer's signature.
if err := m.proposal.VerifySig(c); err != nil {
if err := m.proposal.VerifySig(); err != nil {
return fmt.Errorf("proposal signature: %w", err)
}
// Do we have the required timeoutQC?
Expand Down
Loading
Loading