mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-08 07:58:40 +00:00
core: misc fixes (claude)
This commit is contained in:
parent
87a4f9c674
commit
42a87ae77a
7 changed files with 88 additions and 12 deletions
|
|
@ -5,10 +5,10 @@
|
|||
# https://github.com/ethereum/execution-spec-tests/releases/download/v5.1.0
|
||||
a3192784375acec7eaec492799d5c5d0c47a2909a3cc40178898e4ecd20cc416 fixtures_develop.tar.gz
|
||||
|
||||
# version:spec-tests-bal v5.6.1
|
||||
# version:spec-tests-bal v8037.0.0
|
||||
# https://github.com/ethereum/execution-spec-tests/releases
|
||||
# https://github.com/ethereum/execution-spec-tests/releases/download/bal%40v5.6.1
|
||||
741530c88f6a48c15184d1504316c02c3a76c2322c410a04b643a85185dc62e9 fixtures_bal.tar.gz
|
||||
# https://github.com/ethereum/execution-spec-tests/releases/download/snobal-devnet-5%40v8037.0.0
|
||||
0b0d5b14e9f2b7d3a7037f42703d76c2baf2b20cb550bd6b34ea761b7fd407df fixtures_snobal-devnet-5.tar.gz
|
||||
|
||||
# version:golang 1.25.9
|
||||
# https://go.dev/dl/
|
||||
|
|
|
|||
|
|
@ -455,7 +455,7 @@ func downloadSpecTestFixtures(csdb *download.ChecksumDB, cachedir string) string
|
|||
|
||||
func downloadBALSpecTestFixtures(csdb *download.ChecksumDB, cachedir string) string {
|
||||
ext := ".tar.gz"
|
||||
base := "fixtures_bal"
|
||||
base := "fixtures_snobal-devnet-5"
|
||||
archivePath := filepath.Join(cachedir, base+ext)
|
||||
if err := csdb.DownloadFileFromKnownURL(archivePath); err != nil {
|
||||
log.Fatal(err)
|
||||
|
|
|
|||
|
|
@ -287,7 +287,20 @@ func (j *journal) stateChangedBytes(revid int, stateObjects map[common.Address]*
|
|||
}
|
||||
|
||||
var totalBytes int64
|
||||
for range created {
|
||||
// Per EIP-8037 spec compute_state_byte_diff: only count +112 for accounts
|
||||
// that exist at frame exit. Per EIP-161, accounts that end up with
|
||||
// nonce=0, balance=0, and empty code are considered non-existent and
|
||||
// pruned — these don't count even though we created the object record
|
||||
// (e.g. AddBalance(addr, 0) for a zero-value SELFDESTRUCT to a
|
||||
// non-existent beneficiary).
|
||||
for addr := range created {
|
||||
obj := stateObjects[addr]
|
||||
if obj == nil {
|
||||
continue
|
||||
}
|
||||
if obj.empty() {
|
||||
continue
|
||||
}
|
||||
totalBytes += CostPerAccount
|
||||
}
|
||||
for sk, si := range slots {
|
||||
|
|
|
|||
|
|
@ -650,8 +650,6 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
|||
if rules.IsAmsterdam {
|
||||
if vmerr == nil {
|
||||
outerBytes := st.state.StateChangedBytes(outerSnapshot, false)
|
||||
// Refund state gas for selfdestructed accounts.
|
||||
outerBytes -= st.state.SelfDestructRefundBytes()
|
||||
// For contract-creation txs the intrinsic already paid for the
|
||||
// account creation; subtract it so we don't double-charge.
|
||||
if contractCreation {
|
||||
|
|
@ -661,6 +659,20 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
|||
alreadyPaid := st.gasRemaining.StateGasUsed
|
||||
thisCallCost := outerBytes*int64(st.evm.Context.CostPerStateByte) - alreadyPaid
|
||||
st.gasRemaining.Charge(vm.GasCosts{StateGas: thisCallCost})
|
||||
|
||||
// EIP-8037 + EIP-6780: refund state gas for accounts created and
|
||||
// selfdestructed in the same tx. Per spec interpreter.py:200-201,
|
||||
// this runs at the top-level after the frame's apply_frame_state_gas:
|
||||
// reservoir is credited and state_gas_used is decremented. The
|
||||
// decrement may go negative when account-creation was paid via the
|
||||
// intrinsic (CREATE tx) rather than execution state-gas; the
|
||||
// negative offsets the intrinsic at tx-level state-gas accounting.
|
||||
refundBytes := st.state.SelfDestructRefundBytes()
|
||||
if refundBytes > 0 {
|
||||
refundCost := refundBytes * int64(st.evm.Context.CostPerStateByte)
|
||||
st.gasRemaining.StateGas += uint64(refundCost)
|
||||
st.gasRemaining.StateGasUsed -= refundCost
|
||||
}
|
||||
} else {
|
||||
// On top-level error, restore state-gas reservoir and reset
|
||||
// the state-gas-used counter; state changes are reverted, no
|
||||
|
|
|
|||
|
|
@ -346,8 +346,16 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
|||
bytesCharged, alreadyPaid, thisCallCost, gas.CanAfford(stateGasCost))
|
||||
}
|
||||
if !gas.CanAfford(stateGasCost) {
|
||||
// EIP-8037 spec apply_frame_state_gas OOG branch: roll back
|
||||
// state, set OOG, preserve reservoir + remaining regular gas.
|
||||
// Per incorporate_child_on_error: child's reservoir + max(0,
|
||||
// state_gas_used) flows to caller's reservoir; state_gas_used
|
||||
// is dropped. Convert here so RefundGas does the right thing.
|
||||
evm.StateDB.RevertToSnapshot(snapshot1)
|
||||
gas.Exhaust()
|
||||
if gas.StateGasUsed > 0 {
|
||||
gas.StateGas += uint64(gas.StateGasUsed)
|
||||
}
|
||||
gas.StateGasUsed = 0
|
||||
return ret, gas, ErrOutOfGas
|
||||
}
|
||||
gas.Charge(stateGasCost)
|
||||
|
|
@ -432,7 +440,17 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt
|
|||
bytesCharged, alreadyPaid, thisCallCost, gas.CanAfford(stateGasCost))
|
||||
}
|
||||
if !gas.CanAfford(stateGasCost) {
|
||||
gas.Exhaust()
|
||||
// EIP-8037 spec apply_frame_state_gas OOG branch: roll back
|
||||
// state, set OOG, preserve reservoir and remaining regular
|
||||
// gas. Per incorporate_child_on_error: child's reservoir
|
||||
// AND max(0, state_gas_used) both flow to the caller's
|
||||
// reservoir; state_gas_used itself is dropped (not
|
||||
// propagated as credit). Convert here.
|
||||
evm.StateDB.RevertToSnapshot(snapshot1)
|
||||
if gas.StateGasUsed > 0 {
|
||||
gas.StateGas += uint64(gas.StateGasUsed)
|
||||
}
|
||||
gas.StateGasUsed = 0
|
||||
return ret, gas, ErrOutOfGas
|
||||
}
|
||||
gas.Charge(stateGasCost)
|
||||
|
|
@ -512,7 +530,17 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address,
|
|||
bytesCharged, alreadyPaid, thisCallCost, gas.CanAfford(stateGasCost))
|
||||
}
|
||||
if !gas.CanAfford(stateGasCost) {
|
||||
gas.Exhaust()
|
||||
// EIP-8037 spec apply_frame_state_gas OOG branch: roll back
|
||||
// state, set OOG, preserve reservoir and remaining regular
|
||||
// gas. Per incorporate_child_on_error: child's reservoir
|
||||
// AND max(0, state_gas_used) both flow to the caller's
|
||||
// reservoir; state_gas_used itself is dropped (not
|
||||
// propagated as credit). Convert here.
|
||||
evm.StateDB.RevertToSnapshot(snapshot1)
|
||||
if gas.StateGasUsed > 0 {
|
||||
gas.StateGas += uint64(gas.StateGasUsed)
|
||||
}
|
||||
gas.StateGasUsed = 0
|
||||
return ret, gas, ErrOutOfGas
|
||||
}
|
||||
gas.Charge(stateGasCost)
|
||||
|
|
@ -710,8 +738,15 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
|||
thisCallCost := bytesCharged*int64(evm.Context.CostPerStateByte) - alreadyPaid
|
||||
stateGasCost := GasCosts{StateGas: thisCallCost}
|
||||
if !contract.Gas.CanAfford(stateGasCost) {
|
||||
// EIP-8037 spec: state-gas OOG rolls back state, preserves
|
||||
// reservoir+regular, converts max(0, state_gas_used) into
|
||||
// reservoir credit (incorporate_child_on_error semantics),
|
||||
// then drops state_gas_used.
|
||||
evm.StateDB.RevertToSnapshot(snapshot1)
|
||||
contract.Gas.Exhaust()
|
||||
if contract.Gas.StateGasUsed > 0 {
|
||||
contract.Gas.StateGas += uint64(contract.Gas.StateGasUsed)
|
||||
}
|
||||
contract.Gas.StateGasUsed = 0
|
||||
return ret, address, contract.Gas, ErrOutOfGas
|
||||
}
|
||||
contract.Gas.Charge(stateGasCost)
|
||||
|
|
|
|||
|
|
@ -127,6 +127,12 @@ func (g GasBudget) CanAfford(cost GasCosts) bool {
|
|||
// Charge deducts the given gas cost from the budget. It returns the
|
||||
// pre-charge regular gas value and false if the budget does not have
|
||||
// sufficient gas to cover the cost.
|
||||
//
|
||||
// Per EIP-8037 spec apply_frame_state_gas: a negative state-gas cost
|
||||
// (refund from net state shrinkage) credits only the reservoir, not the
|
||||
// per-frame state_gas_used tracker. Otherwise the negative would
|
||||
// propagate to the parent's already_paid and cause the parent's
|
||||
// frame-end charge to be over-counted.
|
||||
func (g *GasBudget) Charge(cost GasCosts) (uint64, bool) {
|
||||
prior := g.RegularGas
|
||||
if !g.CanAfford(cost) {
|
||||
|
|
@ -134,11 +140,11 @@ func (g *GasBudget) Charge(cost GasCosts) (uint64, bool) {
|
|||
}
|
||||
g.RegularGas -= cost.RegularGas
|
||||
g.RegularGasUsed += cost.RegularGas
|
||||
g.StateGasUsed += cost.StateGas
|
||||
if cost.StateGas < 0 {
|
||||
g.StateGas -= uint64(cost.StateGas)
|
||||
return prior, true
|
||||
}
|
||||
g.StateGasUsed += cost.StateGas
|
||||
if uint64(cost.StateGas) > g.StateGas {
|
||||
spillover := uint64(cost.StateGas) - g.StateGas
|
||||
g.StateGas = 0
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
|
|
@ -771,7 +773,15 @@ func opCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
|||
// reset parent's reservoir to zero. Leftover comes back via RefundGas.
|
||||
childStateGas := scope.Contract.Gas.StateGas
|
||||
scope.Contract.Gas.StateGas = 0
|
||||
if os.Getenv("DEBUG_8037") != "" {
|
||||
fmt.Fprintf(os.Stderr, " opCall depth=%d childStateGas=%d gas=%d to=%v\n",
|
||||
evm.depth, childStateGas, gas, toAddr)
|
||||
}
|
||||
ret, returnGas, err := evm.Call(scope.Contract.Address(), toAddr, args, NewGasBudget(gas, childStateGas), &value)
|
||||
if os.Getenv("DEBUG_8037") != "" {
|
||||
fmt.Fprintf(os.Stderr, " opCall depth=%d returnGas=<%d,%d>su=%d err=%v\n",
|
||||
evm.depth, returnGas.RegularGas, returnGas.StateGas, returnGas.StateGasUsed, err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
temp.Clear()
|
||||
|
|
|
|||
Loading…
Reference in a new issue