Skip to content

Integrate Autobahn with in-memory EVM-only executor - #4028

Open
codchen wants to merge 7 commits into
mainfrom
codex/autobahn-evmonly-integration
Open

Integrate Autobahn with in-memory EVM-only executor#4028
codchen wants to merge 7 commits into
mainfrom
codex/autobahn-evmonly-integration

Conversation

@codchen

@codchen codchen commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Describe your changes and provide context

This PR builds on the EVM-only Giga store merged in #3864 and is rebased onto that merge commit.

  • Add a test-only top-level evm-only-in-memory node setting that replaces the Cosmos ABCI application before proxy.New, so Autobahn and the executor share the same application.
  • Initialize the EVM-only executor from InitChain, accept protected raw Ethereum transactions on chain ID 1337, and execute finalized blocks with a deterministic app hash.
  • Add a minimal EVM JSON-RPC listener on port 8545 with only eth_sendRawTransaction. It validates Ethereum encoding, routes by Autobahn EVM shard ownership, submits through the in-process mempool, and returns the Ethereum transaction hash.
  • Do not start Tendermint RPC for EVM-only nodes. The Docker harness also disables the unused Cosmos REST, gRPC, and gRPC-web servers.
  • Keep executor and Autobahn consensus state in memory; Docker disables Autobahn persistence with --persistent-state-dir=.
  • Add make autobahn-evmonly-integration-test, which submits 4,000 signed transfers through EVM JSON-RPC, asserts Tendermint RPC is unavailable, and uses internal Prometheus execution counters to wait for every validator.
  • Add the autobahn-e2e cluster manager with deploy, list, forward, and teardown subcommands for local Docker or a managed EC2 host. list obtains height from internal Prometheus metrics and does not depend on Tendermint RPC.
  • Keep the runtime deliberately ephemeral and load-test-only. Persistence, restart recovery, state sync, receipts, additional EVM RPC methods, and staking or other custom precompiles are out of scope.

Testing performed to validate your change

  • make autobahn-evmonly-integration-test (4,000 raw transfers through EVM JSON-RPC; all four validators executed through height 8; 5,010 tx/s observed locally; Tendermint RPC unavailable)
  • Real autobahn-e2e local lifecycle: deploy four nodes, list live status/Prometheus heights, forward node 2 to 127.0.0.1:18545, call the EVM RPC through the tunnel, confirm Tendermint /status resets, then teardown all containers and the network
  • go test -count=1 ./cmd/autobahn-e2e
  • go test -count=1 -run "^TestEVMOnlyRPC" ./sei-tendermint/node
  • go test -c -tags autobahn_integration ./integration_test/autobahn
  • go vet ./sei-tendermint/node ./cmd/autobahn-e2e
  • go vet -tags autobahn_integration ./integration_test/autobahn
  • golangci-lint v2.8.0 on the changed packages with --build-tags autobahn_integration (0 issues)
  • golangci-lint v2.8.0 fmt --diff across the repository
  • sh -n docker/localnode/scripts/step4_config_override.sh docker/localnode/scripts/step5_start_sei.sh
  • git diff --check

@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown

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

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedSep 1, 2026, 8:39 AM

@codecov

codecov Bot commented Aug 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 41.42012% with 693 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.15%. Comparing base (95f6bfb) to head (b97fa5b).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
cmd/autobahn-e2e/aws.go 53.01% 111 Missing and 45 partials ⚠️
cmd/autobahn-e2e/deploy.go 4.34% 106 Missing and 4 partials ⚠️
cmd/autobahn-e2e/list.go 33.33% 91 Missing and 7 partials ⚠️
cmd/autobahn-e2e/forward.go 20.00% 60 Missing and 4 partials ⚠️
...ei-tendermint/internal/p2p/evmonly_inmemory_app.go 70.89% 33 Missing and 22 partials ⚠️
cmd/autobahn-e2e/state.go 48.35% 29 Missing and 18 partials ⚠️
cmd/autobahn-e2e/teardown.go 25.42% 32 Missing and 12 partials ⚠️
giga/evmonly/rpc/server.go 31.03% 35 Missing and 5 partials ⚠️
cmd/autobahn-e2e/command.go 23.25% 32 Missing and 1 partial ⚠️
cmd/autobahn-e2e/runner.go 0.00% 28 Missing ⚠️
... and 3 more
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #4028      +/-   ##
==========================================
- Coverage   61.33%   60.15%   -1.19%     
==========================================
  Files        2157     2066      -91     
  Lines      188986   178071   -10915     
==========================================
- Hits       115918   107112    -8806     
+ Misses      62235    60992    -1243     
+ Partials    10833     9967     -866     
Flag Coverage Δ
sei-chain-pr 65.58% <41.42%> (?)
sei-db 69.80% <ø> (ø)
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/autobahn.go 50.00% <ø> (ø)
sei-tendermint/config/config.go 82.85% <ø> (ø)
sei-tendermint/config/toml.go 57.62% <ø> (ø)
sei-tendermint/node/public.go 76.92% <84.61%> (+1.20%) ⬆️
cmd/autobahn-e2e/main.go 0.00% <0.00%> (ø)
sei-tendermint/node/node.go 65.62% <12.50%> (-0.98%) ⬇️
cmd/autobahn-e2e/runner.go 0.00% <0.00%> (ø)
cmd/autobahn-e2e/command.go 23.25% <23.25%> (ø)
giga/evmonly/rpc/server.go 31.03% <31.03%> (ø)
cmd/autobahn-e2e/teardown.go 25.42% <25.42%> (ø)
... and 6 more

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

@codchen
codchen marked this pull request as ready for review August 27, 2026 09:22
@cursor

cursor Bot commented Aug 27, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes Tendermint node app selection and RPC startup paths and adds AWS provisioning that opens SSH, though the feature is explicitly test-only and not intended for production networks.

Overview
Adds a test-only Autobahn topology where validators run an ephemeral in-memory EVM executor instead of the Cosmos app, wired through a new evm-only-in-memory node flag and AUTOBAHN_EVMONLY_IN_MEMORY in Docker/Makefile. When enabled, Autobahn uses non-persistent state, Tendermint/Cosmos query surfaces are turned off, and nodes expose a minimal JSON-RPC on :8545 with only eth_sendRawTransaction (local broadcast or shard-owner proxy).

Ships the autobahn-e2e CLI (deploy, list, forward, teardown) to stand up the same four-validator cluster locally or on a single EC2 host (SSH-only ingress; EVM via forward), plus make autobahn-evmonly-integration-test and an EVMOnlyLoad integration path that fires thousands of raw transfers and asserts execution via internal Prometheus metrics.

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

Comment thread sei-tendermint/node/setup.go Outdated

@seidroid seidroid 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.

A well-scoped, test-only Autobahn EVM-only in-memory executor: the app-hash derivation is deterministic (the executor's changeset is sorted before encoding), the RPC head switch to the GigaRouter is behaviour-preserving for the existing Cosmos-app path, and the docker port/env plumbing checks out. No blockers; the notes below concern failure modes of the new runtime (a tx-level execution error halts the whole cluster), an unenforced config constraint, and a few structural/robustness cleanups.

Findings: 0 blocking | 6 non-blocking | 4 posted inline

Blockers

  • None at the file/PR level.

Non-blocking

  • [suggestion] Layering: evmonly_inmemory_app.go lands in sei-tendermint/internal/p2p, and sei-tendermint/config imports that package — so the config package now transitively depends on giga/evmonly and the whole go-ethereum EVM. It compiles today only because nothing under giga/evmonly reaches back to sei-tendermint/config; a future import there becomes a cycle. The app has no p2p concern (it is only constructed from node/setup.go); its own package would keep the dependency out of config's import graph.
  • [suggestion] The block's changeset is encoded twice per block: once inside ExecutePreparedBlock (via the WithStore(store, store.EncodeChangeSet) encoder) and again in hashEVMOnlyInMemoryResult (evmonly.EncodeMemoryStoreChangeSet(result.ChangeSet)). On the 4,000-tx blocks this harness exists to measure, that doubles changeset allocation on the hot path. result.ChangeSet is already deterministically sorted, so hashing it directly avoids the second encode.
  • 4 suggestion(s)/nit(s) flagged inline on specific lines.

Comment thread sei-tendermint/internal/p2p/evmonly_inmemory_app.go
Comment thread sei-tendermint/config/autobahn.go Outdated
// EVMOnlyInMemory replaces the Cosmos application used by Autobahn with an
// ephemeral EVM-only executor. It exists only for Docker load testing and
// must not be enabled on a persistent network.
EVMOnlyInMemory bool `json:"evm_only_in_memory,omitzero"`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[suggestion] The doc comment says this "must not be enabled on a persistent network", but nothing enforces it: AutobahnFileConfig.Validate accepts evm_only_in_memory: true together with persistent_state_dir, and only the docker script happens to del(.persistent_state_dir). A hand-written config with both set gets persisted consensus blocks over an EVM state that resets to the funded base on every restart. Validate() is the choke point every config load passes through — rejecting the combination there makes it an invariant instead of a convention the next config author has to remember.

return env.getHeight(env.App.Info().LastBlockHeight, heightPtr)
giga, ok := env.gigaRouter().Get()
if !ok {
panic("autobahnCheckAndGetHeight called without GigaRouter")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[suggestion] Both callers (Block at line 100, BlockResults at line 261) already hold the router from their own env.gigaRouter().Get() check, so this second lookup can never fail and the panic is unreachable by construction — but it is a panic on the RPC surface if that ever stops holding. Taking giga p2p.GigaRouter as a parameter removes both the redundant lookup and the panic.

seid tendermint gen-autobahn-config $NODE_DIRS --output "$AUTOBAHN_CONFIG"
if [ "$AUTOBAHN_EVMONLY_IN_MEMORY" = "true" ]; then
AUTOBAHN_CONFIG_TMP="$AUTOBAHN_CONFIG.tmp"
jq '.evm_only_in_memory = true | del(.persistent_state_dir)' "$AUTOBAHN_CONFIG" > "$AUTOBAHN_CONFIG_TMP"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[suggestion] This drops the && guard the repo's other jq rewrites use (override_genesis in step2_genesis.sh:13 is jq ... > tmp && mv tmp target). The script has no set -e, so if jq fails the mv on the next line still runs and replaces autobahn.json with a truncated file, and the node fails later with an unrelated-looking config error. Chaining > "$AUTOBAHN_CONFIG_TMP" && mv ... restores the existing idiom.

}
}

func evmOnlyInMemoryEnabled() bool {

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 acknowledge that this is for integration testing, but are there facilities to auto-map env variables to the json config? I'm only seeing JSON for AutobahnFileConfig.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

There is not an automatic Autobahn JSON env mapper here, so I removed this switch from AutobahnFileConfig. It is now the test-only top-level evm-only-in-memory TOML setting beside mock-app; the Docker env variable is only the harness selector and maps into that node config.

seid tendermint gen-autobahn-config $NODE_DIRS --output "$AUTOBAHN_CONFIG"
if [ "$AUTOBAHN_EVMONLY_IN_MEMORY" = "true" ]; then
AUTOBAHN_CONFIG_TMP="$AUTOBAHN_CONFIG.tmp"
jq '.evm_only_in_memory = true | del(.persistent_state_dir)' "$AUTOBAHN_CONFIG" > "$AUTOBAHN_CONFIG_TMP"

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.

You can pass empty string to persistent_state_dir, which I think will disable persistence.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Updated. The harness now passes --persistent-state-dir= to gen-autobahn-config, so the generator omits the persistent state directory without a follow-up jq deletion.

Comment thread sei-tendermint/node/setup.go Outdated
return nil, nil, err
}
logger.Warn("Autobahn EVM-only in-memory execution enabled; state is ephemeral and unsafe for persistent networks")
app = p2p.NewEVMOnlyInMemoryProxy(config.AutobahnEVMOnlyInMemoryChainID, maxGas, genDoc.InitialHeight)

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 this only updates buildGigaRouter's local app. Maybe try to do it like MockApp, do it earlier in node.New? #3905

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Updated to the MockApp pattern. prepareApplication now replaces the app inside node.New before proxy.New, so both RPC and GigaRouter receive the same application. The EVM-only executor derives the initial height and gas limit later from InitChain.

@codchen
codchen force-pushed the codex/integrate-evmonly-giga-store branch from 819a564 to 83f8025 Compare August 31, 2026 03:38
@codchen
codchen force-pushed the codex/autobahn-evmonly-integration branch from a81e71a to 0dfd46e Compare August 31, 2026 03:43

@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 0dfd46e. Configure here.

Comment thread sei-tendermint/internal/p2p/evmonly_inmemory_app.go
Comment thread sei-tendermint/internal/p2p/evmonly_inmemory_app.go
Base automatically changed from codex/integrate-evmonly-giga-store to main August 31, 2026 05:09
@codchen
codchen force-pushed the codex/autobahn-evmonly-integration branch from 359e4a7 to d30250f Compare August 31, 2026 10:08
Comment thread docker/localnode/config/config.toml
Comment thread cmd/autobahn-e2e/aws.go
Comment thread giga/evmonly/rpc/server.go
Comment thread sei-tendermint/config/autobahn.go Outdated
Comment thread sei-tendermint/internal/p2p/evmonly_inmemory_app.go
Comment thread sei-tendermint/internal/p2p/evmonly_inmemory_app.go
@wen-coding

Copy link
Copy Markdown
Contributor

I mostly checked the consensus/execution API, looks good to me.

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.

5 participants