mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-17 18:30:45 +00:00
core/vm: align with current spec (claude)
All these should be removed once we updated the spec
This commit is contained in:
parent
6aa174111e
commit
ff799721ff
8 changed files with 123 additions and 74 deletions
|
|
@ -5,10 +5,10 @@
|
||||||
# https://github.com/ethereum/execution-spec-tests/releases/download/v5.1.0
|
# https://github.com/ethereum/execution-spec-tests/releases/download/v5.1.0
|
||||||
a3192784375acec7eaec492799d5c5d0c47a2909a3cc40178898e4ecd20cc416 fixtures_develop.tar.gz
|
a3192784375acec7eaec492799d5c5d0c47a2909a3cc40178898e4ecd20cc416 fixtures_develop.tar.gz
|
||||||
|
|
||||||
# version:spec-tests-bal v7.2.0
|
# version:spec-tests-bal v7.3.1
|
||||||
# https://github.com/ethereum/execution-specs/releases
|
# https://github.com/ethereum/execution-specs/releases
|
||||||
# https://github.com/ethereum/execution-specs/releases/download/tests-bal%40v7.2.0
|
# https://github.com/ethereum/execution-specs/releases/download/tests-bal%40v7.3.1
|
||||||
fc1d9ae174cdd5db789068839999e6f83666cc79f7dac36e973d7616d9a2e2cf fixtures_bal.tar.gz
|
3c9bd8799a506a96f74162863efdf5eaa00226e645db6523346fdb7c5ba0bf62 fixtures_bal.tar.gz
|
||||||
|
|
||||||
# version:golang 1.25.10
|
# version:golang 1.25.10
|
||||||
# https://go.dev/dl/
|
# https://go.dev/dl/
|
||||||
|
|
|
||||||
|
|
@ -674,11 +674,6 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
ret []byte
|
ret []byte
|
||||||
vmerr error // vm errors do not effect consensus and are therefore not assigned to err
|
vmerr error // vm errors do not effect consensus and are therefore not assigned to err
|
||||||
result vm.GasBudget
|
result vm.GasBudget
|
||||||
|
|
||||||
// Capture the forwarded regular-gas amount BEFORE ForwardAll consumes
|
|
||||||
// it, so Absorb can back out state-gas spillover from UsedRegularGas
|
|
||||||
// per EIP-8037.
|
|
||||||
forwarded = st.gasRemaining.RegularGas
|
|
||||||
)
|
)
|
||||||
if contractCreation {
|
if contractCreation {
|
||||||
// Check whether the init code size has been exceeded.
|
// Check whether the init code size has been exceeded.
|
||||||
|
|
@ -687,7 +682,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
}
|
}
|
||||||
// Execute the transaction's creation.
|
// Execute the transaction's creation.
|
||||||
ret, _, result, vmerr = st.evm.Create(msg.From, msg.Data, st.gasRemaining.ForwardAll(), value)
|
ret, _, result, vmerr = st.evm.Create(msg.From, msg.Data, st.gasRemaining.ForwardAll(), value)
|
||||||
st.gasRemaining.Absorb(result, forwarded)
|
st.gasRemaining.Absorb(result)
|
||||||
|
|
||||||
// If the contract creation failed, refund the account-creation state
|
// If the contract creation failed, refund the account-creation state
|
||||||
// gas pre-charged in IntrinsicGas.
|
// gas pre-charged in IntrinsicGas.
|
||||||
|
|
@ -711,7 +706,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
}
|
}
|
||||||
// Execute the transaction's call.
|
// Execute the transaction's call.
|
||||||
ret, result, vmerr = st.evm.Call(msg.From, st.to(), msg.Data, st.gasRemaining.ForwardAll(), value)
|
ret, result, vmerr = st.evm.Call(msg.From, st.to(), msg.Data, st.gasRemaining.ForwardAll(), value)
|
||||||
st.gasRemaining.Absorb(result, forwarded)
|
st.gasRemaining.Absorb(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Settle down the gas usage and refund the ETH back if any remaining
|
// Settle down the gas usage and refund the ETH back if any remaining
|
||||||
|
|
@ -821,7 +816,13 @@ func (st *stateTransition) settleGas(rules params.Rules, floorDataGas uint64) (g
|
||||||
}
|
}
|
||||||
|
|
||||||
if rules.IsAmsterdam {
|
if rules.IsAmsterdam {
|
||||||
if err = st.gp.ChargeGasAmsterdam(txRegularGas, txStateGas, gasUsed); err != nil {
|
// EIP-7623/7976: the calldata floor applies to the block-level regular
|
||||||
|
// gas dimension as well, mirroring its effect on the receipt gas. The
|
||||||
|
// spec accumulates max(tx_regular_gas, calldata_floor) into
|
||||||
|
// block_gas_used, so the block must never count fewer regular units
|
||||||
|
// than the floor the sender was charged.
|
||||||
|
blockRegularGas := max(txRegularGas, floorDataGas)
|
||||||
|
if err = st.gp.ChargeGasAmsterdam(blockRegularGas, txStateGas, gasUsed); err != nil {
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -153,9 +153,9 @@ func (c *Contract) chargeState(s uint64, logger *tracing.Hooks, reason tracing.G
|
||||||
}
|
}
|
||||||
|
|
||||||
// refundGas absorbs a sub-call's leftover GasBudget into this contract's gas state.
|
// refundGas absorbs a sub-call's leftover GasBudget into this contract's gas state.
|
||||||
func (c *Contract) refundGas(child GasBudget, forwarded uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) {
|
func (c *Contract) refundGas(child GasBudget, logger *tracing.Hooks, reason tracing.GasChangeReason) {
|
||||||
prior := c.Gas
|
prior := c.Gas
|
||||||
c.Gas.Absorb(child, forwarded)
|
c.Gas.Absorb(child)
|
||||||
if logger.HasGasHook() && reason != tracing.GasChangeIgnored {
|
if logger.HasGasHook() && reason != tracing.GasChangeIgnored {
|
||||||
logger.EmitGasChange(prior.AsTracing(), c.Gas.AsTracing(), reason)
|
logger.EmitGasChange(prior.AsTracing(), c.Gas.AsTracing(), reason)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -596,6 +596,8 @@ func enable7843(jt *JumpTable) {
|
||||||
func enable8037(jt *JumpTable) {
|
func enable8037(jt *JumpTable) {
|
||||||
jt[CREATE].constantGas = params.CreateGasAmsterdam
|
jt[CREATE].constantGas = params.CreateGasAmsterdam
|
||||||
jt[CREATE2].constantGas = params.CreateGasAmsterdam
|
jt[CREATE2].constantGas = params.CreateGasAmsterdam
|
||||||
|
jt[CREATE].dynamicGas = gasCreateEip8037
|
||||||
|
jt[CREATE2].dynamicGas = gasCreate2Eip8037
|
||||||
jt[SELFDESTRUCT].dynamicGas = gasSelfdestruct8037
|
jt[SELFDESTRUCT].dynamicGas = gasSelfdestruct8037
|
||||||
jt[SSTORE].dynamicGas = gasSStore8037
|
jt[SSTORE].dynamicGas = gasSStore8037
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -271,7 +271,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
||||||
if !syscall && !value.IsZero() && !evm.Context.CanTransfer(evm.StateDB, caller, value) {
|
if !syscall && !value.IsZero() && !evm.Context.CanTransfer(evm.StateDB, caller, value) {
|
||||||
return nil, gas, ErrInsufficientBalance
|
return nil, gas, ErrInsufficientBalance
|
||||||
}
|
}
|
||||||
snapshot, reservoir := evm.StateDB.Snapshot(), gas.StateGas
|
snapshot := evm.StateDB.Snapshot()
|
||||||
p, isPrecompile := evm.precompile(addr)
|
p, isPrecompile := evm.precompile(addr)
|
||||||
if !evm.StateDB.Exist(addr) {
|
if !evm.StateDB.Exist(addr) {
|
||||||
if !isPrecompile && evm.chainRules.IsEIP4762 && !isSystemCall(caller) {
|
if !isPrecompile && evm.chainRules.IsEIP4762 && !isSystemCall(caller) {
|
||||||
|
|
@ -285,7 +285,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
||||||
wgas := evm.AccessEvents.CodeHashGas(addr, true, gas.RegularGas, false)
|
wgas := evm.AccessEvents.CodeHashGas(addr, true, gas.RegularGas, false)
|
||||||
if _, ok := gas.ChargeRegular(wgas); !ok {
|
if _, ok := gas.ChargeRegular(wgas); !ok {
|
||||||
evm.StateDB.RevertToSnapshot(snapshot)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
return nil, gas.ExitHalt(reservoir), ErrOutOfGas
|
return nil, gas.ExitHalt(), ErrOutOfGas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -299,7 +299,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
||||||
prev, ok := gas.ChargeState(params.AccountCreationSize * evm.Context.CostPerStateByte)
|
prev, ok := gas.ChargeState(params.AccountCreationSize * evm.Context.CostPerStateByte)
|
||||||
if !ok {
|
if !ok {
|
||||||
evm.StateDB.RevertToSnapshot(snapshot)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
return nil, gas.ExitHalt(reservoir), ErrOutOfGas
|
return nil, gas.ExitHalt(), ErrOutOfGas
|
||||||
}
|
}
|
||||||
if evm.Config.Tracer.HasGasHook() {
|
if evm.Config.Tracer.HasGasHook() {
|
||||||
evm.Config.Tracer.EmitGasChange(prev.AsTracing(), gas.AsTracing(), tracing.GasChangeAccountCreation)
|
evm.Config.Tracer.EmitGasChange(prev.AsTracing(), gas.AsTracing(), tracing.GasChangeAccountCreation)
|
||||||
|
|
@ -330,7 +330,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the remaining gas at the end of frame
|
// Calculate the remaining gas at the end of frame
|
||||||
exitGas := gas.Exit(err, reservoir)
|
exitGas := gas.Exit(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
evm.StateDB.RevertToSnapshot(snapshot)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
|
||||||
|
|
@ -372,7 +372,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt
|
||||||
if !evm.Context.CanTransfer(evm.StateDB, caller, value) {
|
if !evm.Context.CanTransfer(evm.StateDB, caller, value) {
|
||||||
return nil, gas, ErrInsufficientBalance
|
return nil, gas, ErrInsufficientBalance
|
||||||
}
|
}
|
||||||
snapshot, reservoir := evm.StateDB.Snapshot(), gas.StateGas
|
snapshot := evm.StateDB.Snapshot()
|
||||||
|
|
||||||
// It is allowed to call precompiles, even via delegatecall
|
// It is allowed to call precompiles, even via delegatecall
|
||||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||||
|
|
@ -387,7 +387,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the remaining gas at the end of frame
|
// Calculate the remaining gas at the end of frame
|
||||||
exitGas := gas.Exit(err, reservoir)
|
exitGas := gas.Exit(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
evm.StateDB.RevertToSnapshot(snapshot)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
|
||||||
|
|
@ -418,7 +418,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address,
|
||||||
if evm.depth > int(params.CallCreateDepth) {
|
if evm.depth > int(params.CallCreateDepth) {
|
||||||
return nil, gas, ErrDepth
|
return nil, gas, ErrDepth
|
||||||
}
|
}
|
||||||
snapshot, reservoir := evm.StateDB.Snapshot(), gas.StateGas
|
snapshot := evm.StateDB.Snapshot()
|
||||||
|
|
||||||
// It is allowed to call precompiles, even via delegatecall
|
// It is allowed to call precompiles, even via delegatecall
|
||||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||||
|
|
@ -431,7 +431,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the remaining gas at the end of frame
|
// Calculate the remaining gas at the end of frame
|
||||||
exitGas := gas.Exit(err, reservoir)
|
exitGas := gas.Exit(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
evm.StateDB.RevertToSnapshot(snapshot)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
|
||||||
|
|
@ -465,7 +465,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b
|
||||||
// after all empty accounts were deleted, so this is not required. However, if we omit this,
|
// after all empty accounts were deleted, so this is not required. However, if we omit this,
|
||||||
// then certain tests start failing; stRevertTest/RevertPrecompiledTouchExactOOG.json.
|
// then certain tests start failing; stRevertTest/RevertPrecompiledTouchExactOOG.json.
|
||||||
// We could change this, but for now it's left for legacy reasons
|
// We could change this, but for now it's left for legacy reasons
|
||||||
snapshot, reservoir := evm.StateDB.Snapshot(), gas.StateGas
|
snapshot := evm.StateDB.Snapshot()
|
||||||
|
|
||||||
// We do an AddBalance of zero here, just in order to trigger a touch.
|
// We do an AddBalance of zero here, just in order to trigger a touch.
|
||||||
// This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium,
|
// This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium,
|
||||||
|
|
@ -483,7 +483,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the remaining gas at the end of frame
|
// Calculate the remaining gas at the end of frame
|
||||||
exitGas := gas.Exit(err, reservoir)
|
exitGas := gas.Exit(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
evm.StateDB.RevertToSnapshot(snapshot)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
if err != ErrExecutionReverted {
|
if err != ErrExecutionReverted {
|
||||||
|
|
@ -521,14 +521,13 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
||||||
}
|
}
|
||||||
// Increment the caller's nonce after passing all validations
|
// Increment the caller's nonce after passing all validations
|
||||||
evm.StateDB.SetNonce(caller, nonce+1, tracing.NonceChangeContractCreator)
|
evm.StateDB.SetNonce(caller, nonce+1, tracing.NonceChangeContractCreator)
|
||||||
reservoir := gas.StateGas
|
|
||||||
|
|
||||||
// Charge the contract creation init gas in verkle mode
|
// Charge the contract creation init gas in verkle mode
|
||||||
if evm.chainRules.IsEIP4762 {
|
if evm.chainRules.IsEIP4762 {
|
||||||
statelessGas := evm.AccessEvents.ContractCreatePreCheckGas(address, gas.RegularGas)
|
statelessGas := evm.AccessEvents.ContractCreatePreCheckGas(address, gas.RegularGas)
|
||||||
prior, ok := gas.Charge(GasCosts{RegularGas: statelessGas})
|
prior, ok := gas.Charge(GasCosts{RegularGas: statelessGas})
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, common.Address{}, gas.ExitHalt(reservoir), ErrOutOfGas
|
return nil, common.Address{}, gas.ExitHalt(), ErrOutOfGas
|
||||||
}
|
}
|
||||||
if evm.Config.Tracer.HasGasHook() {
|
if evm.Config.Tracer.HasGasHook() {
|
||||||
evm.Config.Tracer.EmitGasChange(prior.AsTracing(), gas.AsTracing(), tracing.GasChangeWitnessContractCollisionCheck)
|
evm.Config.Tracer.EmitGasChange(prior.AsTracing(), gas.AsTracing(), tracing.GasChangeWitnessContractCollisionCheck)
|
||||||
|
|
@ -549,7 +548,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
||||||
if evm.StateDB.GetNonce(address) != 0 ||
|
if evm.StateDB.GetNonce(address) != 0 ||
|
||||||
(contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) || // non-empty code
|
(contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) || // non-empty code
|
||||||
isEIP7610RejectedAccount(evm.ChainConfig().ChainID, address, evm.chainRules.IsEIP158) {
|
isEIP7610RejectedAccount(evm.ChainConfig().ChainID, address, evm.chainRules.IsEIP158) {
|
||||||
halt := gas.ExitHalt(reservoir)
|
halt := gas.ExitHalt()
|
||||||
if evm.Config.Tracer.HasGasHook() {
|
if evm.Config.Tracer.HasGasHook() {
|
||||||
evm.Config.Tracer.EmitGasChange(gas.AsTracing(), halt.AsTracing(), tracing.GasChangeCallFailedExecution)
|
evm.Config.Tracer.EmitGasChange(gas.AsTracing(), halt.AsTracing(), tracing.GasChangeCallFailedExecution)
|
||||||
}
|
}
|
||||||
|
|
@ -563,18 +562,9 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
||||||
snapshot := evm.StateDB.Snapshot()
|
snapshot := evm.StateDB.Snapshot()
|
||||||
if !evm.StateDB.Exist(address) {
|
if !evm.StateDB.Exist(address) {
|
||||||
evm.StateDB.CreateAccount(address)
|
evm.StateDB.CreateAccount(address)
|
||||||
|
// EIP-8037: the account-creation state gas is charged before the
|
||||||
if evm.chainRules.IsAmsterdam && evm.depth > 0 {
|
// opcode runs (gasCreateEip8037) for CREATE/CREATE2 opcodes, and in
|
||||||
// Only charge state gas if we are not doing a create transaction.
|
// IntrinsicGas for creation transactions, so there is no charge here.
|
||||||
// Prevents double charging with IntrinsicGas.
|
|
||||||
prev, ok := gas.ChargeState(params.AccountCreationSize * evm.Context.CostPerStateByte)
|
|
||||||
if !ok {
|
|
||||||
return nil, common.Address{}, gas.ExitHalt(reservoir), ErrOutOfGas
|
|
||||||
}
|
|
||||||
if evm.Config.Tracer.HasGasHook() {
|
|
||||||
evm.Config.Tracer.EmitGasChange(prev.AsTracing(), gas.AsTracing(), tracing.GasChangeAccountCreation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// CreateContract means that regardless of whether the account previously existed
|
// CreateContract means that regardless of whether the account previously existed
|
||||||
// in the state trie or not, it _now_ becomes created as a _contract_ account.
|
// in the state trie or not, it _now_ becomes created as a _contract_ account.
|
||||||
|
|
@ -589,7 +579,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
||||||
if evm.chainRules.IsEIP4762 {
|
if evm.chainRules.IsEIP4762 {
|
||||||
consumed, wanted := evm.AccessEvents.ContractCreateInitGas(address, gas.RegularGas)
|
consumed, wanted := evm.AccessEvents.ContractCreateInitGas(address, gas.RegularGas)
|
||||||
if consumed < wanted {
|
if consumed < wanted {
|
||||||
return nil, common.Address{}, gas.ExitHalt(reservoir), ErrOutOfGas
|
return nil, common.Address{}, gas.ExitHalt(), ErrOutOfGas
|
||||||
}
|
}
|
||||||
prior, _ := gas.Charge(GasCosts{RegularGas: consumed})
|
prior, _ := gas.Charge(GasCosts{RegularGas: consumed})
|
||||||
if evm.Config.Tracer.HasGasHook() {
|
if evm.Config.Tracer.HasGasHook() {
|
||||||
|
|
@ -614,7 +604,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
||||||
if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) {
|
if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) {
|
||||||
evm.StateDB.RevertToSnapshot(snapshot)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
|
||||||
exit := contract.Gas.Exit(err, reservoir)
|
exit := contract.Gas.Exit(err)
|
||||||
if err != ErrExecutionReverted {
|
if err != ErrExecutionReverted {
|
||||||
if evm.Config.Tracer.HasGasHook() {
|
if evm.Config.Tracer.HasGasHook() {
|
||||||
evm.Config.Tracer.EmitGasChange(contract.Gas.AsTracing(), exit.AsTracing(), tracing.GasChangeCallFailedExecution)
|
evm.Config.Tracer.EmitGasChange(contract.Gas.AsTracing(), exit.AsTracing(), tracing.GasChangeCallFailedExecution)
|
||||||
|
|
|
||||||
|
|
@ -367,6 +367,62 @@ func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
|
||||||
return GasCosts{RegularGas: gas}, nil
|
return GasCosts{RegularGas: gas}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gasCreateEip8037 is the CREATE gas calculator for Amsterdam. It charges the
|
||||||
|
// account-creation cost as state gas (EIP-8037) here, before the opcode runs,
|
||||||
|
// so the 63/64 gas-forwarding split sees the post-charge regular gas. The
|
||||||
|
// charge is refunded to the reservoir in opCreate on any failure path that
|
||||||
|
// does not create an account.
|
||||||
|
func gasCreateEip8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
|
||||||
|
if evm.readOnly {
|
||||||
|
return GasCosts{}, ErrWriteProtection
|
||||||
|
}
|
||||||
|
gas, err := memoryGasCost(mem, memorySize)
|
||||||
|
if err != nil {
|
||||||
|
return GasCosts{}, err
|
||||||
|
}
|
||||||
|
size, overflow := stack.back(2).Uint64WithOverflow()
|
||||||
|
if overflow {
|
||||||
|
return GasCosts{}, ErrGasUintOverflow
|
||||||
|
}
|
||||||
|
if err := CheckMaxInitCodeSize(&evm.chainRules, size); err != nil {
|
||||||
|
return GasCosts{}, err
|
||||||
|
}
|
||||||
|
// Since size <= MaxInitCodeSizeAmsterdam, these multiplications cannot overflow.
|
||||||
|
wordGas := params.InitCodeWordGas * ((size + 31) / 32)
|
||||||
|
stateGas := params.AccountCreationSize * evm.Context.CostPerStateByte
|
||||||
|
return GasCosts{
|
||||||
|
RegularGas: gas + wordGas,
|
||||||
|
StateGas: stateGas,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// gasCreate2Eip8037 is the CREATE2 gas calculator for Amsterdam. See
|
||||||
|
// gasCreateEip8037; CREATE2 additionally charges Keccak256WordGas for hashing
|
||||||
|
// the init code.
|
||||||
|
func gasCreate2Eip8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
|
||||||
|
if evm.readOnly {
|
||||||
|
return GasCosts{}, ErrWriteProtection
|
||||||
|
}
|
||||||
|
gas, err := memoryGasCost(mem, memorySize)
|
||||||
|
if err != nil {
|
||||||
|
return GasCosts{}, err
|
||||||
|
}
|
||||||
|
size, overflow := stack.back(2).Uint64WithOverflow()
|
||||||
|
if overflow {
|
||||||
|
return GasCosts{}, ErrGasUintOverflow
|
||||||
|
}
|
||||||
|
if err := CheckMaxInitCodeSize(&evm.chainRules, size); err != nil {
|
||||||
|
return GasCosts{}, err
|
||||||
|
}
|
||||||
|
// Since size <= MaxInitCodeSizeAmsterdam, these multiplications cannot overflow.
|
||||||
|
wordGas := (params.InitCodeWordGas + params.Keccak256WordGas) * ((size + 31) / 32)
|
||||||
|
stateGas := params.AccountCreationSize * evm.Context.CostPerStateByte
|
||||||
|
return GasCosts{
|
||||||
|
RegularGas: gas + wordGas,
|
||||||
|
StateGas: stateGas,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
|
func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
|
||||||
expByteLen := uint64((stack.back(1).BitLen() + 7) / 8)
|
expByteLen := uint64((stack.back(1).BitLen() + 7) / 8)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -226,9 +226,11 @@ func (g GasBudget) ExitRevert() GasBudget {
|
||||||
|
|
||||||
// ExitHalt produces the leftover for an exceptional halt.
|
// ExitHalt produces the leftover for an exceptional halt.
|
||||||
//
|
//
|
||||||
// - state_gas_reservoir is reset back to its value at the start of the child frame
|
// Per the updated EIP-8037, only the regular gas_left is burned (folded into
|
||||||
// - the gas_left initially given to the child is consumed (set to zero)
|
// UsedRegularGas); the entire state-gas reservoir — including any portion that
|
||||||
func (g GasBudget) ExitHalt(initStateReservoir uint64) GasBudget {
|
// spilled into the regular pool during execution — is refunded to the caller's
|
||||||
|
// reservoir rather than reclassified as burned regular gas.
|
||||||
|
func (g GasBudget) ExitHalt() GasBudget {
|
||||||
reservoir := int64(g.StateGas) + g.UsedStateGas
|
reservoir := int64(g.StateGas) + g.UsedStateGas
|
||||||
if reservoir < 0 {
|
if reservoir < 0 {
|
||||||
// Reservoir should never be negative. By construction it equals
|
// Reservoir should never be negative. By construction it equals
|
||||||
|
|
@ -237,17 +239,10 @@ func (g GasBudget) ExitHalt(initStateReservoir uint64) GasBudget {
|
||||||
reservoir = 0
|
reservoir = 0
|
||||||
log.Warn("Negative reservoir at halt", "remaining", g.StateGas, "used", g.UsedStateGas)
|
log.Warn("Negative reservoir at halt", "remaining", g.StateGas, "used", g.UsedStateGas)
|
||||||
}
|
}
|
||||||
// The portion of state gas charged from regular gas is also burned
|
|
||||||
// together with the regular gas, rather than being returned to the
|
|
||||||
// parent's state-gas reservoir.
|
|
||||||
var spilled uint64
|
|
||||||
if uint64(reservoir) > initStateReservoir {
|
|
||||||
spilled = uint64(reservoir) - initStateReservoir
|
|
||||||
}
|
|
||||||
return GasBudget{
|
return GasBudget{
|
||||||
RegularGas: 0,
|
RegularGas: 0,
|
||||||
StateGas: initStateReservoir,
|
StateGas: uint64(reservoir),
|
||||||
UsedRegularGas: g.UsedRegularGas + g.RegularGas + spilled,
|
UsedRegularGas: g.UsedRegularGas + g.RegularGas,
|
||||||
UsedStateGas: 0,
|
UsedStateGas: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -261,33 +256,24 @@ func (g GasBudget) ExitHalt(initStateReservoir uint64) GasBudget {
|
||||||
//
|
//
|
||||||
// Soft validation failures (occurring BEFORE evm.Run) should call Preserved
|
// Soft validation failures (occurring BEFORE evm.Run) should call Preserved
|
||||||
// directly instead of going through this dispatcher.
|
// directly instead of going through this dispatcher.
|
||||||
func (g GasBudget) Exit(err error, initStateReservoir uint64) GasBudget {
|
func (g GasBudget) Exit(err error) GasBudget {
|
||||||
switch {
|
switch {
|
||||||
case err == nil:
|
case err == nil:
|
||||||
return g.ExitSuccess()
|
return g.ExitSuccess()
|
||||||
case err == ErrExecutionReverted:
|
case err == ErrExecutionReverted:
|
||||||
return g.ExitRevert()
|
return g.ExitRevert()
|
||||||
default:
|
default:
|
||||||
return g.ExitHalt(initStateReservoir)
|
return g.ExitHalt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Absorb merges a sub-call's leftover GasBudget into this (caller's) running
|
// Absorb merges a sub-call's leftover GasBudget into this (caller's) running
|
||||||
// budget. Additionally, it does an EIP-8037 spillover correction:
|
// budget. Under the updated EIP-8037, state-gas no longer spills into the
|
||||||
// state-gas that spilled into the regular pool inside the child frame is
|
// child's burned regular gas on halt, so the child's UsedRegularGas can be
|
||||||
// excluded from the UsedRegularGas.
|
// folded in directly without a spillover correction.
|
||||||
//
|
func (g *GasBudget) Absorb(child GasBudget) {
|
||||||
// spillover = forwarded - child.RegularGas - child.UsedRegularGas
|
|
||||||
//
|
|
||||||
// forwarded is the regular-gas amount that was passed to the child at call
|
|
||||||
// entry (i.e., the regular initial of the child's GasBudget).
|
|
||||||
func (g *GasBudget) Absorb(child GasBudget, forwarded uint64) {
|
|
||||||
spillover := forwarded - child.RegularGas - child.UsedRegularGas
|
|
||||||
|
|
||||||
g.UsedRegularGas -= child.RegularGas
|
|
||||||
g.RegularGas += child.RegularGas
|
g.RegularGas += child.RegularGas
|
||||||
|
g.UsedRegularGas += child.UsedRegularGas
|
||||||
g.StateGas = child.StateGas
|
g.StateGas = child.StateGas
|
||||||
g.UsedStateGas += child.UsedStateGas
|
g.UsedStateGas += child.UsedStateGas
|
||||||
|
|
||||||
g.UsedRegularGas -= spillover
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -677,7 +677,14 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.push(&stackvalue)
|
scope.Stack.push(&stackvalue)
|
||||||
|
|
||||||
// Refund the leftover gas back to current frame
|
// Refund the leftover gas back to current frame
|
||||||
scope.Contract.refundGas(result, forward, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
scope.Contract.refundGas(result, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||||
|
|
||||||
|
// EIP-8037: no account was created on any failure path, so refund the
|
||||||
|
// account-creation state gas charged before the opcode ran (gasCreateEip8037)
|
||||||
|
// back to the reservoir.
|
||||||
|
if evm.chainRules.IsAmsterdam && suberr != nil {
|
||||||
|
scope.Contract.Gas.RefundState(params.AccountCreationSize * evm.Context.CostPerStateByte)
|
||||||
|
}
|
||||||
|
|
||||||
if suberr == ErrExecutionReverted {
|
if suberr == ErrExecutionReverted {
|
||||||
evm.returnData = res // set REVERT data to return data buffer
|
evm.returnData = res // set REVERT data to return data buffer
|
||||||
|
|
@ -711,7 +718,14 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.push(&stackvalue)
|
scope.Stack.push(&stackvalue)
|
||||||
|
|
||||||
// Refund the leftover gas back to current frame
|
// Refund the leftover gas back to current frame
|
||||||
scope.Contract.refundGas(result, forward, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
scope.Contract.refundGas(result, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||||
|
|
||||||
|
// EIP-8037: no account was created on any failure path, so refund the
|
||||||
|
// account-creation state gas charged before the opcode ran (gasCreate2Eip8037)
|
||||||
|
// back to the reservoir.
|
||||||
|
if evm.chainRules.IsAmsterdam && suberr != nil {
|
||||||
|
scope.Contract.Gas.RefundState(params.AccountCreationSize * evm.Context.CostPerStateByte)
|
||||||
|
}
|
||||||
|
|
||||||
if suberr == ErrExecutionReverted {
|
if suberr == ErrExecutionReverted {
|
||||||
evm.returnData = res // set REVERT data to return data buffer
|
evm.returnData = res // set REVERT data to return data buffer
|
||||||
|
|
@ -756,7 +770,7 @@ func opCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
if err == nil || err == ErrExecutionReverted {
|
if err == nil || err == ErrExecutionReverted {
|
||||||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
scope.Contract.refundGas(result, gas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
scope.Contract.refundGas(result, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||||
|
|
||||||
evm.returnData = ret
|
evm.returnData = ret
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
|
@ -792,7 +806,7 @@ func opCallCode(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.Contract.refundGas(result, gas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
scope.Contract.refundGas(result, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||||
|
|
||||||
evm.returnData = ret
|
evm.returnData = ret
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
|
@ -824,7 +838,7 @@ func opDelegateCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
if err == nil || err == ErrExecutionReverted {
|
if err == nil || err == ErrExecutionReverted {
|
||||||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
scope.Contract.refundGas(result, gas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
scope.Contract.refundGas(result, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||||
|
|
||||||
evm.returnData = ret
|
evm.returnData = ret
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
|
@ -857,7 +871,7 @@ func opStaticCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.Contract.refundGas(result, gas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
scope.Contract.refundGas(result, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||||
|
|
||||||
evm.returnData = ret
|
evm.returnData = ret
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue