diff --git a/core/vm/eips.go b/core/vm/eips.go index 7764bd20b6..edded2260e 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -18,7 +18,7 @@ package vm import ( "fmt" - "math" + stdmath "math" "sort" "github.com/ethereum/go-ethereum/common" @@ -352,7 +352,7 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC ) uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow() if overflow { - uint64CodeOffset = math.MaxUint64 + uint64CodeOffset = stdmath.MaxUint64 } addr := common.Address(a.Bytes20()) code := interpreter.evm.StateDB.GetCode(addr) diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index c7c1274bf2..1410d9dc9e 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -64,37 +64,43 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { // MCOPY (stack position 2) // EXTCODECOPY (stack position 3) // RETURNDATACOPY (stack position 2) -func memoryCopierGas(stackpos int) gasFunc { - return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - // Gas for expanding the memory - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - // And gas for copying data, charged per word at param.CopyGas - words, overflow := stack.Back(stackpos).Uint64WithOverflow() - if overflow { - return 0, ErrGasUintOverflow - } - - if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { - return 0, ErrGasUintOverflow - } - - if gas, overflow = math.SafeAdd(gas, words); overflow { - return 0, ErrGasUintOverflow - } - return gas, nil +func memoryCopierGas(stackpos int, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + // Gas for expanding the memory + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err } + // And gas for copying data, charged per word at param.CopyGas + words, overflow := stack.Back(stackpos).Uint64WithOverflow() + if overflow { + return 0, ErrGasUintOverflow + } + + if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { + return 0, ErrGasUintOverflow + } + + if gas, overflow = math.SafeAdd(gas, words); overflow { + return 0, ErrGasUintOverflow + } + return gas, nil } -var ( - gasCallDataCopy = memoryCopierGas(2) - gasCodeCopy = memoryCopierGas(2) - gasMcopy = memoryCopierGas(2) - gasExtCodeCopy = memoryCopierGas(3) - gasReturnDataCopy = memoryCopierGas(2) -) +func gasCallDataCopy(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return memoryCopierGas(2, evm, contract, stack, mem, memorySize) +} +func gasCodeCopy(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return memoryCopierGas(2, evm, contract, stack, mem, memorySize) +} +func gasMcopy(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return memoryCopierGas(2, evm, contract, stack, mem, memorySize) +} +func gasExtCodeCopy(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return memoryCopierGas(3, evm, contract, stack, mem, memorySize) +} +func gasReturnDataCopy(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return memoryCopierGas(2, evm, contract, stack, mem, memorySize) +} func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { var ( @@ -221,34 +227,48 @@ func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m return params.SloadGasEIP2200, nil // dirty update (2.2) } -func makeGasLog(n uint64) gasFunc { - return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - requestedSize, overflow := stack.Back(1).Uint64WithOverflow() - if overflow { - return 0, ErrGasUintOverflow - } - - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - - if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow { - return 0, ErrGasUintOverflow - } - if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow { - return 0, ErrGasUintOverflow - } - - var memorySizeGas uint64 - if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow { - return 0, ErrGasUintOverflow - } - if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow { - return 0, ErrGasUintOverflow - } - return gas, nil +func makeGasLog(n uint64, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + requestedSize, overflow := stack.Back(1).Uint64WithOverflow() + if overflow { + return 0, ErrGasUintOverflow } + + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + + if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow { + return 0, ErrGasUintOverflow + } + if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow { + return 0, ErrGasUintOverflow + } + + var memorySizeGas uint64 + if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow { + return 0, ErrGasUintOverflow + } + if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow { + return 0, ErrGasUintOverflow + } + return gas, nil +} + +func gasLog0(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return makeGasLog(0, evm, contract, stack, mem, memorySize) +} +func gasLog1(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return makeGasLog(1, evm, contract, stack, mem, memorySize) +} +func gasLog2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return makeGasLog(2, evm, contract, stack, mem, memorySize) +} +func gasLog3(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return makeGasLog(3, evm, contract, stack, mem, memorySize) +} +func gasLog4(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return makeGasLog(4, evm, contract, stack, mem, memorySize) } func gasKeccak256(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { diff --git a/core/vm/generator.go b/core/vm/generator.go new file mode 100644 index 0000000000..79664f848b --- /dev/null +++ b/core/vm/generator.go @@ -0,0 +1,217 @@ +package vm + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "io" + "os" + "reflect" + "runtime" + "strings" +) + +var fSet = token.NewFileSet() + +type opFuncNames struct { + memory string + gas string + execution string +} + +func functionName(f any) string { + fValue := reflect.ValueOf(f) + if fValue.IsNil() { + return "" + } + + rFunc := runtime.FuncForPC(fValue.Pointer()) + if rFunc == nil { + panic(fmt.Sprint(f, "is not a function")) + } + ident := rFunc.Name() + arr := strings.Split(ident, ".") + return arr[len(arr)-1] +} + +func collectFuncNames(jt JumpTable) [256]opFuncNames { + var funcNames [256]opFuncNames + for opCode, entry := range jt { + funcNames[opCode] = opFuncNames{ + memory: functionName(entry.memorySize), + gas: functionName(entry.dynamicGas), + execution: functionName(entry.execute), + } + } + return funcNames +} + +type funcDef struct { + decl *ast.FuncDecl + source string +} + +type opFuncDefs struct { + memory funcDef + gas funcDef + execution funcDef +} + +func definitionTargets(name string, funcNames *[256]opFuncNames, funcDefs *[256]opFuncDefs) []*funcDef { + targets := []*funcDef{} + for op := range funcNames { + if funcNames[op].memory == name { + targets = append(targets, &funcDefs[op].memory) + } + if funcNames[op].gas == name { + targets = append(targets, &funcDefs[op].gas) + } + if funcNames[op].execution == name { + targets = append(targets, &funcDefs[op].execution) + } + } + return targets +} + +func extractBody(funcDef string) string { + start := strings.Index(funcDef, "{") + end := strings.LastIndex(funcDef, "}") + return funcDef[start : end+1] +} + +func collectFuncDefinitions(funcNames [256]opFuncNames) [256]opFuncDefs { + pkgs, err := parser.ParseDir(fSet, ".", nil, 0) + if err != nil { + panic(fmt.Sprint("failed to parse vm package", err)) + } + vmPkg := pkgs["vm"] + if vmPkg == nil { + panic(fmt.Sprint("vm package not found")) + } + + var defs [256]opFuncDefs + for _, astFile := range vmPkg.Files { + f, err := os.Open(fSet.File(astFile.FileStart).Name()) + if err != nil { + panic(fmt.Sprint("failed to open file package", astFile.Name.Name, err)) + } + + for _, decl := range astFile.Decls { + if fDecl, isFunc := decl.(*ast.FuncDecl); isFunc { + defTargets := definitionTargets(fDecl.Name.Name, &funcNames, &defs) + if len(defTargets) == 0 { + continue + } + + declPos := fSet.Position(fDecl.Pos()) + declEndPos := fSet.Position(fDecl.End()) + declSize := declEndPos.Offset - declPos.Offset + + def := make([]byte, declSize) + _, err := f.ReadAt(def, int64(declPos.Offset)) + if err != nil && err != io.EOF { + panic(fmt.Sprint("failed to read function def", fDecl.Name.Name, err)) + } + + for _, defTarget := range defTargets { + (*defTarget) = funcDef{ + source: string(def), + decl: fDecl, + } + } + } + } + } + + return defs +} + +func outputMemoryCalc(w io.Writer, op *funcDef) { + fmt.Fprintf(w, ` + _memorySize, _overflow := func (stack *Stack) (uint64, bool) %s(callContext.Stack) + if _overflow { + return nil, ErrGasUintOverflow + } + `, extractBody(op.source)) +} + +func outputDynamicGas(w io.Writer, op *funcDef, hasDynamicMemory bool) { + dynamicMemory := "0" + if hasDynamicMemory { + dynamicMemory = "_memorySize" + } + fmt.Fprintf(w, ` + _dynamicGas, _gasErr := func (evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) %s(interpreter.evm, callContext.Contract, callContext.Stack, callContext.Memory, %s) + if _gasErr != nil { + return nil, ErrOutOfGas + } + if !callContext.Contract.UseGas(_dynamicGas, nil, tracing.GasChangeIgnored) { + return nil, ErrOutOfGas + } + + `, extractBody(op.source), dynamicMemory) + if hasDynamicMemory { + fmt.Fprintf(w, "callContext.Memory.Resize(_memorySize)\n") + } +} + +func outputExecution(w io.Writer, op *funcDef) { + fmt.Fprintf(w, ` + _, _executionErr := func (pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) %s(&pc, interpreter, callContext) + if _executionErr != nil { + return nil, _executionErr + } + `, extractBody(op.source)) +} + +func GenerateRun() { + set := newLondonInstructionSet() + funcNames := collectFuncNames(set) + funcDefinitions := collectFuncDefinitions(funcNames) + + output, _ := os.Create("out.go") + + fmt.Fprintln(output, `package vm + func Run(interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error) { + + var pc uint64 + for { + op := callContext.Contract.GetOp(pc) + switch op { + `) + for opCode := range funcDefinitions { + fmt.Fprintf(output, `case %d: + if !callContext.Contract.UseGas(%d, nil, tracing.GasChangeIgnored) { + return nil, ErrOutOfGas + } + + if sLen := callContext.Stack.len(); sLen < %d { + return nil, &ErrStackUnderflow{stackLen: sLen, required: %d} + } else if sLen > %d { + return nil, &ErrStackOverflow{stackLen: sLen, limit: %d} + } + `, opCode, set[opCode].constantGas, set[opCode].minStack, set[opCode].minStack, set[opCode].maxStack, set[opCode].maxStack) + if funcDefinitions[opCode].memory.decl != nil { + outputMemoryCalc(output, &funcDefinitions[opCode].memory) + } else if len(funcNames[opCode].memory) > 0 { + panic(fmt.Sprint("failed to get memory handler definition for ", opCodeToString[opCode])) + } + + if funcDefinitions[opCode].gas.decl != nil { + outputDynamicGas(output, &funcDefinitions[opCode].gas, funcDefinitions[opCode].memory.decl != nil) + } else if len(funcNames[opCode].gas) > 0 { + panic(fmt.Sprint("failed to get gas handler definition for ", opCodeToString[opCode])) + } + + if funcDefinitions[opCode].execution.decl != nil { + outputExecution(output, &funcDefinitions[opCode].execution) + } else if len(funcNames[opCode].execution) > 0 { + panic(fmt.Sprint("failed to get exec handler definition for ", opCodeToString[opCode])) + } + } + fmt.Fprintln(output, `} + pc++ + }}`) + output.Close() +} diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 63bb6d2d51..2ad931d887 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -17,7 +17,7 @@ package vm import ( - "math" + stdmath "math" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" @@ -296,7 +296,7 @@ func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext ) dataOffset64, overflow := dataOffset.Uint64WithOverflow() if overflow { - dataOffset64 = math.MaxUint64 + dataOffset64 = stdmath.MaxUint64 } // These values are checked for overflow during gas cost calculation memOffset64 := memOffset.Uint64() @@ -352,7 +352,7 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ ) uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow() if overflow { - uint64CodeOffset = math.MaxUint64 + uint64CodeOffset = stdmath.MaxUint64 } codeCopy := getData(scope.Contract.Code, uint64CodeOffset, length.Uint64()) @@ -370,7 +370,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ) uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow() if overflow { - uint64CodeOffset = math.MaxUint64 + uint64CodeOffset = stdmath.MaxUint64 } addr := common.Address(a.Bytes20()) code := interpreter.evm.StateDB.GetCode(addr) @@ -924,31 +924,45 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon // following functions are used by the instruction jump table // make log instruction function -func makeLog(size int) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.readOnly { - return nil, ErrWriteProtection - } - topics := make([]common.Hash, size) - stack := scope.Stack - mStart, mSize := stack.pop(), stack.pop() - for i := 0; i < size; i++ { - addr := stack.pop() - topics[i] = addr.Bytes32() - } - - d := scope.Memory.GetCopy(mStart.Uint64(), mSize.Uint64()) - interpreter.evm.StateDB.AddLog(&types.Log{ - Address: scope.Contract.Address(), - Topics: topics, - Data: d, - // This is a non-consensus field, but assigned here because - // core/state doesn't know the current block number. - BlockNumber: interpreter.evm.Context.BlockNumber.Uint64(), - }) - - return nil, nil +func doLog(size int, pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + if interpreter.readOnly { + return nil, ErrWriteProtection } + topics := make([]common.Hash, size) + stack := scope.Stack + mStart, mSize := stack.pop(), stack.pop() + for i := 0; i < size; i++ { + addr := stack.pop() + topics[i] = addr.Bytes32() + } + + d := scope.Memory.GetCopy(mStart.Uint64(), mSize.Uint64()) + interpreter.evm.StateDB.AddLog(&types.Log{ + Address: scope.Contract.Address(), + Topics: topics, + Data: d, + // This is a non-consensus field, but assigned here because + // core/state doesn't know the current block number. + BlockNumber: interpreter.evm.Context.BlockNumber.Uint64(), + }) + + return nil, nil +} + +func opLog0(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doLog(0, pc, interpreter, scope) +} +func opLog1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doLog(1, pc, interpreter, scope) +} +func opLog2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doLog(2, pc, interpreter, scope) +} +func opLog3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doLog(3, pc, interpreter, scope) +} +func opLog4(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doLog(4, pc, interpreter, scope) } // opPush1 is a specialized version of pushN @@ -983,30 +997,176 @@ func opPush2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by return nil, nil } -// make push instruction function -func makePush(size uint64, pushByteSize int) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - var ( - codeLen = len(scope.Contract.Code) - start = min(codeLen, int(*pc+1)) - end = min(codeLen, start+pushByteSize) - ) - a := new(uint256.Int).SetBytes(scope.Contract.Code[start:end]) +func doPush(size uint64, pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + var ( + pushByteSize = int(size) + codeLen = len(scope.Contract.Code) + start = min(codeLen, int(*pc+1)) + end = min(codeLen, start+pushByteSize) + ) + a := new(uint256.Int).SetBytes(scope.Contract.Code[start:end]) - // Missing bytes: pushByteSize - len(pushData) - if missing := pushByteSize - (end - start); missing > 0 { - a.Lsh(a, uint(8*missing)) - } - scope.Stack.push(a) - *pc += size - return nil, nil + // Missing bytes: pushByteSize - len(pushData) + if missing := pushByteSize - (end - start); missing > 0 { + a.Lsh(a, uint(8*missing)) } + scope.Stack.push(a) + *pc += size + return nil, nil } -// make dup instruction function -func makeDup(size int64) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - scope.Stack.dup(int(size)) - return nil, nil - } +func opPush3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(3, pc, interpreter, scope) +} +func opPush4(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(4, pc, interpreter, scope) +} +func opPush5(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(5, pc, interpreter, scope) +} +func opPush6(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(6, pc, interpreter, scope) +} +func opPush7(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(7, pc, interpreter, scope) +} +func opPush8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(8, pc, interpreter, scope) +} +func opPush9(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(9, pc, interpreter, scope) +} +func opPush10(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(10, pc, interpreter, scope) +} +func opPush11(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(11, pc, interpreter, scope) +} +func opPush12(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(12, pc, interpreter, scope) +} +func opPush13(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(13, pc, interpreter, scope) +} +func opPush14(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(14, pc, interpreter, scope) +} +func opPush15(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(15, pc, interpreter, scope) +} +func opPush16(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(16, pc, interpreter, scope) +} +func opPush17(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(17, pc, interpreter, scope) +} +func opPush18(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(18, pc, interpreter, scope) +} +func opPush19(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(19, pc, interpreter, scope) +} +func opPush20(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(20, pc, interpreter, scope) +} +func opPush21(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(21, pc, interpreter, scope) +} +func opPush22(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(22, pc, interpreter, scope) +} +func opPush23(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(23, pc, interpreter, scope) +} +func opPush24(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(24, pc, interpreter, scope) +} +func opPush25(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(25, pc, interpreter, scope) +} +func opPush26(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(26, pc, interpreter, scope) +} +func opPush27(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(27, pc, interpreter, scope) +} +func opPush28(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(28, pc, interpreter, scope) +} +func opPush29(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(29, pc, interpreter, scope) +} +func opPush30(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(30, pc, interpreter, scope) +} +func opPush31(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(31, pc, interpreter, scope) +} +func opPush32(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return doPush(32, pc, interpreter, scope) +} + +func opDup1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(1) + return nil, nil +} +func opDup2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(2) + return nil, nil +} +func opDup3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(3) + return nil, nil +} +func opDup4(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(4) + return nil, nil +} +func opDup5(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(5) + return nil, nil +} +func opDup6(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(6) + return nil, nil +} +func opDup7(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(7) + return nil, nil +} +func opDup8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(8) + return nil, nil +} +func opDup9(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(9) + return nil, nil +} +func opDup10(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(10) + return nil, nil +} +func opDup11(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(11) + return nil, nil +} +func opDup12(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(12) + return nil, nil +} +func opDup13(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(13) + return nil, nil +} +func opDup14(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(14) + return nil, nil +} +func opDup15(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(15) + return nil, nil +} +func opDup16(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + scope.Stack.dup(16) + return nil, nil } diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 8a82de5d8b..60ac61fe23 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -906,7 +906,7 @@ func TestOpMCopy(t *testing.T) { func TestPush(t *testing.T) { code := common.FromHex("0011223344556677889900aabbccddeeff0102030405060708090a0b0c0d0e0ff1e1d1c1b1a19181716151413121") - push32 := makePush(32, 32) + push32 := opPush32 scope := &ScopeContext{ Memory: nil, diff --git a/core/vm/interpreter_test.go b/core/vm/interpreter_test.go index 8ed512316b..4d1abe3c03 100644 --- a/core/vm/interpreter_test.go +++ b/core/vm/interpreter_test.go @@ -88,7 +88,6 @@ func BenchmarkInterpreter(b *testing.B) { ) stack.push(uint256.NewInt(123)) stack.push(uint256.NewInt(123)) - gasSStoreEIP3529 = makeGasSStoreFunc(params.SstoreClearsScheduleRefundEIP3529) b.ResetTimer() for i := 0; i < b.N; i++ { gasSStoreEIP3529(evm, contract, stack, mem, 1234) diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 22eed8754f..920a8a43e8 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -633,277 +633,277 @@ func newFrontierInstructionSet() JumpTable { maxStack: maxStack(0, 1), }, PUSH3: { - execute: makePush(3, 3), + execute: opPush3, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH4: { - execute: makePush(4, 4), + execute: opPush4, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH5: { - execute: makePush(5, 5), + execute: opPush5, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH6: { - execute: makePush(6, 6), + execute: opPush6, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH7: { - execute: makePush(7, 7), + execute: opPush7, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH8: { - execute: makePush(8, 8), + execute: opPush8, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH9: { - execute: makePush(9, 9), + execute: opPush9, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH10: { - execute: makePush(10, 10), + execute: opPush10, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH11: { - execute: makePush(11, 11), + execute: opPush11, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH12: { - execute: makePush(12, 12), + execute: opPush12, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH13: { - execute: makePush(13, 13), + execute: opPush13, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH14: { - execute: makePush(14, 14), + execute: opPush14, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH15: { - execute: makePush(15, 15), + execute: opPush15, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH16: { - execute: makePush(16, 16), + execute: opPush16, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH17: { - execute: makePush(17, 17), + execute: opPush17, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH18: { - execute: makePush(18, 18), + execute: opPush18, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH19: { - execute: makePush(19, 19), + execute: opPush19, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH20: { - execute: makePush(20, 20), + execute: opPush20, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH21: { - execute: makePush(21, 21), + execute: opPush21, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH22: { - execute: makePush(22, 22), + execute: opPush22, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH23: { - execute: makePush(23, 23), + execute: opPush23, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH24: { - execute: makePush(24, 24), + execute: opPush24, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH25: { - execute: makePush(25, 25), + execute: opPush25, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH26: { - execute: makePush(26, 26), + execute: opPush26, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH27: { - execute: makePush(27, 27), + execute: opPush27, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH28: { - execute: makePush(28, 28), + execute: opPush28, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH29: { - execute: makePush(29, 29), + execute: opPush29, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH30: { - execute: makePush(30, 30), + execute: opPush30, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH31: { - execute: makePush(31, 31), + execute: opPush31, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, PUSH32: { - execute: makePush(32, 32), + execute: opPush32, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), }, DUP1: { - execute: makeDup(1), + execute: opDup1, constantGas: GasFastestStep, minStack: minDupStack(1), maxStack: maxDupStack(1), }, DUP2: { - execute: makeDup(2), + execute: opDup2, constantGas: GasFastestStep, minStack: minDupStack(2), maxStack: maxDupStack(2), }, DUP3: { - execute: makeDup(3), + execute: opDup3, constantGas: GasFastestStep, minStack: minDupStack(3), maxStack: maxDupStack(3), }, DUP4: { - execute: makeDup(4), + execute: opDup4, constantGas: GasFastestStep, minStack: minDupStack(4), maxStack: maxDupStack(4), }, DUP5: { - execute: makeDup(5), + execute: opDup5, constantGas: GasFastestStep, minStack: minDupStack(5), maxStack: maxDupStack(5), }, DUP6: { - execute: makeDup(6), + execute: opDup6, constantGas: GasFastestStep, minStack: minDupStack(6), maxStack: maxDupStack(6), }, DUP7: { - execute: makeDup(7), + execute: opDup7, constantGas: GasFastestStep, minStack: minDupStack(7), maxStack: maxDupStack(7), }, DUP8: { - execute: makeDup(8), + execute: opDup8, constantGas: GasFastestStep, minStack: minDupStack(8), maxStack: maxDupStack(8), }, DUP9: { - execute: makeDup(9), + execute: opDup9, constantGas: GasFastestStep, minStack: minDupStack(9), maxStack: maxDupStack(9), }, DUP10: { - execute: makeDup(10), + execute: opDup10, constantGas: GasFastestStep, minStack: minDupStack(10), maxStack: maxDupStack(10), }, DUP11: { - execute: makeDup(11), + execute: opDup11, constantGas: GasFastestStep, minStack: minDupStack(11), maxStack: maxDupStack(11), }, DUP12: { - execute: makeDup(12), + execute: opDup12, constantGas: GasFastestStep, minStack: minDupStack(12), maxStack: maxDupStack(12), }, DUP13: { - execute: makeDup(13), + execute: opDup13, constantGas: GasFastestStep, minStack: minDupStack(13), maxStack: maxDupStack(13), }, DUP14: { - execute: makeDup(14), + execute: opDup14, constantGas: GasFastestStep, minStack: minDupStack(14), maxStack: maxDupStack(14), }, DUP15: { - execute: makeDup(15), + execute: opDup15, constantGas: GasFastestStep, minStack: minDupStack(15), maxStack: maxDupStack(15), }, DUP16: { - execute: makeDup(16), + execute: opDup16, constantGas: GasFastestStep, minStack: minDupStack(16), maxStack: maxDupStack(16), @@ -1005,36 +1005,36 @@ func newFrontierInstructionSet() JumpTable { maxStack: maxSwapStack(17), }, LOG0: { - execute: makeLog(0), - dynamicGas: makeGasLog(0), + execute: opLog0, + dynamicGas: gasLog0, minStack: minStack(2, 0), maxStack: maxStack(2, 0), memorySize: memoryLog, }, LOG1: { - execute: makeLog(1), - dynamicGas: makeGasLog(1), + execute: opLog1, + dynamicGas: gasLog1, minStack: minStack(3, 0), maxStack: maxStack(3, 0), memorySize: memoryLog, }, LOG2: { - execute: makeLog(2), - dynamicGas: makeGasLog(2), + execute: opLog2, + dynamicGas: gasLog2, minStack: minStack(4, 0), maxStack: maxStack(4, 0), memorySize: memoryLog, }, LOG3: { - execute: makeLog(3), - dynamicGas: makeGasLog(3), + execute: opLog3, + dynamicGas: gasLog3, minStack: minStack(5, 0), maxStack: maxStack(5, 0), memorySize: memoryLog, }, LOG4: { - execute: makeLog(4), - dynamicGas: makeGasLog(4), + execute: opLog4, + dynamicGas: gasLog4, minStack: minStack(6, 0), maxStack: maxStack(6, 0), memorySize: memoryLog, diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index 085b018e4c..092a83ffb9 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -26,68 +26,66 @@ import ( "github.com/ethereum/go-ethereum/params" ) -func makeGasSStoreFunc(clearingRefund uint64) gasFunc { - return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - // If we fail the minimum gas availability invariant, fail (0) - if contract.Gas <= params.SstoreSentryGasEIP2200 { - return 0, errors.New("not enough gas for reentrancy sentry") - } - // Gas sentry honoured, do the actual gas calculation based on the stored value - var ( - y, x = stack.Back(1), stack.peek() - slot = common.Hash(x.Bytes32()) - current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), slot) - cost = uint64(0) - ) - // Check slot presence in the access list - if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent { - cost = params.ColdSloadCostEIP2929 - // If the caller cannot afford the cost, this change will be rolled back - evm.StateDB.AddSlotToAccessList(contract.Address(), slot) - } - value := common.Hash(y.Bytes32()) +func gasSStoreFuncEIP(clearingRefund uint64, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + // If we fail the minimum gas availability invariant, fail (0) + if contract.Gas <= params.SstoreSentryGasEIP2200 { + return 0, errors.New("not enough gas for reentrancy sentry") + } + // Gas sentry honoured, do the actual gas calculation based on the stored value + var ( + y, x = stack.Back(1), stack.peek() + slot = common.Hash(x.Bytes32()) + current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), slot) + cost = uint64(0) + ) + // Check slot presence in the access list + if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent { + cost = params.ColdSloadCostEIP2929 + // If the caller cannot afford the cost, this change will be rolled back + evm.StateDB.AddSlotToAccessList(contract.Address(), slot) + } + value := common.Hash(y.Bytes32()) - if current == value { // noop (1) - // EIP 2200 original clause: - // return params.SloadGasEIP2200, nil - return cost + params.WarmStorageReadCostEIP2929, nil // SLOAD_GAS + if current == value { // noop (1) + // EIP 2200 original clause: + // return params.SloadGasEIP2200, nil + return cost + params.WarmStorageReadCostEIP2929, nil // SLOAD_GAS + } + if original == current { + if original == (common.Hash{}) { // create slot (2.1.1) + return cost + params.SstoreSetGasEIP2200, nil } - if original == current { - if original == (common.Hash{}) { // create slot (2.1.1) - return cost + params.SstoreSetGasEIP2200, nil - } - if value == (common.Hash{}) { // delete slot (2.1.2b) - evm.StateDB.AddRefund(clearingRefund) - } - // EIP-2200 original clause: - // return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2) - return cost + (params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929), nil // write existing slot (2.1.2) - } - if original != (common.Hash{}) { - if current == (common.Hash{}) { // recreate slot (2.2.1.1) - evm.StateDB.SubRefund(clearingRefund) - } else if value == (common.Hash{}) { // delete slot (2.2.1.2) - evm.StateDB.AddRefund(clearingRefund) - } - } - if original == value { - if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1) - // EIP 2200 Original clause: - //evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200) - evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.WarmStorageReadCostEIP2929) - } else { // reset to original existing slot (2.2.2.2) - // EIP 2200 Original clause: - // evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200) - // - SSTORE_RESET_GAS redefined as (5000 - COLD_SLOAD_COST) - // - SLOAD_GAS redefined as WARM_STORAGE_READ_COST - // Final: (5000 - COLD_SLOAD_COST) - WARM_STORAGE_READ_COST - evm.StateDB.AddRefund((params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929) - params.WarmStorageReadCostEIP2929) - } + if value == (common.Hash{}) { // delete slot (2.1.2b) + evm.StateDB.AddRefund(clearingRefund) } // EIP-2200 original clause: - //return params.SloadGasEIP2200, nil // dirty update (2.2) - return cost + params.WarmStorageReadCostEIP2929, nil // dirty update (2.2) + // return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2) + return cost + (params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929), nil // write existing slot (2.1.2) } + if original != (common.Hash{}) { + if current == (common.Hash{}) { // recreate slot (2.2.1.1) + evm.StateDB.SubRefund(clearingRefund) + } else if value == (common.Hash{}) { // delete slot (2.2.1.2) + evm.StateDB.AddRefund(clearingRefund) + } + } + if original == value { + if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1) + // EIP 2200 Original clause: + //evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200) + evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.WarmStorageReadCostEIP2929) + } else { // reset to original existing slot (2.2.2.2) + // EIP 2200 Original clause: + // evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200) + // - SSTORE_RESET_GAS redefined as (5000 - COLD_SLOAD_COST) + // - SLOAD_GAS redefined as WARM_STORAGE_READ_COST + // Final: (5000 - COLD_SLOAD_COST) - WARM_STORAGE_READ_COST + evm.StateDB.AddRefund((params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929) - params.WarmStorageReadCostEIP2929) + } + } + // EIP-2200 original clause: + //return params.SloadGasEIP2200, nil // dirty update (2.2) + return cost + params.WarmStorageReadCostEIP2929, nil // dirty update (2.2) } // gasSLoadEIP2929 calculates dynamic gas for SLOAD according to EIP-2929 @@ -152,95 +150,104 @@ func gasEip2929AccountCheck(evm *EVM, contract *Contract, stack *Stack, mem *Mem return 0, nil } -func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int) gasFunc { - return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - addr := common.Address(stack.Back(addressPosition).Bytes20()) - // Check slot presence in the access list - warmAccess := evm.StateDB.AddressInAccessList(addr) - // The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so - // the cost to charge for cold access, if any, is Cold - Warm - coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929 - if !warmAccess { - evm.StateDB.AddAddressToAccessList(addr) - // Charge the remaining difference here already, to correctly calculate available - // gas for call - if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { - return 0, ErrOutOfGas - } +func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + addr := common.Address(stack.Back(addressPosition).Bytes20()) + // Check slot presence in the access list + warmAccess := evm.StateDB.AddressInAccessList(addr) + // The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so + // the cost to charge for cold access, if any, is Cold - Warm + coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929 + if !warmAccess { + evm.StateDB.AddAddressToAccessList(addr) + // Charge the remaining difference here already, to correctly calculate available + // gas for call + if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { + return 0, ErrOutOfGas } - // Now call the old calculator, which takes into account - // - create new account - // - transfer value - // - memory expansion - // - 63/64ths rule - gas, err := oldCalculator(evm, contract, stack, mem, memorySize) - if warmAccess || err != nil { - return gas, err - } - // In case of a cold access, we temporarily add the cold charge back, and also - // add it to the returned gas. By adding it to the return, it will be charged - // outside of this function, as part of the dynamic gas, and that will make it - // also become correctly reported to tracers. - contract.Gas += coldCost - - var overflow bool - if gas, overflow = math.SafeAdd(gas, coldCost); overflow { - return 0, ErrGasUintOverflow - } - return gas, nil } + // Now call the old calculator, which takes into account + // - create new account + // - transfer value + // - memory expansion + // - 63/64ths rule + gas, err := oldCalculator(evm, contract, stack, mem, memorySize) + if warmAccess || err != nil { + return gas, err + } + // In case of a cold access, we temporarily add the cold charge back, and also + // add it to the returned gas. By adding it to the return, it will be charged + // outside of this function, as part of the dynamic gas, and that will make it + // also become correctly reported to tracers. + contract.Gas += coldCost + + var overflow bool + if gas, overflow = math.SafeAdd(gas, coldCost); overflow { + return 0, ErrGasUintOverflow + } + return gas, nil } -var ( - gasCallEIP2929 = makeCallVariantGasCallEIP2929(gasCall, 1) - gasDelegateCallEIP2929 = makeCallVariantGasCallEIP2929(gasDelegateCall, 1) - gasStaticCallEIP2929 = makeCallVariantGasCallEIP2929(gasStaticCall, 1) - gasCallCodeEIP2929 = makeCallVariantGasCallEIP2929(gasCallCode, 1) - gasSelfdestructEIP2929 = makeSelfdestructGasFn(true) - // gasSelfdestructEIP3529 implements the changes in EIP-3529 (no refunds) - gasSelfdestructEIP3529 = makeSelfdestructGasFn(false) +func gasCallEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return makeCallVariantGasCallEIP2929(gasCall, 1, evm, contract, stack, mem, memorySize) +} +func gasDelegateCallEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return makeCallVariantGasCallEIP2929(gasDelegateCall, 1, evm, contract, stack, mem, memorySize) +} +func gasStaticCallEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return makeCallVariantGasCallEIP2929(gasStaticCall, 1, evm, contract, stack, mem, memorySize) +} +func gasCallCodeEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return makeCallVariantGasCallEIP2929(gasCallCode, 1, evm, contract, stack, mem, memorySize) +} +func gasSelfdestructEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return makeSelfdestructGasFn(true, evm, contract, stack, mem, memorySize) +} +func gasSelfdestructEIP3529(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return makeSelfdestructGasFn(false, evm, contract, stack, mem, memorySize) +} - // gasSStoreEIP2929 implements gas cost for SSTORE according to EIP-2929 - // - // When calling SSTORE, check if the (address, storage_key) pair is in accessed_storage_keys. - // If it is not, charge an additional COLD_SLOAD_COST gas, and add the pair to accessed_storage_keys. - // Additionally, modify the parameters defined in EIP 2200 as follows: - // - // Parameter Old value New value - // SLOAD_GAS 800 = WARM_STORAGE_READ_COST - // SSTORE_RESET_GAS 5000 5000 - COLD_SLOAD_COST - // - //The other parameters defined in EIP 2200 are unchanged. - // see gasSStoreEIP2200(...) in core/vm/gas_table.go for more info about how EIP 2200 is specified - gasSStoreEIP2929 = makeGasSStoreFunc(params.SstoreClearsScheduleRefundEIP2200) +// gasSStoreEIP2929 implements gas cost for SSTORE according to EIP-2929 +// +// When calling SSTORE, check if the (address, storage_key) pair is in accessed_storage_keys. +// If it is not, charge an additional COLD_SLOAD_COST gas, and add the pair to accessed_storage_keys. +// Additionally, modify the parameters defined in EIP 2200 as follows: +// +// Parameter Old value New value +// SLOAD_GAS 800 = WARM_STORAGE_READ_COST +// SSTORE_RESET_GAS 5000 5000 - COLD_SLOAD_COST +// +// The other parameters defined in EIP 2200 are unchanged. +// see gasSStoreEIP2200(...) in core/vm/gas_table.go for more info about how EIP 2200 is specified +func gasSStoreEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return gasSStoreFuncEIP(params.SstoreClearsScheduleRefundEIP2200, evm, contract, stack, mem, memorySize) +} - // gasSStoreEIP3529 implements gas cost for SSTORE according to EIP-3529 - // Replace `SSTORE_CLEARS_SCHEDULE` with `SSTORE_RESET_GAS + ACCESS_LIST_STORAGE_KEY_COST` (4,800) - gasSStoreEIP3529 = makeGasSStoreFunc(params.SstoreClearsScheduleRefundEIP3529) -) +// gasSStoreEIP3529 implements gas cost for SSTORE according to EIP-3529 +// Replace `SSTORE_CLEARS_SCHEDULE` with `SSTORE_RESET_GAS + ACCESS_LIST_STORAGE_KEY_COST` (4,800) +func gasSStoreEIP3529(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return gasSStoreFuncEIP(params.SstoreClearsScheduleRefundEIP3529, evm, contract, stack, mem, memorySize) + +} // makeSelfdestructGasFn can create the selfdestruct dynamic gas function for EIP-2929 and EIP-3529 -func makeSelfdestructGasFn(refundsEnabled bool) gasFunc { - gasFunc := func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var ( - gas uint64 - address = common.Address(stack.peek().Bytes20()) - ) - if !evm.StateDB.AddressInAccessList(address) { - // If the caller cannot afford the cost, this change will be rolled back - evm.StateDB.AddAddressToAccessList(address) - gas = params.ColdAccountAccessCostEIP2929 - } - // if empty and transfers value - if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { - gas += params.CreateBySelfdestructGas - } - if refundsEnabled && !evm.StateDB.HasSelfDestructed(contract.Address()) { - evm.StateDB.AddRefund(params.SelfdestructRefundGas) - } - return gas, nil +func makeSelfdestructGasFn(refundsEnabled bool, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + var ( + gas uint64 + address = common.Address(stack.peek().Bytes20()) + ) + if !evm.StateDB.AddressInAccessList(address) { + // If the caller cannot afford the cost, this change will be rolled back + evm.StateDB.AddAddressToAccessList(address) + gas = params.ColdAccountAccessCostEIP2929 } - return gasFunc + // if empty and transfers value + if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { + gas += params.CreateBySelfdestructGas + } + if refundsEnabled && !evm.StateDB.HasSelfDestructed(contract.Address()) { + evm.StateDB.AddRefund(params.SelfdestructRefundGas) + } + return gas, nil } var (