Skip to content

rpc sharding by tx sender for autobahn#3438

Merged
pompon0 merged 80 commits into
mainfrom
gprusak-rpc-sharding9
May 19, 2026
Merged

rpc sharding by tx sender for autobahn#3438
pompon0 merged 80 commits into
mainfrom
gprusak-rpc-sharding9

Conversation

@pompon0
Copy link
Copy Markdown
Contributor

@pompon0 pompon0 commented May 14, 2026

For giga testnet we need every account to send transaction only to a single lane, so that they are included in nonce order. In this pr we are adding proxying of transactions to the correct lane (validator). How it works:

  • only evmrpc endpoint is handled
  • it is using http evmrpc connections for proxying (ws connections are also supported, but with the current impl they would be inefficient - see the comments in code)
  • [evm account -> lane] mapping is deterministic and defined by autobahn committee
  • evmrpc urls of validators of each lane are specified in autobahn config
  • whenever user calls sendRawTransaction or getTransactionCount rpcs to a node, the lane of the evm account is computed. If the lane is produced by the local node, it is added to the mempool. Otherwise url of the lane owner is fetched and the same evmrpc is called on that url.
  • If autobahn is not enabled, we fallback to the previous semantics.

Note

Medium Risk
Introduces request redirection for eth_sendRawTransaction and pending eth_getTransactionCount, which changes transaction submission/nonce semantics and adds cross-validator HTTP RPC dependencies driven by config.

Overview
Adds sender-based RPC sharding for Autobahn by introducing LocalClient.EvmProxy(sender) and wiring it through the Tendermint local client/environment and GigaRouter (deterministic shard selection via Committee.EvmShard).

evmrpc now redirects eth_sendRawTransaction and pending eth_getTransactionCount to the shard owner’s EVM RPC HTTP endpoint when the sender maps to a different validator, with a fallback to existing local behavior when no proxy is configured or Autobahn isn’t active. Adds a new OpenTelemetry counter evmrpc_redirected_requests_total.

Extends Autobahn config generation/consumption to include per-validator evmrpc URLs (new evmrpc_url.txt in localnode init, new evmrpc field in config with URL marshal/unmarshal) and updates/expands tests to cover proxy behavior and the shard→URL mapping.

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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 14, 2026

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

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedMay 19, 2026, 4:12 PM

@codecov
Copy link
Copy Markdown

codecov Bot commented May 14, 2026

Codecov Report

❌ Patch coverage is 58.22785% with 33 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.31%. Comparing base (25a36cb) to head (ce8109f).

Files with missing lines Patch % Lines
evmrpc/send.go 60.00% 6 Missing and 4 partials ⚠️
...int/cmd/tendermint/commands/gen_autobahn_config.go 0.00% 7 Missing ⚠️
evmrpc/tx.go 60.00% 2 Missing and 2 partials ⚠️
sei-tendermint/config/autobahn.go 63.63% 2 Missing and 2 partials ⚠️
sei-tendermint/internal/rpc/core/mempool.go 0.00% 4 Missing ⚠️
evmrpc/tests/mock_client.go 0.00% 2 Missing ⚠️
sei-tendermint/rpc/client/local/local.go 0.00% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3438      +/-   ##
==========================================
+ Coverage   59.30%   59.31%   +0.01%     
==========================================
  Files        2127     2127              
  Lines      175830   175943     +113     
==========================================
+ Hits       104268   104369     +101     
- Misses      62477    62479       +2     
- Partials     9085     9095      +10     
Flag Coverage Δ
sei-chain-pr 68.39% <58.22%> (?)
sei-db 70.41% <ø> (ø)

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

Files with missing lines Coverage Δ
evmrpc/metrics.go 96.00% <100.00%> (+0.65%) ⬆️
sei-cosmos/client/context.go 86.07% <ø> (ø)
...ei-tendermint/internal/autobahn/types/committee.go 96.42% <100.00%> (+0.35%) ⬆️
sei-tendermint/internal/p2p/giga_router.go 69.75% <100.00%> (+0.75%) ⬆️
sei-tendermint/node/setup.go 69.67% <100.00%> (+0.09%) ⬆️
evmrpc/tests/mock_client.go 56.66% <0.00%> (-0.77%) ⬇️
sei-tendermint/rpc/client/local/local.go 55.17% <0.00%> (-0.78%) ⬇️
evmrpc/tx.go 84.68% <60.00%> (-0.80%) ⬇️
sei-tendermint/config/autobahn.go 44.00% <63.63%> (+15.42%) ⬆️
sei-tendermint/internal/rpc/core/mempool.go 63.82% <0.00%> (-2.84%) ⬇️
... and 2 more

... and 32 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 thread evmrpc/send.go Outdated
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 and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

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 9c3516e. Configure here.

Comment thread evmrpc/send.go Outdated
SEI_NODE_ID=$(seid tendermint show-node-id)
NODE_IP=$(hostname -i | awk '{print $1}')
P2P_PORT=26656 # Must match [p2p] laddr in config.toml
EVMRPC_PORT=8545 # Must match the EVM RPC HTTP port (evmrpc DefaultConfig HTTPPort).
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.

nit: would be nice if both ports come from a common config

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.

these are preexisting configs. Merging them would be backward incompatible.

Comment thread evmrpc/metrics.go Outdated
)),
redirectedRequestCount: must(rpcTelemetryMeter.Int64Counter(
"evmrpc_redirected_requests_total",
metric.WithDescription("Number of EVM RPC requests redirected to another validator"),
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.

nit: can you clarify whether this is request you forwarded to someone else or it is request you received from redirection?

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.

reworded to "forwarded to another validator"

Comment thread evmrpc/send.go
// the underlying TCP connection lifecycle is strictly bound to Dial -> Close calls.
client, err := rpc.DialContext(ctx, url.String())
if err != nil {
return hash, fmt.Errorf("rpc.DialContext(%q): %w", url.String(), err)
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.

Would we see one error log per tx when one validator is down? That would be too spammy

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.

I'm not sure if we log all evmrpc RPC errors, but this will be consistent with the current behavior - we return error if tx does not land in the correct mempool

Comment thread evmrpc/send.go
// but we still need to handle it.
sender, senderErr := getSender(tx, s.keeper.ChainID(s.ctxProvider(LatestCtxHeight)))
if senderErr == nil {
if url, ok := s.tmClient.EvmProxy(sender); ok {
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.

What's our plan for handling the case where one validator is down?

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.

for testnet - some accounts will be censored. We need to implement a proper solution afterwards.

Comment thread evmrpc/send.go Outdated
from, err = signer.Sender(tx)
return from, nil
case tx.Protected():
from, err := ethtypes.NewEIP155Signer(chainID).Sender(tx)
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.

Would we always have NewEIP155Signer in tx.Protected()? Would ethtypes.LatestSignerForChainID(chainID)) be better? So we accept non-1559 transactions?

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.

I have just copied over what simulateTx did. Is this not correct?

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 LatestSignerForChainID(chainID) is a better approach guaranteed in go-ethereum library to handle all cases. I think the current code has a gap, but it only affected simulateTx's gas estimate, now we are skipping the proxy for it.

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.

make sense, switched to LatestSignerForChainID

Comment thread evmrpc/send.go Outdated
h := sha256.Sum256(addr[:])
x := new(big.Int).SetBytes(h[:])
i := int(x.Mod(x, big.NewInt(int64(c.replicas.Len()))).Int64())
return c.replicas.At(i)
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.

We don't have that many validators so maybe we can use a cheaper algorithm?

i := int(binary.BigEndian.Uint64(addr[:8]) % uint64(c.replicas.Len()))

I suppose we will have a different algorithm when Autobahn hits mainnet, so we don't need to worry about attacker reverse-engineering this algorithm for now?

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.

good point, although imo it will not be a bottleneck and eventually it will be even more expensive.

@cursor
Copy link
Copy Markdown

cursor Bot commented May 19, 2026

PR Summary

High Risk
High risk because it changes eth_sendRawTransaction and pending eth_getTransactionCount behavior to optionally forward requests over HTTP to other validators based on sender sharding, impacting transaction acceptance/nonce semantics and introducing new network failure modes.

Overview
Implements RPC sharding by EVM sender for Autobahn: nodes now deterministically map a sender address to a committee “lane” and, when the lane owner is another validator with an evmrpc URL configured, HTTP-proxy eth_sendRawTransaction and pending eth_getTransactionCount to that validator instead of handling locally.

Extends Autobahn config generation and node setup to carry per-validator evmrpc endpoints (evmrpc_url.txt, new AutobahnValidator.EVMRPC + URL wrapper), adds EvmProxy plumbing through the local Tendermint client and GigaRouter, and introduces a new metric evmrpc_redirected_requests_total plus tests covering proxy and fallback paths.

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

@pompon0 pompon0 enabled auto-merge May 19, 2026 16:09
@pompon0 pompon0 added this pull request to the merge queue May 19, 2026
Merged via the queue into main with commit 627db96 May 19, 2026
76 of 80 checks passed
@pompon0 pompon0 deleted the gprusak-rpc-sharding9 branch May 19, 2026 18:06
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.

3 participants