core: fix EIP-7778 block gas accounting to exclude refunds

The miner accumulates result.UsedGas (post-refund) into the block
header's GasUsed via ApplyTransactionWithEVM, but the validator
accumulates receipt.GasUsed (which is result.MaxUsedGas = pre-refund
for Amsterdam) into its local gas total. This causes every proposed
block containing refund-generating transactions to be rejected with
"invalid gas used" after the Gloas fork.

Use result.MaxUsedGas (pre-refund gas) for block gas accumulation
when Amsterdam is active, matching EIP-7778's requirement that block
gas accounting excludes refunds.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
qu0b 2026-02-04 11:22:20 +00:00
parent 022e460d1e
commit 514bde14da
2 changed files with 13 additions and 2 deletions

View file

@ -189,7 +189,13 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB,
} else {
root = statedb.IntermediateRoot(evm.ChainConfig().IsEIP158(blockNumber)).Bytes()
}
// EIP-7778: block gas accounting excludes refunds. Use MaxUsedGas
// (pre-refund gas) for Amsterdam, preserving post-refund for earlier forks.
if evm.ChainConfig().IsAmsterdam(blockNumber, blockTime) {
*usedGas += result.MaxUsedGas
} else {
*usedGas += result.UsedGas
}
// Merge the tx-local access event into the "block-local" one, in order to collect
// all values, so that the witness can be built.

View file

@ -300,7 +300,12 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
} else {
root = sim.state.IntermediateRoot(sim.chainConfig.IsEIP158(blockContext.BlockNumber)).Bytes()
}
// EIP-7778: block gas accounting excludes refunds.
if sim.chainConfig.IsAmsterdam(blockContext.BlockNumber, blockContext.Time) {
gasUsed += result.MaxUsedGas
} else {
gasUsed += result.UsedGas
}
receipts[i] = core.MakeReceipt(evm, result, sim.state, blockContext.BlockNumber, common.Hash{}, blockContext.Time, tx, gasUsed, root)
blobGasUsed += receipts[i].BlobGasUsed
logs := tracer.Logs()