mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 03:10:48 +00:00
core/vm, core/vm/gen: charge dynamic gas through a shared chargeDynamic helper
This commit is contained in:
parent
2e0035a63a
commit
bfa0bfdc7c
4 changed files with 59 additions and 68 deletions
|
|
@ -94,6 +94,19 @@ func (g *GasBudget) chargeRegularOnly(r uint64) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// chargeDynamic charges a dynamic gas cost: a regular-only deduction when there
|
||||
// is no state gas, otherwise the full multidimensional charge through the
|
||||
// reservoir.
|
||||
func (g *GasBudget) chargeDynamic(cost GasCosts) error {
|
||||
if cost.StateGas == 0 {
|
||||
return g.chargeRegularOnly(cost.RegularGas)
|
||||
}
|
||||
if !g.charge(cost) {
|
||||
return ErrOutOfGas
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CanAfford reports whether the running budget can cover the given cost vector
|
||||
// without going out of gas.
|
||||
func (g GasBudget) CanAfford(cost GasCosts) bool {
|
||||
|
|
|
|||
|
|
@ -665,7 +665,10 @@ func (g *generator) emitStackChecks(spec opSpec) {
|
|||
}
|
||||
}
|
||||
|
||||
func (g *generator) emitGasCheck(spec opSpec) {
|
||||
// emitStaticGas charges an opcode's constant gas by splicing the chargeRegularOnly
|
||||
// body inline (call-free, for the hot path); a zero constant emits nothing. It is
|
||||
// the static-gas counterpart to emitDynamicGas.
|
||||
func (g *generator) emitStaticGas(spec opSpec) {
|
||||
if spec.constGas == 0 {
|
||||
return
|
||||
}
|
||||
|
|
@ -677,7 +680,7 @@ func (g *generator) emitGasCheck(spec opSpec) {
|
|||
func (g *generator) emitOpBody(code byte) {
|
||||
spec := g.specs[code]
|
||||
g.emitStackChecks(spec)
|
||||
g.emitGasCheck(spec)
|
||||
g.emitStaticGas(spec)
|
||||
|
||||
// PUSH1-PUSH32 swap their execute function under EIP-4762 (verkle) to charge
|
||||
// code-chunk gas on the immediate bytes. Defer to the table handler there.
|
||||
|
|
@ -724,6 +727,26 @@ func (g *generator) emitInlineOp(code byte) {
|
|||
`)
|
||||
}
|
||||
|
||||
// emitDynamicGas emits the dynamic-gas computation and charge shared by the
|
||||
// direct-call and default cases. gasFn is the dynamic-gas function to invoke:
|
||||
// a name like "gasKeccak256" for a direct call, or "operation.dynamicGas" for
|
||||
// the table case. A computation error is wrapped as ErrOutOfGas, then the cost
|
||||
// is charged through GasBudget.chargeDynamic. The doubled %%w/%%v are not
|
||||
// generator verbs: Fprintf collapses each %% to one %, leaving a literal
|
||||
// fmt.Errorf("%w: %v", ...) in the generated code.
|
||||
func (g *generator) emitDynamicGas(gasFn string) {
|
||||
g.p(`
|
||||
var dynamicCost GasCosts
|
||||
dynamicCost, err = %s(evm, contract, stack, mem, memorySize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%%w: %%v", ErrOutOfGas, err)
|
||||
}
|
||||
if err := contract.Gas.chargeDynamic(dynamicCost); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
`, gasFn)
|
||||
}
|
||||
|
||||
// emitDirectCallOp emits an opcode case identical to the default case, except
|
||||
// the handler, dynamic-gas, and memory-size functions are called by name
|
||||
// rather than through the indirect operation.* table pointers. Valid only for
|
||||
|
|
@ -733,11 +756,8 @@ func (g *generator) emitDirectCallOp(code byte) {
|
|||
fns := directCallOps[code]
|
||||
g.p("case %s:\n", spec.name)
|
||||
g.emitStackChecks(spec)
|
||||
g.emitGasCheck(spec)
|
||||
// The three %s are the memory-size, dynamic-gas and handler names, in the
|
||||
// order fns[2], fns[1], fns[0]. The doubled %%w and %%v are not generator
|
||||
// verbs: Fprintf collapses each %% to a single %, so the generated code ends
|
||||
// up with a literal fmt.Errorf("%w: %v", ...).
|
||||
g.emitStaticGas(spec)
|
||||
// fns[2], fns[1], fns[0] are the memory-size, dynamic-gas and handler names.
|
||||
g.p(`
|
||||
var memorySize uint64
|
||||
{
|
||||
|
|
@ -749,18 +769,9 @@ func (g *generator) emitDirectCallOp(code byte) {
|
|||
return nil, ErrGasUintOverflow
|
||||
}
|
||||
}
|
||||
var dynamicCost GasCosts
|
||||
dynamicCost, err = %s(evm, contract, stack, mem, memorySize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%%w: %%v", ErrOutOfGas, err)
|
||||
}
|
||||
if dynamicCost.StateGas == 0 {
|
||||
if err := contract.Gas.chargeRegularOnly(dynamicCost.RegularGas); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if !contract.Gas.charge(dynamicCost) {
|
||||
return nil, ErrOutOfGas
|
||||
}
|
||||
`, fns[2])
|
||||
g.emitDynamicGas(fns[1])
|
||||
g.p(`
|
||||
if memorySize > 0 {
|
||||
mem.Resize(memorySize)
|
||||
}
|
||||
|
|
@ -770,7 +781,7 @@ func (g *generator) emitDirectCallOp(code byte) {
|
|||
}
|
||||
pc++
|
||||
continue mainLoop
|
||||
`, fns[2], fns[1], fns[0])
|
||||
`, fns[0])
|
||||
}
|
||||
|
||||
func (g *generator) emitDefault() {
|
||||
|
|
@ -800,18 +811,9 @@ func (g *generator) emitDefault() {
|
|||
return nil, ErrGasUintOverflow
|
||||
}
|
||||
}
|
||||
var dynamicCost GasCosts
|
||||
dynamicCost, err = operation.dynamicGas(evm, contract, stack, mem, memorySize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%%w: %%v", ErrOutOfGas, err)
|
||||
}
|
||||
if dynamicCost.StateGas == 0 {
|
||||
if err := contract.Gas.chargeRegularOnly(dynamicCost.RegularGas); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if !contract.Gas.charge(dynamicCost) {
|
||||
return nil, ErrOutOfGas
|
||||
}
|
||||
`)
|
||||
g.emitDynamicGas("operation.dynamicGas")
|
||||
g.p(`
|
||||
}
|
||||
if memorySize > 0 {
|
||||
mem.Resize(memorySize)
|
||||
|
|
|
|||
|
|
@ -595,12 +595,8 @@ mainLoop:
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||
}
|
||||
if dynamicCost.StateGas == 0 {
|
||||
if err := contract.Gas.chargeRegularOnly(dynamicCost.RegularGas); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if !contract.Gas.charge(dynamicCost) {
|
||||
return nil, ErrOutOfGas
|
||||
if err := contract.Gas.chargeDynamic(dynamicCost); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if memorySize > 0 {
|
||||
mem.Resize(memorySize)
|
||||
|
|
@ -652,12 +648,8 @@ mainLoop:
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||
}
|
||||
if dynamicCost.StateGas == 0 {
|
||||
if err := contract.Gas.chargeRegularOnly(dynamicCost.RegularGas); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if !contract.Gas.charge(dynamicCost) {
|
||||
return nil, ErrOutOfGas
|
||||
if err := contract.Gas.chargeDynamic(dynamicCost); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if memorySize > 0 {
|
||||
mem.Resize(memorySize)
|
||||
|
|
@ -694,12 +686,8 @@ mainLoop:
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||
}
|
||||
if dynamicCost.StateGas == 0 {
|
||||
if err := contract.Gas.chargeRegularOnly(dynamicCost.RegularGas); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if !contract.Gas.charge(dynamicCost) {
|
||||
return nil, ErrOutOfGas
|
||||
if err := contract.Gas.chargeDynamic(dynamicCost); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if memorySize > 0 {
|
||||
mem.Resize(memorySize)
|
||||
|
|
@ -736,12 +724,8 @@ mainLoop:
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||
}
|
||||
if dynamicCost.StateGas == 0 {
|
||||
if err := contract.Gas.chargeRegularOnly(dynamicCost.RegularGas); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if !contract.Gas.charge(dynamicCost) {
|
||||
return nil, ErrOutOfGas
|
||||
if err := contract.Gas.chargeDynamic(dynamicCost); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if memorySize > 0 {
|
||||
mem.Resize(memorySize)
|
||||
|
|
@ -2561,12 +2545,8 @@ mainLoop:
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||
}
|
||||
if dynamicCost.StateGas == 0 {
|
||||
if err := contract.Gas.chargeRegularOnly(dynamicCost.RegularGas); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if !contract.Gas.charge(dynamicCost) {
|
||||
return nil, ErrOutOfGas
|
||||
if err := contract.Gas.chargeDynamic(dynamicCost); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if memorySize > 0 {
|
||||
|
|
|
|||
|
|
@ -247,12 +247,8 @@ func (evm *EVM) execTraced(scope *ScopeContext) (ret []byte, err error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||
}
|
||||
if dynamicCost.StateGas == 0 {
|
||||
if err := contract.Gas.chargeRegularOnly(dynamicCost.RegularGas); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if !contract.Gas.charge(dynamicCost) {
|
||||
return nil, ErrOutOfGas
|
||||
if err := contract.Gas.chargeDynamic(dynamicCost); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue