fix(evm): populate fields on V2 synthetic receipts for state-transition errors#3448
fix(evm): populate fields on V2 synthetic receipts for state-transition errors#3448wen-coding wants to merge 1 commit into
Conversation
…on errors The EndBlock synthetic-receipt path for txs that bumped nonce but failed in msg_server before WriteReceipt (notably EIP-7623 floor-data-gas underflow) left GasUsed=0, EffectiveGasPrice=0, From="", and TxType=0. RPC clients relying on these fields saw a charged-and-included tx as if it had used no gas, which is misleading: the sender paid gasLimit * effectiveGasPrice in ante with no refund. The closest in-spec analog for this failure shape is OOG, which go-ethereum reports as GasUsed = gasLimit. Match that here, and populate From/To/ ContractAddress/TxType/EffectiveGasPrice/Status from the original message + captured base fee, so V2 synthetic receipts match the Giga path (which already calls WriteReceipt directly with these values, see #3383). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR SummaryMedium Risk Overview The EndBlock path captures the current block Reviewed by Cursor Bugbot for commit d775dee. Bugbot is set up for automated code reviews on this repo. Configure here. |
|
The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).
|
|
Closing — Giga executor is rolling out everywhere soon, so V2's EndBlock synthetic-receipt path will be dead code shortly. The cosmetic improvement isn't worth the merge surface in the migration window. Receipts for floor-data-gas failures under Giga are already correct via #3383's inline WriteReceipt. |
Why
Follow-up to #3383, which fixed the Giga path's receipt-iff-nonce-bumped invariant for EIP-7623 floor-data-gas failures. That PR's Giga code writes the receipt with
GasUsed = ethTx.Gas()and EIP-1559EffectiveGasPrice. The V2 path, which catches the same failure shape via the EndBlock synthetic-receipt loop, was emitting onlyTxHashHex,TransactionIndex,VmError, andBlockNumber— everything else defaulted to zero/empty.So an RPC client polling
eth_getTransactionReceiptfor a floor-data-gas-failed tx on V2 sawGasUsed=0,EffectiveGasPrice=0,From="",TxType=0. The sender did paygasLimit * effectiveGasPricein the ante handler with no refund, so this misrepresents what was actually charged.The closest in-spec analog for this failure shape is OOG, which go-ethereum reports as
GasUsed = gasLimit. (Mainnet go-ethereum would reject these txs before block inclusion entirely — but Sei's ante/Execute split means they can land in a block, and we have to pick a convention. OOG is the right one.)What
In
x/evm/keeper/abci.go:GetBaseFee(ctx)beforeAdjustDynamicBaseFeePerGasruns — that call overwrites the stored value with the next block's base fee, so reading it later in the loop would return the wrong price.buildSyntheticReceipthelper that populatesGasUsed=etx.Gas(),Status=Failed,TxType,From,To/ContractAddress, and EIP-1559EffectiveGasPricefrom the original message and captured base fee.msg, missingDerived, orbaseFee == nil(pre-v6.2.0 pacific-1).Downstream effects of the field changes
Three read-time call sites that touch synthetic-receipt-shaped data:
evmrpc/tx.go:147—eth_getTransactionReceiptread-time backfill. Predicate isStatus==0 && GasUsed==0. New receipts skip it (already populated). Old receipts (GasUsed==0) continue to hit it and getGasUsed=0reaffirmed — historical wire-format preserved. Not touched.evmrpc/utils.go:254— block-tx-list nonce verification. Predicate isStatus==0 && EffectiveGasPrice==0. New receipts skip it (now populated) — safe, the EndBlock loop already gates writes onGetNonceBumped. The verification was a belt-and-suspenders. Not touched.evmrpc/info.go:377,406,456—eth_feeHistory/ gas-price congestion /CalculateGasUsedRatiosumreceipt.GasUsedacross a block. For floor-data-gas-failed txs, contribution goes from0→etx.Gas(). So:eth_feeHistoryreward percentiles include floor-data-gas txs as full-gas contributors.eth_gasPricecongestion detection may flipisChainCongestedslightly sooner.CalculateGasUsedRatioreports higher ratios for blocks containing these failures.Note:
AdjustDynamicBaseFeePerGasuses cosmos-sdk'sblockGasUsed(block gas meter), not receipts, so base fee adjustment is unaffected. Post-fix, the receipt says "I used etx.Gas()" while the block gas meter says "I used 0" — matches the spec interpretation: the user paid for the full gas (receipt), but no opcodes ran (gas meter). Floor-data-gas failures are rare enough that the practical impact on (1)-(3) is minimal.Tests
TestEndBlock_ReceiptCreatedWhenNonceBumpedextended to setmsg.Derived(mirroring what the ante handler does in prod) and assert the newStatus/TxType/GasUsed/From/EffectiveGasPrice/Tofields.Things done
gofmt -scleango test ./x/evm/keeper/...🤖 Generated with Claude Code