From aec81c69f58e4e97ce81ee6f5086d6095c9b7f50 Mon Sep 17 00:00:00 2001 From: qu0b Date: Thu, 5 Feb 2026 13:31:10 +0000 Subject: [PATCH] fix(eip-7778): use separate gas accumulators in parallel processor The parallel state processor was using receipt.GasUsed (pre-refund, MaxUsedGas for Amsterdam) for both CumulativeGasUsed and block gas. This caused receipt root mismatches because CumulativeGasUsed must be post-refund. The fix: - cumulativeGasUsed: accumulates receipt.CumulativeGasUsed (post-refund from execTx) for proper receipt CumulativeGasUsed - blockGasUsed: accumulates receipt.GasUsed (pre-refund for Amsterdam) for block header GasUsed and gas limit validation Co-Authored-By: Claude Opus 4.5 --- core/parallel_state_processor.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/core/parallel_state_processor.go b/core/parallel_state_processor.go index a1c07bfd20..beeb3f5c2d 100644 --- a/core/parallel_state_processor.go +++ b/core/parallel_state_processor.go @@ -77,12 +77,22 @@ func (p *ParallelStateProcessor) prepareExecResult(block *types.Block, allStateR return cmp.Compare(a.TransactionIndex, b.TransactionIndex) }) - var cumulativeGasUsed uint64 + var ( + // cumulativeGasUsed tracks post-refund gas for receipt.CumulativeGasUsed + cumulativeGasUsed uint64 + // blockGasUsed tracks pre-refund gas (receipt.GasUsed = MaxUsedGas for Amsterdam) + // for block header and gas limit validation per EIP-7778 + blockGasUsed uint64 + ) var allLogs []*types.Log for _, receipt := range receipts { - receipt.CumulativeGasUsed = cumulativeGasUsed + receipt.GasUsed - cumulativeGasUsed += receipt.GasUsed - if receipt.CumulativeGasUsed > header.GasLimit { + // receipt.CumulativeGasUsed holds this tx's post-refund gas (result.UsedGas) + // since execTx called ApplyTransactionWithEVM with cumulativeGas=0 + cumulativeGasUsed += receipt.CumulativeGasUsed + receipt.CumulativeGasUsed = cumulativeGasUsed + // receipt.GasUsed is pre-refund (MaxUsedGas for Amsterdam) for block accounting + blockGasUsed += receipt.GasUsed + if blockGasUsed > header.GasLimit { return &ProcessResultWithMetrics{ ProcessResult: &ProcessResult{Error: fmt.Errorf("gas limit exceeded")}, } @@ -148,7 +158,7 @@ func (p *ParallelStateProcessor) prepareExecResult(block *types.Block, allStateR Receipts: receipts, Requests: requests, Logs: allLogs, - GasUsed: cumulativeGasUsed, + GasUsed: blockGasUsed, }, PostProcessTime: tPostprocess, ExecTime: tExec,