fix(giga): write receipt for state-transition errors that bump the nonce (CON-256)#3383
Open
wen-coding wants to merge 9 commits intomainfrom
Open
fix(giga): write receipt for state-transition errors that bump the nonce (CON-256)#3383wen-coding wants to merge 9 commits intomainfrom
wen-coding wants to merge 9 commits intomainfrom
Conversation
Tx that's included in a block must produce an EVM receipt. The msg_server err-not-VM-error branch (V2: x/evm/keeper/msg_server.go; Giga: app/app.go executeEVMTxWithGigaExecutor) used to drop the receipt and log only — leaving eth_getTransactionByHash and eth_getTransactionReceipt returning null forever for included-but-failed txs. Write a status=0 receipt with gasUsed=gasLimit instead. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3383 +/- ##
=======================================
Coverage 59.08% 59.08%
=======================================
Files 2100 2099 -1
Lines 173008 173019 +11
=======================================
+ Hits 102222 102235 +13
+ Misses 61922 61920 -2
Partials 8864 8864
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Adds TestGiga_FailedExecution_ProducesReceipt — the Giga-path counterpart to TestEVMTransactionStateTransitionErrorProducesReceipt. Triggers the EIP-7623 floor-data-gas check inside go-ethereum's Execute() (intrinsic gas passes EvmStatelessChecks but floor data gas fails inside Execute()), then asserts the transient receipt store contains a status=0 receipt with gasUsed=gasLimit and a populated VmError. Without the app.go fix, the receipt is dropped and the assertion fails with "receipt not found"; with the fix it passes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
Mirror the success-branch evmMsg construction (PR #3384): use effectiveGasPrice (computed at line 1866) for receipt's EffectiveGasPrice field instead of ethTx.GasPrice() which returns GasFeeCap for dynamic-fee txs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
LegacyTx had GasPrice == GasFeeCap == GasTipCap, so the EffectiveGasPrice assertion would pass equally whether the receipt stored maxFee or the EIP-1559 effective price. Switch to a DynamicFeeTx where tip < cap so the assertion discriminates: if anyone reverts the err-branch evmMsg to hand-roll with ethTx.GasPrice() (returns GasFeeCap for dynamic-fee txs), the assertion catches it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
V2's existing EndBlock synthetic-receipt path (x/evm/keeper/abci.go:100) already writes a receipt for state-transition errors: the GetAllEVMTxDeferredInfo fallback synthesizes a DeferredInfo from txRes.Log when none was appended, and EndBlock's loop gates the synthetic-receipt write on GetNonceBumped. BasicDecorator's WithDeliverTxCallback bumps the nonce + calls SetNonceBumped on every DeliverTx (including failures), so the rule "receipt iff the tx bumped the sender's nonce" already holds for V2. The explicit WriteReceipt added to msg_server.go was redundant and also bypassed the GetNonceBumped gate, so it's removed. The Giga path is still missing the receipt because its AppendToEvmTxDeferredInfo call in the err-branch doesn't propagate the Error string, so EndBlock's `if deferredInfo.Error != ""` check fails and skips the synthetic-receipt write. Giga's explicit WriteReceipt in app.go is kept and is gated on the explicit nonce bump it already does at app.go:1887. Both tests are extended with nonce-before/after assertions to lock in the invariant. The V2 test is rewritten to drive the full production sequence (BasicDecorator -> msgServer -> deliverTxCallback -> SetMsgs/SetTxResults -> EndBlock) so it exercises the synthetic path end-to-end for an EIP-7623 floor-data-gas-underflow tx. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
V2's msg_server.go is unchanged on this branch (the EndBlock synthetic path already handles state-transition errors), so the V2 test added earlier — useful as the experiment that proved the V2 path works for floor-data-gas-underflow — is out of scope for a Giga-only PR. The existing tests in x/evm/keeper/abci_test.go (TestEndBlock_NoReceipt ForNonceMismatch, TestEndBlock_ReceiptCreatedWhenNonceBumped) already cover the EndBlock synthetic-receipt mechanism and its GetNonceBumped gate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Invariant
A receipt is written for an EVM tx iff that tx bumped the sender's nonce. Equivalently: any tx the chain treats as having advanced the sender's account state — and only those — is observable via
eth_getTransactionByHash/eth_getTransactionReceipt. Txs included in a block but rejected before the nonce bump (e.g. ante-handler failures, pre-execution state-transition errors) leave no receipt and are invisible to standard EVM clients, matching go-ethereum semantics.This PR fixes a place where the Giga executor violated the invariant: a state-transition error inside
Execute()(notably EIP-7623 floor-data-gas underflow, post-Pectra) bumped the sender's nonce but produced no receipt, soeth_getTransactionReceiptreturned null forever and clients that polled for it hung. The invariant is now enforced symmetrically across V2 and Giga.How the invariant is enforced
V2 path (no change in this PR — already correct):
BasicDecorator.AnteHandleregisters aWithDeliverTxCallback(x/evm/ante/basic.go:33-39) that fires afterDeliverTxregardless of success/failure. The callback bumps the sender's nonce and callsSetNonceBumped.msgServer.EVMTransactionreturns err, the SDK populatesExecTxResult.Code != 0andExecTxResult.Log = err.Error().GetAllEVMTxDeferredInfo(x/evm/keeper/deferred.go:24) synthesizes aDeferredInfo{TxHash, Error: txRes.Log}for each tx that didn't append its own.x/evm/keeper/abci.go:100-113) writes a synthetic receipt for entries withError != ""— gated onGetNonceBumped, which is exactly the invariant. Existing coverage:TestEndBlock_NoReceiptForNonceMismatchandTestEndBlock_ReceiptCreatedWhenNonceBumpedinx/evm/keeper/abci_test.go.Giga path (fixed in this PR):
executeEVMTxWithGigaExecutoralready explicitly bumps the sender's nonce in itsexecErr != nilbranch (app/app.go:1887).AppendToEvmTxDeferredInfofor surplus tracking — but withError == "", so the EndBlock synthetic-receipt loop above skips it.WriteReceiptdirectly in the err-branch, gated on the explicit nonce bump it already does. EIP-1559 effective gas price is used (notGasFeeCap) so the receipt'sEffectiveGasPricematches go-ethereum semantics for dynamic-fee txs.Tests
TestGiga_FailedExecution_ProducesReceipt(giga/tests/giga_test.go) drives the EIP-7623 floor-data-gas-underflow case through the Giga executor, asserts the explicit nonce bump (nonceBefore+1 == nonceAfter) to lock in the invariant, and asserts the receipt was written withstatus=0,gasUsed=gasLimit, and the floor-data-gas error inVmError.Things done
app/app.go): write receipt inexecErr != nilbranch using EIP-1559 effective gas pricegofmt -sclean🤖 Generated with Claude Code