mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-12 01:41:36 +00:00
core: apply changes from bal-devnet-3 branch
This commit is contained in:
parent
4e46fb1b8d
commit
223f1c50ce
6 changed files with 120 additions and 77 deletions
|
|
@ -73,18 +73,21 @@ func (gp *GasPool) ReturnGas(returned uint64, gasUsed uint64) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ReturnGasAmsterdam handles 2D gas accounting for Amsterdam (EIP-8037).
|
||||
// It undoes the SubGas deduction fully and accumulates per-dimension block totals.
|
||||
func (gp *GasPool) ReturnGasAmsterdam(returned, txRegular, txState, receiptGasUsed uint64) error {
|
||||
if gp.remaining > math.MaxUint64-returned {
|
||||
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
|
||||
// ReturnGasAmsterdam calculates the new remaining gas in the pool after the
|
||||
// execution of a message.
|
||||
func (gp *GasPool) ReturnGasAmsterdam(txRegular, txState, receiptGasUsed uint64) error {
|
||||
gp.cumulativeRegular += txRegular
|
||||
gp.cumulativeState += txState
|
||||
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)
|
||||
}
|
||||
// TX inclusion: only the regular dimension is checked when deciding
|
||||
// whether the next transaction fits.
|
||||
gp.remaining = gp.initial - gp.cumulativeRegular
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -132,6 +135,12 @@ func (gp *GasPool) Set(other *GasPool) {
|
|||
gp.cumulativeState = other.cumulativeState
|
||||
}
|
||||
|
||||
// AmsterdamDimensions returns the per-dimension cumulative gas values
|
||||
// for 2D gas accounting (EIP-8037).
|
||||
func (gp *GasPool) AmsterdamDimensions() (regular, state uint64) {
|
||||
return gp.cumulativeRegular, gp.cumulativeState
|
||||
}
|
||||
|
||||
func (gp *GasPool) String() string {
|
||||
return fmt.Sprintf("initial: %d, remaining: %d, cumulative used: %d", gp.initial, gp.remaining, gp.cumulativeUsed)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -608,7 +608,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
|||
txState := (gas.StateGas - authRefund) + execGasUsed.StateGasCharged
|
||||
txRegular := gas.RegularGas + execGasUsed.RegularGasUsed
|
||||
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
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -479,27 +479,30 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b
|
|||
}
|
||||
|
||||
// create creates a new contract using code as deployment code.
|
||||
func (evm *EVM) create(caller common.Address, code []byte, gas GasCosts, value *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, leftOverGas GasCosts, gasUsed GasUsed, err error) {
|
||||
if evm.Config.Tracer != nil {
|
||||
evm.captureBegin(evm.depth, typ, caller, address, code, gas, value.ToBig())
|
||||
defer func(startGas GasCosts) {
|
||||
evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err)
|
||||
}(gas)
|
||||
}
|
||||
func (evm *EVM) create(caller common.Address, code []byte, gas GasCosts, value *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, leftOverGas GasCosts, used GasUsed, err error) {
|
||||
// Depth check execution. Fail if we're trying to execute above the
|
||||
// limit.
|
||||
var nonce uint64
|
||||
if evm.depth > int(params.CallCreateDepth) {
|
||||
err = ErrDepth
|
||||
} else if !evm.Context.CanTransfer(evm.StateDB, caller, value) {
|
||||
err = ErrInsufficientBalance
|
||||
} else {
|
||||
nonce := evm.StateDB.GetNonce(caller)
|
||||
nonce = evm.StateDB.GetNonce(caller)
|
||||
if nonce+1 < nonce {
|
||||
err = ErrNonceUintOverflow
|
||||
} else {
|
||||
evm.StateDB.SetNonce(caller, nonce+1, tracing.NonceChangeContractCreator)
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
evm.StateDB.SetNonce(caller, nonce+1, tracing.NonceChangeContractCreator)
|
||||
}
|
||||
if evm.Config.Tracer != nil {
|
||||
evm.captureBegin(evm.depth, typ, caller, address, code, gas, value.ToBig())
|
||||
defer func(startGas GasCosts) {
|
||||
evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err)
|
||||
}(gas)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, common.Address{}, gas, GasUsed{}, err
|
||||
}
|
||||
|
|
@ -534,8 +537,10 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasCosts, value *
|
|||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution)
|
||||
}
|
||||
// Burn all gas on collision
|
||||
collisionUsed := GasUsed{RegularGasUsed: gas.RegularGas}
|
||||
gas.RegularGas = 0
|
||||
return nil, common.Address{}, gas, GasUsed{}, ErrContractAddressCollision
|
||||
return nil, common.Address{}, gas, collisionUsed, ErrContractAddressCollision
|
||||
}
|
||||
// Create a new account on the state only if the object was not present.
|
||||
// It might be possible the contract code is deployed to a pre-existent
|
||||
|
|
@ -580,6 +585,9 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasCosts, value *
|
|||
if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != ErrExecutionReverted {
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(contract.Gas.RegularGas, 0, tracing.GasChangeCallFailedExecution)
|
||||
}
|
||||
contract.GasUsed.RegularGasUsed += contract.Gas.RegularGas
|
||||
contract.Gas.RegularGas = 0
|
||||
}
|
||||
|
|
@ -601,35 +609,39 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b
|
|||
return ret, ErrInvalidCode
|
||||
}
|
||||
|
||||
if !evm.chainRules.IsEIP4762 {
|
||||
if evm.chainRules.IsAmsterdam {
|
||||
// EIP-8037: Split code deposit into state gas (code storage) and
|
||||
// regular gas (keccak256 hashing).
|
||||
stateGas := GasCosts{StateGas: uint64(len(ret)) * evm.Context.CostPerGasByte}
|
||||
if !contract.UseGas(stateGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
|
||||
return ret, ErrCodeStoreOutOfGas
|
||||
}
|
||||
regularGas := GasCosts{RegularGas: toWordSize(uint64(len(ret))) * params.Keccak256WordGas}
|
||||
if !contract.UseGas(regularGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
|
||||
return ret, ErrCodeStoreOutOfGas
|
||||
}
|
||||
} else {
|
||||
createDataGas := GasCosts{RegularGas: uint64(len(ret)) * params.CreateDataGas}
|
||||
if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
|
||||
return ret, ErrCodeStoreOutOfGas
|
||||
}
|
||||
if evm.chainRules.IsAmsterdam {
|
||||
// Check max code size BEFORE charging gas so over-max code
|
||||
// does not consume state gas (which would inflate tx_state).
|
||||
if err := CheckMaxCodeSize(&evm.chainRules, uint64(len(ret))); err != nil {
|
||||
return ret, err
|
||||
}
|
||||
} else {
|
||||
// EIP-8037: Charge regular gas (keccak256 hash) first, then state gas
|
||||
// (code storage). Regular-before-state prevents reservoir inflation.
|
||||
regularGas := GasCosts{RegularGas: toWordSize(uint64(len(ret))) * params.Keccak256WordGas}
|
||||
if !contract.UseGas(regularGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
|
||||
return ret, ErrCodeStoreOutOfGas
|
||||
}
|
||||
stateGas := GasCosts{StateGas: uint64(len(ret)) * evm.Context.CostPerGasByte}
|
||||
if !contract.UseGas(stateGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
|
||||
return ret, ErrCodeStoreOutOfGas
|
||||
}
|
||||
} else if evm.chainRules.IsEIP4762 {
|
||||
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true, contract.Gas.RegularGas)
|
||||
contract.UseGas(GasCosts{RegularGas: consumed}, evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk)
|
||||
if len(ret) > 0 && (consumed < wanted) {
|
||||
return ret, ErrCodeStoreOutOfGas
|
||||
}
|
||||
}
|
||||
|
||||
// Verify max code size after gas calculation.
|
||||
if err := CheckMaxCodeSize(&evm.chainRules, uint64(len(ret))); err != nil {
|
||||
return ret, err
|
||||
if err := CheckMaxCodeSize(&evm.chainRules, uint64(len(ret))); err != nil {
|
||||
return ret, err
|
||||
}
|
||||
} else {
|
||||
createDataGas := GasCosts{RegularGas: uint64(len(ret)) * params.CreateDataGas}
|
||||
if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
|
||||
return ret, ErrCodeStoreOutOfGas
|
||||
}
|
||||
if err := CheckMaxCodeSize(&evm.chainRules, uint64(len(ret))); err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(ret) > 0 {
|
||||
|
|
|
|||
|
|
@ -477,11 +477,14 @@ func gasCallCodeIntrinsic(evm *EVM, contract *Contract, stack *Stack, mem *Memor
|
|||
return 0, err
|
||||
}
|
||||
var (
|
||||
gas uint64
|
||||
overflow bool
|
||||
gas uint64
|
||||
overflow bool
|
||||
transfersValue = !stack.Back(2).IsZero()
|
||||
)
|
||||
if stack.Back(2).Sign() != 0 && !evm.chainRules.IsEIP4762 {
|
||||
gas += params.CallValueTransferGas
|
||||
if transfersValue {
|
||||
if !evm.chainRules.IsEIP4762 {
|
||||
gas += params.CallValueTransferGas
|
||||
}
|
||||
}
|
||||
if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
|
||||
return 0, ErrGasUintOverflow
|
||||
|
|
@ -505,8 +508,11 @@ func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
|
|||
// EIP150 homestead gas reprice fork:
|
||||
if evm.chainRules.IsEIP150 {
|
||||
gas = params.SelfdestructGasEIP150
|
||||
var address = common.Address(stack.Back(0).Bytes20())
|
||||
if gas > contract.Gas.RegularGas {
|
||||
return GasCosts{RegularGas: gas}, nil
|
||||
}
|
||||
|
||||
var address = common.Address(stack.Back(0).Bytes20())
|
||||
if evm.chainRules.IsEIP158 {
|
||||
// if empty and transfers value
|
||||
if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
|
||||
|
|
@ -639,17 +645,13 @@ func gasSStore8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memo
|
|||
}
|
||||
if original == current {
|
||||
if original == (common.Hash{}) { // create slot (2.1.1)
|
||||
// EIP-8037: Charge state gas first (before regular gas), matching the
|
||||
// spec's charge_state_gas → charge_gas ordering. This ensures that
|
||||
// state_gas_used is recorded even if the subsequent regular gas charge
|
||||
// fails with OOG.
|
||||
stateGas := GasCosts{StateGas: params.StorageCreationSize * evm.Context.CostPerGasByte}
|
||||
if contract.Gas.Underflow(stateGas) {
|
||||
return GasCosts{}, errors.New("out of gas for state gas")
|
||||
}
|
||||
contract.GasUsed.Add(stateGas)
|
||||
contract.Gas.Sub(stateGas)
|
||||
return GasCosts{RegularGas: cost.RegularGas + params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929}, nil
|
||||
// EIP-8037: Return both regular and state gas. The interpreter
|
||||
// charges regular gas before state gas, preventing reservoir
|
||||
// inflation when the regular charge OOGs.
|
||||
return GasCosts{
|
||||
RegularGas: cost.RegularGas + params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929,
|
||||
StateGas: params.StorageCreationSize * evm.Context.CostPerGasByte,
|
||||
}, nil
|
||||
}
|
||||
if value == (common.Hash{}) { // delete slot (2.1.2b)
|
||||
evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP3529)
|
||||
|
|
|
|||
|
|
@ -226,7 +226,20 @@ func (evm *EVM) Run(contract *Contract, input []byte, readOnly bool) (ret []byte
|
|||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||
}
|
||||
// for tracing: this gas consumption event is emitted below in the debug section.
|
||||
if contract.Gas.Underflow(dynamicCost) {
|
||||
if evm.chainRules.IsAmsterdam && dynamicCost.StateGas > 0 {
|
||||
// EIP-8037: charge regular gas before state gas.
|
||||
if contract.Gas.RegularGas < dynamicCost.RegularGas {
|
||||
return nil, ErrOutOfGas
|
||||
}
|
||||
contract.GasUsed.RegularGasUsed += dynamicCost.RegularGas
|
||||
contract.Gas.RegularGas -= dynamicCost.RegularGas
|
||||
stateOnly := GasCosts{StateGas: dynamicCost.StateGas}
|
||||
if contract.Gas.Underflow(stateOnly) {
|
||||
return nil, ErrOutOfGas
|
||||
}
|
||||
contract.GasUsed.Add(stateOnly)
|
||||
contract.Gas.Sub(stateOnly)
|
||||
} else if contract.Gas.Underflow(dynamicCost) {
|
||||
return nil, ErrOutOfGas
|
||||
} else {
|
||||
contract.GasUsed.Add(dynamicCost)
|
||||
|
|
|
|||
|
|
@ -243,6 +243,10 @@ func makeSelfdestructGasFn(refundsEnabled bool) gasFunc {
|
|||
return GasCosts{}, ErrOutOfGas
|
||||
}
|
||||
}
|
||||
if gas > contract.Gas.RegularGas {
|
||||
return GasCosts{RegularGas: gas}, nil
|
||||
}
|
||||
|
||||
// if empty and transfers value
|
||||
if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
|
||||
gas += params.CreateBySelfdestructGas
|
||||
|
|
@ -349,6 +353,10 @@ func makeCallVariantGasCallEIP7702(intrinsicFunc intrinsicGasFunc) gasFunc {
|
|||
// part of the dynamic gas. This will ensure it is correctly reported to
|
||||
// tracers.
|
||||
contract.Gas.RegularGas += eip2929Cost + eip7702Cost
|
||||
// Undo the RegularGasUsed increments from the direct UseGas charges,
|
||||
// since this gas will be re-charged via the returned cost.
|
||||
contract.GasUsed.RegularGasUsed -= eip2929Cost
|
||||
contract.GasUsed.RegularGasUsed -= eip7702Cost
|
||||
|
||||
// Aggregate the gas costs from all components, including EIP-2929, EIP-7702,
|
||||
// the CALL opcode itself, and the cost incurred by nested calls.
|
||||
|
|
@ -394,15 +402,12 @@ func makeCallVariantGasCallEIP8037(intrinsicFunc intrinsicGasFunc, stateGasFunc
|
|||
if err != nil {
|
||||
return GasCosts{}, err
|
||||
}
|
||||
// Early OOG check before stateful operations.
|
||||
if contract.Gas.RegularGas < intrinsicCost {
|
||||
return GasCosts{}, ErrOutOfGas
|
||||
}
|
||||
|
||||
// Compute state gas (new account creation as state gas).
|
||||
stateGas, err := stateGasFunc(evm, contract, stack, mem, memorySize)
|
||||
if err != nil {
|
||||
return GasCosts{}, err
|
||||
// Charge intrinsic cost directly (regular gas). This must happen
|
||||
// BEFORE state gas to prevent reservoir inflation, and also serves
|
||||
// as the OOG guard before stateful operations.
|
||||
if !contract.UseGas(GasCosts{RegularGas: intrinsicCost}, evm.Config.Tracer, tracing.GasChangeCallOpCode) {
|
||||
return GasCosts{}, ErrOutOfGas
|
||||
}
|
||||
|
||||
// EIP-7702 delegation check.
|
||||
|
|
@ -418,8 +423,11 @@ func makeCallVariantGasCallEIP8037(intrinsicFunc intrinsicGasFunc, stateGasFunc
|
|||
}
|
||||
}
|
||||
|
||||
// Charge state gas directly before callGas computation. State gas that
|
||||
// spills to regular gas must reduce the gas available for callGasTemp.
|
||||
// Compute and charge state gas (new account creation) AFTER regular gas.
|
||||
stateGas, err := stateGasFunc(evm, contract, stack, mem, memorySize)
|
||||
if err != nil {
|
||||
return GasCosts{}, err
|
||||
}
|
||||
if stateGas.StateGas > 0 {
|
||||
stateGasCost := GasCosts{StateGas: stateGas.StateGas}
|
||||
if contract.Gas.Underflow(stateGasCost) {
|
||||
|
|
@ -430,16 +438,15 @@ func makeCallVariantGasCallEIP8037(intrinsicFunc intrinsicGasFunc, stateGasFunc
|
|||
}
|
||||
|
||||
// Calculate the gas budget for the nested call (63/64 rule).
|
||||
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas.RegularGas, intrinsicCost, stack.Back(0))
|
||||
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas.RegularGas, 0, stack.Back(0))
|
||||
if err != nil {
|
||||
return GasCosts{}, err
|
||||
}
|
||||
|
||||
// Temporarily add gas charges back for tracer reporting.
|
||||
contract.Gas.RegularGas += eip2929Cost + eip7702Cost
|
||||
// Undo GasUsed increments from direct UseGas charges.
|
||||
contract.GasUsed.RegularGasUsed -= eip2929Cost
|
||||
contract.GasUsed.RegularGasUsed -= eip7702Cost
|
||||
// Temporarily undo direct regular charges for tracer reporting.
|
||||
// The interpreter will charge the returned totalCost.
|
||||
contract.Gas.RegularGas += eip2929Cost + eip7702Cost + intrinsicCost
|
||||
contract.GasUsed.RegularGasUsed -= eip2929Cost + eip7702Cost + intrinsicCost
|
||||
|
||||
// Aggregate total cost.
|
||||
var (
|
||||
|
|
|
|||
Loading…
Reference in a new issue