mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 21:56:43 +00:00
core/vm: interpreter loop generator PoC
This commit is contained in:
parent
f17df6db91
commit
ae63a92d08
8 changed files with 705 additions and 302 deletions
|
|
@ -18,7 +18,7 @@ package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
stdmath "math"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -352,7 +352,7 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC
|
||||||
)
|
)
|
||||||
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
uint64CodeOffset = math.MaxUint64
|
uint64CodeOffset = stdmath.MaxUint64
|
||||||
}
|
}
|
||||||
addr := common.Address(a.Bytes20())
|
addr := common.Address(a.Bytes20())
|
||||||
code := interpreter.evm.StateDB.GetCode(addr)
|
code := interpreter.evm.StateDB.GetCode(addr)
|
||||||
|
|
|
||||||
|
|
@ -64,37 +64,43 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
|
||||||
// MCOPY (stack position 2)
|
// MCOPY (stack position 2)
|
||||||
// EXTCODECOPY (stack position 3)
|
// EXTCODECOPY (stack position 3)
|
||||||
// RETURNDATACOPY (stack position 2)
|
// RETURNDATACOPY (stack position 2)
|
||||||
func memoryCopierGas(stackpos int) gasFunc {
|
func memoryCopierGas(stackpos int, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
// Gas for expanding the memory
|
||||||
// Gas for expanding the memory
|
gas, err := memoryGasCost(mem, memorySize)
|
||||||
gas, err := memoryGasCost(mem, memorySize)
|
if err != nil {
|
||||||
if err != nil {
|
return 0, err
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
// 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 (
|
func gasCallDataCopy(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gasCallDataCopy = memoryCopierGas(2)
|
return memoryCopierGas(2, evm, contract, stack, mem, memorySize)
|
||||||
gasCodeCopy = memoryCopierGas(2)
|
}
|
||||||
gasMcopy = memoryCopierGas(2)
|
func gasCodeCopy(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gasExtCodeCopy = memoryCopierGas(3)
|
return memoryCopierGas(2, evm, contract, stack, mem, memorySize)
|
||||||
gasReturnDataCopy = memoryCopierGas(2)
|
}
|
||||||
)
|
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) {
|
func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
var (
|
var (
|
||||||
|
|
@ -221,34 +227,48 @@ func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
|
||||||
return params.SloadGasEIP2200, nil // dirty update (2.2)
|
return params.SloadGasEIP2200, nil // dirty update (2.2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeGasLog(n uint64) gasFunc {
|
func makeGasLog(n uint64, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
requestedSize, overflow := stack.Back(1).Uint64WithOverflow()
|
||||||
requestedSize, overflow := stack.Back(1).Uint64WithOverflow()
|
if overflow {
|
||||||
if overflow {
|
return 0, ErrGasUintOverflow
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
func gasKeccak256(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
|
|
||||||
217
core/vm/generator.go
Normal file
217
core/vm/generator.go
Normal file
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
stdmath "math"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
|
|
@ -296,7 +296,7 @@ func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
|
||||||
)
|
)
|
||||||
dataOffset64, overflow := dataOffset.Uint64WithOverflow()
|
dataOffset64, overflow := dataOffset.Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
dataOffset64 = math.MaxUint64
|
dataOffset64 = stdmath.MaxUint64
|
||||||
}
|
}
|
||||||
// These values are checked for overflow during gas cost calculation
|
// These values are checked for overflow during gas cost calculation
|
||||||
memOffset64 := memOffset.Uint64()
|
memOffset64 := memOffset.Uint64()
|
||||||
|
|
@ -352,7 +352,7 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
||||||
)
|
)
|
||||||
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
uint64CodeOffset = math.MaxUint64
|
uint64CodeOffset = stdmath.MaxUint64
|
||||||
}
|
}
|
||||||
|
|
||||||
codeCopy := getData(scope.Contract.Code, uint64CodeOffset, length.Uint64())
|
codeCopy := getData(scope.Contract.Code, uint64CodeOffset, length.Uint64())
|
||||||
|
|
@ -370,7 +370,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
||||||
)
|
)
|
||||||
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
uint64CodeOffset = math.MaxUint64
|
uint64CodeOffset = stdmath.MaxUint64
|
||||||
}
|
}
|
||||||
addr := common.Address(a.Bytes20())
|
addr := common.Address(a.Bytes20())
|
||||||
code := interpreter.evm.StateDB.GetCode(addr)
|
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
|
// following functions are used by the instruction jump table
|
||||||
|
|
||||||
// make log instruction function
|
// make log instruction function
|
||||||
func makeLog(size int) executionFunc {
|
func doLog(size int, pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
if interpreter.readOnly {
|
||||||
if interpreter.readOnly {
|
return nil, ErrWriteProtection
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
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
|
// opPush1 is a specialized version of pushN
|
||||||
|
|
@ -983,30 +997,176 @@ func opPush2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// make push instruction function
|
func doPush(size uint64, pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
func makePush(size uint64, pushByteSize int) executionFunc {
|
var (
|
||||||
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
pushByteSize = int(size)
|
||||||
var (
|
codeLen = len(scope.Contract.Code)
|
||||||
codeLen = len(scope.Contract.Code)
|
start = min(codeLen, int(*pc+1))
|
||||||
start = min(codeLen, int(*pc+1))
|
end = min(codeLen, start+pushByteSize)
|
||||||
end = min(codeLen, start+pushByteSize)
|
)
|
||||||
)
|
a := new(uint256.Int).SetBytes(scope.Contract.Code[start:end])
|
||||||
a := new(uint256.Int).SetBytes(scope.Contract.Code[start:end])
|
|
||||||
|
|
||||||
// Missing bytes: pushByteSize - len(pushData)
|
// Missing bytes: pushByteSize - len(pushData)
|
||||||
if missing := pushByteSize - (end - start); missing > 0 {
|
if missing := pushByteSize - (end - start); missing > 0 {
|
||||||
a.Lsh(a, uint(8*missing))
|
a.Lsh(a, uint(8*missing))
|
||||||
}
|
|
||||||
scope.Stack.push(a)
|
|
||||||
*pc += size
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
scope.Stack.push(a)
|
||||||
|
*pc += size
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// make dup instruction function
|
func opPush3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
func makeDup(size int64) executionFunc {
|
return doPush(3, pc, interpreter, scope)
|
||||||
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
}
|
||||||
scope.Stack.dup(int(size))
|
func opPush4(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
return nil, nil
|
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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -906,7 +906,7 @@ func TestOpMCopy(t *testing.T) {
|
||||||
func TestPush(t *testing.T) {
|
func TestPush(t *testing.T) {
|
||||||
code := common.FromHex("0011223344556677889900aabbccddeeff0102030405060708090a0b0c0d0e0ff1e1d1c1b1a19181716151413121")
|
code := common.FromHex("0011223344556677889900aabbccddeeff0102030405060708090a0b0c0d0e0ff1e1d1c1b1a19181716151413121")
|
||||||
|
|
||||||
push32 := makePush(32, 32)
|
push32 := opPush32
|
||||||
|
|
||||||
scope := &ScopeContext{
|
scope := &ScopeContext{
|
||||||
Memory: nil,
|
Memory: nil,
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,6 @@ func BenchmarkInterpreter(b *testing.B) {
|
||||||
)
|
)
|
||||||
stack.push(uint256.NewInt(123))
|
stack.push(uint256.NewInt(123))
|
||||||
stack.push(uint256.NewInt(123))
|
stack.push(uint256.NewInt(123))
|
||||||
gasSStoreEIP3529 = makeGasSStoreFunc(params.SstoreClearsScheduleRefundEIP3529)
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
gasSStoreEIP3529(evm, contract, stack, mem, 1234)
|
gasSStoreEIP3529(evm, contract, stack, mem, 1234)
|
||||||
|
|
|
||||||
|
|
@ -633,277 +633,277 @@ func newFrontierInstructionSet() JumpTable {
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH3: {
|
PUSH3: {
|
||||||
execute: makePush(3, 3),
|
execute: opPush3,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH4: {
|
PUSH4: {
|
||||||
execute: makePush(4, 4),
|
execute: opPush4,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH5: {
|
PUSH5: {
|
||||||
execute: makePush(5, 5),
|
execute: opPush5,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH6: {
|
PUSH6: {
|
||||||
execute: makePush(6, 6),
|
execute: opPush6,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH7: {
|
PUSH7: {
|
||||||
execute: makePush(7, 7),
|
execute: opPush7,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH8: {
|
PUSH8: {
|
||||||
execute: makePush(8, 8),
|
execute: opPush8,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH9: {
|
PUSH9: {
|
||||||
execute: makePush(9, 9),
|
execute: opPush9,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH10: {
|
PUSH10: {
|
||||||
execute: makePush(10, 10),
|
execute: opPush10,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH11: {
|
PUSH11: {
|
||||||
execute: makePush(11, 11),
|
execute: opPush11,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH12: {
|
PUSH12: {
|
||||||
execute: makePush(12, 12),
|
execute: opPush12,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH13: {
|
PUSH13: {
|
||||||
execute: makePush(13, 13),
|
execute: opPush13,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH14: {
|
PUSH14: {
|
||||||
execute: makePush(14, 14),
|
execute: opPush14,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH15: {
|
PUSH15: {
|
||||||
execute: makePush(15, 15),
|
execute: opPush15,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH16: {
|
PUSH16: {
|
||||||
execute: makePush(16, 16),
|
execute: opPush16,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH17: {
|
PUSH17: {
|
||||||
execute: makePush(17, 17),
|
execute: opPush17,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH18: {
|
PUSH18: {
|
||||||
execute: makePush(18, 18),
|
execute: opPush18,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH19: {
|
PUSH19: {
|
||||||
execute: makePush(19, 19),
|
execute: opPush19,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH20: {
|
PUSH20: {
|
||||||
execute: makePush(20, 20),
|
execute: opPush20,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH21: {
|
PUSH21: {
|
||||||
execute: makePush(21, 21),
|
execute: opPush21,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH22: {
|
PUSH22: {
|
||||||
execute: makePush(22, 22),
|
execute: opPush22,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH23: {
|
PUSH23: {
|
||||||
execute: makePush(23, 23),
|
execute: opPush23,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH24: {
|
PUSH24: {
|
||||||
execute: makePush(24, 24),
|
execute: opPush24,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH25: {
|
PUSH25: {
|
||||||
execute: makePush(25, 25),
|
execute: opPush25,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH26: {
|
PUSH26: {
|
||||||
execute: makePush(26, 26),
|
execute: opPush26,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH27: {
|
PUSH27: {
|
||||||
execute: makePush(27, 27),
|
execute: opPush27,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH28: {
|
PUSH28: {
|
||||||
execute: makePush(28, 28),
|
execute: opPush28,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH29: {
|
PUSH29: {
|
||||||
execute: makePush(29, 29),
|
execute: opPush29,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH30: {
|
PUSH30: {
|
||||||
execute: makePush(30, 30),
|
execute: opPush30,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH31: {
|
PUSH31: {
|
||||||
execute: makePush(31, 31),
|
execute: opPush31,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
PUSH32: {
|
PUSH32: {
|
||||||
execute: makePush(32, 32),
|
execute: opPush32,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
},
|
},
|
||||||
DUP1: {
|
DUP1: {
|
||||||
execute: makeDup(1),
|
execute: opDup1,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(1),
|
minStack: minDupStack(1),
|
||||||
maxStack: maxDupStack(1),
|
maxStack: maxDupStack(1),
|
||||||
},
|
},
|
||||||
DUP2: {
|
DUP2: {
|
||||||
execute: makeDup(2),
|
execute: opDup2,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(2),
|
minStack: minDupStack(2),
|
||||||
maxStack: maxDupStack(2),
|
maxStack: maxDupStack(2),
|
||||||
},
|
},
|
||||||
DUP3: {
|
DUP3: {
|
||||||
execute: makeDup(3),
|
execute: opDup3,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(3),
|
minStack: minDupStack(3),
|
||||||
maxStack: maxDupStack(3),
|
maxStack: maxDupStack(3),
|
||||||
},
|
},
|
||||||
DUP4: {
|
DUP4: {
|
||||||
execute: makeDup(4),
|
execute: opDup4,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(4),
|
minStack: minDupStack(4),
|
||||||
maxStack: maxDupStack(4),
|
maxStack: maxDupStack(4),
|
||||||
},
|
},
|
||||||
DUP5: {
|
DUP5: {
|
||||||
execute: makeDup(5),
|
execute: opDup5,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(5),
|
minStack: minDupStack(5),
|
||||||
maxStack: maxDupStack(5),
|
maxStack: maxDupStack(5),
|
||||||
},
|
},
|
||||||
DUP6: {
|
DUP6: {
|
||||||
execute: makeDup(6),
|
execute: opDup6,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(6),
|
minStack: minDupStack(6),
|
||||||
maxStack: maxDupStack(6),
|
maxStack: maxDupStack(6),
|
||||||
},
|
},
|
||||||
DUP7: {
|
DUP7: {
|
||||||
execute: makeDup(7),
|
execute: opDup7,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(7),
|
minStack: minDupStack(7),
|
||||||
maxStack: maxDupStack(7),
|
maxStack: maxDupStack(7),
|
||||||
},
|
},
|
||||||
DUP8: {
|
DUP8: {
|
||||||
execute: makeDup(8),
|
execute: opDup8,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(8),
|
minStack: minDupStack(8),
|
||||||
maxStack: maxDupStack(8),
|
maxStack: maxDupStack(8),
|
||||||
},
|
},
|
||||||
DUP9: {
|
DUP9: {
|
||||||
execute: makeDup(9),
|
execute: opDup9,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(9),
|
minStack: minDupStack(9),
|
||||||
maxStack: maxDupStack(9),
|
maxStack: maxDupStack(9),
|
||||||
},
|
},
|
||||||
DUP10: {
|
DUP10: {
|
||||||
execute: makeDup(10),
|
execute: opDup10,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(10),
|
minStack: minDupStack(10),
|
||||||
maxStack: maxDupStack(10),
|
maxStack: maxDupStack(10),
|
||||||
},
|
},
|
||||||
DUP11: {
|
DUP11: {
|
||||||
execute: makeDup(11),
|
execute: opDup11,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(11),
|
minStack: minDupStack(11),
|
||||||
maxStack: maxDupStack(11),
|
maxStack: maxDupStack(11),
|
||||||
},
|
},
|
||||||
DUP12: {
|
DUP12: {
|
||||||
execute: makeDup(12),
|
execute: opDup12,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(12),
|
minStack: minDupStack(12),
|
||||||
maxStack: maxDupStack(12),
|
maxStack: maxDupStack(12),
|
||||||
},
|
},
|
||||||
DUP13: {
|
DUP13: {
|
||||||
execute: makeDup(13),
|
execute: opDup13,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(13),
|
minStack: minDupStack(13),
|
||||||
maxStack: maxDupStack(13),
|
maxStack: maxDupStack(13),
|
||||||
},
|
},
|
||||||
DUP14: {
|
DUP14: {
|
||||||
execute: makeDup(14),
|
execute: opDup14,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(14),
|
minStack: minDupStack(14),
|
||||||
maxStack: maxDupStack(14),
|
maxStack: maxDupStack(14),
|
||||||
},
|
},
|
||||||
DUP15: {
|
DUP15: {
|
||||||
execute: makeDup(15),
|
execute: opDup15,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(15),
|
minStack: minDupStack(15),
|
||||||
maxStack: maxDupStack(15),
|
maxStack: maxDupStack(15),
|
||||||
},
|
},
|
||||||
DUP16: {
|
DUP16: {
|
||||||
execute: makeDup(16),
|
execute: opDup16,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastestStep,
|
||||||
minStack: minDupStack(16),
|
minStack: minDupStack(16),
|
||||||
maxStack: maxDupStack(16),
|
maxStack: maxDupStack(16),
|
||||||
|
|
@ -1005,36 +1005,36 @@ func newFrontierInstructionSet() JumpTable {
|
||||||
maxStack: maxSwapStack(17),
|
maxStack: maxSwapStack(17),
|
||||||
},
|
},
|
||||||
LOG0: {
|
LOG0: {
|
||||||
execute: makeLog(0),
|
execute: opLog0,
|
||||||
dynamicGas: makeGasLog(0),
|
dynamicGas: gasLog0,
|
||||||
minStack: minStack(2, 0),
|
minStack: minStack(2, 0),
|
||||||
maxStack: maxStack(2, 0),
|
maxStack: maxStack(2, 0),
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
},
|
},
|
||||||
LOG1: {
|
LOG1: {
|
||||||
execute: makeLog(1),
|
execute: opLog1,
|
||||||
dynamicGas: makeGasLog(1),
|
dynamicGas: gasLog1,
|
||||||
minStack: minStack(3, 0),
|
minStack: minStack(3, 0),
|
||||||
maxStack: maxStack(3, 0),
|
maxStack: maxStack(3, 0),
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
},
|
},
|
||||||
LOG2: {
|
LOG2: {
|
||||||
execute: makeLog(2),
|
execute: opLog2,
|
||||||
dynamicGas: makeGasLog(2),
|
dynamicGas: gasLog2,
|
||||||
minStack: minStack(4, 0),
|
minStack: minStack(4, 0),
|
||||||
maxStack: maxStack(4, 0),
|
maxStack: maxStack(4, 0),
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
},
|
},
|
||||||
LOG3: {
|
LOG3: {
|
||||||
execute: makeLog(3),
|
execute: opLog3,
|
||||||
dynamicGas: makeGasLog(3),
|
dynamicGas: gasLog3,
|
||||||
minStack: minStack(5, 0),
|
minStack: minStack(5, 0),
|
||||||
maxStack: maxStack(5, 0),
|
maxStack: maxStack(5, 0),
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
},
|
},
|
||||||
LOG4: {
|
LOG4: {
|
||||||
execute: makeLog(4),
|
execute: opLog4,
|
||||||
dynamicGas: makeGasLog(4),
|
dynamicGas: gasLog4,
|
||||||
minStack: minStack(6, 0),
|
minStack: minStack(6, 0),
|
||||||
maxStack: maxStack(6, 0),
|
maxStack: maxStack(6, 0),
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
|
|
|
||||||
|
|
@ -26,68 +26,66 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
|
func gasSStoreFuncEIP(clearingRefund uint64, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
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 we fail the minimum gas availability invariant, fail (0)
|
if contract.Gas <= params.SstoreSentryGasEIP2200 {
|
||||||
if contract.Gas <= params.SstoreSentryGasEIP2200 {
|
return 0, errors.New("not enough gas for reentrancy sentry")
|
||||||
return 0, errors.New("not enough gas for reentrancy sentry")
|
}
|
||||||
}
|
// Gas sentry honoured, do the actual gas calculation based on the stored value
|
||||||
// Gas sentry honoured, do the actual gas calculation based on the stored value
|
var (
|
||||||
var (
|
y, x = stack.Back(1), stack.peek()
|
||||||
y, x = stack.Back(1), stack.peek()
|
slot = common.Hash(x.Bytes32())
|
||||||
slot = common.Hash(x.Bytes32())
|
current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), slot)
|
||||||
current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), slot)
|
cost = uint64(0)
|
||||||
cost = uint64(0)
|
)
|
||||||
)
|
// Check slot presence in the access list
|
||||||
// Check slot presence in the access list
|
if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent {
|
||||||
if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent {
|
cost = params.ColdSloadCostEIP2929
|
||||||
cost = params.ColdSloadCostEIP2929
|
// If the caller cannot afford the cost, this change will be rolled back
|
||||||
// If the caller cannot afford the cost, this change will be rolled back
|
evm.StateDB.AddSlotToAccessList(contract.Address(), slot)
|
||||||
evm.StateDB.AddSlotToAccessList(contract.Address(), slot)
|
}
|
||||||
}
|
value := common.Hash(y.Bytes32())
|
||||||
value := common.Hash(y.Bytes32())
|
|
||||||
|
|
||||||
if current == value { // noop (1)
|
if current == value { // noop (1)
|
||||||
// EIP 2200 original clause:
|
// EIP 2200 original clause:
|
||||||
// return params.SloadGasEIP2200, nil
|
// return params.SloadGasEIP2200, nil
|
||||||
return cost + params.WarmStorageReadCostEIP2929, nil // SLOAD_GAS
|
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 value == (common.Hash{}) { // delete slot (2.1.2b)
|
||||||
if original == (common.Hash{}) { // create slot (2.1.1)
|
evm.StateDB.AddRefund(clearingRefund)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// EIP-2200 original clause:
|
// EIP-2200 original clause:
|
||||||
//return params.SloadGasEIP2200, nil // dirty update (2.2)
|
// return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2)
|
||||||
return cost + params.WarmStorageReadCostEIP2929, nil // dirty update (2.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
|
// 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
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int) gasFunc {
|
func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
addr := common.Address(stack.Back(addressPosition).Bytes20())
|
||||||
addr := common.Address(stack.Back(addressPosition).Bytes20())
|
// Check slot presence in the access list
|
||||||
// Check slot presence in the access list
|
warmAccess := evm.StateDB.AddressInAccessList(addr)
|
||||||
warmAccess := evm.StateDB.AddressInAccessList(addr)
|
// The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so
|
||||||
// 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
|
||||||
// the cost to charge for cold access, if any, is Cold - Warm
|
coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929
|
||||||
coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929
|
if !warmAccess {
|
||||||
if !warmAccess {
|
evm.StateDB.AddAddressToAccessList(addr)
|
||||||
evm.StateDB.AddAddressToAccessList(addr)
|
// Charge the remaining difference here already, to correctly calculate available
|
||||||
// Charge the remaining difference here already, to correctly calculate available
|
// gas for call
|
||||||
// gas for call
|
if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
|
||||||
if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
|
return 0, ErrOutOfGas
|
||||||
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 (
|
func gasCallEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gasCallEIP2929 = makeCallVariantGasCallEIP2929(gasCall, 1)
|
return makeCallVariantGasCallEIP2929(gasCall, 1, evm, contract, stack, mem, memorySize)
|
||||||
gasDelegateCallEIP2929 = makeCallVariantGasCallEIP2929(gasDelegateCall, 1)
|
}
|
||||||
gasStaticCallEIP2929 = makeCallVariantGasCallEIP2929(gasStaticCall, 1)
|
func gasDelegateCallEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gasCallCodeEIP2929 = makeCallVariantGasCallEIP2929(gasCallCode, 1)
|
return makeCallVariantGasCallEIP2929(gasDelegateCall, 1, evm, contract, stack, mem, memorySize)
|
||||||
gasSelfdestructEIP2929 = makeSelfdestructGasFn(true)
|
}
|
||||||
// gasSelfdestructEIP3529 implements the changes in EIP-3529 (no refunds)
|
func gasStaticCallEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gasSelfdestructEIP3529 = makeSelfdestructGasFn(false)
|
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
|
// 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.
|
// 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.
|
// 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:
|
// Additionally, modify the parameters defined in EIP 2200 as follows:
|
||||||
//
|
//
|
||||||
// Parameter Old value New value
|
// Parameter Old value New value
|
||||||
// SLOAD_GAS 800 = WARM_STORAGE_READ_COST
|
// SLOAD_GAS 800 = WARM_STORAGE_READ_COST
|
||||||
// SSTORE_RESET_GAS 5000 5000 - COLD_SLOAD_COST
|
// SSTORE_RESET_GAS 5000 5000 - COLD_SLOAD_COST
|
||||||
//
|
//
|
||||||
//The other parameters defined in EIP 2200 are unchanged.
|
// 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
|
// see gasSStoreEIP2200(...) in core/vm/gas_table.go for more info about how EIP 2200 is specified
|
||||||
gasSStoreEIP2929 = makeGasSStoreFunc(params.SstoreClearsScheduleRefundEIP2200)
|
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
|
// 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)
|
// Replace `SSTORE_CLEARS_SCHEDULE` with `SSTORE_RESET_GAS + ACCESS_LIST_STORAGE_KEY_COST` (4,800)
|
||||||
gasSStoreEIP3529 = makeGasSStoreFunc(params.SstoreClearsScheduleRefundEIP3529)
|
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
|
// makeSelfdestructGasFn can create the selfdestruct dynamic gas function for EIP-2929 and EIP-3529
|
||||||
func makeSelfdestructGasFn(refundsEnabled bool) gasFunc {
|
func makeSelfdestructGasFn(refundsEnabled bool, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
gasFunc := func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
var (
|
||||||
var (
|
gas uint64
|
||||||
gas uint64
|
address = common.Address(stack.peek().Bytes20())
|
||||||
address = common.Address(stack.peek().Bytes20())
|
)
|
||||||
)
|
if !evm.StateDB.AddressInAccessList(address) {
|
||||||
if !evm.StateDB.AddressInAccessList(address) {
|
// If the caller cannot afford the cost, this change will be rolled back
|
||||||
// If the caller cannot afford the cost, this change will be rolled back
|
evm.StateDB.AddAddressToAccessList(address)
|
||||||
evm.StateDB.AddAddressToAccessList(address)
|
gas = params.ColdAccountAccessCostEIP2929
|
||||||
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
|
|
||||||
}
|
}
|
||||||
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 (
|
var (
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue