mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 19:00:46 +00:00
core: fix 8037 gas accounting (#34631)
To check whether a transaction can be applied, we validate that `blockGasLimit > txGasLimit + (cumulativeRegularGasUsed + cumulativeStateGasUsed)`. However, the check should only be applied to the bottleneck resource, i.e. `blockGasLimit > max(txRegularGasUsed+cumulativeRegularGasUsed, txStateGasUsed+ cumulativeStateGasUsed)`. The changes here break multiple tests. I am trying to determine why. --------- Co-authored-by: qu0b <stefan@starflinger.eu>
This commit is contained in:
parent
710ffb03ad
commit
985cdac8a7
3 changed files with 16 additions and 13 deletions
|
|
@ -73,18 +73,20 @@ func (gp *GasPool) ReturnGas(returned uint64, gasUsed uint64) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReturnGasAmsterdam handles 2D gas accounting for Amsterdam (EIP-8037).
|
// ReturnGasAmsterdam calculates the new remaining gas in the pool after the
|
||||||
// It undoes the SubGas deduction fully and accumulates per-dimension block totals.
|
// execution of a message. The remaining gas in the pool is
|
||||||
func (gp *GasPool) ReturnGasAmsterdam(returned, txRegular, txState, receiptGasUsed uint64) error {
|
// block.gasLimit - max(cumulative_regular, cumulative_state)
|
||||||
if gp.remaining > math.MaxUint64-returned {
|
func (gp *GasPool) ReturnGasAmsterdam(txRegular, txState, receiptGasUsed uint64) error {
|
||||||
return fmt.Errorf("%w: remaining: %d, returned: %d", ErrGasLimitOverflow, gp.remaining, returned)
|
|
||||||
}
|
|
||||||
// Undo SubGas deduction fully (Amsterdam uses cumulative tracking)
|
|
||||||
gp.remaining += returned
|
|
||||||
// Accumulate 2D block dimensions
|
|
||||||
gp.cumulativeRegular += txRegular
|
gp.cumulativeRegular += txRegular
|
||||||
gp.cumulativeState += txState
|
gp.cumulativeState += txState
|
||||||
gp.cumulativeUsed += receiptGasUsed
|
gp.cumulativeUsed += receiptGasUsed
|
||||||
|
|
||||||
|
blockUsed := max(gp.cumulativeRegular, gp.cumulativeState)
|
||||||
|
if gp.initial < blockUsed {
|
||||||
|
return fmt.Errorf("%w: block gas overflow: initial %d, used %d (regular: %d, state: %d)",
|
||||||
|
ErrGasLimitReached, gp.initial, blockUsed, gp.cumulativeRegular, gp.cumulativeState)
|
||||||
|
}
|
||||||
|
gp.remaining = gp.initial - blockUsed
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,7 @@ func (p *ParallelStateProcessor) resultHandler(block *types.Block, preTxReads ba
|
||||||
// 1. if the block has transactions, receive the execution results from all of them and return an error on resCh if any txs err'd
|
// 1. if the block has transactions, receive the execution results from all of them and return an error on resCh if any txs err'd
|
||||||
// 2. once all txs are executed, compute the post-tx state transition and produce the ProcessResult sending it on resCh (or an error if the post-tx state didn't match what is reported in the BAL)
|
// 2. once all txs are executed, compute the post-tx state transition and produce the ProcessResult sending it on resCh (or an error if the post-tx state didn't match what is reported in the BAL)
|
||||||
var results []txExecResult
|
var results []txExecResult
|
||||||
gp := NewGasPool(block.GasLimit())
|
var cumulativeStateGas, cumulativeRegularGas uint64
|
||||||
var execErr error
|
var execErr error
|
||||||
var numTxComplete int
|
var numTxComplete int
|
||||||
|
|
||||||
|
|
@ -217,9 +217,10 @@ func (p *ParallelStateProcessor) resultHandler(block *types.Block, preTxReads ba
|
||||||
// short-circuit if invalid block was detected
|
// short-circuit if invalid block was detected
|
||||||
if res.err != nil {
|
if res.err != nil {
|
||||||
execErr = res.err
|
execErr = res.err
|
||||||
} else if err := gp.SubGas(res.receipt.CumulativeGasUsed); err != nil {
|
} else if bottleneck := max(cumulativeRegularGas+res.txRegular, cumulativeStateGas+res.txState); bottleneck > block.GasLimit() {
|
||||||
execErr = err
|
execErr = fmt.Errorf("block used too much gas in bottleneck dimension: %d. block gas limit is %d", bottleneck, block.GasLimit())
|
||||||
} else {
|
} else {
|
||||||
|
cumulativeStateGas += res.txState
|
||||||
results = append(results, res)
|
results = append(results, res)
|
||||||
accesses.Merge(res.stateReads)
|
accesses.Merge(res.stateReads)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -608,7 +608,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
txState := (gas.StateGas - authRefund) + execGasUsed.StateGasCharged
|
txState := (gas.StateGas - authRefund) + execGasUsed.StateGasCharged
|
||||||
txRegular := gas.RegularGas + execGasUsed.RegularGasUsed
|
txRegular := gas.RegularGas + execGasUsed.RegularGasUsed
|
||||||
txRegular = max(txRegular, floorDataGas)
|
txRegular = max(txRegular, floorDataGas)
|
||||||
if err := st.gp.ReturnGasAmsterdam(returned, txRegular, txState, st.gasUsed()); err != nil {
|
if err := st.gp.ReturnGasAmsterdam(txRegular, txState, st.gasUsed()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue