Skip to content

Implement tx write in Autobahn rpc-only node (CON-309)#3525

Open
wen-coding wants to merge 12 commits into
mainfrom
wen/autobahn_rpc_write_side
Open

Implement tx write in Autobahn rpc-only node (CON-309)#3525
wen-coding wants to merge 12 commits into
mainfrom
wen/autobahn_rpc_write_side

Conversation

@wen-coding
Copy link
Copy Markdown
Contributor

@wen-coding wen-coding commented May 30, 2026

Summary

Adds an autobahn-role config (validator | rpc-only). With autobahn-role="rpc-only", a non-validator RPC node loads the committee from autobahn.json as a routing table only — no consensus participation, no block execution, no validator key required.

eth_sendRawTransaction submitted to such a node is recovered, sender-shard-mapped via Committee.EvmShard, and forwarded over HTTP to the shard owner's EVM RPC. The rest of the giga stack (consensus, producer, data, service) stays nil; Run is a no-op; block-read methods return a sentinel error.

InitRPCOnly bootstraps the app once at startup so x/evm params (chain ID, signer config) are populated. app.go pre-fires the EVM HTTP/WS start gate since rpc-only nodes don't call ProcessBlock in the current write-only milestone — see TODO(autobahn-read-path) in NewGigaRouter for the read-side scope.

Test plan

  • go vet + gofmt -s -l clean
  • go test ./sei-tendermint/internal/p2p/ -run TestGigaRouter_RPCOnly passes
  • make autobahn-integration-test locally: all 6 sub-tests pass (BlockProduction, BankTransfer, RPCOnlyForwarding, LivenessUnderMaxFaults, HaltsBeyondMaxFaults, Recovery)
  • CI autobahn-integration-tests job green

Follow-up

Read-path milestone: rpc-only nodes subscribe to finalized blocks and serve receipts/logs locally. At that point the autobahnRPCOnly gate-bypass in app.go, the read-path sentinel errors in giga_router.go, and the data/consensus skips in NewGigaRouter can be partially reverted — see the single TODO(autobahn-read-path) in NewGigaRouter for the consolidated plan.

🤖 Generated with Claude Code

Adds an autobahn-role config (validator|rpc-only). With autobahn-role=
"rpc-only", a non-validator RPC node loads the committee from autobahn.json
as a routing table only — no consensus participation, no block execution,
no validator key required.

eth_sendRawTransaction submitted to such a node is recovered, sender-shard-
mapped via Committee.EvmShard, and forwarded over HTTP to the shard owner's
EVM RPC. The rest of the giga stack (consensus, producer, data, service)
stays nil; Run is a no-op; block-read methods return a sentinel error.

InitRPCOnly bootstraps the app once at startup so x/evm params (chain ID,
signer config) are populated. app.go pre-fires the EVM HTTP/WS start gate
since rpc-only nodes don't call ProcessBlock in the current milestone — see
TODO(autobahn-read-path) in NewGigaRouter for the read-side scope.

CI: wires PR #3234's make autobahn-integration-test into the workflow as a
new top-level job (it owns its own cluster via TestMain, so can't share the
matrix's cluster), and adds a TestAutobahn/RPCOnlyForwarding sub-test that
verifies an actual signed tx round-trips through the proxy: rpc-only sidecar
→ shard owner → block inclusion → receipt on validator.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cursor
Copy link
Copy Markdown

cursor Bot commented May 30, 2026

PR Summary

Medium Risk
Touches Autobahn routing, node startup, and EVM RPC readiness timing; rpc-only path intentionally skips block reads and full consensus, so misconfiguration could affect tx submission or listener behavior until the read-path milestone lands.

Overview
Introduces autobahn-role="rpc-only" so a non-validator RPC node can join Autobahn with only the committee routing table: no validator key, no consensus/producer/data stack, and eth_sendRawTransaction forwarded to the shard owner’s EVM RPC via GigaRouter.EvmProxy.

Tendermint / node: New AutobahnRole config and validation; buildRPCOnlyGigaConfig and a slim NewGigaRouter path with InitRPCOnly (genesis InitChain when needed). Rpc-only Run is idle; block read APIs return a sentinel error. node.go skips remote-signer checks and optional validator key for rpc-only; calls InitRPCOnly after startup.

App: Replaces racy HTTP/WS start flags with sync.Once and signalEVMRPCReady, plus an Info override so rpc-only nodes (which don’t run ProcessBlock) still open EVM listeners on restart without firing during Comet handshake replay on validators.

Docker / CI: Rpc init script generates autobahn.json and rpc-only role when AUTOBAHN=true; Makefile passes AUTOBAHN, CLUSTER_SIZE, and uses DOCKER_PLATFORM for rpc images. New autobahn-integration-tests job and RPCOnlyForwarding integration test (sidecar + eth_sendRawTransaction end-to-end).

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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 30, 2026

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

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedMay 31, 2026, 12:53 AM

@codecov
Copy link
Copy Markdown

codecov Bot commented May 30, 2026

Codecov Report

❌ Patch coverage is 54.80769% with 47 lines in your changes missing coverage. Please review.
✅ Project coverage is 58.27%. Comparing base (0ce9176) to head (e25d6b1).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
sei-tendermint/node/setup.go 28.57% 25 Missing ⚠️
sei-tendermint/internal/p2p/giga_router.go 70.00% 7 Missing and 5 partials ⚠️
sei-tendermint/config/config.go 33.33% 4 Missing ⚠️
sei-tendermint/node/node.go 60.00% 2 Missing and 2 partials ⚠️
app/app.go 84.61% 1 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3525      +/-   ##
==========================================
- Coverage   59.12%   58.27%   -0.85%     
==========================================
  Files        2204     2131      -73     
  Lines      182630   174339    -8291     
==========================================
- Hits       107983   101599    -6384     
+ Misses      64942    63707    -1235     
+ Partials     9705     9033     -672     
Flag Coverage Δ
sei-chain-pr 60.84% <54.80%> (?)
sei-db 70.41% <ø> (ø)
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-tendermint/config/toml.go 55.00% <ø> (ø)
app/app.go 69.26% <84.61%> (-0.01%) ⬇️
sei-tendermint/config/config.go 72.66% <33.33%> (-0.51%) ⬇️
sei-tendermint/node/node.go 65.22% <60.00%> (-0.15%) ⬇️
sei-tendermint/internal/p2p/giga_router.go 69.83% <70.00%> (+0.07%) ⬆️
sei-tendermint/node/setup.go 66.16% <28.57%> (-3.07%) ⬇️

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

@wen-coding wen-coding changed the title feat(autobahn): rpc-only mode forwards eth_sendRawTransaction (CON-309) Implement tx write in Autobahn rpc-only node (CON-309) May 30, 2026
Comment thread app/app.go Outdated
Comment thread app/app.go
Comment thread sei-tendermint/internal/p2p/giga_router_test.go Outdated
wen-coding and others added 2 commits May 29, 2026 18:14
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Guard autobahnRPCOnly on AutobahnConfigFile != "" so a stray
  autobahn-role without a config file doesn't pre-fire the EVM gate
  (matches node.go's gigaRPCOnly construction and the AutobahnRole
  godoc, which already says the role is ignored when the config file
  is empty).
- Drop time.Sleep + time.After from the rpc-only Run-cancel test; a
  pre-cancelled context proves the unblock path without any goroutine-
  timing synchronization.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread sei-tendermint/node/setup.go
wen-coding and others added 2 commits May 29, 2026 19:57
ProcessBlock's deferred gate-fire didn't cover rpc-only nodes because
they never execute a block. Factor the gate-fire into a helper and
call it from InitChainer as well — fresh-start validators reach it via
the handshaker / runExecute InitChain call, rpc-only nodes via
GigaRouter.InitRPCOnly. Both paths converge on the same chain event.
The *Sent flags keep the second fire a no-op.

Drops the autobahnRPCOnly field on App and the consensus-mode branch in
RegisterLocalServices that bugbot flagged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bugbot caught the leftover copy-paste from buildGigaConfig — the rpc-only
variant intentionally skips the membership check, so nodeKey was never
read.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread sei-tendermint/internal/p2p/giga_router.go
wen-coding and others added 2 commits May 29, 2026 20:42
Bot caught a latent issue: InitRPCOnly's early-return (when the app
already has committed state) skipped the InitChain call, so the
InitChainer defer never fired and the EVM RPC goroutines would block
forever. Today the path is unreachable (rpc-only never commits) but
read-side scope changes that.

Wrap BaseApp.Info to also fire the gate when LastBlockHeight > 0. The
trigger is the app's own committed state, not a consensus-engine flag,
so no cross-layer branching. Pairs naturally with InitChainer's defer:
fresh start fires via InitChain, restart-with-state via Info, steady-
state via ProcessBlock.

Verified: make autobahn-integration-test passes all 6 sub-tests
including RPCOnlyForwarding.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor Bot left a comment

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.

Reviewed by Cursor Bugbot for commit 0cb13f5. Configure here.

Comment thread sei-tendermint/node/setup.go
wen-coding and others added 5 commits May 29, 2026 21:04
Bugbot caught the validator-address-map construction was copy-pasted
between buildGigaConfig and buildRPCOnlyGigaConfig. Pull it into a
single loadAutobahnCommittee helper that returns the parsed file
config + the committee map; both callers compose the rest of their
config from there.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The override is a sei-tendermint-specific concession (rpc-only nodes
have no ProcessBlock to fire the gate from), not a general improvement
to Info. Calling that out in the header so a future reader doesn't
wonder why we touched an ABCI method that looks innocent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Review caught that the unconditional Info wrapper fires the gate
before CometBFT Handshaker's ReplayBlocks runs, binding EVM HTTP/WS
while replay is mid-flight — strictly worse staleness window than the
original ProcessBlock-defer trigger (which fires after the first
replayed block commits). Re-introduce autobahnRPCOnly as a single
bool on App, set from tmConfig (guarded on AutobahnConfigFile != ""),
and gate the Info-side fire on it. Autobahn nodes skip the Handshaker
entirely, so the gating is also what makes the override safe for the
mode it exists for.

Also addresses smaller review feedback:
- LastCommittedBlockNumber: reword to match /status's actual
  committed > 0 guard; the "LastCommitted >= Latest" framing was
  overstated and fragile.
- rpc_only_test.go: rename identical-string constants to expose the
  routing intent at call sites (validatorEVMRPCURLOnHost vs
  evmRPCURLOnContainerLocalhost — one is host-curled, the other goes
  through docker exec into the rpc-only sidecar).

Verified: make autobahn-integration-test passes all 6 sub-tests
including RPCOnlyForwarding.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI fresh-cluster runs failed at TestAutobahn/RPCOnlyForwarding with
"sei_associate error: : unknown" because the V/R/S hex encoding
differed from what `seid tx evm associate-address` produces:
crypto.Sign returns sig[64] as a raw byte and hex.EncodeToString of
[]byte{0x00} produces "00", but the CLI uses big.Int.Bytes() which
strips leading zeros to "" for V=0. The chain's signature
verification rejects the encoding mismatch (CheckTx code != 0).

Match the CLI exactly: round-trip through big.Int.Bytes() for R, S,
and V. Local runs previously passed because they hit the
"balance > 0 → skip associate" branch against a long-lived cluster
where admin was already associated from prior runs.

Also silence `git describe --tags 2>/dev/null` in Makefile — the
"fatal: No names found, cannot describe anything" line was cluttering
every CI log and surfaced from a shallow clone with no tags.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- app/app.go: replace racy *Sent flag pair on signalEVMRPCReady with
  sync.Once. The Info-side fire site makes the race reachable from any
  concurrent /abci_info RPC call once read-path lands; cheap to fix
  now. Also restore the InitChainer doc comment that an earlier edit
  orphaned onto the helper above it.

- sei-tendermint/internal/p2p/giga_router.go: change LastCommittedBlockNumber's
  rpc-only sentinel from -1 to 0 so /status's JSON response carries a
  non-negative integer for downstream clients. status.go's "committed >
  0" guard still silently skips it, so the invariant warning stays
  quiet. Update unit test.

- integration_test/autobahn: fold teardownRPCOnlyNode into
  teardownCluster. TestMain no longer repeats the kill in the two error
  paths + the success path; adding future sidecars goes in the same
  centralized teardown.

Verified: make autobahn-integration-test passes all 6 sub-tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.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