Skip to content

evmonly: let a node run without a receipt store (autobahn enable_receipt_store) - #4265

Merged
bdchatham merged 5 commits into
giga-1from
devin/1789914153-receipts-optional
Sep 20, 2026
Merged

bdchatham merged 5 commits into
giga-1from
devin/1789914153-receipts-optional

Conversation

@bdchatham

@bdchatham bdchatham commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor

Since #4264, Commit on an EVM-only node waits for the block's receipts to land in the litt store before advancing the RPC-visible head. On testnet-2 that wait (app_commit ≈ 0.16 s/s, await_receipts ≈ 0.17 s/s) outweighed the loop time #4264 saved, and the 40 validators went from ~96k to ~87k tx/s. Validators serve no receipt reads, so both the write and the wait buy them nothing; GigaStorageConfig.WithValidatorMode() already turns the receipt DB off, but NewValidatorStorageConfig immediately forced it back on and the executor and RPC server refused to start without one.

NewValidatorStorageConfig(homePath, receipts bool) now takes the choice, and node/setup.go passes a new AutobahnFileConfig.EnableReceiptStore (enable_receipt_store, utils.Option[bool], default true, so nothing changes for a node that does not set it). With it off, bootstrap.GigaStorageManager.ReceiptDB() is nil as its docs already allow; the executor drops errMissingReceiptStore, startPipelineCommit skips persistReceipts and closes the receipt gate at once, so AwaitReceipts returns immediately and the pipeline goes straight to commitStateChanges. Block results still carry receipts, they are just not persisted. evmonlyrpc.newHandler accepts a nil store: eth_getBlockBy* still serve, with gasUsed 0 as blockGasUsed already did outside the receipt range, and eth_getTransactionReceipt/eth_getTransactionByHash return a new ErrNoReceiptStore rather than null, which a client would read as "not mined". Registering a reduced eth namespace was the rejected alternative: sei-load and the proxy still need block, send and nonce methods on validators, and a missing method is harder to diagnose than an explicit error.

No consensus or on-disk format impact: the app hash and state commit are untouched, and a node that keeps receipts behaves exactly as before. Rollout is a config change per validator (enable_receipt_store = false), leaving RPC nodes on. Turning it off on a node whose receipt directory already holds blocks is refused at startup (bootstrap.ErrDisabledReceiptStoreHoldsBlocks, naming the directory): a disabled store would otherwise sit out recovery at its old head, and turning receipts back on later would make findTargetRecoveryHeight converge state back onto that stale head. With the directory removed, a later re-enable is the empty-store case recovery already handles and receipts fill from the current height — so an RPC node that ever ran without receipts has a gap, which is why the default stays true. Validated with new tests for the storage config, the executor without a receipt store (state still commits, pool result released, AwaitReceipts returns), the RPC handler over a nil store, the disable → advance → re-enable restart loop in sei-db/bootstrap, and prepareApplication producing a nil ReceiptDB() from the file config; race tests for giga/evmonly, giga/evmonly/rpc, evmonlyapp and node pass.

Link to Devin session: https://app.devin.ai/sessions/ff612badcded4aa5914ea408dbb41888
Open in Devin Desktop: https://app.devin.ai/desktop/session/ff612badcded4aa5914ea408dbb41888?variant=devin
Requested by: @bdchatham

…ipt_store)

Validators serve no receipt reads, so the receipt write and the wait for it to
land in Commit buy them nothing. NewValidatorStorageConfig now takes the
choice; node/setup passes AutobahnFileConfig.EnableReceiptStore (default true).
The executor commits state only when it has no receipt store and AwaitReceipts
returns at once; EVM-only RPC still serves blocks and receipt lookups report
ErrNoReceiptStore.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@cursor

cursor Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes validator commit timing and EVM RPC behavior for receipt-backed methods when receipts are disabled; state/consensus paths are unchanged, but misconfigured disable-with-existing-receipt-data is blocked at startup.

Overview
Adds enable_receipt_store (Autobahn JSON, default true) so EVM-only validators can run without persisting receipts, avoiding Commit/AwaitReceipts latency when they never serve receipt reads.

Storage & executor: NewValidatorStorageConfig(home, receipts) toggles ReceiptDBConfig.Enable. The executor only requires state store + encoder; with no receipt store it skips background receipt writes, AwaitReceipts returns immediately, and state commits proceed as before (block results still carry receipts in memory).

RPC: newHandler accepts a nil receipt store—eth_getBlockBy* still work (gasUsed 0 without receipts); eth_getTransactionReceipt / eth_getTransactionByHash return ErrNoReceiptStore instead of null.

Safety at startup: If receipts are disabled but the receipt directory still has data, startup fails with ErrDisabledReceiptStoreHoldsBlocks until the directory is removed (prevents a later re-enable from rolling other stores back to a stale receipt head).

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

@github-actions

github-actions Bot commented Sep 20, 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 20, 2026, 3:38 PM

@codecov

codecov Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.45455% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 82.36%. Comparing base (7e3ca24) to head (5886a4e).
⚠️ Report is 46 commits behind head on giga-1.

Files with missing lines Patch % Lines
sei-db/bootstrap/recovery.go 90.90% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           giga-1    #4265       +/-   ##
===========================================
+ Coverage   65.55%   82.36%   +16.81%     
===========================================
  Files        2081       52     -2029     
  Lines      157460     7356   -150104     
===========================================
- Hits       103222     6059    -97163     
+ Misses      54097     1296    -52801     
+ Partials      141        1      -140     
Flag Coverage Δ
sei-chain ?
sei-chain-pr 82.36% <95.45%> (?)
sei-db ?

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

Files with missing lines Coverage Δ
giga/evmonly/cmd/evmonly-loadtest/pipeline.go 64.86% <100.00%> (-13.43%) ⬇️
giga/evmonly/giga_store.go 93.39% <100.00%> (+0.28%) ⬆️
giga/evmonly/rpc/block.go 89.07% <100.00%> (ø)
giga/evmonly/rpc/server.go 16.94% <ø> (-25.16%) ⬇️
giga/evmonly/rpc/tx.go 85.00% <100.00%> (ø)
giga/evmonly/storage_manager.go 93.75% <100.00%> (ø)
sei-tendermint/config/autobahn.go 71.73% <100.00%> (-0.36%) ⬇️
sei-tendermint/internal/evmonlyapp/app.go 87.04% <ø> (+5.27%) ⬆️
sei-tendermint/node/setup.go 62.61% <100.00%> (-0.46%) ⬇️
sei-db/bootstrap/recovery.go 88.17% <90.90%> (+0.36%) ⬆️

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

seidroid[bot]
seidroid Bot previously requested changes Sep 20, 2026

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

The receipt store is cleanly made optional across the executor, the EVM-only RPC handler and the storage config, with matching test coverage. The gap is the toggle's reverse direction: re-enabling enable_receipt_store on a node that ran without it leaves a stale receipt head that recovery folds into its convergence target, rolling state back or refusing startup — contrary to what the PR description states.

Findings: 1 blocking | 2 non-blocking | 1 posted inline

Blockers

  • None at the file/PR level.
  • 1 blocking issue(s) flagged inline on specific lines.

Non-blocking

  • [suggestion] evmOnlyApplication.Commit's godoc (sei-tendermint/internal/evmonlyapp/app.go:868-875) still states the invariant "once its receipts are readable: the height this advances is what RPC serves as latest, and a block it serves has its receipts." With enable_receipt_store = false that is no longer true — AwaitReceipts returns with nothing written. The README, AwaitReceipts and startPipelineCommit docs were all updated for the new mode; this one was missed, and it is the load-bearing statement of the property the flag removes.
  • [suggestion] Receipt-derived fields degrade to plausible-but-wrong zeros rather than an error on a receipt-less node: blockGasUsed returns 0 (documented in the PR) but so does eth_feeHistory's gasUsedRatio (giga/evmonly/rpc/info.go:222), which clients use for fee estimation. Worth either stating this in the AutobahnFileConfig.EnableReceiptStore doc alongside "serves no receipts or logs", or handling fee history the way tx lookups are handled, so the two halves of the RPC surface answer consistently.

Comment thread sei-tendermint/node/setup.go
… document receipt-less RPC semantics

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

Both non-blocking notes taken in 84c817e:

  • evmOnlyApplication.Commit godoc now scopes the receipts-readable invariant to nodes with a receipt store.
  • eth_feeHistory gasUsedRatio: kept the zero rather than erroring, for consistency with eth_getBlockBy*'s gasUsed (same source, blockGasUsed) — failing one and zeroing the other would be the surprising combination, and a receipt-less node is a validator whose RPC sei-load/the proxy only use for blocks, send and nonce. Documented both zeros on AutobahnFileConfig.EnableReceiptStore.

@bdchatham

Copy link
Copy Markdown
Contributor Author

@seidroid review

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

The optional receipt store is wired cleanly end to end — executor, RPC handler, storage config and recovery — and the previously blocking re-enable hazard is now closed by a startup refusal at the one function every open passes through, with a restart-loop test that exercises the whole sequence. Only a small doc-accuracy point remains.

Findings: 0 blocking | 1 non-blocking | 1 posted inline

Blockers

  • None at the file/PR level.

Non-blocking

  • None at the file/PR level.
  • 1 suggestion(s)/nit(s) flagged inline on specific lines.

Comment thread sei-tendermint/internal/evmonlyapp/app.go Outdated
@seidroid
seidroid Bot dismissed their stale review September 20, 2026 14:58

Superseded: latest AI review found no blocking issues.

bdchatham and others added 2 commits September 20, 2026 15:00
…tore

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ner)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@bdchatham
bdchatham enabled auto-merge September 20, 2026 15:13
@bdchatham
bdchatham added this pull request to the merge queue Sep 20, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Sep 20, 2026
@bdchatham
bdchatham enabled auto-merge September 20, 2026 15:36
… skips the receipt write

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@bdchatham
bdchatham added this pull request to the merge queue Sep 20, 2026
Merged via the queue into giga-1 with commit f37a3d3 Sep 20, 2026
62 checks passed
@bdchatham
bdchatham deleted the devin/1789914153-receipts-optional branch September 20, 2026 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant