Skip to content

Autobahn migrated from sei-v3#2791

Open
pompon0 wants to merge 173 commits intomainfrom
gprusak-autobahn
Open

Autobahn migrated from sei-v3#2791
pompon0 wants to merge 173 commits intomainfrom
gprusak-autobahn

Conversation

@pompon0
Copy link
Contributor

@pompon0 pompon0 commented Feb 3, 2026

Migrated consensus,avail,data,producer and types modules. Migrated corresponding tests. Replaced gRPC usage with custom rpc layer on top of mux. GigaRouter is still hardcoded to be disabled.

NOTE: there is a lot of missing parts and coverage, but this pr will allow us to stop development of autobahn in sei-v3, so that we can start making it production-ready in sei-chain.

@pompon0 pompon0 changed the base branch from main to gprusak-router February 3, 2026 13:15
@github-actions
Copy link

github-actions bot commented Feb 3, 2026

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

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedFeb 5, 2026, 1:34 PM

@pompon0 pompon0 marked this pull request as ready for review February 3, 2026 13:22
@codecov
Copy link

codecov bot commented Feb 3, 2026

Codecov Report

❌ Patch coverage is 69.72763% with 778 lines in your changes missing coverage. Please review.
✅ Project coverage is 56.79%. Comparing base (ec9e52e) to head (50ea1d9).

Files with missing lines Patch % Lines
sei-tendermint/internal/autobahn/types/proposal.go 66.66% 48 Missing and 37 partials ⚠️
sei-tendermint/internal/autobahn/data/state.go 63.91% 52 Missing and 18 partials ⚠️
sei-tendermint/internal/autobahn/avail/state.go 73.22% 41 Missing and 23 partials ⚠️
sei-tendermint/internal/p2p/giga/avail.go 59.87% 32 Missing and 31 partials ⚠️
sei-tendermint/internal/autobahn/types/timeout.go 60.95% 40 Missing and 17 partials ⚠️
sei-tendermint/internal/autobahn/producer/state.go 0.00% 51 Missing ⚠️
sei-tendermint/internal/autobahn/types/msg.go 68.70% 31 Missing and 15 partials ⚠️
sei-tendermint/internal/autobahn/data/testonly.go 58.82% 41 Missing and 1 partial ⚠️
sei-tendermint/internal/autobahn/types/block.go 65.21% 27 Missing and 13 partials ⚠️
sei-tendermint/internal/p2p/giga/consensus.go 46.57% 29 Missing and 10 partials ⚠️
... and 26 more
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2791      +/-   ##
==========================================
+ Coverage   46.94%   56.79%   +9.85%     
==========================================
  Files        1965     2068     +103     
  Lines      160525   167802    +7277     
==========================================
+ Hits        75352    95297   +19945     
+ Misses      78643    64056   -14587     
- Partials     6530     8449    +1919     
Flag Coverage Δ
sei-chain 40.83% <0.00%> (-0.69%) ⬇️
sei-cosmos 48.13% <ø> (+<0.01%) ⬆️
sei-db 68.72% <ø> (ø)
sei-tendermint 58.68% <69.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/avail/queue.go 100.00% <100.00%> (ø)
sei-tendermint/internal/autobahn/types/opt.go 100.00% <100.00%> (ø)
sei-tendermint/internal/p2p/giga/service.go 100.00% <100.00%> (ø)
sei-tendermint/internal/p2p/mux/mux.go 76.88% <100.00%> (+76.88%) ⬆️
sei-tendermint/internal/p2p/rpc/rpc.go 94.82% <100.00%> (+82.54%) ⬆️
...-tendermint/internal/autobahn/avail/block_votes.go 85.71% <85.71%> (ø)
sei-tendermint/internal/autobahn/types/app_vote.go 81.81% <81.81%> (ø)
...-tendermint/internal/autobahn/types/commit_vote.go 81.81% <81.81%> (ø)
...ei-tendermint/internal/autobahn/types/committee.go 95.74% <95.74%> (ø)
...endermint/internal/autobahn/types/lane_proposal.go 84.61% <84.61%> (ø)
... and 31 more

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

Comment on lines +35 to +39
for _, vs := range i.votes[lane].q[n].byHeader {
if len(vs) >= c.LaneQuorum() {
return types.NewLaneQC(vs[:c.LaneQuorum()]), true
}
}

Check warning

Code scanning / CodeQL

Iteration over map Warning

Iteration over map may be a possible source of non-determinism
Comment on lines +55 to +59
for lane := range i.votes {
lr := commitQC.LaneRange(lane)
i.votes[lr.Lane()].prune(lr.First())
i.blocks[lr.Lane()].prune(lr.First())
}

Check warning

Code scanning / CodeQL

Iteration over map Warning

Iteration over map may be a possible source of non-determinism
Comment on lines +49 to +54
for lane, bq := range inner.blocks {
for i := max(bq.first, r.next[lane]); i < bq.next; i++ {
batch = append(batch, bq.q[i].Msg().Block().Header())
}
r.next[lane] = bq.next
}

Check warning

Code scanning / CodeQL

Iteration over map Warning

Iteration over map may be a possible source of non-determinism
Comment on lines +62 to +64
for _, v := range cv.byHash[h] {
votes = append(votes, v)
}

Check warning

Code scanning / CodeQL

Iteration over map Warning

Iteration over map may be a possible source of non-determinism
Comment on lines +64 to +66
for _, v := range pv.byHash[h] {
votes = append(votes, v)
}

Check warning

Code scanning / CodeQL

Iteration over map Warning

Iteration over map may be a possible source of non-determinism
Comment on lines +468 to +470
for _, qc := range m.laneQCs {
laneQCs = append(laneQCs, qc)
}

Check warning

Code scanning / CodeQL

Iteration over map Warning

Iteration over map may be a possible source of non-determinism

// GenProposal generates a random Proposal.
func GenProposal(rng utils.Rng) *Proposal {
return newProposal(GenView(rng), time.Now(), utils.GenSlice(rng, GenLaneRange), utils.Some(GenAppProposal(rng)))

Check warning

Code scanning / CodeQL

Calling the system time Warning test

Calling the system time may be a possible source of non-determinism
Comment on lines +194 to +196
for _, l := range p.laneRanges {
laneRanges = append(laneRanges, l)
}

Check warning

Code scanning / CodeQL

Iteration over map Warning

Iteration over map may be a possible source of non-determinism
pb "github.com/tendermint/tendermint/internal/autobahn/pb"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"

Check notice

Code scanning / CodeQL

Sensitive package import Note

Certain system packages contain functions which may be a possible source of non-determinism
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"

Check notice

Code scanning / CodeQL

Sensitive package import Note

Certain system packages contain functions which may be a possible source of non-determinism
Base automatically changed from gprusak-router to main February 3, 2026 14:51
}
time.Sleep(time.Second)
t.Logf("wait for the blocks used in test")
utils.OrPanic1(waitForBlock(ctx, primary, 3))

Choose a reason for hiding this comment

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

Just curious, why do we need to change this test?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The test is flaky, it is not related to the autobahn in any sense.

// Equivalent of `google.protobuf.Timestamp` but supports canonical encoding.
// See `google.protobuf.Timestamp` for more detailed specification.
message Timestamp {
option (hashable.hashable) = true;

Choose a reason for hiding this comment

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

nit: comment what this does?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is documented on the hashable package.

}
}
}
// TODO(gprusak): this is counterintuitive asymmetric behavior:

Choose a reason for hiding this comment

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

Sorry I'm confused, didn't find this in v3 code, Is this migrated from some other repo?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No this is my own code. I've found a bug when plugging the mux into autobahn, which is a result of this inconsistency.


// Ping implements pb.StreamAPIServer.
// Note that we use streaming RPC, because unary RPC apparently causes 10ms extra delay on avg (empirically tested).
func (x *Service) serverPing(ctx context.Context, server rpc.Server[API]) error {

Choose a reason for hiding this comment

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

And from here on is from stream/consensus/server.go?

Why don't we keep the original client/server separation?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the client and server implementation are tightly coupled, given that we use streaming RPCs. However, the way I've distributed the code across the files is kinda arbitrary, we can cleanup it later. A lot of it will need to be moved around anyway.

"github.com/tendermint/tendermint/internal/p2p/rpc"
)

func (x *Service) serverStreamLaneProposals(ctx context.Context, server rpc.Server[API]) error {

Choose a reason for hiding this comment

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

So from here on it's stream/consensus/avail/server.go?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah

})
}

func (x *Service) clientStreamLaneProposals(ctx context.Context, c rpc.Client[API]) error {

Choose a reason for hiding this comment

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

nit: If we have to put client and server in the same file, can we always do client first or always do server first maybe?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure, this is a work-in-progress layout, definitely will need a cleanup.

@@ -0,0 +1,33 @@
package avail

Choose a reason for hiding this comment

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

Since queue sounds like a general enough data structure, can you maybe comment why we need it defined in avail/, not at some more generic location?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

my rule of thumb is to write general enough abstractions to avoid tangling logic. The question of visibility (where the code should be located, which packages should have access to it) is a totally separate question. So far this struct was under a lot of code churn, that's why it is in the package that is making use of it.

@@ -0,0 +1,103 @@
package avail

Choose a reason for hiding this comment

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

I believe this file is new, can you maybe explain a little bit why it's organized this way? How many receiver instances do we plan to have for each kind?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is 1 receiver per connection currently. I wanted to separate autobahn from the transport layer. Autobahn api surface is way too large atm (number of receivers, custom receivers for each consensus message type, proper buffer sizes in rpcs, etc), it will require some work to simplify it. Or we can fallback to merge back the transport layer into autobahn (which is currently under p2p/giga). This is TBD.

for _, v := range cv.byHash[h] {
votes = append(votes, v)
}
cv.qc.Store(utils.Some(types.NewCommitQC(votes)))

Choose a reason for hiding this comment

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

Why are we changing from cv.qc.Update to cv.qc.Load and cv.qc.Store now?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thank for reminding me. The AtomicWatch has evolved since I implemented it in sei-v3. Now it is separated into AtomicSend and AtomicRecv and does not provide atomic updated by default - you need to wrap AtomicSend into a mutex - it simplifies the AtomicSend api AND allows AtomicSend to share mutex with other data, which is usually very convenient.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've left a bunch of TODOs, because this change introduces some race conditions. Let me address them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

return types.NewLaneQC(votes)
}

func TestCommitQC(

Choose a reason for hiding this comment

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

Nice, I like that the helpers are all moved here.

MaxGasPerBlock uint64
MaxTxsPerBlock uint64
MaxTxsPerSecond utils.Option[uint64]
MempoolSize uint64

Choose a reason for hiding this comment

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

Do we still have a mempool in Giga?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the block production pipeline in giga needs to be designed and implemented. I've copied over the producer for reference.

)

// Sends a consensus message to the peer whenever atomic watch is updated.
func sendUpdates[T interface {

Choose a reason for hiding this comment

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

Okay, this one is moved from stream/consensus/client.go?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes

@pompon0 pompon0 requested a review from wen-coding February 5, 2026 13:34
if qc.Proposal().Index() < types.NextIndexOpt(i.viewSpec.CommitQC) {
return nil
for i := range s.inner.Lock() {
if qc.Proposal().Index() < types.NextIndexOpt(i.Load().viewSpec.CommitQC) {

Choose a reason for hiding this comment

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

nit: is this the same check as the one on line 26:
i.viewSpec.View().Index > qc.Proposal().Index()

Would help readability if we use the same expression to show that we are just rechecking the same condition.

inner := utils.Alloc(utils.NewAtomicSend(inner{}))
return &State{
cfg: cfg,
// metrics: NewMetrics(),

Choose a reason for hiding this comment

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

We do plan to add metrics back right?

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