diff --git a/core/vm/gascosts.go b/core/vm/gascosts.go index 220e7d650f..b73732daa3 100644 --- a/core/vm/gascosts.go +++ b/core/vm/gascosts.go @@ -84,15 +84,14 @@ func (g *GasBudget) Charge(cost GasCosts) (GasBudget, bool) { return prior, ok } -// ChargeRegularOnly deducts a regular-only cost. It's always preferred for -// performance consideration if the opcode doesn't have any state cost. -func (g *GasBudget) ChargeRegularOnly(r uint64) bool { +// chargeRegularOnly deducts a regular-only cost. +func (g *GasBudget) chargeRegularOnly(r uint64) error { if g.RegularGas < r { - return false + return ErrOutOfGas } g.RegularGas -= r g.UsedRegularGas += r - return true + return nil } // CanAfford reports whether the running budget can cover the given cost vector diff --git a/core/vm/gen/main.go b/core/vm/gen/main.go index ddc9223387..0c8f805e17 100644 --- a/core/vm/gen/main.go +++ b/core/vm/gen/main.go @@ -24,7 +24,7 @@ // derived from the per-fork instruction tables via vm.GenForks. // // - calls the fork-invariant ops (KECCAK256 / MLOAD / MSTORE / MSTORE8, -// see directCall) directly by name, skipping the table's function +// see directCallOps) directly by name, skipping the table's function // pointers, which Go cannot inline through. // // - dispatches everything fork-varying (CALL / CREATE / SSTORE / SLOAD / LOG / @@ -57,14 +57,14 @@ import ( const stackLimit = 1024 // params.StackLimit -// inlineHandler maps an opcode byte to the handler whose body is spliced inline +// inlineOps maps an opcode byte to the handler whose body is spliced inline // for that opcode. These are the hot, fork-stable opcodes with no dynamic gas. // The value is usually an opXxx handler, but PUSH3-PUSH32 and DUP1-DUP16 are // factory-built (one shared makePush / makeDup each), so their value is the // factory name and emitOpBody splices the factory body with the per-opcode size. -// Opcodes not listed here (or in directCall) fall through to the default case, +// Opcodes not listed here (or in directCallOps) fall through to the default case, // which dispatches via the per-fork table. -var inlineHandler = func() map[byte]string { +var inlineOps = func() map[byte]string { m := map[byte]string{ 0x01: "opAdd", 0x02: "opMul", 0x03: "opSub", 0x04: "opDiv", 0x05: "opSdiv", 0x06: "opMod", 0x07: "opSmod", 0x08: "opAddmod", 0x09: "opMulmod", 0x0b: "opSignExtend", @@ -87,7 +87,7 @@ var inlineHandler = func() map[byte]string { return m }() -// directCall lists the opcodes (dynamic gas, not inlined) whose handler, +// directCallOps lists the opcodes (dynamic gas, not inlined) whose handler, // dynamic-gas, and memory-size functions are the same across every fork // (verified: untouched by any enableXxx). They are emitted as direct calls to // those functions by name instead of the indirect operation.* pointer calls @@ -102,7 +102,7 @@ var inlineHandler = func() map[byte]string { // Limited to the memory/hash ops that appear in hot loops. Adding more (e.g. // CALLDATACOPY/RETURN, typically once per call) grows the generated function // and regresses tiny benchmarks through code layout, for negligible gain. -var directCall = map[byte][3]string{ +var directCallOps = map[byte][3]string{ 0x20: {"opKeccak256", "gasKeccak256", "memoryKeccak256"}, // KECCAK256 0x51: {"opMload", "gasMLoad", "memoryMLoad"}, // MLOAD 0x52: {"opMstore", "gasMStore", "memoryMStore"}, // MSTORE @@ -113,7 +113,7 @@ var directCall = map[byte][3]string{ type opSpec struct { defined bool name string // opcode mnemonic, e.g. "ADD" - introF string // params.Rules field activating it, empty for Frontier (always on) + fork string // params.Rules field activating it, empty for Frontier (always on) constGas uint64 minStack int maxStack int @@ -123,6 +123,7 @@ type generator struct { fset *token.FileSet handlers map[string]*ast.FuncDecl // opXxx handlers from instructions.go and eips.go stackHelpers map[string]*ast.FuncDecl // (s *Stack) helpers from stack.go, spliced inline + gasHelpers map[string]*ast.FuncDecl // (g *GasBudget) charge methods from gascosts.go, spliced by name specs [256]opSpec buf *bytes.Buffer } @@ -138,14 +139,16 @@ func (g *generator) p(format string, args ...any) { // Handler parsing + body splicing // --------------------------------------------------------------------------- -// parseHandlers parses instructions.go, eips.go and stack.go. It returns the -// top-level opXxx handlers by name, and separately the *Stack helper methods by -// name (the inliner splices the latter into the former). -func parseHandlers(vmDir string) (fset *token.FileSet, handlers, stackHelpers map[string]*ast.FuncDecl) { +// parseHandlers parses instructions.go, eips.go, stack.go and gascosts.go. It +// returns the top-level opXxx handlers by name, the //gen:inline *Stack helper +// methods by name (spliced into handler bodies), and the *GasBudget charge +// methods by name (spliced directly at gas steps). +func parseHandlers(vmDir string) (fset *token.FileSet, handlers, stackHelpers, gasHelpers map[string]*ast.FuncDecl) { fset = token.NewFileSet() handlers = map[string]*ast.FuncDecl{} stackHelpers = map[string]*ast.FuncDecl{} - for _, name := range []string{"instructions.go", "eips.go", "stack.go"} { + gasHelpers = map[string]*ast.FuncDecl{} + for _, name := range []string{"instructions.go", "eips.go", "stack.go", "gascosts.go"} { path := filepath.Join(vmDir, name) f, err := parser.ParseFile(fset, path, nil, parser.ParseComments) if err != nil { @@ -159,25 +162,31 @@ func parseHandlers(vmDir string) (fset *token.FileSet, handlers, stackHelpers ma switch { case fn.Recv == nil: // top-level opXxx handler handlers[fn.Name.Name] = fn - case isStackMethod(fn) && hasInlineMarker(fn): // (s *Stack) helper tagged //gen:inline + case methodReceiver(fn) == "Stack" && hasInlineMarker(fn): // (s *Stack) helper tagged //gen:inline stackHelpers[fn.Name.Name] = fn + case methodReceiver(fn) == "GasBudget": // (g *GasBudget) charge method, spliced by name at gas steps + gasHelpers[fn.Name.Name] = fn } } } - return fset, handlers, stackHelpers + return fset, handlers, stackHelpers, gasHelpers } -// isStackMethod reports whether fn is a method on *Stack. -func isStackMethod(fn *ast.FuncDecl) bool { +// methodReceiver returns the receiver type name of a pointer-receiver method +// (e.g. "Stack" for (s *Stack)), or "" if fn is not such a method. +func methodReceiver(fn *ast.FuncDecl) string { if fn.Recv == nil || len(fn.Recv.List) != 1 { - return false + return "" } star, ok := fn.Recv.List[0].Type.(*ast.StarExpr) if !ok { - return false + return "" } id, ok := star.X.(*ast.Ident) - return ok && id.Name == "Stack" + if !ok { + return "" + } + return id.Name } // hasInlineMarker reports whether fn is tagged //gen:inline, which marks a stack @@ -194,25 +203,25 @@ func hasInlineMarker(fn *ast.FuncDecl) bool { return false } -var returnRe = regexp.MustCompile(`^(\s*)return\s+([^,]+),\s*(.+)$`) +var opcodeReturnRe = regexp.MustCompile(`^(\s*)return\s+([^,]+),\s*(.+)$`) -// inlineBody returns a named handler's body, rewritten so it can be spliced -// into the dispatch loop (see rewriteSplicedBody). The caller emits it with p. -func (g *generator) inlineBody(handler string) string { +// inlineOpcodeBody returns a named handler's body, rewritten so it can be spliced +// into the dispatch loop (see rewriteOpcodeReturns). The caller emits it with p. +func (g *generator) inlineOpcodeBody(handler string) string { fn := g.handlers[handler] if fn == nil { fatalf("no handler %q to inline", handler) } - return g.rewriteSplicedBody(g.inlineStackHelpers(fn.Body.List, nil)) + return g.rewriteOpcodeReturns(g.inlineStackHelpers(fn.Body.List, nil)) } -// inlineFactoryBody splices the body of the executionFunc closure that a make* +// inlineOpcodeFactoryBody splices the body of the executionFunc closure that a make* // factory returns, substituting the factory's parameters with the per-opcode // constants in args (positional, matching the factory signature). This lets // closure-built handlers (makePush, makeDup) be derived from their single // definition rather than restated in the generator. The caller emits the // result with p. -func (g *generator) inlineFactoryBody(factory string, args ...int) string { +func (g *generator) inlineOpcodeFactoryBody(factory string, args ...int) string { fn := g.handlers[factory] if fn == nil { fatalf("no factory %q to inline", factory) @@ -227,7 +236,7 @@ func (g *generator) inlineFactoryBody(factory string, args ...int) string { for i, nm := range names { params[nm] = args[i] } - return g.rewriteSplicedBody(g.inlineStackHelpers(lit.Body.List, params)) + return g.rewriteOpcodeReturns(g.inlineStackHelpers(lit.Body.List, params)) } // factoryClosure returns the executionFunc literal that a make* factory's body @@ -262,17 +271,17 @@ func (g *generator) renderAst(stmts []ast.Stmt) string { return raw.String() } -// rewriteSplicedBody rewrites a printed handler body so it runs inside the +// rewriteOpcodeReturns rewrites a printed handler body so it runs inside the // dispatch loop: the `*pc` dereference becomes the loop's `pc` local, and each // `return r0, r1` becomes loop control flow. Success (r1 == nil) advances pc // and continues, an error sets err and breaks. (Stack helpers were already // inlined by inlineStackHelpers before the body was printed.) -func (g *generator) rewriteSplicedBody(src string) string { +func (g *generator) rewriteOpcodeReturns(src string) string { src = strings.ReplaceAll(src, "*pc", "pc") var out bytes.Buffer for _, line := range strings.Split(src, "\n") { - if m := returnRe.FindStringSubmatch(line); m != nil { + if m := opcodeReturnRe.FindStringSubmatch(line); m != nil { indent, r0, r1 := m[1], strings.TrimSpace(m[2]), strings.TrimSpace(m[3]) // The error and halt path must overwrite res and err. Otherwise a // halting inlined op (JUMPI on an invalid jump, say) returns stale @@ -297,6 +306,50 @@ func (g *generator) rewriteSplicedBody(src string) string { return out.String() } +var gasReturnRe = regexp.MustCompile(`^(\s*)return\s+(\S.*)$`) + +// inlineGasBody splices a (g *GasBudget) charge method's body at a gas step, +// mapping the receiver to contract.Gas and the method's single uint64 parameter +// to the per-opcode gas constant. It is the gas-step analog of inlineOpcodeBody: the +// method's `return ` becomes the loop's out-of-gas exit and its trailing +// `return nil` is dropped so the opcode falls through to its remaining steps (see +// rewriteGasReturns). The receiver and parameter are substituted textually on +// word boundaries, which cannot touch fields like RegularGas. +func (g *generator) inlineGasBody(name string, arg int) string { + fn := g.gasHelpers[name] + if fn == nil { + fatalf("no gas helper %q to inline", name) + } + names := paramNames(fn) + if len(names) != 1 { + fatalf("gas helper %q takes %d params, want 1", name, len(names)) + } + src := g.renderAst(fn.Body.List) + src = regexp.MustCompile(`\b`+recvName(fn)+`\b`).ReplaceAllString(src, "contract.Gas") + src = substParams(src, map[string]int{names[0]: arg}) + return g.rewriteGasReturns(src) +} + +// rewriteGasReturns rewrites a spliced charge body so it runs as a gas step in +// the dispatch loop: a `return ` becomes the out-of-gas break, and the +// trailing `return nil` (success) is dropped so the opcode continues. +func (g *generator) rewriteGasReturns(src string) string { + var out bytes.Buffer + for _, line := range strings.Split(src, "\n") { + if m := gasReturnRe.FindStringSubmatch(line); m != nil { + indent, val := m[1], strings.TrimSpace(m[2]) + if val == "nil" { + continue // success: fall through to the rest of the op + } + out.WriteString(indent + "res, err = nil, " + val + "\n") + out.WriteString(indent + "break mainLoop\n") + continue + } + out.WriteString(line + "\n") + } + return out.String() +} + // stackCall is a matched call to a tagged helper. type stackCall struct { helper string // helper method name @@ -506,7 +559,7 @@ func (g *generator) deriveSpecs(forks []vm.GenFork) { g.specs[code] = opSpec{ defined: true, name: o.Name, - introF: fork.RuleField, + fork: fork.RuleField, constGas: o.ConstantGas, minStack: o.MinStack, maxStack: o.MaxStack, @@ -517,13 +570,13 @@ func (g *generator) deriveSpecs(forks []vm.GenFork) { // Sanity: every inlined opcode must be defined and have fork-stable static // gas / stack bounds across all forks where it appears (that is what makes // it safe to bake as a constant). Bail loudly otherwise. - for code, handler := range inlineHandler { + for code, handler := range inlineOps { g.checkStable(code, handler, forks) } - // directCall opcodes bake their static gas and stack bounds the same way, so + // directCallOps opcodes bake their static gas and stack bounds the same way, so // they must be fork-stable too. Dynamic gas is allowed (it is charged through // the named gas function, not baked). - for code := range directCall { + for code := range directCallOps { g.checkDirectCallStable(code, forks) } } @@ -544,17 +597,17 @@ func (g *generator) checkStable(code byte, what string, forks []vm.GenFork) { } } -// checkDirectCallStable verifies a directCall opcode is safe to direct-call. Its static +// checkDirectCallStable verifies a directCallOps opcode is safe to direct-call. Its static // gas and stack bounds must be the same across every fork it appears in (they are // baked as constants), and its handler, gas and memory functions must be the same // across those forks too (they are called by name, so a fork that swapped one // would otherwise be missed). Unlike checkStable it allows dynamic gas, which -// directCall ops carry by definition. It does not check the directCall map's names +// directCallOps ops carry by definition. It does not check the directCallOps map's names // against the table, which the differential test covers. func (g *generator) checkDirectCallStable(code byte, forks []vm.GenFork) { spec := g.specs[code] if !spec.defined { - fatalf("opcode %#x (directCall) is never defined", code) + fatalf("opcode %#x (directCallOps) is never defined", code) } var exec, dyn, mem string seen := false @@ -564,7 +617,7 @@ func (g *generator) checkDirectCallStable(code byte, forks []vm.GenFork) { continue } if o.ConstantGas != spec.constGas || o.MinStack != spec.minStack || o.MaxStack != spec.maxStack { - fatalf("opcode %#x (%s) is in directCall but not fork-stable (fork %s): static gas or stack bounds vary, cannot bake", code, spec.name, fork.Name) + fatalf("opcode %#x (%s) is in directCallOps but not fork-stable (fork %s): static gas or stack bounds vary, cannot bake", code, spec.name, fork.Name) } // Handler, gas and memory functions must match across forks too, or // direct-calling them by name would skip a fork that swapped one. Names @@ -573,7 +626,7 @@ func (g *generator) checkDirectCallStable(code byte, forks []vm.GenFork) { if !seen { exec, dyn, mem, seen = o.ExecuteFn, o.DynamicGasFn, o.MemorySizeFn, true } else if o.ExecuteFn != exec || o.DynamicGasFn != dyn || o.MemorySizeFn != mem { - fatalf("opcode %#x (%s) is in directCall but its functions vary by fork (fork %s): got %s/%s/%s, want %s/%s/%s, cannot direct-call", + fatalf("opcode %#x (%s) is in directCallOps but its functions vary by fork (fork %s): got %s/%s/%s, want %s/%s/%s, cannot direct-call", code, spec.name, fork.Name, o.ExecuteFn, o.DynamicGasFn, o.MemorySizeFn, exec, dyn, mem) } } @@ -616,12 +669,7 @@ func (g *generator) emitGasCheck(spec opSpec) { if spec.constGas == 0 { return } - g.p(` - if contract.Gas.RegularGas < %d { - return nil, ErrOutOfGas - } - contract.Gas.RegularGas -= %d - `, spec.constGas, spec.constGas) + g.p("%s", g.inlineGasBody("chargeRegularOnly", int(spec.constGas))) } // emitOpBody emits the stack/gas guards and the opcode body (the portion that runs @@ -647,27 +695,27 @@ func (g *generator) emitOpBody(code byte) { `) } - switch h := inlineHandler[code]; h { + switch h := inlineOps[code]; h { case "makePush": // PUSH3-PUSH32: splice makePush(size, size) n := int(code) - 0x5f - g.p("%s", g.inlineFactoryBody("makePush", n, n)) + g.p("%s", g.inlineOpcodeFactoryBody("makePush", n, n)) case "makeDup": // DUP1-DUP16: splice makeDup(n) - g.p("%s", g.inlineFactoryBody("makeDup", int(code)-0x7f)) + g.p("%s", g.inlineOpcodeFactoryBody("makeDup", int(code)-0x7f)) default: // the rest: splice the opXxx handler body - g.p("%s", g.inlineBody(h)) + g.p("%s", g.inlineOpcodeBody(h)) } } func (g *generator) emitInlineOp(code byte) { spec := g.specs[code] g.p("case %s:\n", spec.name) - if spec.introF == "" { + if spec.fork == "" { g.emitOpBody(code) return } // Fork-gated: run the inlined body only when the opcode is active for the // current fork. Otherwise mirror the legacy loop's undefined-opcode handling. - g.p("if rules.%s {\n", spec.introF) + g.p("if rules.%s {\n", spec.fork) g.emitOpBody(code) g.p("}\n") g.p(` @@ -679,10 +727,10 @@ func (g *generator) emitInlineOp(code byte) { // 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 -// fork-invariant ops (see directCall). +// fork-invariant ops (see directCallOps). func (g *generator) emitDirectCallOp(code byte) { spec := g.specs[code] - fns := directCall[code] + fns := directCallOps[code] g.p("case %s:\n", spec.name) g.emitStackChecks(spec) g.emitGasCheck(spec) @@ -706,10 +754,13 @@ func (g *generator) emitDirectCallOp(code byte) { if err != nil { return nil, fmt.Errorf("%%w: %%v", ErrOutOfGas, err) } - if contract.Gas.RegularGas < dynamicCost.RegularGas { + 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 } - contract.Gas.RegularGas -= dynamicCost.RegularGas if memorySize > 0 { mem.Resize(memorySize) } @@ -735,10 +786,9 @@ func (g *generator) emitDefault() { return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack} } cost := operation.constantGas - if contract.Gas.RegularGas < cost { - return nil, ErrOutOfGas + if err := contract.Gas.chargeRegularOnly(cost); err != nil { + return nil, err } - contract.Gas.RegularGas -= cost var memorySize uint64 if operation.dynamicGas != nil { if operation.memorySize != nil { @@ -755,10 +805,13 @@ func (g *generator) emitDefault() { if err != nil { return nil, fmt.Errorf("%%w: %%v", ErrOutOfGas, err) } - if contract.Gas.RegularGas < dynamicCost.RegularGas { + 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 } - contract.Gas.RegularGas -= dynamicCost.RegularGas } if memorySize > 0 { mem.Resize(memorySize) @@ -829,9 +882,9 @@ func (g *generator) emitFile() { // Inlined cases, in opcode order for readability. for code := 0; code < 256; code++ { b := byte(code) - if _, named := inlineHandler[b]; named { + if _, named := inlineOps[b]; named { g.emitInlineOp(b) - } else if _, dc := directCall[b]; dc { + } else if _, dc := directCallOps[b]; dc { g.emitDirectCallOp(b) } } @@ -857,8 +910,8 @@ func main() { } vmDir := filepath.Dir(filepath.Dir(self)) // .../core/vm/gen -> .../core/vm - fset, handlers, stackHelpers := parseHandlers(vmDir) - g := &generator{fset: fset, handlers: handlers, stackHelpers: stackHelpers, buf: new(bytes.Buffer)} + fset, handlers, stackHelpers, gasHelpers := parseHandlers(vmDir) + g := &generator{fset: fset, handlers: handlers, stackHelpers: stackHelpers, gasHelpers: gasHelpers, buf: new(bytes.Buffer)} g.deriveSpecs(vm.GenForks()) g.emitFile() diff --git a/core/vm/interp_gen.go b/core/vm/interp_gen.go index 2161ad67bc..3a8cd501cc 100644 --- a/core/vm/interp_gen.go +++ b/core/vm/interp_gen.go @@ -47,9 +47,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.top-- stack.size-- x := &stack.inner.data[stack.inner.top] @@ -63,9 +66,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 5 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 5 + contract.Gas.UsedRegularGas += 5 + stack.inner.top-- stack.size-- x := &stack.inner.data[stack.inner.top] @@ -79,9 +85,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.top-- stack.size-- x := &stack.inner.data[stack.inner.top] @@ -95,9 +104,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 5 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 5 + contract.Gas.UsedRegularGas += 5 + stack.inner.top-- stack.size-- x := &stack.inner.data[stack.inner.top] @@ -111,9 +123,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 5 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 5 + contract.Gas.UsedRegularGas += 5 + stack.inner.top-- stack.size-- x := &stack.inner.data[stack.inner.top] @@ -127,9 +142,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 5 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 5 + contract.Gas.UsedRegularGas += 5 + stack.inner.top-- stack.size-- x := &stack.inner.data[stack.inner.top] @@ -143,9 +161,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 5 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 5 + contract.Gas.UsedRegularGas += 5 + stack.inner.top-- stack.size-- x := &stack.inner.data[stack.inner.top] @@ -159,9 +180,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 3} } if contract.Gas.RegularGas < 8 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 8 + contract.Gas.UsedRegularGas += 8 + stack.inner.top -= 2 stack.size -= 2 x := &stack.inner.data[stack.inner.top+1] @@ -176,9 +200,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 3} } if contract.Gas.RegularGas < 8 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 8 + contract.Gas.UsedRegularGas += 8 + stack.inner.top -= 2 stack.size -= 2 x := &stack.inner.data[stack.inner.top+1] @@ -193,9 +220,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 5 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 5 + contract.Gas.UsedRegularGas += 5 + stack.inner.top-- stack.size-- back := &stack.inner.data[stack.inner.top] @@ -209,9 +239,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.top-- stack.size-- x := &stack.inner.data[stack.inner.top] @@ -229,9 +262,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.top-- stack.size-- x := &stack.inner.data[stack.inner.top] @@ -249,9 +285,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.top-- stack.size-- x := &stack.inner.data[stack.inner.top] @@ -269,9 +308,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.top-- stack.size-- x := &stack.inner.data[stack.inner.top] @@ -289,9 +331,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.top-- stack.size-- x := &stack.inner.data[stack.inner.top] @@ -309,9 +354,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 1} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + x := scope.Stack.peek() if x.IsZero() { x.SetOne() @@ -326,9 +374,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.top-- stack.size-- x := &stack.inner.data[stack.inner.top] @@ -342,9 +393,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.top-- stack.size-- x := &stack.inner.data[stack.inner.top] @@ -358,9 +412,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.top-- stack.size-- x := &stack.inner.data[stack.inner.top] @@ -374,9 +431,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 1} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + x := scope.Stack.peek() x.Not(x) pc++ @@ -387,9 +447,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.top-- stack.size-- th := &stack.inner.data[stack.inner.top] @@ -404,9 +467,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.top-- stack.size-- shift := &stack.inner.data[stack.inner.top] @@ -428,9 +494,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.top-- stack.size-- shift := &stack.inner.data[stack.inner.top] @@ -452,9 +521,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.top-- stack.size-- shift := &stack.inner.data[stack.inner.top] @@ -483,9 +555,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 1} } if contract.Gas.RegularGas < 5 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 5 + contract.Gas.UsedRegularGas += 5 + x := scope.Stack.peek() x.SetUint64(256 - uint64(x.BitLen())) pc++ @@ -499,9 +574,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 30 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 30 + contract.Gas.UsedRegularGas += 30 + var memorySize uint64 { memSize, overflow := memoryKeccak256(stack) @@ -517,10 +595,13 @@ mainLoop: if err != nil { return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err) } - if contract.Gas.RegularGas < dynamicCost.RegularGas { + 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 } - contract.Gas.RegularGas -= dynamicCost.RegularGas if memorySize > 0 { mem.Resize(memorySize) } @@ -535,9 +616,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 1} } if contract.Gas.RegularGas < 2 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 2 + contract.Gas.UsedRegularGas += 2 + scope.Stack.drop() pc++ continue mainLoop @@ -547,9 +631,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 1} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + var memorySize uint64 { memSize, overflow := memoryMLoad(stack) @@ -565,10 +652,13 @@ mainLoop: if err != nil { return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err) } - if contract.Gas.RegularGas < dynamicCost.RegularGas { + 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 } - contract.Gas.RegularGas -= dynamicCost.RegularGas if memorySize > 0 { mem.Resize(memorySize) } @@ -583,9 +673,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + var memorySize uint64 { memSize, overflow := memoryMStore(stack) @@ -601,10 +694,13 @@ mainLoop: if err != nil { return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err) } - if contract.Gas.RegularGas < dynamicCost.RegularGas { + 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 } - contract.Gas.RegularGas -= dynamicCost.RegularGas if memorySize > 0 { mem.Resize(memorySize) } @@ -619,9 +715,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + var memorySize uint64 { memSize, overflow := memoryMStore8(stack) @@ -637,10 +736,13 @@ mainLoop: if err != nil { return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err) } - if contract.Gas.RegularGas < dynamicCost.RegularGas { + 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 } - contract.Gas.RegularGas -= dynamicCost.RegularGas if memorySize > 0 { mem.Resize(memorySize) } @@ -655,9 +757,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 1} } if contract.Gas.RegularGas < 8 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 8 + contract.Gas.UsedRegularGas += 8 + if evm.abort.Load() { res, err = nil, errStopToken break mainLoop @@ -676,9 +781,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 10 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 10 + contract.Gas.UsedRegularGas += 10 + if evm.abort.Load() { res, err = nil, errStopToken break mainLoop @@ -702,9 +810,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 2 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 2 + contract.Gas.UsedRegularGas += 2 + stack.inner.top++ stack.size++ elem := &stack.inner.data[stack.inner.top-1] @@ -717,9 +828,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 2 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 2 + contract.Gas.UsedRegularGas += 2 + stack.inner.top++ stack.size++ elem := &stack.inner.data[stack.inner.top-1] @@ -729,9 +843,12 @@ mainLoop: case JUMPDEST: if contract.Gas.RegularGas < 1 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 1 + contract.Gas.UsedRegularGas += 1 + pc++ continue mainLoop @@ -741,9 +858,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 2 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 2 + contract.Gas.UsedRegularGas += 2 + stack.inner.top++ stack.size++ elem := &stack.inner.data[stack.inner.top-1] @@ -759,9 +879,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -788,9 +911,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -819,9 +945,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -851,9 +980,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -883,9 +1015,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -915,9 +1050,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -947,9 +1085,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -979,9 +1120,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1011,9 +1155,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1043,9 +1190,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1075,9 +1225,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1107,9 +1260,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1139,9 +1295,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1171,9 +1330,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1203,9 +1365,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1235,9 +1400,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1267,9 +1435,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1299,9 +1470,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1331,9 +1505,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1363,9 +1540,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1395,9 +1575,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1427,9 +1610,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1459,9 +1645,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1491,9 +1680,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1523,9 +1715,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1555,9 +1750,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1587,9 +1785,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1619,9 +1820,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1651,9 +1855,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1683,9 +1890,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1715,9 +1925,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1747,9 +1960,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + if isEIP4762 { res, err = table[op].execute(&pc, evm, scope) if err != nil { @@ -1781,9 +1997,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-1] stack.size++ stack.inner.top++ @@ -1797,9 +2016,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-2] stack.size++ stack.inner.top++ @@ -1813,9 +2035,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-3] stack.size++ stack.inner.top++ @@ -1829,9 +2054,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-4] stack.size++ stack.inner.top++ @@ -1845,9 +2073,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-5] stack.size++ stack.inner.top++ @@ -1861,9 +2092,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-6] stack.size++ stack.inner.top++ @@ -1877,9 +2111,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-7] stack.size++ stack.inner.top++ @@ -1893,9 +2130,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-8] stack.size++ stack.inner.top++ @@ -1909,9 +2149,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-9] stack.size++ stack.inner.top++ @@ -1925,9 +2168,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-10] stack.size++ stack.inner.top++ @@ -1941,9 +2187,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-11] stack.size++ stack.inner.top++ @@ -1957,9 +2206,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-12] stack.size++ stack.inner.top++ @@ -1973,9 +2225,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-13] stack.size++ stack.inner.top++ @@ -1989,9 +2244,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-14] stack.size++ stack.inner.top++ @@ -2005,9 +2263,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-15] stack.size++ stack.inner.top++ @@ -2021,9 +2282,12 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: 1023} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size] = stack.inner.data[stack.bottom+stack.size-16] stack.size++ stack.inner.top++ @@ -2035,9 +2299,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 2} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-2], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-2] pc++ continue mainLoop @@ -2047,9 +2314,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 3} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-3], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-3] pc++ continue mainLoop @@ -2059,9 +2329,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 4} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-4], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-4] pc++ continue mainLoop @@ -2071,9 +2344,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 5} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-5], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-5] pc++ continue mainLoop @@ -2083,9 +2359,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 6} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-6], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-6] pc++ continue mainLoop @@ -2095,9 +2374,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 7} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-7], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-7] pc++ continue mainLoop @@ -2107,9 +2389,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 8} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-8], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-8] pc++ continue mainLoop @@ -2119,9 +2404,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 9} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-9], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-9] pc++ continue mainLoop @@ -2131,9 +2419,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 10} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-10], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-10] pc++ continue mainLoop @@ -2143,9 +2434,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 11} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-11], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-11] pc++ continue mainLoop @@ -2155,9 +2449,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 12} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-12], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-12] pc++ continue mainLoop @@ -2167,9 +2464,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 13} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-13], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-13] pc++ continue mainLoop @@ -2179,9 +2479,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 14} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-14], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-14] pc++ continue mainLoop @@ -2191,9 +2494,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 15} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-15], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-15] pc++ continue mainLoop @@ -2203,9 +2509,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 16} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-16], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-16] pc++ continue mainLoop @@ -2215,9 +2524,12 @@ mainLoop: return nil, &ErrStackUnderflow{stackLen: sLen, required: 17} } if contract.Gas.RegularGas < 3 { - return nil, ErrOutOfGas + res, err = nil, ErrOutOfGas + break mainLoop } contract.Gas.RegularGas -= 3 + contract.Gas.UsedRegularGas += 3 + stack.inner.data[stack.bottom+stack.size-17], stack.inner.data[stack.bottom+stack.size-1] = stack.inner.data[stack.bottom+stack.size-1], stack.inner.data[stack.bottom+stack.size-17] pc++ continue mainLoop @@ -2230,10 +2542,9 @@ mainLoop: return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack} } cost := operation.constantGas - if contract.Gas.RegularGas < cost { - return nil, ErrOutOfGas + if err := contract.Gas.chargeRegularOnly(cost); err != nil { + return nil, err } - contract.Gas.RegularGas -= cost var memorySize uint64 if operation.dynamicGas != nil { if operation.memorySize != nil { @@ -2250,10 +2561,13 @@ mainLoop: if err != nil { return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err) } - if contract.Gas.RegularGas < dynamicCost.RegularGas { + 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 } - contract.Gas.RegularGas -= dynamicCost.RegularGas } if memorySize > 0 { mem.Resize(memorySize) diff --git a/core/vm/interp_gen_test.go b/core/vm/interp_gen_test.go index 119faba910..5ca2039e31 100644 --- a/core/vm/interp_gen_test.go +++ b/core/vm/interp_gen_test.go @@ -103,6 +103,14 @@ var diffForks = func() []struct { preCon.ArrowGlacierBlock = nil preCon.GrayGlacierBlock = nil + // amsterdam: Merged plus the Amsterdam (EIP-8037) timestamp, so the diff test + // exercises the multidimensional gas accounting (regular + state gas). Without + // this lane a state-gas charging divergence between the two interpreters would + // go unnoticed. + ams := *params.MergedTestChainConfig + amsTime := uint64(0) + ams.AmsterdamTime = &amsTime + return []struct { name string cfg *params.ChainConfig @@ -112,6 +120,7 @@ var diffForks = func() []struct { {"Byzantium", &preCon, false}, {"London", params.TestChainConfig, false}, {"Merged", params.MergedTestChainConfig, true}, + {"Amsterdam", &ams, true}, } }() @@ -295,6 +304,9 @@ func diffBlockCtx(merged bool) BlockContext { GasLimit: 30_000_000, BaseFee: big.NewInt(7), BlobBaseFee: big.NewInt(3), + // Price state gas as mainnet does (see core.NewEVMBlockContext), so the + // Amsterdam diff lane exercises the EIP-8037 state-gas charging path. + CostPerStateByte: params.CostPerStateByte, } if merged { h := common.HexToHash("0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20") diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 4c0dd799dc..60d0888bd6 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -217,8 +217,8 @@ func (evm *EVM) execTraced(scope *ScopeContext) (ret []byte, err error) { return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack} } // for tracing: this gas consumption event is emitted below in the debug section. - if !contract.Gas.ChargeRegularOnly(cost) { - return nil, ErrOutOfGas + if err := contract.Gas.chargeRegularOnly(cost); err != nil { + return nil, err } // All ops with a dynamic memory usage also has a dynamic gas cost. @@ -248,8 +248,8 @@ func (evm *EVM) execTraced(scope *ScopeContext) (ret []byte, err error) { return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err) } if dynamicCost.StateGas == 0 { - if !contract.Gas.ChargeRegularOnly(dynamicCost.RegularGas) { - return nil, ErrOutOfGas + if err := contract.Gas.chargeRegularOnly(dynamicCost.RegularGas); err != nil { + return nil, err } } else if !contract.Gas.charge(dynamicCost) { return nil, ErrOutOfGas