mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-11 01:11:37 +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
|
# 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 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
|
||||||
# https://github.com/ethereum/execution-spec-tests/releases/download/bal%40v5.6.1
|
# https://github.com/ethereum/execution-spec-tests/releases/download/snobal-devnet-5%40v8037.0.0
|
||||||
741530c88f6a48c15184d1504316c02c3a76c2322c410a04b643a85185dc62e9 fixtures_bal.tar.gz
|
0b0d5b14e9f2b7d3a7037f42703d76c2baf2b20cb550bd6b34ea761b7fd407df fixtures_snobal-devnet-5.tar.gz
|
||||||
|
|
||||||
# version:golang 1.25.9
|
# version:golang 1.25.9
|
||||||
# https://go.dev/dl/
|
# https://go.dev/dl/
|
||||||
|
|
|
||||||
|
|
@ -455,7 +455,7 @@ func downloadSpecTestFixtures(csdb *download.ChecksumDB, cachedir string) string
|
||||||
|
|
||||||
func downloadBALSpecTestFixtures(csdb *download.ChecksumDB, cachedir string) string {
|
func downloadBALSpecTestFixtures(csdb *download.ChecksumDB, cachedir string) string {
|
||||||
ext := ".tar.gz"
|
ext := ".tar.gz"
|
||||||
base := "fixtures_bal"
|
base := "fixtures_snobal-devnet-5"
|
||||||
archivePath := filepath.Join(cachedir, base+ext)
|
archivePath := filepath.Join(cachedir, base+ext)
|
||||||
if err := csdb.DownloadFileFromKnownURL(archivePath); err != nil {
|
if err := csdb.DownloadFileFromKnownURL(archivePath); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|
|
||||||
|
|
@ -287,7 +287,20 @@ func (j *journal) stateChangedBytes(revid int, stateObjects map[common.Address]*
|
||||||
}
|
}
|
||||||
|
|
||||||
var totalBytes int64
|
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
|
totalBytes += CostPerAccount
|
||||||
}
|
}
|
||||||
for sk, si := range slots {
|
for sk, si := range slots {
|
||||||
|
|
|
||||||
|
|
@ -650,8 +650,6 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
if rules.IsAmsterdam {
|
if rules.IsAmsterdam {
|
||||||
if vmerr == nil {
|
if vmerr == nil {
|
||||||
outerBytes := st.state.StateChangedBytes(outerSnapshot, false)
|
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
|
// For contract-creation txs the intrinsic already paid for the
|
||||||
// account creation; subtract it so we don't double-charge.
|
// account creation; subtract it so we don't double-charge.
|
||||||
if contractCreation {
|
if contractCreation {
|
||||||
|
|
@ -661,6 +659,20 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
alreadyPaid := st.gasRemaining.StateGasUsed
|
alreadyPaid := st.gasRemaining.StateGasUsed
|
||||||
thisCallCost := outerBytes*int64(st.evm.Context.CostPerStateByte) - alreadyPaid
|
thisCallCost := outerBytes*int64(st.evm.Context.CostPerStateByte) - alreadyPaid
|
||||||
st.gasRemaining.Charge(vm.GasCosts{StateGas: thisCallCost})
|
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 {
|
} else {
|
||||||
// On top-level error, restore state-gas reservoir and reset
|
// On top-level error, restore state-gas reservoir and reset
|
||||||
// the state-gas-used counter; state changes are reverted, no
|
// 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))
|
bytesCharged, alreadyPaid, thisCallCost, gas.CanAfford(stateGasCost))
|
||||||
}
|
}
|
||||||
if !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)
|
evm.StateDB.RevertToSnapshot(snapshot1)
|
||||||
gas.Exhaust()
|
if gas.StateGasUsed > 0 {
|
||||||
|
gas.StateGas += uint64(gas.StateGasUsed)
|
||||||
|
}
|
||||||
|
gas.StateGasUsed = 0
|
||||||
return ret, gas, ErrOutOfGas
|
return ret, gas, ErrOutOfGas
|
||||||
}
|
}
|
||||||
gas.Charge(stateGasCost)
|
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))
|
bytesCharged, alreadyPaid, thisCallCost, gas.CanAfford(stateGasCost))
|
||||||
}
|
}
|
||||||
if !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
|
return ret, gas, ErrOutOfGas
|
||||||
}
|
}
|
||||||
gas.Charge(stateGasCost)
|
gas.Charge(stateGasCost)
|
||||||
|
|
@ -512,7 +530,17 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address,
|
||||||
bytesCharged, alreadyPaid, thisCallCost, gas.CanAfford(stateGasCost))
|
bytesCharged, alreadyPaid, thisCallCost, gas.CanAfford(stateGasCost))
|
||||||
}
|
}
|
||||||
if !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
|
return ret, gas, ErrOutOfGas
|
||||||
}
|
}
|
||||||
gas.Charge(stateGasCost)
|
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
|
thisCallCost := bytesCharged*int64(evm.Context.CostPerStateByte) - alreadyPaid
|
||||||
stateGasCost := GasCosts{StateGas: thisCallCost}
|
stateGasCost := GasCosts{StateGas: thisCallCost}
|
||||||
if !contract.Gas.CanAfford(stateGasCost) {
|
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)
|
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
|
return ret, address, contract.Gas, ErrOutOfGas
|
||||||
}
|
}
|
||||||
contract.Gas.Charge(stateGasCost)
|
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
|
// 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
|
// pre-charge regular gas value and false if the budget does not have
|
||||||
// sufficient gas to cover the cost.
|
// 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) {
|
func (g *GasBudget) Charge(cost GasCosts) (uint64, bool) {
|
||||||
prior := g.RegularGas
|
prior := g.RegularGas
|
||||||
if !g.CanAfford(cost) {
|
if !g.CanAfford(cost) {
|
||||||
|
|
@ -134,11 +140,11 @@ func (g *GasBudget) Charge(cost GasCosts) (uint64, bool) {
|
||||||
}
|
}
|
||||||
g.RegularGas -= cost.RegularGas
|
g.RegularGas -= cost.RegularGas
|
||||||
g.RegularGasUsed += cost.RegularGas
|
g.RegularGasUsed += cost.RegularGas
|
||||||
g.StateGasUsed += cost.StateGas
|
|
||||||
if cost.StateGas < 0 {
|
if cost.StateGas < 0 {
|
||||||
g.StateGas -= uint64(cost.StateGas)
|
g.StateGas -= uint64(cost.StateGas)
|
||||||
return prior, true
|
return prior, true
|
||||||
}
|
}
|
||||||
|
g.StateGasUsed += cost.StateGas
|
||||||
if uint64(cost.StateGas) > g.StateGas {
|
if uint64(cost.StateGas) > g.StateGas {
|
||||||
spillover := uint64(cost.StateGas) - g.StateGas
|
spillover := uint64(cost.StateGas) - g.StateGas
|
||||||
g.StateGas = 0
|
g.StateGas = 0
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,9 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"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.
|
// reset parent's reservoir to zero. Leftover comes back via RefundGas.
|
||||||
childStateGas := scope.Contract.Gas.StateGas
|
childStateGas := scope.Contract.Gas.StateGas
|
||||||
scope.Contract.Gas.StateGas = 0
|
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)
|
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 {
|
if err != nil {
|
||||||
temp.Clear()
|
temp.Clear()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue