mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 11:20:45 +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
|
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
|
// CanAfford reports whether the running budget can cover the given cost vector
|
||||||
// without going out of gas.
|
// without going out of gas.
|
||||||
func (g GasBudget) CanAfford(cost GasCosts) bool {
|
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 {
|
if spec.constGas == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -677,7 +680,7 @@ func (g *generator) emitGasCheck(spec opSpec) {
|
||||||
func (g *generator) emitOpBody(code byte) {
|
func (g *generator) emitOpBody(code byte) {
|
||||||
spec := g.specs[code]
|
spec := g.specs[code]
|
||||||
g.emitStackChecks(spec)
|
g.emitStackChecks(spec)
|
||||||
g.emitGasCheck(spec)
|
g.emitStaticGas(spec)
|
||||||
|
|
||||||
// PUSH1-PUSH32 swap their execute function under EIP-4762 (verkle) to charge
|
// 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.
|
// 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
|
// emitDirectCallOp emits an opcode case identical to the default case, except
|
||||||
// the handler, dynamic-gas, and memory-size functions are called by name
|
// the handler, dynamic-gas, and memory-size functions are called by name
|
||||||
// rather than through the indirect operation.* table pointers. Valid only for
|
// rather than through the indirect operation.* table pointers. Valid only for
|
||||||
|
|
@ -733,11 +756,8 @@ func (g *generator) emitDirectCallOp(code byte) {
|
||||||
fns := directCallOps[code]
|
fns := directCallOps[code]
|
||||||
g.p("case %s:\n", spec.name)
|
g.p("case %s:\n", spec.name)
|
||||||
g.emitStackChecks(spec)
|
g.emitStackChecks(spec)
|
||||||
g.emitGasCheck(spec)
|
g.emitStaticGas(spec)
|
||||||
// The three %s are the memory-size, dynamic-gas and handler names, in the
|
// fns[2], fns[1], fns[0] are the memory-size, dynamic-gas and handler names.
|
||||||
// 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.p(`
|
g.p(`
|
||||||
var memorySize uint64
|
var memorySize uint64
|
||||||
{
|
{
|
||||||
|
|
@ -749,18 +769,9 @@ func (g *generator) emitDirectCallOp(code byte) {
|
||||||
return nil, ErrGasUintOverflow
|
return nil, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var dynamicCost GasCosts
|
`, fns[2])
|
||||||
dynamicCost, err = %s(evm, contract, stack, mem, memorySize)
|
g.emitDynamicGas(fns[1])
|
||||||
if err != nil {
|
g.p(`
|
||||||
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 memorySize > 0 {
|
if memorySize > 0 {
|
||||||
mem.Resize(memorySize)
|
mem.Resize(memorySize)
|
||||||
}
|
}
|
||||||
|
|
@ -770,7 +781,7 @@ func (g *generator) emitDirectCallOp(code byte) {
|
||||||
}
|
}
|
||||||
pc++
|
pc++
|
||||||
continue mainLoop
|
continue mainLoop
|
||||||
`, fns[2], fns[1], fns[0])
|
`, fns[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *generator) emitDefault() {
|
func (g *generator) emitDefault() {
|
||||||
|
|
@ -800,18 +811,9 @@ func (g *generator) emitDefault() {
|
||||||
return nil, ErrGasUintOverflow
|
return nil, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var dynamicCost GasCosts
|
`)
|
||||||
dynamicCost, err = operation.dynamicGas(evm, contract, stack, mem, memorySize)
|
g.emitDynamicGas("operation.dynamicGas")
|
||||||
if err != nil {
|
g.p(`
|
||||||
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 memorySize > 0 {
|
if memorySize > 0 {
|
||||||
mem.Resize(memorySize)
|
mem.Resize(memorySize)
|
||||||
|
|
|
||||||
|
|
@ -595,12 +595,8 @@ mainLoop:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||||
}
|
}
|
||||||
if dynamicCost.StateGas == 0 {
|
if err := contract.Gas.chargeDynamic(dynamicCost); err != nil {
|
||||||
if err := contract.Gas.chargeRegularOnly(dynamicCost.RegularGas); err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else if !contract.Gas.charge(dynamicCost) {
|
|
||||||
return nil, ErrOutOfGas
|
|
||||||
}
|
}
|
||||||
if memorySize > 0 {
|
if memorySize > 0 {
|
||||||
mem.Resize(memorySize)
|
mem.Resize(memorySize)
|
||||||
|
|
@ -652,12 +648,8 @@ mainLoop:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||||
}
|
}
|
||||||
if dynamicCost.StateGas == 0 {
|
if err := contract.Gas.chargeDynamic(dynamicCost); err != nil {
|
||||||
if err := contract.Gas.chargeRegularOnly(dynamicCost.RegularGas); err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else if !contract.Gas.charge(dynamicCost) {
|
|
||||||
return nil, ErrOutOfGas
|
|
||||||
}
|
}
|
||||||
if memorySize > 0 {
|
if memorySize > 0 {
|
||||||
mem.Resize(memorySize)
|
mem.Resize(memorySize)
|
||||||
|
|
@ -694,12 +686,8 @@ mainLoop:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||||
}
|
}
|
||||||
if dynamicCost.StateGas == 0 {
|
if err := contract.Gas.chargeDynamic(dynamicCost); err != nil {
|
||||||
if err := contract.Gas.chargeRegularOnly(dynamicCost.RegularGas); err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else if !contract.Gas.charge(dynamicCost) {
|
|
||||||
return nil, ErrOutOfGas
|
|
||||||
}
|
}
|
||||||
if memorySize > 0 {
|
if memorySize > 0 {
|
||||||
mem.Resize(memorySize)
|
mem.Resize(memorySize)
|
||||||
|
|
@ -736,12 +724,8 @@ mainLoop:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||||
}
|
}
|
||||||
if dynamicCost.StateGas == 0 {
|
if err := contract.Gas.chargeDynamic(dynamicCost); err != nil {
|
||||||
if err := contract.Gas.chargeRegularOnly(dynamicCost.RegularGas); err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else if !contract.Gas.charge(dynamicCost) {
|
|
||||||
return nil, ErrOutOfGas
|
|
||||||
}
|
}
|
||||||
if memorySize > 0 {
|
if memorySize > 0 {
|
||||||
mem.Resize(memorySize)
|
mem.Resize(memorySize)
|
||||||
|
|
@ -2561,12 +2545,8 @@ mainLoop:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||||
}
|
}
|
||||||
if dynamicCost.StateGas == 0 {
|
if err := contract.Gas.chargeDynamic(dynamicCost); err != nil {
|
||||||
if err := contract.Gas.chargeRegularOnly(dynamicCost.RegularGas); err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else if !contract.Gas.charge(dynamicCost) {
|
|
||||||
return nil, ErrOutOfGas
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if memorySize > 0 {
|
if memorySize > 0 {
|
||||||
|
|
|
||||||
|
|
@ -247,12 +247,8 @@ func (evm *EVM) execTraced(scope *ScopeContext) (ret []byte, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||||
}
|
}
|
||||||
if dynamicCost.StateGas == 0 {
|
if err := contract.Gas.chargeDynamic(dynamicCost); err != nil {
|
||||||
if err := contract.Gas.chargeRegularOnly(dynamicCost.RegularGas); err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else if !contract.Gas.charge(dynamicCost) {
|
|
||||||
return nil, ErrOutOfGas
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue