diff --git a/config/config.toml b/config/config.toml
index b873a641a..aa6cf602c 100644
--- a/config/config.toml
+++ b/config/config.toml
@@ -209,6 +209,49 @@
ManagedMapRemove = 10
ManagedMapContains = 10
+[EVMOpcodeCost]
+ QuickStep = 1
+ FastestStep = 1
+ FastStep = 1
+ MidStep = 1
+ SlowStep = 1
+ ExtStep = 1
+ Ecrecover = 1
+ Sha256PerWord = 1
+ Sha256Base = 1
+ Ripemd160PerWord = 1
+ Ripemd160Base = 1
+ IdentityPerWord = 1
+ IdentityBase = 1
+ Bn256Add = 1
+ Bn256ScalarMul = 1
+ Bn256PairingBase = 1
+ Bn256PairingPerPoint = 1
+ BlobTxPointEvaluation = 1
+ Keccak256 = 1
+ Balance = 1
+ ExtcodeSize = 1
+ ExtcodeCopy = 1
+ ExtcodeHash = 1
+ Sload = 1
+ Sstore = 1
+ Jumpdest = 1
+ Tload = 1
+ Tstore = 1
+ Create = 1
+ Call = 1
+ Create2 = 1
+ Selfdestruct = 1
+ Memory = 1
+ Copy = 1
+ Log = 1
+ LogTopic = 1
+ LogData = 1
+ Keccak256Word = 1
+ InitCodeWord = 1
+ ExpByte = 1
+ Exp = 1
+
[WASMOpcodeCost]
AtomicFence = 1
AtomicNotify = 1
diff --git a/config/gasCost.go b/config/gasCost.go
index 8cf0b3638..0fed3ae76 100644
--- a/config/gasCost.go
+++ b/config/gasCost.go
@@ -14,6 +14,7 @@ type GasCost struct {
ManagedBufferAPICost ManagedBufferAPICost
ManagedMapAPICost ManagedMapAPICost
CryptoAPICost CryptoAPICost
+ EVMOpcodeCost *executor.EVMOpcodeCost
WASMOpcodeCost *executor.WASMOpcodeCost
DynamicStorageLoad DynamicStorageLoadCostCoefficients
}
diff --git a/config/gasSchedule.go b/config/gasSchedule.go
index 55866fd55..608e57f4b 100644
--- a/config/gasSchedule.go
+++ b/config/gasSchedule.go
@@ -90,6 +90,17 @@ func CreateGasConfig(gasMap GasScheduleMap) (*GasCost, error) {
return nil, err
}
+ evmOps := &executor.EVMOpcodeCost{}
+ err = mapstructure.Decode(gasMap["EVMOpcodeCost"], evmOps)
+ if err != nil {
+ return nil, err
+ }
+
+ err = checkForZeroUint64Fields(*evmOps)
+ if err != nil {
+ return nil, err
+ }
+
wasmOps := &executor.WASMOpcodeCost{}
err = mapstructure.Decode(gasMap["WASMOpcodeCost"], wasmOps)
if err != nil {
@@ -127,6 +138,7 @@ func CreateGasConfig(gasMap GasScheduleMap) (*GasCost, error) {
BaseOpsAPICost: *baseOpsAPI,
CryptoAPICost: *cryptOps,
ManagedBufferAPICost: *MBufferOps,
+ EVMOpcodeCost: evmOps,
WASMOpcodeCost: wasmOps,
DynamicStorageLoad: *dynamicStorageLoadParams,
ManagedMapAPICost: *managedMapOps,
@@ -211,6 +223,7 @@ func FillGasMap(gasMap GasScheduleMap, value, asyncCallbackGasLock uint64) GasSc
gasMap["BigFloatAPICost"] = FillGasMapBigFloatAPICosts(value)
gasMap["CryptoAPICost"] = FillGasMapCryptoAPICosts(value)
gasMap["ManagedBufferAPICost"] = FillGasMapManagedBufferAPICosts(value)
+ gasMap["EVMOpcodeCost"] = FillGasMapEVMOpcodeCosts(value)
gasMap["WASMOpcodeCost"] = FillGasMapWASMOpcodeValues(value)
gasMap["DynamicStorageLoad"] = FillGasMapDynamicStorageLoad()
@@ -500,6 +513,55 @@ func FillGasMapManagedBufferAPICosts(value uint64) map[string]uint64 {
return gasMap
}
+// FillGasMapEVMOpcodeCosts fills the evm opcodes costs
+func FillGasMapEVMOpcodeCosts(value uint64) map[string]uint64 {
+ gasMap := make(map[string]uint64)
+
+ gasMap["QuickStep"] = value
+ gasMap["FastestStep"] = value
+ gasMap["FastStep"] = value
+ gasMap["MidStep"] = value
+ gasMap["SlowStep"] = value
+ gasMap["ExtStep"] = value
+ gasMap["Ecrecover"] = value
+ gasMap["Sha256PerWord"] = value
+ gasMap["Sha256Base"] = value
+ gasMap["Ripemd160PerWord"] = value
+ gasMap["Ripemd160Base"] = value
+ gasMap["IdentityPerWord"] = value
+ gasMap["IdentityBase"] = value
+ gasMap["Bn256Add"] = value
+ gasMap["Bn256ScalarMul"] = value
+ gasMap["Bn256PairingBase"] = value
+ gasMap["Bn256PairingPerPoint"] = value
+ gasMap["BlobTxPointEvaluation"] = value
+ gasMap["Keccak256"] = value
+ gasMap["Balance"] = value
+ gasMap["ExtcodeSize"] = value
+ gasMap["ExtcodeCopy"] = value
+ gasMap["ExtcodeHash"] = value
+ gasMap["Sload"] = value
+ gasMap["Sstore"] = value
+ gasMap["Jumpdest"] = value
+ gasMap["Tload"] = value
+ gasMap["Tstore"] = value
+ gasMap["Create"] = value
+ gasMap["Call"] = value
+ gasMap["Create2"] = value
+ gasMap["Selfdestruct"] = value
+ gasMap["Memory"] = value
+ gasMap["Copy"] = value
+ gasMap["Log"] = value
+ gasMap["LogTopic"] = value
+ gasMap["LogData"] = value
+ gasMap["Keccak256Word"] = value
+ gasMap["InitCodeWord"] = value
+ gasMap["ExpByte"] = value
+ gasMap["Exp"] = value
+
+ return gasMap
+}
+
// FillGasMapWASMOpcodeValues fills the wasm opcodes costs
func FillGasMapWASMOpcodeValues(value uint64) map[string]uint64 {
gasMap := make(map[string]uint64)
diff --git a/evm/evmError.go b/evm/evmError.go
new file mode 100644
index 000000000..d7bed41e6
--- /dev/null
+++ b/evm/evmError.go
@@ -0,0 +1,9 @@
+package evm
+
+import "errors"
+
+var ErrActionNotSupported = errors.New("action not supported on EVM")
+
+var ErrCodeNotCompiled = errors.New("code is not compiled")
+
+var ErrExecutionAborted = errors.New("execution aborted")
diff --git a/evm/evmExecutor.go b/evm/evmExecutor.go
new file mode 100644
index 000000000..052d948bc
--- /dev/null
+++ b/evm/evmExecutor.go
@@ -0,0 +1,103 @@
+package evm
+
+import (
+ vmcommon "github.com/multiversx/mx-chain-vm-common-go"
+ evm "github.com/multiversx/mx-chain-vm-go/evm/interpreter"
+ "github.com/multiversx/mx-chain-vm-go/executor"
+)
+
+var _ executor.Executor = (*EVMExecutor)(nil)
+
+// EVMExecutor oversees the creation of EVM instances and execution.
+type EVMExecutor struct {
+ evmHooks executor.EVMHooks
+ gasConfig *evm.GasConfig
+ instructionSet evm.JumpTable
+}
+
+// CreateExecutor creates a new EVM executor.
+func CreateExecutor(args executor.ExecutorFactoryArgs) (*EVMExecutor, error) {
+ evmExecutor := &EVMExecutor{evmHooks: args.EvmHooks}
+ evmExecutor.SetOpcodeCosts(args.OpcodeCosts)
+ return evmExecutor, nil
+}
+
+func (evmExecutor *EVMExecutor) SetOpcodeCosts(opcodeCost executor.VMOpcodeCost) {
+ if opcodeCost.EVMOpcodeCost != nil {
+ evmExecutor.gasConfig = extractOpcodeCost(opcodeCost.EVMOpcodeCost)
+ evmExecutor.instructionSet = evm.NewCancunInstructionSet(evmExecutor.gasConfig)
+ }
+}
+
+func (evmExecutor *EVMExecutor) FunctionNames() vmcommon.FunctionNames {
+ return map[string]struct{}{}
+}
+
+// NewInstanceWithOptions creates a new EVM instance from EVM bytecode,
+// respecting the provided options
+func (evmExecutor *EVMExecutor) NewInstanceWithOptions(
+ contractCode []byte,
+ options executor.CompilationOptions,
+) (executor.Instance, error) {
+ return newInstance(evmExecutor, false, contractCode, options)
+}
+
+// NewInstanceFromCompiledCodeWithOptions creates a new EVM instance from compiled code,
+// respecting the provided options
+func (evmExecutor *EVMExecutor) NewInstanceFromCompiledCodeWithOptions(
+ compiledCode []byte,
+ options executor.CompilationOptions,
+) (executor.Instance, error) {
+ return newInstance(evmExecutor, true, compiledCode, options)
+}
+
+// IsInterfaceNil returns true if underlying object is nil
+func (evmExecutor *EVMExecutor) IsInterfaceNil() bool {
+ return evmExecutor == nil
+}
+
+func extractOpcodeCost(opcodeCost *executor.EVMOpcodeCost) *evm.GasConfig {
+ return &evm.GasConfig{
+ QuickStep: opcodeCost.QuickStep,
+ FastestStep: opcodeCost.FastestStep,
+ FastStep: opcodeCost.FastStep,
+ MidStep: opcodeCost.MidStep,
+ SlowStep: opcodeCost.SlowStep,
+ ExtStep: opcodeCost.ExtStep,
+ Ecrecover: opcodeCost.Ecrecover,
+ Sha256PerWord: opcodeCost.Sha256PerWord,
+ Sha256Base: opcodeCost.Sha256Base,
+ Ripemd160PerWord: opcodeCost.Ripemd160PerWord,
+ Ripemd160Base: opcodeCost.Ripemd160Base,
+ IdentityPerWord: opcodeCost.IdentityPerWord,
+ IdentityBase: opcodeCost.IdentityBase,
+ Bn256Add: opcodeCost.Bn256Add,
+ Bn256ScalarMul: opcodeCost.Bn256ScalarMul,
+ Bn256PairingBase: opcodeCost.Bn256PairingBase,
+ Bn256PairingPerPoint: opcodeCost.Bn256PairingPerPoint,
+ BlobTxPointEvaluation: opcodeCost.BlobTxPointEvaluation,
+ Keccak256: opcodeCost.Keccak256,
+ Balance: opcodeCost.Balance,
+ ExtcodeSize: opcodeCost.ExtcodeSize,
+ ExtcodeCopy: opcodeCost.ExtcodeCopy,
+ ExtcodeHash: opcodeCost.ExtcodeHash,
+ Sload: opcodeCost.Sload,
+ Sstore: opcodeCost.Sstore,
+ Jumpdest: opcodeCost.Jumpdest,
+ Tload: opcodeCost.Tload,
+ Tstore: opcodeCost.Tstore,
+ Create: opcodeCost.Create,
+ Call: opcodeCost.Call,
+ Create2: opcodeCost.Create2,
+ Selfdestruct: opcodeCost.Selfdestruct,
+ Memory: opcodeCost.Memory,
+ Copy: opcodeCost.Copy,
+ Log: opcodeCost.Log,
+ LogTopic: opcodeCost.LogTopic,
+ LogData: opcodeCost.LogData,
+ Keccak256Word: opcodeCost.Keccak256Word,
+ InitCodeWord: opcodeCost.InitCodeWord,
+ ExpByte: opcodeCost.ExpByte,
+ Exp: opcodeCost.Exp,
+ }
+}
diff --git a/evm/evmExecutorFactory.go b/evm/evmExecutorFactory.go
new file mode 100644
index 000000000..b417a8813
--- /dev/null
+++ b/evm/evmExecutorFactory.go
@@ -0,0 +1,25 @@
+package evm
+
+import (
+ "github.com/multiversx/mx-chain-vm-go/executor"
+)
+
+var _ = (executor.ExecutorAbstractFactory)((*EVMExecutorFactory)(nil))
+
+// EVMExecutorFactory builds EVM Executors.
+type EVMExecutorFactory struct{}
+
+// ExecutorFactory returns the EVM executor factory.
+func ExecutorFactory() *EVMExecutorFactory {
+ return &EVMExecutorFactory{}
+}
+
+// CreateExecutor creates a new Executor instance.
+func (eef *EVMExecutorFactory) CreateExecutor(args executor.ExecutorFactoryArgs) (executor.Executor, error) {
+ return CreateExecutor(args)
+}
+
+// IsInterfaceNil returns true if there is no value under the interface
+func (eef *EVMExecutorFactory) IsInterfaceNil() bool {
+ return eef == nil
+}
diff --git a/evm/evmInstance.go b/evm/evmInstance.go
new file mode 100644
index 000000000..580257e29
--- /dev/null
+++ b/evm/evmInstance.go
@@ -0,0 +1,234 @@
+package evm
+
+import (
+ "fmt"
+ "github.com/multiversx/mx-chain-vm-common-go/parsers"
+ interpreter "github.com/multiversx/mx-chain-vm-go/evm/interpreter"
+ "github.com/multiversx/mx-chain-vm-go/executor"
+ "github.com/multiversx/mx-chain-vm-go/vmhost"
+)
+
+const NoBreakpoint = uint64(vmhost.BreakpointNone)
+
+var _ executor.Instance = (*EVMInstance)(nil)
+
+// EVMInstance represents a EVM instance.
+type EVMInstance struct {
+ evmExecutor *EVMExecutor
+ evm *interpreter.EVM
+ options executor.CompilationOptions
+
+ isCompiled bool
+ wasCleaned bool
+ code []byte
+ gasUsed uint64
+ breakpoint uint64
+}
+
+func newInstance(
+ evmExecutor *EVMExecutor,
+ isCompiled bool,
+ code []byte,
+ options executor.CompilationOptions,
+) (*EVMInstance, error) {
+ instance := &EVMInstance{
+ evmExecutor: evmExecutor,
+ options: options,
+
+ isCompiled: isCompiled,
+ wasCleaned: false,
+ code: code,
+ gasUsed: 0,
+ breakpoint: NoBreakpoint,
+ }
+
+ instance.resetEVM()
+ return instance, nil
+}
+
+// Clean cleans instance
+func (instance *EVMInstance) Clean() bool {
+ logEVM.Trace("clean: start", "id", instance.ID())
+ if instance.wasCleaned {
+ logEVM.Trace("clean: was cleaned", "id", instance.ID())
+ return false
+ }
+
+ instance.evm = nil
+ instance.evmExecutor = nil
+ instance.options = executor.CompilationOptions{}
+
+ instance.isCompiled = false
+ instance.wasCleaned = true
+ instance.code = []byte{}
+ instance.gasUsed = 0
+ instance.breakpoint = NoBreakpoint
+
+ logEVM.Trace("clean: end", "id", instance.ID())
+ return true
+}
+
+// IsAlreadyCleaned returns the internal field AlreadyClean
+func (instance *EVMInstance) IsAlreadyCleaned() bool {
+ return instance.wasCleaned
+}
+
+// SetGasLimit sets the gas limit for the instance
+func (instance *EVMInstance) SetGasLimit(uint64) {
+}
+
+// SetPointsUsed sets the internal instance gas counter
+func (instance *EVMInstance) SetPointsUsed(points uint64) {
+ if !instance.options.Metering {
+ return
+ }
+
+ instance.gasUsed = points
+}
+
+// GetPointsUsed returns the internal instance gas counter
+func (instance *EVMInstance) GetPointsUsed() uint64 {
+ return instance.gasUsed
+}
+
+// SetBreakpointValue sets the breakpoint value for the instance
+func (instance *EVMInstance) SetBreakpointValue(value uint64) {
+ if !instance.options.RuntimeBreakpoints {
+ return
+ }
+
+ instance.breakpoint = value
+ if value != NoBreakpoint {
+ instance.evm.Cancel()
+ }
+}
+
+// GetBreakpointValue returns the breakpoint value
+func (instance *EVMInstance) GetBreakpointValue() uint64 {
+ return instance.breakpoint
+}
+
+// HasCompiledCode specifies if the code is compiled
+func (instance *EVMInstance) HasCompiledCode() bool {
+ return instance.isCompiled
+}
+
+// Cache caches the instance
+func (instance *EVMInstance) Cache() ([]byte, error) {
+ if !instance.isCompiled {
+ return nil, ErrCodeNotCompiled
+ }
+ return instance.code, nil
+}
+
+// IsFunctionImported returns true if the instance imports the specified function
+func (instance *EVMInstance) IsFunctionImported(string) bool {
+ return false
+}
+
+// CallFunction executes given function from loaded contract.
+func (instance *EVMInstance) CallFunction(functionName string) error {
+ err := instance.prepareAddress(functionName)
+ if err != nil {
+ return err
+ }
+
+ contract, input := instance.prepareContract(functionName)
+ returnData, err := instance.evm.Interpreter().Run(contract, input, instance.evmExecutor.evmHooks.ReadOnly())
+ if err != nil {
+ return err
+ }
+ if instance.evm.Cancelled() {
+ return ErrExecutionAborted
+ }
+
+ instance.consumeOutput(functionName, returnData)
+ return nil
+}
+
+// HasFunction checks if loaded contract has a function (endpoint) with given name.
+func (instance *EVMInstance) HasFunction(functionName string) bool {
+ switch functionName {
+ case vmhost.InitFunctionName:
+ return true
+ case vmhost.UpgradeFunctionName, vmhost.DeleteFunctionName, vmhost.CallbackFunctionName, vmhost.ContractsUpgradeFunctionName:
+ return false
+ default:
+ return parsers.EVMSelectorSize == len(functionNameToSelector(functionName))
+ }
+}
+
+// GetFunctionNames returns a list of the function names exported by the contract.
+func (instance *EVMInstance) GetFunctionNames() []string {
+ return []string{}
+}
+
+// ValidateFunctionArities checks that no function (endpoint) of the given contract has any parameters or returns any result.
+// All arguments and results should be transferred via the import functions.
+func (instance *EVMInstance) ValidateFunctionArities() error {
+ return nil
+}
+
+// HasMemory checks whether the instance has at least one exported memory.
+func (instance *EVMInstance) HasMemory() bool {
+ return true
+}
+
+// MemLoad returns the contents from the given offset of the EVM memory.
+func (instance *EVMInstance) MemLoad(executor.MemPtr, executor.MemLength) ([]byte, error) {
+ return nil, ErrActionNotSupported
+}
+
+// MemStore stores the given data in the EVM memory at the given offset.
+func (instance *EVMInstance) MemStore(executor.MemPtr, []byte) error {
+ return ErrActionNotSupported
+}
+
+// MemLength returns the length of the allocated memory. Only called directly in tests.
+func (instance *EVMInstance) MemLength() uint32 {
+ return 0
+}
+
+// MemGrow allocates more pages to the current memory. Only called directly in tests.
+func (instance *EVMInstance) MemGrow(uint32) error {
+ return ErrActionNotSupported
+}
+
+// MemDump yields the entire contents of the memory. Only used in tests.
+func (instance *EVMInstance) MemDump() []byte {
+ return []byte{}
+}
+
+// ID Id returns an identifier for the instance, unique at runtime
+func (instance *EVMInstance) ID() string {
+ return fmt.Sprintf("%p", instance)
+}
+
+// Reset resets the instance memories and globals
+func (instance *EVMInstance) Reset() bool {
+ if instance.wasCleaned {
+ logEVM.Trace("reset: was cleaned", "id", instance.ID())
+ return false
+ }
+
+ instance.resetEVM()
+ instance.gasUsed = 0
+ instance.breakpoint = NoBreakpoint
+
+ logEVM.Trace("reset: warm instance", "id", instance.ID())
+ return true
+}
+
+// IsInterfaceNil returns true if underlying object is nil
+func (instance *EVMInstance) IsInterfaceNil() bool {
+ return instance == nil
+}
+
+// SetVMHooksPtr sets the VM hooks pointer
+func (instance *EVMInstance) SetVMHooksPtr(uintptr) {
+}
+
+// GetVMHooksPtr returns the VM hooks pointer
+func (instance *EVMInstance) GetVMHooksPtr() uintptr {
+ return uintptr(0)
+}
diff --git a/evm/evmInstanceHelper.go b/evm/evmInstanceHelper.go
new file mode 100644
index 000000000..7d79ff715
--- /dev/null
+++ b/evm/evmInstanceHelper.go
@@ -0,0 +1,119 @@
+package evm
+
+import (
+ "encoding/hex"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/params"
+ interpreter "github.com/multiversx/mx-chain-vm-go/evm/interpreter"
+ "github.com/multiversx/mx-chain-vm-go/vmhost"
+ "math/big"
+)
+
+func (instance *EVMInstance) resetEVM() {
+ instance.evm = interpreter.NewEVM(
+ instance.buildBlockContext(),
+ instance.buildTxContext(),
+ interpreter.CreateEVMStateDB(instance.evmExecutor.evmHooks),
+ instance.buildChainConfig(),
+ instance.evmExecutor.gasConfig,
+ &instance.evmExecutor.instructionSet,
+ )
+}
+
+func (instance *EVMInstance) prepareAddress(functionName string) error {
+ if functionName != vmhost.InitFunctionName {
+ return nil
+ }
+
+ return instance.evmExecutor.evmHooks.SaveAliasAddress()
+}
+
+func (instance *EVMInstance) prepareContract(functionName string) (*interpreter.Contract, []byte) {
+ evmHooks := instance.evmExecutor.evmHooks
+ input, code := instance.prepareInputAndCode(functionName)
+
+ contractAddress := evmHooks.ContractAddress()
+ contract := interpreter.NewContract(
+ interpreter.AccountRef(evmHooks.CallerAddress()),
+ interpreter.AccountRef(contractAddress),
+ evmHooks.CallValue(),
+ )
+ contract.Code = code
+ contract.CodeHash = evmHooks.CodeHash()
+ return contract, input
+}
+
+func (instance *EVMInstance) consumeOutput(functionName string, returnData []byte) {
+ evmHooks := instance.evmExecutor.evmHooks
+
+ switch functionName {
+ case vmhost.InitFunctionName:
+ instance.isCompiled = true
+ instance.code = returnData
+ evmHooks.FinishCreate(returnData)
+ default:
+ evmHooks.Finish(returnData)
+ }
+}
+
+func (instance *EVMInstance) prepareInputAndCode(functionName string) ([]byte, []byte) {
+ code := instance.code
+ input := instance.flattenInput()
+
+ switch functionName {
+ case vmhost.InitFunctionName:
+ return nil, append(code, input...)
+ default:
+ selector := functionNameToSelector(functionName)
+ return append(selector, input...), code
+ }
+}
+
+func (instance *EVMInstance) flattenInput() []byte {
+ var input []byte
+ arguments := instance.evmExecutor.evmHooks.Arguments()
+ for _, slice := range arguments {
+ input = append(input, slice...)
+ }
+ return input
+}
+
+func (instance *EVMInstance) buildBlockContext() interpreter.BlockContext {
+ evmHooks := instance.evmExecutor.evmHooks
+ return interpreter.BlockContext{
+ GetHash: evmHooks.GetHash,
+ Coinbase: common.Address{},
+ GasLimit: evmHooks.BlockGasLimit(),
+ BlockNumber: evmHooks.BlockNumber(),
+ Time: evmHooks.Time(),
+ Difficulty: new(big.Int),
+ BaseFee: new(big.Int),
+ BlobBaseFee: new(big.Int),
+ Random: evmHooks.Random(),
+ }
+}
+
+func (instance *EVMInstance) buildTxContext() interpreter.TxContext {
+ evmHooks := instance.evmExecutor.evmHooks
+ return interpreter.TxContext{
+ Origin: evmHooks.Origin(),
+ GasPrice: evmHooks.GasPrice(),
+ BlobHashes: make([]common.Hash, 0),
+ BlobFeeCap: new(big.Int),
+ }
+}
+
+func (instance *EVMInstance) buildChainConfig() *params.ChainConfig {
+ evmHooks := instance.evmExecutor.evmHooks
+ return ¶ms.ChainConfig{
+ ChainID: evmHooks.ChainID(),
+ }
+}
+
+func functionNameToSelector(functionName string) []byte {
+ selector, err := hex.DecodeString(functionName)
+ if err != nil {
+ return nil
+ }
+ return selector
+}
diff --git a/evm/evmLogger.go b/evm/evmLogger.go
new file mode 100644
index 000000000..b5c2b45ea
--- /dev/null
+++ b/evm/evmLogger.go
@@ -0,0 +1,6 @@
+package evm
+
+import logger "github.com/multiversx/mx-chain-logger-go"
+
+// EVM logger.
+var logEVM = logger.GetOrCreate("vm/evm")
diff --git a/evm/interpreter/analysis.go b/evm/interpreter/analysis.go
new file mode 100644
index 000000000..563eebea4
--- /dev/null
+++ b/evm/interpreter/analysis.go
@@ -0,0 +1,118 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+const (
+ set2BitsMask = uint16(0b11)
+ set3BitsMask = uint16(0b111)
+ set4BitsMask = uint16(0b1111)
+ set5BitsMask = uint16(0b1_1111)
+ set6BitsMask = uint16(0b11_1111)
+ set7BitsMask = uint16(0b111_1111)
+)
+
+// bitvec is a bit vector which maps bytes in a program.
+// An unset bit means the byte is an opcode, a set bit means
+// it's data (i.e. argument of PUSHxx).
+type bitvec []byte
+
+func (bits bitvec) set1(pos uint64) {
+ bits[pos/8] |= 1 << (pos % 8)
+}
+
+func (bits bitvec) setN(flag uint16, pos uint64) {
+ a := flag << (pos % 8)
+ bits[pos/8] |= byte(a)
+ if b := byte(a >> 8); b != 0 {
+ bits[pos/8+1] = b
+ }
+}
+
+func (bits bitvec) set8(pos uint64) {
+ a := byte(0xFF << (pos % 8))
+ bits[pos/8] |= a
+ bits[pos/8+1] = ^a
+}
+
+func (bits bitvec) set16(pos uint64) {
+ a := byte(0xFF << (pos % 8))
+ bits[pos/8] |= a
+ bits[pos/8+1] = 0xFF
+ bits[pos/8+2] = ^a
+}
+
+// codeSegment checks if the position is in a code segment.
+func (bits *bitvec) codeSegment(pos uint64) bool {
+ return (((*bits)[pos/8] >> (pos % 8)) & 1) == 0
+}
+
+// codeBitmap collects data locations in code.
+func codeBitmap(code []byte) bitvec {
+ // The bitmap is 4 bytes longer than necessary, in case the code
+ // ends with a PUSH32, the algorithm will set bits on the
+ // bitvector outside the bounds of the actual code.
+ bits := make(bitvec, len(code)/8+1+4)
+ return codeBitmapInternal(code, bits)
+}
+
+// codeBitmapInternal is the internal implementation of codeBitmap.
+// It exists for the purpose of being able to run benchmark tests
+// without dynamic allocations affecting the results.
+func codeBitmapInternal(code, bits bitvec) bitvec {
+ for pc := uint64(0); pc < uint64(len(code)); {
+ op := OpCode(code[pc])
+ pc++
+ if int8(op) < int8(PUSH1) { // If not PUSH (the int8(op) > int(PUSH32) is always false).
+ continue
+ }
+ numbits := op - PUSH1 + 1
+ if numbits >= 8 {
+ for ; numbits >= 16; numbits -= 16 {
+ bits.set16(pc)
+ pc += 16
+ }
+ for ; numbits >= 8; numbits -= 8 {
+ bits.set8(pc)
+ pc += 8
+ }
+ }
+ switch numbits {
+ case 1:
+ bits.set1(pc)
+ pc += 1
+ case 2:
+ bits.setN(set2BitsMask, pc)
+ pc += 2
+ case 3:
+ bits.setN(set3BitsMask, pc)
+ pc += 3
+ case 4:
+ bits.setN(set4BitsMask, pc)
+ pc += 4
+ case 5:
+ bits.setN(set5BitsMask, pc)
+ pc += 5
+ case 6:
+ bits.setN(set6BitsMask, pc)
+ pc += 6
+ case 7:
+ bits.setN(set7BitsMask, pc)
+ pc += 7
+ }
+ }
+ return bits
+}
diff --git a/evm/interpreter/common.go b/evm/interpreter/common.go
new file mode 100644
index 000000000..3ae26a7ff
--- /dev/null
+++ b/evm/interpreter/common.go
@@ -0,0 +1,82 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
+ "github.com/holiman/uint256"
+)
+
+// calcMemSize64 calculates the required memory size, and returns
+// the size and whether the result overflowed uint64
+func calcMemSize64(off, l *uint256.Int) (uint64, bool) {
+ if !l.IsUint64() {
+ return 0, true
+ }
+ return calcMemSize64WithUint(off, l.Uint64())
+}
+
+// calcMemSize64WithUint calculates the required memory size, and returns
+// the size and whether the result overflowed uint64
+// Identical to calcMemSize64, but length is a uint64
+func calcMemSize64WithUint(off *uint256.Int, length64 uint64) (uint64, bool) {
+ // if length is zero, memsize is always zero, regardless of offset
+ if length64 == 0 {
+ return 0, false
+ }
+ // Check that offset doesn't overflow
+ offset64, overflow := off.Uint64WithOverflow()
+ if overflow {
+ return 0, true
+ }
+ val := offset64 + length64
+ // if value < either of it's parts, then it overflowed
+ return val, val < offset64
+}
+
+// getData returns a slice from the data based on the start and size and pads
+// up to size with zero's. This function is overflow safe.
+func getData(data []byte, start uint64, size uint64) []byte {
+ length := uint64(len(data))
+ if start > length {
+ start = length
+ }
+ end := start + size
+ if end > length {
+ end = length
+ }
+ return common.RightPadBytes(data[start:end], int(size))
+}
+
+// toWordSize returns the ceiled word size required for memory expansion.
+func toWordSize(size uint64) uint64 {
+ if size > math.MaxUint64-31 {
+ return math.MaxUint64/32 + 1
+ }
+
+ return (size + 31) / 32
+}
+
+func allZero(b []byte) bool {
+ for _, byte := range b {
+ if byte != 0 {
+ return false
+ }
+ }
+ return true
+}
diff --git a/evm/interpreter/contract.go b/evm/interpreter/contract.go
new file mode 100644
index 000000000..0bffda3e3
--- /dev/null
+++ b/evm/interpreter/contract.go
@@ -0,0 +1,150 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/holiman/uint256"
+)
+
+// ContractRef is a reference to the contract's backing object
+type ContractRef interface {
+ Address() common.Address
+}
+
+// AccountRef implements ContractRef.
+//
+// Account references are used during EVM initialisation and
+// its primary use is to fetch addresses. Removing this object
+// proves difficult because of the cached jump destinations which
+// are fetched from the parent contract (i.e. the caller), which
+// is a ContractRef.
+type AccountRef common.Address
+
+// Address casts AccountRef to an Address
+func (ar AccountRef) Address() common.Address { return (common.Address)(ar) }
+
+// Contract represents an ethereum contract in the state database. It contains
+// the contract code, calling arguments. Contract implements ContractRef
+type Contract struct {
+ // CallerAddress is the result of the caller which initialised this
+ // contract. However when the "call method" is delegated this value
+ // needs to be initialised to that of the caller's caller.
+ CallerAddress common.Address
+ caller ContractRef
+ self ContractRef
+
+ jumpdests map[common.Hash]bitvec // Aggregated result of JUMPDEST analysis.
+ analysis bitvec // Locally cached result of JUMPDEST analysis
+
+ Code []byte
+ CodeHash common.Hash
+ Input []byte
+
+ value *uint256.Int
+}
+
+// NewContract returns a new contract environment for the execution of EVM.
+func NewContract(caller ContractRef, object ContractRef, value *uint256.Int) *Contract {
+ c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object}
+
+ if parent, ok := caller.(*Contract); ok {
+ // Reuse JUMPDEST analysis from parent context if available.
+ c.jumpdests = parent.jumpdests
+ } else {
+ c.jumpdests = make(map[common.Hash]bitvec)
+ }
+
+ // ensures a value is set
+ c.value = value
+
+ return c
+}
+
+func (c *Contract) validJumpdest(dest *uint256.Int) bool {
+ udest, overflow := dest.Uint64WithOverflow()
+ // PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
+ // Don't bother checking for JUMPDEST in that case.
+ if overflow || udest >= uint64(len(c.Code)) {
+ return false
+ }
+ // Only JUMPDESTs allowed for destinations
+ if OpCode(c.Code[udest]) != JUMPDEST {
+ return false
+ }
+ return c.isCode(udest)
+}
+
+// isCode returns true if the provided PC location is an actual opcode, as
+// opposed to a data-segment following a PUSHN operation.
+func (c *Contract) isCode(udest uint64) bool {
+ // Do we already have an analysis laying around?
+ if c.analysis != nil {
+ return c.analysis.codeSegment(udest)
+ }
+ // Do we have a contract hash already?
+ // If we do have a hash, that means it's a 'regular' contract. For regular
+ // contracts ( not temporary initcode), we store the analysis in a map
+ if c.CodeHash != (common.Hash{}) {
+ // Does parent context have the analysis?
+ analysis, exist := c.jumpdests[c.CodeHash]
+ if !exist {
+ // Do the analysis and save in parent context
+ // We do not need to store it in c.analysis
+ analysis = codeBitmap(c.Code)
+ c.jumpdests[c.CodeHash] = analysis
+ }
+ // Also stash it in current contract for faster access
+ c.analysis = analysis
+ return analysis.codeSegment(udest)
+ }
+ // We don't have the code hash, most likely a piece of initcode not already
+ // in state trie. In that case, we do an analysis, and save it locally, so
+ // we don't have to recalculate it for every JUMP instruction in the execution
+ // However, we don't save it within the parent context
+ if c.analysis == nil {
+ c.analysis = codeBitmap(c.Code)
+ }
+ return c.analysis.codeSegment(udest)
+}
+
+// GetOp returns the n'th element in the contract's byte array
+func (c *Contract) GetOp(n uint64) OpCode {
+ if n < uint64(len(c.Code)) {
+ return OpCode(c.Code[n])
+ }
+
+ return STOP
+}
+
+// Caller returns the caller of the contract.
+//
+// Caller will recursively call caller when the contract is a delegate
+// call, including that of caller's caller.
+func (c *Contract) Caller() common.Address {
+ return c.CallerAddress
+}
+
+// Address returns the contracts address
+func (c *Contract) Address() common.Address {
+ return c.self.Address()
+}
+
+// Value returns the contract's value (sent to it from it's caller)
+func (c *Contract) Value() *uint256.Int {
+ return c.value
+}
diff --git a/evm/interpreter/contracts.go b/evm/interpreter/contracts.go
new file mode 100644
index 000000000..9d72afacb
--- /dev/null
+++ b/evm/interpreter/contracts.go
@@ -0,0 +1,564 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "crypto/sha256"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/crypto/blake2b"
+ "github.com/ethereum/go-ethereum/crypto/bn256"
+ "github.com/ethereum/go-ethereum/crypto/kzg4844"
+ "golang.org/x/crypto/ripemd160"
+)
+
+// PrecompiledContract is the basic interface for native Go contracts. The implementation
+// requires a deterministic gas count based on the input size of the Run method of the
+// contract.
+type PrecompiledContract interface {
+ RequiredGas(params *GasConfig, input []byte) uint64 // RequiredPrice calculates the contract gas use
+ Run(input []byte) ([]byte, error) // Run runs the precompiled contract
+}
+
+// PrecompiledContractsCancun contains the default set of pre-compiled Ethereum
+// contracts used in the Cancun release.
+var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{
+ common.BytesToAddress([]byte{1}): &ecrecover{},
+ common.BytesToAddress([]byte{2}): &sha256hash{},
+ common.BytesToAddress([]byte{3}): &ripemd160hash{},
+ common.BytesToAddress([]byte{4}): &dataCopy{},
+ common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
+ common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
+ common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
+ common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
+ common.BytesToAddress([]byte{9}): &blake2F{},
+ common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},
+}
+
+// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
+// It returns
+// - the returned bytes,
+// - the _remaining_ gas,
+// - any error that occurred
+func RunPrecompiledContract(evm *EVM, p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) {
+ gasCost := p.RequiredGas(evm.GasConfig, input)
+ if suppliedGas < gasCost {
+ return nil, 0, ErrOutOfGas
+ }
+ suppliedGas -= gasCost
+ output, err := p.Run(input)
+ return output, suppliedGas, err
+}
+
+// ECRECOVER implemented as a native contract.
+type ecrecover struct{}
+
+func (c *ecrecover) RequiredGas(params *GasConfig, input []byte) uint64 {
+ return params.Ecrecover
+}
+
+func (c *ecrecover) Run(input []byte) ([]byte, error) {
+ const ecRecoverInputLength = 128
+
+ input = common.RightPadBytes(input, ecRecoverInputLength)
+ // "input" is (hash, v, r, s), each 32 bytes
+ // but for ecrecover we want (r, s, v)
+
+ r := new(big.Int).SetBytes(input[64:96])
+ s := new(big.Int).SetBytes(input[96:128])
+ v := input[63] - 27
+
+ // tighter sig s values input homestead only apply to tx sigs
+ if !allZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) {
+ return nil, nil
+ }
+ // We must make sure not to modify the 'input', so placing the 'v' along with
+ // the signature needs to be done on a new allocation
+ sig := make([]byte, 65)
+ copy(sig, input[64:128])
+ sig[64] = v
+ // v needs to be at the end for libsecp256k1
+ pubKey, err := crypto.Ecrecover(input[:32], sig)
+ // make sure the public key is a valid one
+ if err != nil {
+ return nil, nil
+ }
+
+ // the first byte of pubkey is bitcoin heritage
+ return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32), nil
+}
+
+// SHA256 implemented as a native contract.
+type sha256hash struct{}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+//
+// This method does not require any overflow checking as the input size gas costs
+// required for anything significant is so high it's impossible to pay for.
+func (c *sha256hash) RequiredGas(params *GasConfig, input []byte) uint64 {
+ return uint64(len(input)+31)/32*params.Sha256PerWord + params.Sha256Base
+}
+func (c *sha256hash) Run(input []byte) ([]byte, error) {
+ h := sha256.Sum256(input)
+ return h[:], nil
+}
+
+// RIPEMD160 implemented as a native contract.
+type ripemd160hash struct{}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+//
+// This method does not require any overflow checking as the input size gas costs
+// required for anything significant is so high it's impossible to pay for.
+func (c *ripemd160hash) RequiredGas(params *GasConfig, input []byte) uint64 {
+ return uint64(len(input)+31)/32*params.Ripemd160PerWord + params.Ripemd160Base
+}
+func (c *ripemd160hash) Run(input []byte) ([]byte, error) {
+ ripemd := ripemd160.New()
+ ripemd.Write(input)
+ return common.LeftPadBytes(ripemd.Sum(nil), 32), nil
+}
+
+// data copy implemented as a native contract.
+type dataCopy struct{}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+//
+// This method does not require any overflow checking as the input size gas costs
+// required for anything significant is so high it's impossible to pay for.
+func (c *dataCopy) RequiredGas(params *GasConfig, input []byte) uint64 {
+ return uint64(len(input)+31)/32*params.IdentityPerWord + params.IdentityBase
+}
+func (c *dataCopy) Run(in []byte) ([]byte, error) {
+ return common.CopyBytes(in), nil
+}
+
+// bigModExp implements a native big integer exponential modular operation.
+type bigModExp struct {
+ eip2565 bool
+}
+
+var (
+ big1 = big.NewInt(1)
+ big3 = big.NewInt(3)
+ big4 = big.NewInt(4)
+ big7 = big.NewInt(7)
+ big8 = big.NewInt(8)
+ big16 = big.NewInt(16)
+ big20 = big.NewInt(20)
+ big32 = big.NewInt(32)
+ big64 = big.NewInt(64)
+ big96 = big.NewInt(96)
+ big480 = big.NewInt(480)
+ big1024 = big.NewInt(1024)
+ big3072 = big.NewInt(3072)
+ big199680 = big.NewInt(199680)
+)
+
+// modexpMultComplexity implements bigModexp multComplexity formula, as defined in EIP-198
+//
+// def mult_complexity(x):
+// if x <= 64: return x ** 2
+// elif x <= 1024: return x ** 2 // 4 + 96 * x - 3072
+// else: return x ** 2 // 16 + 480 * x - 199680
+//
+// where is x is max(length_of_MODULUS, length_of_BASE)
+func modexpMultComplexity(x *big.Int) *big.Int {
+ switch {
+ case x.Cmp(big64) <= 0:
+ x.Mul(x, x) // x ** 2
+ case x.Cmp(big1024) <= 0:
+ // (x ** 2 // 4 ) + ( 96 * x - 3072)
+ x = new(big.Int).Add(
+ new(big.Int).Div(new(big.Int).Mul(x, x), big4),
+ new(big.Int).Sub(new(big.Int).Mul(big96, x), big3072),
+ )
+ default:
+ // (x ** 2 // 16) + (480 * x - 199680)
+ x = new(big.Int).Add(
+ new(big.Int).Div(new(big.Int).Mul(x, x), big16),
+ new(big.Int).Sub(new(big.Int).Mul(big480, x), big199680),
+ )
+ }
+ return x
+}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+func (c *bigModExp) RequiredGas(params *GasConfig, input []byte) uint64 {
+ var (
+ baseLen = new(big.Int).SetBytes(getData(input, 0, 32))
+ expLen = new(big.Int).SetBytes(getData(input, 32, 32))
+ modLen = new(big.Int).SetBytes(getData(input, 64, 32))
+ )
+ if len(input) > 96 {
+ input = input[96:]
+ } else {
+ input = input[:0]
+ }
+ // Retrieve the head 32 bytes of exp for the adjusted exponent length
+ var expHead *big.Int
+ if big.NewInt(int64(len(input))).Cmp(baseLen) <= 0 {
+ expHead = new(big.Int)
+ } else {
+ if expLen.Cmp(big32) > 0 {
+ expHead = new(big.Int).SetBytes(getData(input, baseLen.Uint64(), 32))
+ } else {
+ expHead = new(big.Int).SetBytes(getData(input, baseLen.Uint64(), expLen.Uint64()))
+ }
+ }
+ // Calculate the adjusted exponent length
+ var msb int
+ if bitlen := expHead.BitLen(); bitlen > 0 {
+ msb = bitlen - 1
+ }
+ adjExpLen := new(big.Int)
+ if expLen.Cmp(big32) > 0 {
+ adjExpLen.Sub(expLen, big32)
+ adjExpLen.Mul(big8, adjExpLen)
+ }
+ adjExpLen.Add(adjExpLen, big.NewInt(int64(msb)))
+ // Calculate the gas cost of the operation
+ gas := new(big.Int).Set(math.BigMax(modLen, baseLen))
+ if c.eip2565 {
+ // EIP-2565 has three changes
+ // 1. Different multComplexity (inlined here)
+ // in EIP-2565 (https://eips.ethereum.org/EIPS/eip-2565):
+ //
+ // def mult_complexity(x):
+ // ceiling(x/8)^2
+ //
+ //where is x is max(length_of_MODULUS, length_of_BASE)
+ gas = gas.Add(gas, big7)
+ gas = gas.Div(gas, big8)
+ gas.Mul(gas, gas)
+
+ gas.Mul(gas, math.BigMax(adjExpLen, big1))
+ // 2. Different divisor (`GQUADDIVISOR`) (3)
+ gas.Div(gas, big3)
+ if gas.BitLen() > 64 {
+ return math.MaxUint64
+ }
+ // 3. Minimum price of 200 gas
+ if gas.Uint64() < 200 {
+ return 200
+ }
+ return gas.Uint64()
+ }
+ gas = modexpMultComplexity(gas)
+ gas.Mul(gas, math.BigMax(adjExpLen, big1))
+ gas.Div(gas, big20)
+
+ if gas.BitLen() > 64 {
+ return math.MaxUint64
+ }
+ return gas.Uint64()
+}
+
+func (c *bigModExp) Run(input []byte) ([]byte, error) {
+ var (
+ baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64()
+ expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64()
+ modLen = new(big.Int).SetBytes(getData(input, 64, 32)).Uint64()
+ )
+ if len(input) > 96 {
+ input = input[96:]
+ } else {
+ input = input[:0]
+ }
+ // Handle a special case when both the base and mod length is zero
+ if baseLen == 0 && modLen == 0 {
+ return []byte{}, nil
+ }
+ // Retrieve the operands and execute the exponentiation
+ var (
+ base = new(big.Int).SetBytes(getData(input, 0, baseLen))
+ exp = new(big.Int).SetBytes(getData(input, baseLen, expLen))
+ mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen))
+ v []byte
+ )
+ switch {
+ case mod.BitLen() == 0:
+ // Modulo 0 is undefined, return zero
+ return common.LeftPadBytes([]byte{}, int(modLen)), nil
+ case base.BitLen() == 1: // a bit length of 1 means it's 1 (or -1).
+ //If base == 1, then we can just return base % mod (if mod >= 1, which it is)
+ v = base.Mod(base, mod).Bytes()
+ default:
+ v = base.Exp(base, exp, mod).Bytes()
+ }
+ return common.LeftPadBytes(v, int(modLen)), nil
+}
+
+// newCurvePoint unmarshals a binary blob into a bn256 elliptic curve point,
+// returning it, or an error if the point is invalid.
+func newCurvePoint(blob []byte) (*bn256.G1, error) {
+ p := new(bn256.G1)
+ if _, err := p.Unmarshal(blob); err != nil {
+ return nil, err
+ }
+ return p, nil
+}
+
+// newTwistPoint unmarshals a binary blob into a bn256 elliptic curve point,
+// returning it, or an error if the point is invalid.
+func newTwistPoint(blob []byte) (*bn256.G2, error) {
+ p := new(bn256.G2)
+ if _, err := p.Unmarshal(blob); err != nil {
+ return nil, err
+ }
+ return p, nil
+}
+
+// runBn256Add implements the Bn256Add precompile, referenced by both
+// Byzantium and Istanbul operations.
+func runBn256Add(input []byte) ([]byte, error) {
+ x, err := newCurvePoint(getData(input, 0, 64))
+ if err != nil {
+ return nil, err
+ }
+ y, err := newCurvePoint(getData(input, 64, 64))
+ if err != nil {
+ return nil, err
+ }
+ res := new(bn256.G1)
+ res.Add(x, y)
+ return res.Marshal(), nil
+}
+
+// bn256Add implements a native elliptic curve point addition conforming to
+// Istanbul consensus rules.
+type bn256AddIstanbul struct{}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+func (c *bn256AddIstanbul) RequiredGas(params *GasConfig, input []byte) uint64 {
+ return params.Bn256Add
+}
+
+func (c *bn256AddIstanbul) Run(input []byte) ([]byte, error) {
+ return runBn256Add(input)
+}
+
+// runBn256ScalarMul implements the Bn256ScalarMul precompile, referenced by
+// both Byzantium and Istanbul operations.
+func runBn256ScalarMul(input []byte) ([]byte, error) {
+ p, err := newCurvePoint(getData(input, 0, 64))
+ if err != nil {
+ return nil, err
+ }
+ res := new(bn256.G1)
+ res.ScalarMult(p, new(big.Int).SetBytes(getData(input, 64, 32)))
+ return res.Marshal(), nil
+}
+
+// bn256ScalarMulIstanbul implements a native elliptic curve scalar
+// multiplication conforming to Istanbul consensus rules.
+type bn256ScalarMulIstanbul struct{}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+func (c *bn256ScalarMulIstanbul) RequiredGas(params *GasConfig, input []byte) uint64 {
+ return params.Bn256ScalarMul
+}
+
+func (c *bn256ScalarMulIstanbul) Run(input []byte) ([]byte, error) {
+ return runBn256ScalarMul(input)
+}
+
+var (
+ // true32Byte is returned if the bn256 pairing check succeeds.
+ true32Byte = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
+
+ // false32Byte is returned if the bn256 pairing check fails.
+ false32Byte = make([]byte, 32)
+
+ // errBadPairingInput is returned if the bn256 pairing input is invalid.
+ errBadPairingInput = errors.New("bad elliptic curve pairing size")
+)
+
+// runBn256Pairing implements the Bn256Pairing precompile, referenced by both
+// Byzantium and Istanbul operations.
+func runBn256Pairing(input []byte) ([]byte, error) {
+ // Handle some corner cases cheaply
+ if len(input)%192 > 0 {
+ return nil, errBadPairingInput
+ }
+ // Convert the input into a set of coordinates
+ var (
+ cs []*bn256.G1
+ ts []*bn256.G2
+ )
+ for i := 0; i < len(input); i += 192 {
+ c, err := newCurvePoint(input[i : i+64])
+ if err != nil {
+ return nil, err
+ }
+ t, err := newTwistPoint(input[i+64 : i+192])
+ if err != nil {
+ return nil, err
+ }
+ cs = append(cs, c)
+ ts = append(ts, t)
+ }
+ // Execute the pairing checks and return the results
+ if bn256.PairingCheck(cs, ts) {
+ return true32Byte, nil
+ }
+ return false32Byte, nil
+}
+
+// bn256PairingIstanbul implements a pairing pre-compile for the bn256 curve
+// conforming to Istanbul consensus rules.
+type bn256PairingIstanbul struct{}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+func (c *bn256PairingIstanbul) RequiredGas(params *GasConfig, input []byte) uint64 {
+ return params.Bn256PairingBase + uint64(len(input)/192)*params.Bn256PairingPerPoint
+}
+
+func (c *bn256PairingIstanbul) Run(input []byte) ([]byte, error) {
+ return runBn256Pairing(input)
+}
+
+type blake2F struct{}
+
+func (c *blake2F) RequiredGas(params *GasConfig, input []byte) uint64 {
+ // If the input is malformed, we can't calculate the gas, return 0 and let the
+ // actual call choke and fault.
+ if len(input) != blake2FInputLength {
+ return 0
+ }
+ return uint64(binary.BigEndian.Uint32(input[0:4]))
+}
+
+const (
+ blake2FInputLength = 213
+ blake2FFinalBlockBytes = byte(1)
+ blake2FNonFinalBlockBytes = byte(0)
+)
+
+var (
+ errBlake2FInvalidInputLength = errors.New("invalid input length")
+ errBlake2FInvalidFinalFlag = errors.New("invalid final flag")
+)
+
+func (c *blake2F) Run(input []byte) ([]byte, error) {
+ // Make sure the input is valid (correct length and final flag)
+ if len(input) != blake2FInputLength {
+ return nil, errBlake2FInvalidInputLength
+ }
+ if input[212] != blake2FNonFinalBlockBytes && input[212] != blake2FFinalBlockBytes {
+ return nil, errBlake2FInvalidFinalFlag
+ }
+ // Parse the input into the Blake2b call parameters
+ var (
+ rounds = binary.BigEndian.Uint32(input[0:4])
+ final = input[212] == blake2FFinalBlockBytes
+
+ h [8]uint64
+ m [16]uint64
+ t [2]uint64
+ )
+ for i := 0; i < 8; i++ {
+ offset := 4 + i*8
+ h[i] = binary.LittleEndian.Uint64(input[offset : offset+8])
+ }
+ for i := 0; i < 16; i++ {
+ offset := 68 + i*8
+ m[i] = binary.LittleEndian.Uint64(input[offset : offset+8])
+ }
+ t[0] = binary.LittleEndian.Uint64(input[196:204])
+ t[1] = binary.LittleEndian.Uint64(input[204:212])
+
+ // Execute the compression function, extract and return the result
+ blake2b.F(&h, m, t, final, rounds)
+
+ output := make([]byte, 64)
+ for i := 0; i < 8; i++ {
+ offset := i * 8
+ binary.LittleEndian.PutUint64(output[offset:offset+8], h[i])
+ }
+ return output, nil
+}
+
+// kzgPointEvaluation implements the EIP-4844 point evaluation precompile.
+type kzgPointEvaluation struct{}
+
+// RequiredGas estimates the gas required for running the point evaluation precompile.
+func (b *kzgPointEvaluation) RequiredGas(params *GasConfig, input []byte) uint64 {
+ return params.BlobTxPointEvaluation
+}
+
+const (
+ blobVerifyInputLength = 192 // Max input length for the point evaluation precompile.
+ blobCommitmentVersionKZG uint8 = 0x01 // Version byte for the point evaluation precompile.
+ blobPrecompileReturnValue = "000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"
+)
+
+var (
+ errBlobVerifyInvalidInputLength = errors.New("invalid input length")
+ errBlobVerifyMismatchedVersion = errors.New("mismatched versioned hash")
+ errBlobVerifyKZGProof = errors.New("error verifying kzg proof")
+)
+
+// Run executes the point evaluation precompile.
+func (b *kzgPointEvaluation) Run(input []byte) ([]byte, error) {
+ if len(input) != blobVerifyInputLength {
+ return nil, errBlobVerifyInvalidInputLength
+ }
+ // versioned hash: first 32 bytes
+ var versionedHash common.Hash
+ copy(versionedHash[:], input[:])
+
+ var (
+ point kzg4844.Point
+ claim kzg4844.Claim
+ )
+ // Evaluation point: next 32 bytes
+ copy(point[:], input[32:])
+ // Expected output: next 32 bytes
+ copy(claim[:], input[64:])
+
+ // input kzg point: next 48 bytes
+ var commitment kzg4844.Commitment
+ copy(commitment[:], input[96:])
+ if kZGToVersionedHash(commitment) != versionedHash {
+ return nil, errBlobVerifyMismatchedVersion
+ }
+
+ // Proof: next 48 bytes
+ var proof kzg4844.Proof
+ copy(proof[:], input[144:])
+
+ if err := kzg4844.VerifyProof(commitment, point, claim, proof); err != nil {
+ return nil, fmt.Errorf("%w: %v", errBlobVerifyKZGProof, err)
+ }
+
+ return common.Hex2Bytes(blobPrecompileReturnValue), nil
+}
+
+// kZGToVersionedHash implements kzg_to_versioned_hash from EIP-4844
+func kZGToVersionedHash(kzg kzg4844.Commitment) common.Hash {
+ h := sha256.Sum256(kzg[:])
+ h[0] = blobCommitmentVersionKZG
+
+ return h
+}
diff --git a/evm/interpreter/doc.go b/evm/interpreter/doc.go
new file mode 100644
index 000000000..27986e0c4
--- /dev/null
+++ b/evm/interpreter/doc.go
@@ -0,0 +1,24 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+/*
+Package vm implements the Ethereum Virtual Machine.
+
+The vm package implements one EVM, a byte code VM. The BC (Byte Code) VM loops
+over a set of bytes and executes them according to the set of rules defined
+in the Ethereum yellow paper.
+*/
+package evm
diff --git a/evm/interpreter/eips.go b/evm/interpreter/eips.go
new file mode 100644
index 000000000..7b63a4380
--- /dev/null
+++ b/evm/interpreter/eips.go
@@ -0,0 +1,206 @@
+// Copyright 2019 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/holiman/uint256"
+)
+
+// enable1884 applies EIP-1884 to the given jump table:
+// - Define SELFBALANCE
+func enable1884(jt *JumpTable, gasConfig *GasConfig) {
+ // New opcode
+ jt[SELFBALANCE] = &operation{
+ execute: opSelfBalance,
+ constantGas: gasConfig.Balance,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ }
+}
+
+func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ balance := interpreter.evm.StateDB.GetSelfBalance()
+ scope.Stack.push(balance)
+ return nil, nil
+}
+
+// enable1344 applies EIP-1344 (ChainID Opcode)
+// - Adds an opcode that returns the current chain’s EIP-155 unique identifier
+func enable1344(jt *JumpTable, gasConfig *GasConfig) {
+ // New opcode
+ jt[CHAINID] = &operation{
+ execute: opChainID,
+ constantGas: gasConfig.QuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ }
+}
+
+// opChainID implements CHAINID opcode
+func opChainID(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainID)
+ scope.Stack.push(chainId)
+ return nil, nil
+}
+
+// enable3198 applies EIP-3198 (BASEFEE Opcode)
+// - Adds an opcode that returns the current block's base fee.
+func enable3198(jt *JumpTable, gasConfig *GasConfig) {
+ // New opcode
+ jt[BASEFEE] = &operation{
+ execute: opBaseFee,
+ constantGas: gasConfig.QuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ }
+}
+
+// enable1153 applies EIP-1153 "Transient Storage"
+// - Adds TLOAD that reads from transient storage
+// - Adds TSTORE that writes to transient storage
+func enable1153(jt *JumpTable, gasConfig *GasConfig) {
+ jt[TLOAD] = &operation{
+ execute: opTload,
+ constantGas: gasConfig.Tload,
+ minStack: minStack(1, 1),
+ maxStack: maxStack(1, 1),
+ }
+
+ jt[TSTORE] = &operation{
+ execute: opTstore,
+ constantGas: gasConfig.Tstore,
+ minStack: minStack(2, 0),
+ maxStack: maxStack(2, 0),
+ }
+}
+
+// opTload implements TLOAD opcode
+func opTload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ loc := scope.Stack.peek()
+ hash := common.Hash(loc.Bytes32())
+ val := interpreter.evm.StateDB.GetTransientState(scope.Contract.Address(), hash)
+ loc.SetBytes(val.Bytes())
+ return nil, nil
+}
+
+// opTstore implements TSTORE opcode
+func opTstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ if interpreter.readOnly {
+ return nil, ErrWriteProtection
+ }
+ loc := scope.Stack.pop()
+ val := scope.Stack.pop()
+ interpreter.evm.StateDB.SetTransientState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32())
+ return nil, nil
+}
+
+// opBaseFee implements BASEFEE opcode
+func opBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ baseFee, _ := uint256.FromBig(interpreter.evm.Context.BaseFee)
+ scope.Stack.push(baseFee)
+ return nil, nil
+}
+
+// enable3855 applies EIP-3855 (PUSH0 opcode)
+func enable3855(jt *JumpTable, gasConfig *GasConfig) {
+ // New opcode
+ jt[PUSH0] = &operation{
+ execute: opPush0,
+ constantGas: gasConfig.QuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ }
+}
+
+// opPush0 implements the PUSH0 opcode
+func opPush0(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.push(new(uint256.Int))
+ return nil, nil
+}
+
+// enable3860 enables "EIP-3860: Limit and meter initcode"
+// https://eips.ethereum.org/EIPS/eip-3860
+func enable3860(jt *JumpTable) {
+ jt[CREATE].dynamicGas = gasCreateEip3860
+ jt[CREATE2].dynamicGas = gasCreate2Eip3860
+}
+
+// enable5656 enables EIP-5656 (MCOPY opcode)
+// https://eips.ethereum.org/EIPS/eip-5656
+func enable5656(jt *JumpTable, gasConfig *GasConfig) {
+ jt[MCOPY] = &operation{
+ execute: opMcopy,
+ constantGas: gasConfig.FastestStep,
+ dynamicGas: gasMcopy,
+ minStack: minStack(3, 0),
+ maxStack: maxStack(3, 0),
+ memorySize: memoryMcopy,
+ }
+}
+
+// opMcopy implements the MCOPY opcode (https://eips.ethereum.org/EIPS/eip-5656)
+func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ var (
+ dst = scope.Stack.pop()
+ src = scope.Stack.pop()
+ length = scope.Stack.pop()
+ )
+ // These values are checked for overflow during memory expansion calculation
+ // (the memorySize function on the opcode).
+ scope.Memory.Copy(dst.Uint64(), src.Uint64(), length.Uint64())
+ return nil, nil
+}
+
+// opBlobHash implements the BLOBHASH opcode
+func opBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ index := scope.Stack.peek()
+ if index.LtUint64(uint64(len(interpreter.evm.TxContext.BlobHashes))) {
+ blobHash := interpreter.evm.TxContext.BlobHashes[index.Uint64()]
+ index.SetBytes32(blobHash[:])
+ } else {
+ index.Clear()
+ }
+ return nil, nil
+}
+
+// opBlobBaseFee implements BLOBBASEFEE opcode
+func opBlobBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ blobBaseFee, _ := uint256.FromBig(interpreter.evm.Context.BlobBaseFee)
+ scope.Stack.push(blobBaseFee)
+ return nil, nil
+}
+
+// enable4844 applies EIP-4844 (BLOBHASH opcode)
+func enable4844(jt *JumpTable, gasConfig *GasConfig) {
+ jt[BLOBHASH] = &operation{
+ execute: opBlobHash,
+ constantGas: gasConfig.FastestStep,
+ minStack: minStack(1, 1),
+ maxStack: maxStack(1, 1),
+ }
+}
+
+// enable7516 applies EIP-7516 (BLOBBASEFEE opcode)
+func enable7516(jt *JumpTable, gasConfig *GasConfig) {
+ jt[BLOBBASEFEE] = &operation{
+ execute: opBlobBaseFee,
+ constantGas: gasConfig.QuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ }
+}
diff --git a/evm/interpreter/errors.go b/evm/interpreter/errors.go
new file mode 100644
index 000000000..686ef1988
--- /dev/null
+++ b/evm/interpreter/errors.go
@@ -0,0 +1,73 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "errors"
+ "fmt"
+)
+
+// List evm execution errors
+var (
+ ErrOutOfGas = errors.New("out of gas")
+ ErrCodeStoreOutOfGas = errors.New("contract creation code storage out of gas")
+ ErrDepth = errors.New("max call depth exceeded")
+ ErrInsufficientBalance = errors.New("insufficient balance for transfer")
+ ErrContractAddressCollision = errors.New("contract address collision")
+ ErrExecutionReverted = errors.New("execution reverted")
+ ErrMaxInitCodeSizeExceeded = errors.New("max initcode size exceeded")
+ ErrMaxCodeSizeExceeded = errors.New("max code size exceeded")
+ ErrInvalidJump = errors.New("invalid jump destination")
+ ErrWriteProtection = errors.New("write protection")
+ ErrReturnDataOutOfBounds = errors.New("return data out of bounds")
+ ErrGasUintOverflow = errors.New("gas uint64 overflow")
+ ErrInvalidCode = errors.New("invalid code: must not begin with 0xef")
+ ErrNonceUintOverflow = errors.New("nonce uint64 overflow")
+
+ // errStopToken is an internal token indicating interpreter loop termination,
+ // never returned to outside callers.
+ errStopToken = errors.New("stop token")
+)
+
+// ErrStackUnderflow wraps an evm error when the items on the stack less
+// than the minimal requirement.
+type ErrStackUnderflow struct {
+ stackLen int
+ required int
+}
+
+func (e *ErrStackUnderflow) Error() string {
+ return fmt.Sprintf("stack underflow (%d <=> %d)", e.stackLen, e.required)
+}
+
+// ErrStackOverflow wraps an evm error when the items on the stack exceeds
+// the maximum allowance.
+type ErrStackOverflow struct {
+ stackLen int
+ limit int
+}
+
+func (e *ErrStackOverflow) Error() string {
+ return fmt.Sprintf("stack limit reached %d (%d)", e.stackLen, e.limit)
+}
+
+// ErrInvalidOpCode wraps an evm error when an invalid opcode is encountered.
+type ErrInvalidOpCode struct {
+ opcode OpCode
+}
+
+func (e *ErrInvalidOpCode) Error() string { return fmt.Sprintf("invalid opcode: %s", e.opcode) }
diff --git a/evm/interpreter/evm.go b/evm/interpreter/evm.go
new file mode 100644
index 000000000..2b76a617d
--- /dev/null
+++ b/evm/interpreter/evm.go
@@ -0,0 +1,183 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "fmt"
+ "github.com/ethereum/go-ethereum/params"
+ "github.com/holiman/uint256"
+ "math/big"
+ "sync/atomic"
+
+ "github.com/ethereum/go-ethereum/common"
+)
+
+type (
+ // GetHashFunc returns the n'th block hash in the blockchain
+ // and is used by the BLOCKHASH EVM op code.
+ GetHashFunc func(uint64) common.Hash
+)
+
+func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
+ var precompiles map[common.Address]PrecompiledContract
+ switch {
+ default:
+ precompiles = PrecompiledContractsCancun
+ }
+ p, ok := precompiles[addr]
+ return p, ok
+}
+
+// BlockContext provides the EVM with auxiliary information. Once provided
+// it shouldn't be modified.
+type BlockContext struct {
+ // GetHash returns the hash corresponding to n
+ GetHash GetHashFunc
+
+ // Block information
+ Coinbase common.Address // Provides information for COINBASE
+ GasLimit uint64 // Provides information for GASLIMIT
+ BlockNumber *big.Int // Provides information for NUMBER
+ Time uint64 // Provides information for TIME
+ Difficulty *big.Int // Provides information for DIFFICULTY
+ BaseFee *big.Int // Provides information for BASEFEE (0 if vm runs with NoBaseFee flag and 0 gas price)
+ BlobBaseFee *big.Int // Provides information for BLOBBASEFEE (0 if vm runs with NoBaseFee flag and 0 blob gas price)
+ Random *common.Hash // Provides information for PREVRANDAO
+}
+
+// TxContext provides the EVM with information about a transaction.
+// All fields can change between transactions.
+type TxContext struct {
+ // Message information
+ Origin common.Address // Provides information for ORIGIN
+ GasPrice *big.Int // Provides information for GASPRICE (and is used to zero the basefee if NoBaseFee is set)
+ BlobHashes []common.Hash // Provides information for BLOBHASH
+ BlobFeeCap *big.Int // Is used to zero the blobbasefee if NoBaseFee is set
+}
+
+// EVM is the Ethereum Virtual Machine base object and provides
+// the necessary tools to run a contract on the given state with
+// the provided context. It should be noted that any error
+// generated through any of the calls should be considered a
+// revert-state-and-consume-all-gas operation, no checks on
+// specific errors should ever be performed. The interpreter makes
+// sure that any errors generated are to be considered faulty code.
+//
+// The EVM should never be reused and is not thread safe.
+type EVM struct {
+ // Context provides auxiliary blockchain related information
+ Context BlockContext
+ TxContext
+ // StateDB gives access to the underlying state
+ StateDB StateDB
+ // chainConfig contains information about the current chain
+ chainConfig *params.ChainConfig
+ // GasConfig contains the gas costs
+ GasConfig *GasConfig
+ // global (to this context) ethereum virtual machine
+ // used throughout the execution of the tx.
+ interpreter *EVMInterpreter
+ // abort is used to abort the EVM calling operations
+ abort atomic.Bool
+ // callGasTemp holds the gas available for the current call. This is needed because the
+ // available gas is calculated in gasCall* and later
+ // applied in opCall*.
+ callGasTemp uint64
+}
+
+// NewEVM returns a new EVM. The returned EVM is not thread safe and should
+// only ever be used *once*.
+func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, gasConfig *GasConfig, instructionSet *JumpTable) *EVM {
+ evm := &EVM{
+ Context: blockCtx,
+ TxContext: txCtx,
+ StateDB: statedb,
+ chainConfig: chainConfig,
+ GasConfig: gasConfig,
+ }
+ evm.interpreter = NewEVMInterpreter(evm, instructionSet)
+ return evm
+}
+
+// Cancel cancels any running EVM operation. This may be called concurrently and
+// it's safe to be called multiple times.
+func (evm *EVM) Cancel() {
+ evm.abort.Store(true)
+}
+
+// Cancelled returns true if Cancel has been called
+func (evm *EVM) Cancelled() bool {
+ return evm.abort.Load()
+}
+
+// Interpreter returns the current interpreter
+func (evm *EVM) Interpreter() *EVMInterpreter {
+ return evm.interpreter
+}
+
+func (evm *EVM) Call(addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, err error) {
+ if p, isPrecompile := evm.precompile(addr); isPrecompile {
+ ret, err = evm.RunPrecompiledAndConsumeGas(p, input, gas)
+ } else {
+ if evm.StateDB.IsSmartContractAddress(addr) {
+ ret, err = evm.StateDB.Call(addr, value, input, gas)
+ } else {
+ ret, err = nil, evm.StateDB.TransferBalance(addr, value)
+ }
+ }
+ return ret, err
+}
+
+func (evm *EVM) CallCode(addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, err error) {
+ if p, isPrecompile := evm.precompile(addr); isPrecompile {
+ ret, err = evm.RunPrecompiledAndConsumeGas(p, input, gas)
+ } else {
+ ret, err = evm.StateDB.CallCode(addr, value, input, gas)
+ }
+ return ret, err
+}
+
+func (evm *EVM) DelegateCall(addr common.Address, input []byte, gas uint64) (ret []byte, err error) {
+ if p, isPrecompile := evm.precompile(addr); isPrecompile {
+ ret, err = evm.RunPrecompiledAndConsumeGas(p, input, gas)
+ } else {
+ ret, err = evm.StateDB.DelegateCall(addr, input, gas)
+ }
+ return ret, err
+}
+
+func (evm *EVM) StaticCall(addr common.Address, input []byte, gas uint64) (ret []byte, err error) {
+ if p, isPrecompile := evm.precompile(addr); isPrecompile {
+ ret, err = evm.RunPrecompiledAndConsumeGas(p, input, gas)
+ } else {
+ ret, err = evm.StateDB.StaticCall(addr, input, gas)
+ }
+ return ret, err
+}
+
+func (evm *EVM) RunPrecompiledAndConsumeGas(p PrecompiledContract, input []byte, suppliedGas uint64) ([]byte, error) {
+ ret, remainingGas, err := RunPrecompiledContract(evm, p, input, suppliedGas)
+
+ usedGas := suppliedGas - remainingGas
+ precompileIdentifier := fmt.Sprintf("%T", p)
+ if !evm.StateDB.UseGas(precompileIdentifier, usedGas) {
+ err = ErrOutOfGas
+ evm.StateDB.FailExecution(err)
+ }
+
+ return ret, err
+}
diff --git a/evm/interpreter/gas.go b/evm/interpreter/gas.go
new file mode 100644
index 000000000..68bc015c0
--- /dev/null
+++ b/evm/interpreter/gas.go
@@ -0,0 +1,41 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "github.com/holiman/uint256"
+)
+
+// callGas returns the actual gas cost of the call.
+//
+// The cost of gas was changed during the homestead price change HF.
+func callGas(isEip150 bool, availableGas, base uint64, callCost *uint256.Int) (uint64, error) {
+ if isEip150 {
+ gas := availableGas - base
+ // If the bit length exceeds 64 bit we know that the newly calculated "gas" for EIP150
+ // is smaller than the requested amount. Therefore we return the new gas instead
+ // of returning an error.
+ if !callCost.IsUint64() || gas < callCost.Uint64() {
+ return gas, nil
+ }
+ }
+ if !callCost.IsUint64() {
+ return 0, ErrGasUintOverflow
+ }
+
+ return callCost.Uint64(), nil
+}
diff --git a/evm/interpreter/gas_config.go b/evm/interpreter/gas_config.go
new file mode 100644
index 000000000..1c651fb2d
--- /dev/null
+++ b/evm/interpreter/gas_config.go
@@ -0,0 +1,51 @@
+// Code generated by vmhooks generator. DO NOT EDIT.
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!! AUTO-GENERATED FILE !!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+package evm
+
+type GasConfig struct {
+ QuickStep uint64
+ FastestStep uint64
+ FastStep uint64
+ MidStep uint64
+ SlowStep uint64
+ ExtStep uint64
+ Ecrecover uint64
+ Sha256PerWord uint64
+ Sha256Base uint64
+ Ripemd160PerWord uint64
+ Ripemd160Base uint64
+ IdentityPerWord uint64
+ IdentityBase uint64
+ Bn256Add uint64
+ Bn256ScalarMul uint64
+ Bn256PairingBase uint64
+ Bn256PairingPerPoint uint64
+ BlobTxPointEvaluation uint64
+ Keccak256 uint64
+ Balance uint64
+ ExtcodeSize uint64
+ ExtcodeCopy uint64
+ ExtcodeHash uint64
+ Sload uint64
+ Sstore uint64
+ Jumpdest uint64
+ Tload uint64
+ Tstore uint64
+ Create uint64
+ Call uint64
+ Create2 uint64
+ Selfdestruct uint64
+ Memory uint64
+ Copy uint64
+ Log uint64
+ LogTopic uint64
+ LogData uint64
+ Keccak256Word uint64
+ InitCodeWord uint64
+ ExpByte uint64
+ Exp uint64
+}
diff --git a/evm/interpreter/gas_table.go b/evm/interpreter/gas_table.go
new file mode 100644
index 000000000..f190f06d2
--- /dev/null
+++ b/evm/interpreter/gas_table.go
@@ -0,0 +1,233 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "github.com/ethereum/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/params"
+)
+
+// memoryGasCost calculates the quadratic gas for memory expansion. It does so
+// only for the memory region that is expanded, not the total memory.
+func memoryGasCost(evm *EVM, mem *Memory, newMemSize uint64) (uint64, error) {
+ if newMemSize == 0 {
+ return 0, nil
+ }
+ // The maximum that will fit in a uint64 is max_word_count - 1. Anything above
+ // that will result in an overflow. Additionally, a newMemSize which results in
+ // a newMemSizeWords larger than 0xFFFFFFFF will cause the square operation to
+ // overflow. The constant 0x1FFFFFFFE0 is the highest number that can be used
+ // without overflowing the gas calculation.
+ if newMemSize > 0x1FFFFFFFE0 {
+ return 0, ErrGasUintOverflow
+ }
+ newMemSizeWords := toWordSize(newMemSize)
+ newMemSize = newMemSizeWords * 32
+
+ if newMemSize > uint64(mem.Len()) {
+ square := newMemSizeWords * newMemSizeWords
+ linCoef := newMemSizeWords * evm.GasConfig.Memory
+ quadCoef := square / params.QuadCoeffDiv
+ newTotalFee := linCoef + quadCoef
+
+ fee := newTotalFee - mem.lastGasCost
+ mem.lastGasCost = newTotalFee
+
+ return fee, nil
+ }
+ return 0, nil
+}
+
+// memoryCopierGas creates the gas functions for the following opcodes, and takes
+// the stack position of the operand which determines the size of the data to copy
+// as argument:
+// CALLDATACOPY (stack position 2)
+// CODECOPY (stack position 2)
+// 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(evm, 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), evm.GasConfig.Copy); 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 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(evm, mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
+
+ if gas, overflow = math.SafeAdd(gas, evm.GasConfig.Log); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ if gas, overflow = math.SafeAdd(gas, n*evm.GasConfig.LogTopic); overflow {
+ return 0, ErrGasUintOverflow
+ }
+
+ var memorySizeGas uint64
+ if memorySizeGas, overflow = math.SafeMul(requestedSize, evm.GasConfig.LogData); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ return gas, nil
+ }
+}
+
+func gasKeccak256(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ gas, err := memoryGasCost(evm, mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
+ wordGas, overflow := stack.Back(1).Uint64WithOverflow()
+ if overflow {
+ return 0, ErrGasUintOverflow
+ }
+ if wordGas, overflow = math.SafeMul(toWordSize(wordGas), evm.GasConfig.Keccak256Word); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ return gas, nil
+}
+
+// pureMemoryGascost is used by several operations, which aside from their
+// static cost have a dynamic cost which is solely based on the memory
+// expansion
+func pureMemoryGascost(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ return memoryGasCost(evm, mem, memorySize)
+}
+
+var (
+ gasReturn = pureMemoryGascost
+ gasRevert = pureMemoryGascost
+ gasMLoad = pureMemoryGascost
+ gasMStore8 = pureMemoryGascost
+ gasMStore = pureMemoryGascost
+ gasCreate = pureMemoryGascost
+)
+
+func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ gas, err := memoryGasCost(evm, mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
+ wordGas, overflow := stack.Back(2).Uint64WithOverflow()
+ if overflow {
+ return 0, ErrGasUintOverflow
+ }
+ if wordGas, overflow = math.SafeMul(toWordSize(wordGas), evm.GasConfig.Keccak256Word); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ return gas, nil
+}
+
+func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ gas, err := memoryGasCost(evm, mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
+ size, overflow := stack.Back(2).Uint64WithOverflow()
+ if overflow || size > params.MaxInitCodeSize {
+ return 0, ErrGasUintOverflow
+ }
+ // Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
+ moreGas := evm.GasConfig.InitCodeWord * ((size + 31) / 32)
+ if gas, overflow = math.SafeAdd(gas, moreGas); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ return gas, nil
+}
+func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ gas, err := memoryGasCost(evm, mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
+ size, overflow := stack.Back(2).Uint64WithOverflow()
+ if overflow || size > params.MaxInitCodeSize {
+ return 0, ErrGasUintOverflow
+ }
+ // Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
+ moreGas := (evm.GasConfig.InitCodeWord + evm.GasConfig.Keccak256Word) * ((size + 31) / 32)
+ if gas, overflow = math.SafeAdd(gas, moreGas); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ return gas, nil
+}
+
+func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
+
+ var (
+ gas = expByteLen * evm.GasConfig.ExpByte // no overflow check required. Max is 256 * ExpByte gas
+ overflow bool
+ )
+ if gas, overflow = math.SafeAdd(gas, evm.GasConfig.Exp); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ return gas, nil
+}
+
+func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ gas, err := memoryGasCost(evm, mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
+ evm.callGasTemp, err = callGas(true, evm.StateDB.GasLeft(), gas, stack.Back(0))
+ if err != nil {
+ return 0, err
+ }
+ return gas, nil
+}
diff --git a/evm/interpreter/instructions.go b/evm/interpreter/instructions.go
new file mode 100644
index 000000000..d0479cc48
--- /dev/null
+++ b/evm/interpreter/instructions.go
@@ -0,0 +1,826 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "math"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/holiman/uint256"
+)
+
+func opAdd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y := scope.Stack.pop(), scope.Stack.peek()
+ y.Add(&x, y)
+ return nil, nil
+}
+
+func opSub(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y := scope.Stack.pop(), scope.Stack.peek()
+ y.Sub(&x, y)
+ return nil, nil
+}
+
+func opMul(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y := scope.Stack.pop(), scope.Stack.peek()
+ y.Mul(&x, y)
+ return nil, nil
+}
+
+func opDiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y := scope.Stack.pop(), scope.Stack.peek()
+ y.Div(&x, y)
+ return nil, nil
+}
+
+func opSdiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y := scope.Stack.pop(), scope.Stack.peek()
+ y.SDiv(&x, y)
+ return nil, nil
+}
+
+func opMod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y := scope.Stack.pop(), scope.Stack.peek()
+ y.Mod(&x, y)
+ return nil, nil
+}
+
+func opSmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y := scope.Stack.pop(), scope.Stack.peek()
+ y.SMod(&x, y)
+ return nil, nil
+}
+
+func opExp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ base, exponent := scope.Stack.pop(), scope.Stack.peek()
+ exponent.Exp(&base, exponent)
+ return nil, nil
+}
+
+func opSignExtend(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ back, num := scope.Stack.pop(), scope.Stack.peek()
+ num.ExtendSign(num, &back)
+ return nil, nil
+}
+
+func opNot(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x := scope.Stack.peek()
+ x.Not(x)
+ return nil, nil
+}
+
+func opLt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y := scope.Stack.pop(), scope.Stack.peek()
+ if x.Lt(y) {
+ y.SetOne()
+ } else {
+ y.Clear()
+ }
+ return nil, nil
+}
+
+func opGt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y := scope.Stack.pop(), scope.Stack.peek()
+ if x.Gt(y) {
+ y.SetOne()
+ } else {
+ y.Clear()
+ }
+ return nil, nil
+}
+
+func opSlt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y := scope.Stack.pop(), scope.Stack.peek()
+ if x.Slt(y) {
+ y.SetOne()
+ } else {
+ y.Clear()
+ }
+ return nil, nil
+}
+
+func opSgt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y := scope.Stack.pop(), scope.Stack.peek()
+ if x.Sgt(y) {
+ y.SetOne()
+ } else {
+ y.Clear()
+ }
+ return nil, nil
+}
+
+func opEq(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y := scope.Stack.pop(), scope.Stack.peek()
+ if x.Eq(y) {
+ y.SetOne()
+ } else {
+ y.Clear()
+ }
+ return nil, nil
+}
+
+func opIszero(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x := scope.Stack.peek()
+ if x.IsZero() {
+ x.SetOne()
+ } else {
+ x.Clear()
+ }
+ return nil, nil
+}
+
+func opAnd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y := scope.Stack.pop(), scope.Stack.peek()
+ y.And(&x, y)
+ return nil, nil
+}
+
+func opOr(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y := scope.Stack.pop(), scope.Stack.peek()
+ y.Or(&x, y)
+ return nil, nil
+}
+
+func opXor(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y := scope.Stack.pop(), scope.Stack.peek()
+ y.Xor(&x, y)
+ return nil, nil
+}
+
+func opByte(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ th, val := scope.Stack.pop(), scope.Stack.peek()
+ val.Byte(&th)
+ return nil, nil
+}
+
+func opAddmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek()
+ if z.IsZero() {
+ z.Clear()
+ } else {
+ z.AddMod(&x, &y, z)
+ }
+ return nil, nil
+}
+
+func opMulmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek()
+ z.MulMod(&x, &y, z)
+ return nil, nil
+}
+
+// opSHL implements Shift Left
+// The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2,
+// and pushes on the stack arg2 shifted to the left by arg1 number of bits.
+func opSHL(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
+ shift, value := scope.Stack.pop(), scope.Stack.peek()
+ if shift.LtUint64(256) {
+ value.Lsh(value, uint(shift.Uint64()))
+ } else {
+ value.Clear()
+ }
+ return nil, nil
+}
+
+// opSHR implements Logical Shift Right
+// The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2,
+// and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill.
+func opSHR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
+ shift, value := scope.Stack.pop(), scope.Stack.peek()
+ if shift.LtUint64(256) {
+ value.Rsh(value, uint(shift.Uint64()))
+ } else {
+ value.Clear()
+ }
+ return nil, nil
+}
+
+// opSAR implements Arithmetic Shift Right
+// The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2,
+// and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension.
+func opSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ shift, value := scope.Stack.pop(), scope.Stack.peek()
+ if shift.GtUint64(256) {
+ if value.Sign() >= 0 {
+ value.Clear()
+ } else {
+ // Max negative shift: all bits set
+ value.SetAllOne()
+ }
+ return nil, nil
+ }
+ n := uint(shift.Uint64())
+ value.SRsh(value, n)
+ return nil, nil
+}
+
+func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ offset, size := scope.Stack.pop(), scope.Stack.peek()
+ data := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
+
+ if interpreter.hasher == nil {
+ interpreter.hasher = crypto.NewKeccakState()
+ } else {
+ interpreter.hasher.Reset()
+ }
+ interpreter.hasher.Write(data)
+ _, _ = interpreter.hasher.Read(interpreter.hasherBuf[:])
+
+ size.SetBytes(interpreter.hasherBuf[:])
+ return nil, nil
+}
+
+func opAddress(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Address().Bytes()))
+ return nil, nil
+}
+
+func opBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ slot := scope.Stack.peek()
+ address := common.Address(slot.Bytes20())
+ slot.Set(interpreter.evm.StateDB.GetBalance(address))
+ return nil, nil
+}
+
+func opOrigin(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Origin.Bytes()))
+ return nil, nil
+}
+
+func opCaller(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Caller().Bytes()))
+ return nil, nil
+}
+
+func opCallValue(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.push(scope.Contract.value)
+ return nil, nil
+}
+
+func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ x := scope.Stack.peek()
+ if offset, overflow := x.Uint64WithOverflow(); !overflow {
+ data := getData(scope.Contract.Input, offset, 32)
+ x.SetBytes(data)
+ } else {
+ x.Clear()
+ }
+ return nil, nil
+}
+
+func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Input))))
+ return nil, nil
+}
+
+func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ var (
+ memOffset = scope.Stack.pop()
+ dataOffset = scope.Stack.pop()
+ length = scope.Stack.pop()
+ )
+ dataOffset64, overflow := dataOffset.Uint64WithOverflow()
+ if overflow {
+ dataOffset64 = 0xffffffffffffffff
+ }
+ // These values are checked for overflow during gas cost calculation
+ memOffset64 := memOffset.Uint64()
+ length64 := length.Uint64()
+ scope.Memory.Set(memOffset64, length64, getData(scope.Contract.Input, dataOffset64, length64))
+
+ return nil, nil
+}
+
+func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(interpreter.returnData))))
+ return nil, nil
+}
+
+func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ var (
+ memOffset = scope.Stack.pop()
+ dataOffset = scope.Stack.pop()
+ length = scope.Stack.pop()
+ )
+
+ offset64, overflow := dataOffset.Uint64WithOverflow()
+ if overflow {
+ return nil, ErrReturnDataOutOfBounds
+ }
+ // we can reuse dataOffset now (aliasing it for clarity)
+ var end = dataOffset
+ end.Add(&dataOffset, &length)
+ end64, overflow := end.Uint64WithOverflow()
+ if overflow || uint64(len(interpreter.returnData)) < end64 {
+ return nil, ErrReturnDataOutOfBounds
+ }
+ scope.Memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[offset64:end64])
+ return nil, nil
+}
+
+func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ slot := scope.Stack.peek()
+ slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20())))
+ return nil, nil
+}
+
+func opCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Code))))
+ return nil, nil
+}
+
+func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ var (
+ memOffset = scope.Stack.pop()
+ codeOffset = scope.Stack.pop()
+ length = scope.Stack.pop()
+ )
+ uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
+ if overflow {
+ uint64CodeOffset = math.MaxUint64
+ }
+ codeCopy := getData(scope.Contract.Code, uint64CodeOffset, length.Uint64())
+ scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
+
+ return nil, nil
+}
+
+func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ var (
+ stack = scope.Stack
+ a = stack.pop()
+ memOffset = stack.pop()
+ codeOffset = stack.pop()
+ length = stack.pop()
+ )
+ uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
+ if overflow {
+ uint64CodeOffset = math.MaxUint64
+ }
+ addr := common.Address(a.Bytes20())
+ codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64())
+ scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
+
+ return nil, nil
+}
+
+func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ slot := scope.Stack.peek()
+ address := common.Address(slot.Bytes20())
+ codeHash := interpreter.evm.StateDB.GetCodeHash(address)
+ if codeHash == (common.Hash{}) {
+ slot.Clear()
+ } else {
+ slot.SetBytes(codeHash.Bytes())
+ }
+ return nil, nil
+}
+
+func opGasprice(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ v, _ := uint256.FromBig(interpreter.evm.GasPrice)
+ scope.Stack.push(v)
+ return nil, nil
+}
+
+func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ num := scope.Stack.peek()
+ num64, overflow := num.Uint64WithOverflow()
+ if overflow {
+ num.Clear()
+ return nil, nil
+ }
+ var upper, lower uint64
+ upper = interpreter.evm.Context.BlockNumber.Uint64()
+ if upper < 257 {
+ lower = 0
+ } else {
+ lower = upper - 256
+ }
+ if num64 >= lower && num64 < upper {
+ num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes())
+ } else {
+ num.Clear()
+ }
+ return nil, nil
+}
+
+func opCoinbase(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Context.Coinbase.Bytes()))
+ return nil, nil
+}
+
+func opTimestamp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.Time))
+ return nil, nil
+}
+
+func opNumber(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ v, _ := uint256.FromBig(interpreter.evm.Context.BlockNumber)
+ scope.Stack.push(v)
+ return nil, nil
+}
+
+func opDifficulty(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ v, _ := uint256.FromBig(interpreter.evm.Context.Difficulty)
+ scope.Stack.push(v)
+ return nil, nil
+}
+
+func opRandom(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ v := new(uint256.Int).SetBytes(interpreter.evm.Context.Random.Bytes())
+ scope.Stack.push(v)
+ return nil, nil
+}
+
+func opGasLimit(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.GasLimit))
+ return nil, nil
+}
+
+func opPop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.pop()
+ return nil, nil
+}
+
+func opMload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ v := scope.Stack.peek()
+ offset := int64(v.Uint64())
+ v.SetBytes(scope.Memory.GetPtr(offset, 32))
+ return nil, nil
+}
+
+func opMstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ // pop value of the stack
+ mStart, val := scope.Stack.pop(), scope.Stack.pop()
+ scope.Memory.Set32(mStart.Uint64(), &val)
+ return nil, nil
+}
+
+func opMstore8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ off, val := scope.Stack.pop(), scope.Stack.pop()
+ scope.Memory.store[off.Uint64()] = byte(val.Uint64())
+ return nil, nil
+}
+
+func opSload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ loc := scope.Stack.peek()
+ hash := common.Hash(loc.Bytes32())
+ val := interpreter.evm.StateDB.GetState(hash)
+ loc.SetBytes(val.Bytes())
+ return nil, nil
+}
+
+func opSstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ if interpreter.readOnly {
+ return nil, ErrWriteProtection
+ }
+ loc := scope.Stack.pop()
+ val := scope.Stack.pop()
+ interpreter.evm.StateDB.SetState(loc.Bytes32(), val.Bytes32())
+ return nil, nil
+}
+
+func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ if interpreter.evm.abort.Load() {
+ return nil, errStopToken
+ }
+ pos := scope.Stack.pop()
+ if !scope.Contract.validJumpdest(&pos) {
+ return nil, ErrInvalidJump
+ }
+ *pc = pos.Uint64() - 1 // pc will be increased by the interpreter loop
+ return nil, nil
+}
+
+func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ if interpreter.evm.abort.Load() {
+ return nil, errStopToken
+ }
+ pos, cond := scope.Stack.pop(), scope.Stack.pop()
+ if !cond.IsZero() {
+ if !scope.Contract.validJumpdest(&pos) {
+ return nil, ErrInvalidJump
+ }
+ *pc = pos.Uint64() - 1 // pc will be increased by the interpreter loop
+ }
+ return nil, nil
+}
+
+func opJumpdest(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, nil
+}
+
+func opPc(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.push(new(uint256.Int).SetUint64(*pc))
+ return nil, nil
+}
+
+func opMsize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.push(new(uint256.Int).SetUint64(uint64(scope.Memory.Len())))
+ return nil, nil
+}
+
+func opGas(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.StateDB.GasLeft()))
+ return nil, nil
+}
+
+func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ if interpreter.readOnly {
+ return nil, ErrWriteProtection
+ }
+ var (
+ value = scope.Stack.pop()
+ offset, size = scope.Stack.pop(), scope.Stack.pop()
+ input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
+ gas = interpreter.evm.StateDB.GasLeft()
+ )
+ // reuse size int for stackvalue
+ stackvalue := size
+
+ _, addr, suberr := interpreter.evm.StateDB.Create(input, gas, &value)
+
+ if suberr != nil {
+ stackvalue.Clear()
+ } else {
+ stackvalue.SetBytes(addr.Bytes())
+ }
+ scope.Stack.push(&stackvalue)
+
+ interpreter.returnData = nil // clear dirty return data buffer
+ return nil, nil
+}
+
+func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ if interpreter.readOnly {
+ return nil, ErrWriteProtection
+ }
+ var (
+ endowment = scope.Stack.pop()
+ offset, size = scope.Stack.pop(), scope.Stack.pop()
+ salt = scope.Stack.pop()
+ input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
+ gas = interpreter.evm.StateDB.GasLeft()
+ )
+ // reuse size int for stackvalue
+ stackvalue := size
+ _, addr, suberr := interpreter.evm.StateDB.Create2(input, gas, &endowment, &salt)
+ // Push item on the stack based on the returned error.
+ if suberr != nil {
+ stackvalue.Clear()
+ } else {
+ stackvalue.SetBytes(addr.Bytes())
+ }
+ scope.Stack.push(&stackvalue)
+
+ interpreter.returnData = nil // clear dirty return data buffer
+ return nil, nil
+}
+
+func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ stack := scope.Stack
+ // Pop gas. The actual gas in interpreter.evm.callGasTemp.
+ // We can use this as a temporary value
+ temp := stack.pop()
+ gas := interpreter.evm.callGasTemp
+ // Pop other call parameters.
+ addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
+ toAddr := common.Address(addr.Bytes20())
+ // Get the arguments from the memory.
+ args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
+
+ if interpreter.readOnly && !value.IsZero() {
+ return nil, ErrWriteProtection
+ }
+ ret, err := interpreter.evm.Call(toAddr, args, gas, &value)
+
+ if err != nil {
+ temp.Clear()
+ } else {
+ temp.SetOne()
+ }
+ stack.push(&temp)
+ if err == nil {
+ scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
+ }
+
+ interpreter.returnData = ret
+ return ret, nil
+}
+
+func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ // Pop gas. The actual gas is in interpreter.evm.callGasTemp.
+ stack := scope.Stack
+ // We use it as a temporary value
+ temp := stack.pop()
+ gas := interpreter.evm.callGasTemp
+ // Pop other call parameters.
+ addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
+ toAddr := common.Address(addr.Bytes20())
+ // Get arguments from the memory.
+ args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
+
+ ret, err := interpreter.evm.CallCode(toAddr, args, gas, &value)
+ if err != nil {
+ temp.Clear()
+ } else {
+ temp.SetOne()
+ }
+ stack.push(&temp)
+ if err == nil {
+ scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
+ }
+
+ interpreter.returnData = ret
+ return ret, nil
+}
+
+func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ stack := scope.Stack
+ // Pop gas. The actual gas is in interpreter.evm.callGasTemp.
+ // We use it as a temporary value
+ temp := stack.pop()
+ gas := interpreter.evm.callGasTemp
+ // Pop other call parameters.
+ addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
+ toAddr := common.Address(addr.Bytes20())
+ // Get arguments from the memory.
+ args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
+
+ ret, err := interpreter.evm.DelegateCall(toAddr, args, gas)
+ if err != nil {
+ temp.Clear()
+ } else {
+ temp.SetOne()
+ }
+ stack.push(&temp)
+ if err == nil {
+ scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
+ }
+
+ interpreter.returnData = ret
+ return ret, nil
+}
+
+func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ // Pop gas. The actual gas is in interpreter.evm.callGasTemp.
+ stack := scope.Stack
+ // We use it as a temporary value
+ temp := stack.pop()
+ gas := interpreter.evm.callGasTemp
+ // Pop other call parameters.
+ addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
+ toAddr := common.Address(addr.Bytes20())
+ // Get arguments from the memory.
+ args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
+
+ ret, err := interpreter.evm.StaticCall(toAddr, args, gas)
+ if err != nil {
+ temp.Clear()
+ } else {
+ temp.SetOne()
+ }
+ stack.push(&temp)
+ if err == nil {
+ scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
+ }
+
+ interpreter.returnData = ret
+ return ret, nil
+}
+
+func opReturn(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ offset, size := scope.Stack.pop(), scope.Stack.pop()
+ ret := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
+
+ return ret, errStopToken
+}
+
+func opRevert(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ offset, size := scope.Stack.pop(), scope.Stack.pop()
+ ret := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
+
+ interpreter.returnData = ret
+ return ret, ErrExecutionReverted
+}
+
+func opUndefined(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, &ErrInvalidOpCode{opcode: OpCode(scope.Contract.Code[*pc])}
+}
+
+func opStop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, errStopToken
+}
+
+func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ if interpreter.readOnly {
+ return nil, ErrWriteProtection
+ }
+ beneficiary := scope.Stack.pop()
+ interpreter.evm.StateDB.SelfDestruct(beneficiary.Bytes20())
+ return nil, errStopToken
+}
+
+// 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(int64(mStart.Uint64()), int64(mSize.Uint64()))
+ interpreter.evm.StateDB.AddLog(&types.Log{
+ 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
+ }
+}
+
+// opPush1 is a specialized version of pushN
+func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ var (
+ codeLen = uint64(len(scope.Contract.Code))
+ integer = new(uint256.Int)
+ )
+ *pc += 1
+ if *pc < codeLen {
+ scope.Stack.push(integer.SetUint64(uint64(scope.Contract.Code[*pc])))
+ } else {
+ scope.Stack.push(integer.Clear())
+ }
+ return nil, nil
+}
+
+// make push instruction function
+func makePush(size uint64, pushByteSize int) executionFunc {
+ return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ codeLen := len(scope.Contract.Code)
+
+ startMin := codeLen
+ if int(*pc+1) < startMin {
+ startMin = int(*pc + 1)
+ }
+
+ endMin := codeLen
+ if startMin+pushByteSize < endMin {
+ endMin = startMin + pushByteSize
+ }
+
+ integer := new(uint256.Int)
+ scope.Stack.push(integer.SetBytes(common.RightPadBytes(
+ scope.Contract.Code[startMin:endMin], pushByteSize)))
+
+ *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
+ }
+}
+
+// make swap instruction function
+func makeSwap(size int64) executionFunc {
+ // switch n + 1 otherwise n would be swapped with n
+ size++
+ return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.swap(int(size))
+ return nil, nil
+ }
+}
diff --git a/evm/interpreter/interface.go b/evm/interpreter/interface.go
new file mode 100644
index 000000000..34194ea66
--- /dev/null
+++ b/evm/interpreter/interface.go
@@ -0,0 +1,56 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/holiman/uint256"
+)
+
+type StateDB interface {
+ FailExecution(err error)
+
+ GetSelfBalance() *uint256.Int
+ GetBalance(address common.Address) *uint256.Int
+ TransferBalance(destination common.Address, value *uint256.Int) error
+
+ GetCodeHash(address common.Address) common.Hash
+ GetCode(address common.Address) []byte
+ GetCodeSize(address common.Address) int
+
+ GetState(key common.Hash) common.Hash
+ SetState(key common.Hash, value common.Hash)
+
+ GetTransientState(address common.Address, key common.Hash) common.Hash
+ SetTransientState(address common.Address, key common.Hash, value common.Hash)
+
+ SelfDestruct(destination common.Address)
+
+ AddLog(log *types.Log)
+
+ GasLeft() uint64
+ UseGas(opCode string, gas uint64) bool
+
+ IsSmartContractAddress(address common.Address) bool
+ Create(code []byte, gas uint64, value *uint256.Int) ([]byte, common.Address, error)
+ Create2(code []byte, gas uint64, value *uint256.Int, salt *uint256.Int) ([]byte, common.Address, error)
+ Call(address common.Address, value *uint256.Int, input []byte, gas uint64) ([]byte, error)
+ StaticCall(address common.Address, input []byte, gas uint64) ([]byte, error)
+ CallCode(address common.Address, value *uint256.Int, input []byte, gas uint64) ([]byte, error)
+ DelegateCall(address common.Address, input []byte, gas uint64) ([]byte, error)
+}
diff --git a/evm/interpreter/interpreter.go b/evm/interpreter/interpreter.go
new file mode 100644
index 000000000..879a24dfe
--- /dev/null
+++ b/evm/interpreter/interpreter.go
@@ -0,0 +1,160 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/crypto"
+)
+
+// ScopeContext contains the things that are per-call, such as stack and memory,
+// but not transients like pc and gas
+type ScopeContext struct {
+ Memory *Memory
+ Stack *Stack
+ Contract *Contract
+}
+
+// EVMInterpreter represents an EVM interpreter
+type EVMInterpreter struct {
+ evm *EVM
+ table *JumpTable
+
+ hasher crypto.KeccakState // Keccak256 hasher instance shared across opcodes
+ hasherBuf common.Hash // Keccak256 hasher result array shared across opcodes
+
+ readOnly bool // Whether to throw on stateful modifications
+ returnData []byte // Last CALL's return data for subsequent reuse
+}
+
+// NewEVMInterpreter returns a new instance of the Interpreter.
+func NewEVMInterpreter(evm *EVM, instructionSet *JumpTable) *EVMInterpreter {
+ return &EVMInterpreter{evm: evm, table: instructionSet}
+}
+
+// Run loops and evaluates the contract's code with the given input data and returns
+// the return byte-slice and an error if one occurred.
+//
+// It's important to note that any errors returned by the interpreter should be
+// considered a revert-and-consume-all-gas operation except for
+// ErrExecutionReverted which means revert-and-keep-gas-left.
+func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) {
+ // Make sure the readOnly is only set if we aren't in readOnly yet.
+ // This also makes sure that the readOnly flag isn't removed for child calls.
+ if readOnly && !in.readOnly {
+ in.readOnly = true
+ defer func() { in.readOnly = false }()
+ }
+
+ // Reset the previous call's return data. It's unimportant to preserve the old buffer
+ // as every returning call will return new data anyway.
+ in.returnData = nil
+
+ // Don't bother with the execution if there's no code.
+ if len(contract.Code) == 0 {
+ return nil, nil
+ }
+
+ var (
+ op OpCode // current opcode
+ mem = NewMemory() // bound memory
+ stack = newstack() // local stack
+ callContext = &ScopeContext{
+ Memory: mem,
+ Stack: stack,
+ Contract: contract,
+ }
+ // For optimisation reason we're using uint64 as the program counter.
+ // It's theoretically possible to go above 2^64. The YP defines the PC
+ // to be uint256. Practically much less so feasible.
+ pc = uint64(0) // program counter
+ cost uint64
+ // copies used by tracer
+ res []byte // result of the opcode execution function
+ )
+ // Don't move this deferred function, it's placed before the capturestate-deferred method,
+ // so that it gets executed _after_: the capturestate needs the stacks before
+ // they are returned to the pools
+ defer func() {
+ returnStack(stack)
+ }()
+ contract.Input = input
+
+ // The Interpreter main run loop (contextual). This loop runs until either an
+ // explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during
+ // the execution of one of the operations or until the done flag is set by the
+ // parent context.
+ for {
+ // Get the operation from the jump table and validate the stack to ensure there are
+ // enough stack items available to perform the operation.
+ op = contract.GetOp(pc)
+ operation := in.table[op]
+ cost = operation.constantGas // For tracing
+ // Validate stack
+ if sLen := stack.len(); sLen < operation.minStack {
+ return nil, &ErrStackUnderflow{stackLen: sLen, required: operation.minStack}
+ } else if sLen > operation.maxStack {
+ return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack}
+ }
+ if !in.evm.StateDB.UseGas(op.String(), cost) {
+ return nil, ErrOutOfGas
+ }
+ if operation.dynamicGas != nil {
+ // All ops with a dynamic memory usage also has a dynamic gas cost.
+ var memorySize uint64
+ // calculate the new memory size and expand the memory to fit
+ // the operation
+ // Memory check needs to be done prior to evaluating the dynamic gas portion,
+ // to detect calculation overflows
+ if operation.memorySize != nil {
+ memSize, overflow := operation.memorySize(stack)
+ if overflow {
+ return nil, ErrGasUintOverflow
+ }
+ // memory is expanded in words of 32 bytes. Gas
+ // is also calculated in words.
+ if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow {
+ return nil, ErrGasUintOverflow
+ }
+ }
+ // Consume the gas and return an error if not enough gas is available.
+ // cost is explicitly set so that the capture state defer method can get the proper cost
+ var dynamicCost uint64
+ dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize)
+ cost += dynamicCost // for tracing
+ if err != nil || !in.evm.StateDB.UseGas(op.String(), dynamicCost) {
+ return nil, ErrOutOfGas
+ }
+ if memorySize > 0 {
+ mem.Resize(memorySize)
+ }
+ }
+ // execute the operation
+ res, err = operation.execute(&pc, in, callContext)
+ if err != nil {
+ break
+ }
+ pc++
+ }
+
+ if err == errStopToken {
+ err = nil // clear stop token error
+ }
+
+ return res, err
+}
diff --git a/evm/interpreter/jump_table.go b/evm/interpreter/jump_table.go
new file mode 100644
index 000000000..62653e531
--- /dev/null
+++ b/evm/interpreter/jump_table.go
@@ -0,0 +1,1055 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "fmt"
+)
+
+type (
+ executionFunc func(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error)
+ gasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64
+ // memorySizeFunc returns the required size, and whether the operation overflowed a uint64
+ memorySizeFunc func(*Stack) (size uint64, overflow bool)
+)
+
+type operation struct {
+ // execute is the operation function
+ execute executionFunc
+ constantGas uint64
+ dynamicGas gasFunc
+ // minStack tells how many stack items are required
+ minStack int
+ // maxStack specifies the max length the stack can have for this operation
+ // to not overflow the stack.
+ maxStack int
+
+ // memorySize returns the memory size required for the operation
+ memorySize memorySizeFunc
+}
+
+// JumpTable contains the EVM opcodes supported at a given fork.
+type JumpTable [256]*operation
+
+func validate(jt JumpTable) JumpTable {
+ for i, op := range jt {
+ if op == nil {
+ panic(fmt.Sprintf("op %#x is not set", i))
+ }
+ // The interpreter has an assumption that if the memorySize function is
+ // set, then the dynamicGas function is also set. This is a somewhat
+ // arbitrary assumption, and can be removed if we need to -- but it
+ // allows us to avoid a condition check. As long as we have that assumption
+ // in there, this little sanity check prevents us from merging in a
+ // change which violates it.
+ if op.memorySize != nil && op.dynamicGas == nil {
+ panic(fmt.Sprintf("op %v has dynamic memory but not dynamic gas", OpCode(i).String()))
+ }
+ }
+ return jt
+}
+
+func NewCancunInstructionSet(gasConfig *GasConfig) JumpTable {
+ instructionSet := newShanghaiInstructionSet(gasConfig)
+ enable4844(&instructionSet, gasConfig) // EIP-4844 (BLOBHASH opcode)
+ enable7516(&instructionSet, gasConfig) // EIP-7516 (BLOBBASEFEE opcode)
+ enable1153(&instructionSet, gasConfig) // EIP-1153 "Transient Storage"
+ enable5656(&instructionSet, gasConfig) // EIP-5656 (MCOPY opcode)
+ return validate(instructionSet)
+}
+
+func newShanghaiInstructionSet(gasConfig *GasConfig) JumpTable {
+ instructionSet := newMergeInstructionSet(gasConfig)
+ enable3855(&instructionSet, gasConfig) // PUSH0 instruction
+ enable3860(&instructionSet) // Limit and meter initcode
+
+ return validate(instructionSet)
+}
+
+func newMergeInstructionSet(gasConfig *GasConfig) JumpTable {
+ instructionSet := newLondonInstructionSet(gasConfig)
+ instructionSet[PREVRANDAO] = &operation{
+ execute: opRandom,
+ constantGas: gasConfig.QuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ }
+ return validate(instructionSet)
+}
+
+// newLondonInstructionSet returns the frontier, homestead, byzantium,
+// constantinople, istanbul, petersburg, berlin and london instructions.
+func newLondonInstructionSet(gasConfig *GasConfig) JumpTable {
+ instructionSet := newBerlinInstructionSet(gasConfig)
+ enable3198(&instructionSet, gasConfig) // Base fee opcode https://eips.ethereum.org/EIPS/eip-3198
+ return validate(instructionSet)
+}
+
+// newBerlinInstructionSet returns the frontier, homestead, byzantium,
+// constantinople, istanbul, petersburg and berlin instructions.
+func newBerlinInstructionSet(gasConfig *GasConfig) JumpTable {
+ instructionSet := newIstanbulInstructionSet(gasConfig)
+ return validate(instructionSet)
+}
+
+// newIstanbulInstructionSet returns the frontier, homestead, byzantium,
+// constantinople, istanbul and petersburg instructions.
+func newIstanbulInstructionSet(gasConfig *GasConfig) JumpTable {
+ instructionSet := newConstantinopleInstructionSet(gasConfig)
+
+ enable1344(&instructionSet, gasConfig) // ChainID opcode - https://eips.ethereum.org/EIPS/eip-1344
+ enable1884(&instructionSet, gasConfig) // Reprice reader opcodes - https://eips.ethereum.org/EIPS/eip-1884
+
+ return validate(instructionSet)
+}
+
+// newConstantinopleInstructionSet returns the frontier, homestead,
+// byzantium and constantinople instructions.
+func newConstantinopleInstructionSet(gasConfig *GasConfig) JumpTable {
+ instructionSet := newByzantiumInstructionSet(gasConfig)
+ instructionSet[SHL] = &operation{
+ execute: opSHL,
+ constantGas: gasConfig.FastestStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ }
+ instructionSet[SHR] = &operation{
+ execute: opSHR,
+ constantGas: gasConfig.FastestStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ }
+ instructionSet[SAR] = &operation{
+ execute: opSAR,
+ constantGas: gasConfig.FastestStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ }
+ instructionSet[EXTCODEHASH] = &operation{
+ execute: opExtCodeHash,
+ constantGas: gasConfig.ExtcodeHash,
+ minStack: minStack(1, 1),
+ maxStack: maxStack(1, 1),
+ }
+ instructionSet[CREATE2] = &operation{
+ execute: opCreate2,
+ constantGas: gasConfig.Create2,
+ dynamicGas: gasCreate2,
+ minStack: minStack(4, 1),
+ maxStack: maxStack(4, 1),
+ memorySize: memoryCreate2,
+ }
+ return validate(instructionSet)
+}
+
+// newByzantiumInstructionSet returns the frontier, homestead and
+// byzantium instructions.
+func newByzantiumInstructionSet(gasConfig *GasConfig) JumpTable {
+ instructionSet := newSpuriousDragonInstructionSet(gasConfig)
+ instructionSet[STATICCALL] = &operation{
+ execute: opStaticCall,
+ constantGas: gasConfig.Call,
+ dynamicGas: gasCall,
+ minStack: minStack(6, 1),
+ maxStack: maxStack(6, 1),
+ memorySize: memoryStaticCall,
+ }
+ instructionSet[RETURNDATASIZE] = &operation{
+ execute: opReturnDataSize,
+ constantGas: gasConfig.QuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ }
+ instructionSet[RETURNDATACOPY] = &operation{
+ execute: opReturnDataCopy,
+ constantGas: gasConfig.FastestStep,
+ dynamicGas: gasReturnDataCopy,
+ minStack: minStack(3, 0),
+ maxStack: maxStack(3, 0),
+ memorySize: memoryReturnDataCopy,
+ }
+ instructionSet[REVERT] = &operation{
+ execute: opRevert,
+ dynamicGas: gasRevert,
+ minStack: minStack(2, 0),
+ maxStack: maxStack(2, 0),
+ memorySize: memoryRevert,
+ }
+ return validate(instructionSet)
+}
+
+// EIP 158 a.k.a Spurious Dragon
+func newSpuriousDragonInstructionSet(gasConfig *GasConfig) JumpTable {
+ instructionSet := newTangerineWhistleInstructionSet(gasConfig)
+ instructionSet[EXP].dynamicGas = gasExpEIP158
+ return validate(instructionSet)
+}
+
+// EIP 150 a.k.a Tangerine Whistle
+func newTangerineWhistleInstructionSet(gasConfig *GasConfig) JumpTable {
+ instructionSet := newHomesteadInstructionSet(gasConfig)
+ return validate(instructionSet)
+}
+
+// newHomesteadInstructionSet returns the frontier and homestead
+// instructions that can be executed during the homestead phase.
+func newHomesteadInstructionSet(gasConfig *GasConfig) JumpTable {
+ instructionSet := newFrontierInstructionSet(gasConfig)
+ instructionSet[DELEGATECALL] = &operation{
+ execute: opDelegateCall,
+ dynamicGas: gasCall,
+ constantGas: gasConfig.Call,
+ minStack: minStack(6, 1),
+ maxStack: maxStack(6, 1),
+ memorySize: memoryDelegateCall,
+ }
+ return validate(instructionSet)
+}
+
+// newFrontierInstructionSet returns the frontier instructions
+// that can be executed during the frontier phase.
+func newFrontierInstructionSet(gasConfig *GasConfig) JumpTable {
+ GasQuickStep := gasConfig.QuickStep
+ GasFastestStep := gasConfig.FastestStep
+ GasFastStep := gasConfig.FastStep
+ GasMidStep := gasConfig.MidStep
+ GasSlowStep := gasConfig.SlowStep
+ GasExtStep := gasConfig.ExtStep
+
+ tbl := JumpTable{
+ STOP: {
+ execute: opStop,
+ constantGas: 0,
+ minStack: minStack(0, 0),
+ maxStack: maxStack(0, 0),
+ },
+ ADD: {
+ execute: opAdd,
+ constantGas: GasFastestStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ MUL: {
+ execute: opMul,
+ constantGas: GasFastStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ SUB: {
+ execute: opSub,
+ constantGas: GasFastestStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ DIV: {
+ execute: opDiv,
+ constantGas: GasFastStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ SDIV: {
+ execute: opSdiv,
+ constantGas: GasFastStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ MOD: {
+ execute: opMod,
+ constantGas: GasFastStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ SMOD: {
+ execute: opSmod,
+ constantGas: GasFastStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ ADDMOD: {
+ execute: opAddmod,
+ constantGas: GasMidStep,
+ minStack: minStack(3, 1),
+ maxStack: maxStack(3, 1),
+ },
+ MULMOD: {
+ execute: opMulmod,
+ constantGas: GasMidStep,
+ minStack: minStack(3, 1),
+ maxStack: maxStack(3, 1),
+ },
+ EXP: {
+ execute: opExp,
+ constantGas: 0,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ SIGNEXTEND: {
+ execute: opSignExtend,
+ constantGas: GasFastStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ LT: {
+ execute: opLt,
+ constantGas: GasFastestStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ GT: {
+ execute: opGt,
+ constantGas: GasFastestStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ SLT: {
+ execute: opSlt,
+ constantGas: GasFastestStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ SGT: {
+ execute: opSgt,
+ constantGas: GasFastestStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ EQ: {
+ execute: opEq,
+ constantGas: GasFastestStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ ISZERO: {
+ execute: opIszero,
+ constantGas: GasFastestStep,
+ minStack: minStack(1, 1),
+ maxStack: maxStack(1, 1),
+ },
+ AND: {
+ execute: opAnd,
+ constantGas: GasFastestStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ XOR: {
+ execute: opXor,
+ constantGas: GasFastestStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ OR: {
+ execute: opOr,
+ constantGas: GasFastestStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ NOT: {
+ execute: opNot,
+ constantGas: GasFastestStep,
+ minStack: minStack(1, 1),
+ maxStack: maxStack(1, 1),
+ },
+ BYTE: {
+ execute: opByte,
+ constantGas: GasFastestStep,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ },
+ KECCAK256: {
+ execute: opKeccak256,
+ constantGas: gasConfig.Keccak256,
+ dynamicGas: gasKeccak256,
+ minStack: minStack(2, 1),
+ maxStack: maxStack(2, 1),
+ memorySize: memoryKeccak256,
+ },
+ ADDRESS: {
+ execute: opAddress,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ BALANCE: {
+ execute: opBalance,
+ constantGas: gasConfig.Balance,
+ minStack: minStack(1, 1),
+ maxStack: maxStack(1, 1),
+ },
+ ORIGIN: {
+ execute: opOrigin,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ CALLER: {
+ execute: opCaller,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ CALLVALUE: {
+ execute: opCallValue,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ CALLDATALOAD: {
+ execute: opCallDataLoad,
+ constantGas: GasFastestStep,
+ minStack: minStack(1, 1),
+ maxStack: maxStack(1, 1),
+ },
+ CALLDATASIZE: {
+ execute: opCallDataSize,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ CALLDATACOPY: {
+ execute: opCallDataCopy,
+ constantGas: GasFastestStep,
+ dynamicGas: gasCallDataCopy,
+ minStack: minStack(3, 0),
+ maxStack: maxStack(3, 0),
+ memorySize: memoryCallDataCopy,
+ },
+ CODESIZE: {
+ execute: opCodeSize,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ CODECOPY: {
+ execute: opCodeCopy,
+ constantGas: GasFastestStep,
+ dynamicGas: gasCodeCopy,
+ minStack: minStack(3, 0),
+ maxStack: maxStack(3, 0),
+ memorySize: memoryCodeCopy,
+ },
+ GASPRICE: {
+ execute: opGasprice,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ EXTCODESIZE: {
+ execute: opExtCodeSize,
+ constantGas: gasConfig.ExtcodeSize,
+ minStack: minStack(1, 1),
+ maxStack: maxStack(1, 1),
+ },
+ EXTCODECOPY: {
+ execute: opExtCodeCopy,
+ constantGas: gasConfig.ExtcodeCopy,
+ dynamicGas: gasExtCodeCopy,
+ minStack: minStack(4, 0),
+ maxStack: maxStack(4, 0),
+ memorySize: memoryExtCodeCopy,
+ },
+ BLOCKHASH: {
+ execute: opBlockhash,
+ constantGas: GasExtStep,
+ minStack: minStack(1, 1),
+ maxStack: maxStack(1, 1),
+ },
+ COINBASE: {
+ execute: opCoinbase,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ TIMESTAMP: {
+ execute: opTimestamp,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ NUMBER: {
+ execute: opNumber,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ DIFFICULTY: {
+ execute: opDifficulty,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ GASLIMIT: {
+ execute: opGasLimit,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ POP: {
+ execute: opPop,
+ constantGas: GasQuickStep,
+ minStack: minStack(1, 0),
+ maxStack: maxStack(1, 0),
+ },
+ MLOAD: {
+ execute: opMload,
+ constantGas: GasFastestStep,
+ dynamicGas: gasMLoad,
+ minStack: minStack(1, 1),
+ maxStack: maxStack(1, 1),
+ memorySize: memoryMLoad,
+ },
+ MSTORE: {
+ execute: opMstore,
+ constantGas: GasFastestStep,
+ dynamicGas: gasMStore,
+ minStack: minStack(2, 0),
+ maxStack: maxStack(2, 0),
+ memorySize: memoryMStore,
+ },
+ MSTORE8: {
+ execute: opMstore8,
+ constantGas: GasFastestStep,
+ dynamicGas: gasMStore8,
+ memorySize: memoryMStore8,
+ minStack: minStack(2, 0),
+ maxStack: maxStack(2, 0),
+ },
+ SLOAD: {
+ execute: opSload,
+ constantGas: 0,
+ minStack: minStack(1, 1),
+ maxStack: maxStack(1, 1),
+ },
+ SSTORE: {
+ execute: opSstore,
+ constantGas: gasConfig.Sstore,
+ minStack: minStack(2, 0),
+ maxStack: maxStack(2, 0),
+ },
+ JUMP: {
+ execute: opJump,
+ constantGas: GasMidStep,
+ minStack: minStack(1, 0),
+ maxStack: maxStack(1, 0),
+ },
+ JUMPI: {
+ execute: opJumpi,
+ constantGas: GasSlowStep,
+ minStack: minStack(2, 0),
+ maxStack: maxStack(2, 0),
+ },
+ PC: {
+ execute: opPc,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ MSIZE: {
+ execute: opMsize,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ GAS: {
+ execute: opGas,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ JUMPDEST: {
+ execute: opJumpdest,
+ constantGas: gasConfig.Jumpdest,
+ minStack: minStack(0, 0),
+ maxStack: maxStack(0, 0),
+ },
+ PUSH1: {
+ execute: opPush1,
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH2: {
+ execute: makePush(2, 2),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH3: {
+ execute: makePush(3, 3),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH4: {
+ execute: makePush(4, 4),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH5: {
+ execute: makePush(5, 5),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH6: {
+ execute: makePush(6, 6),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH7: {
+ execute: makePush(7, 7),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH8: {
+ execute: makePush(8, 8),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH9: {
+ execute: makePush(9, 9),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH10: {
+ execute: makePush(10, 10),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH11: {
+ execute: makePush(11, 11),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH12: {
+ execute: makePush(12, 12),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH13: {
+ execute: makePush(13, 13),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH14: {
+ execute: makePush(14, 14),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH15: {
+ execute: makePush(15, 15),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH16: {
+ execute: makePush(16, 16),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH17: {
+ execute: makePush(17, 17),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH18: {
+ execute: makePush(18, 18),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH19: {
+ execute: makePush(19, 19),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH20: {
+ execute: makePush(20, 20),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH21: {
+ execute: makePush(21, 21),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH22: {
+ execute: makePush(22, 22),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH23: {
+ execute: makePush(23, 23),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH24: {
+ execute: makePush(24, 24),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH25: {
+ execute: makePush(25, 25),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH26: {
+ execute: makePush(26, 26),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH27: {
+ execute: makePush(27, 27),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH28: {
+ execute: makePush(28, 28),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH29: {
+ execute: makePush(29, 29),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH30: {
+ execute: makePush(30, 30),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH31: {
+ execute: makePush(31, 31),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ PUSH32: {
+ execute: makePush(32, 32),
+ constantGas: GasFastestStep,
+ minStack: minStack(0, 1),
+ maxStack: maxStack(0, 1),
+ },
+ DUP1: {
+ execute: makeDup(1),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(1),
+ maxStack: maxDupStack(1),
+ },
+ DUP2: {
+ execute: makeDup(2),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(2),
+ maxStack: maxDupStack(2),
+ },
+ DUP3: {
+ execute: makeDup(3),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(3),
+ maxStack: maxDupStack(3),
+ },
+ DUP4: {
+ execute: makeDup(4),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(4),
+ maxStack: maxDupStack(4),
+ },
+ DUP5: {
+ execute: makeDup(5),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(5),
+ maxStack: maxDupStack(5),
+ },
+ DUP6: {
+ execute: makeDup(6),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(6),
+ maxStack: maxDupStack(6),
+ },
+ DUP7: {
+ execute: makeDup(7),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(7),
+ maxStack: maxDupStack(7),
+ },
+ DUP8: {
+ execute: makeDup(8),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(8),
+ maxStack: maxDupStack(8),
+ },
+ DUP9: {
+ execute: makeDup(9),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(9),
+ maxStack: maxDupStack(9),
+ },
+ DUP10: {
+ execute: makeDup(10),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(10),
+ maxStack: maxDupStack(10),
+ },
+ DUP11: {
+ execute: makeDup(11),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(11),
+ maxStack: maxDupStack(11),
+ },
+ DUP12: {
+ execute: makeDup(12),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(12),
+ maxStack: maxDupStack(12),
+ },
+ DUP13: {
+ execute: makeDup(13),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(13),
+ maxStack: maxDupStack(13),
+ },
+ DUP14: {
+ execute: makeDup(14),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(14),
+ maxStack: maxDupStack(14),
+ },
+ DUP15: {
+ execute: makeDup(15),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(15),
+ maxStack: maxDupStack(15),
+ },
+ DUP16: {
+ execute: makeDup(16),
+ constantGas: GasFastestStep,
+ minStack: minDupStack(16),
+ maxStack: maxDupStack(16),
+ },
+ SWAP1: {
+ execute: makeSwap(1),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(2),
+ maxStack: maxSwapStack(2),
+ },
+ SWAP2: {
+ execute: makeSwap(2),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(3),
+ maxStack: maxSwapStack(3),
+ },
+ SWAP3: {
+ execute: makeSwap(3),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(4),
+ maxStack: maxSwapStack(4),
+ },
+ SWAP4: {
+ execute: makeSwap(4),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(5),
+ maxStack: maxSwapStack(5),
+ },
+ SWAP5: {
+ execute: makeSwap(5),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(6),
+ maxStack: maxSwapStack(6),
+ },
+ SWAP6: {
+ execute: makeSwap(6),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(7),
+ maxStack: maxSwapStack(7),
+ },
+ SWAP7: {
+ execute: makeSwap(7),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(8),
+ maxStack: maxSwapStack(8),
+ },
+ SWAP8: {
+ execute: makeSwap(8),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(9),
+ maxStack: maxSwapStack(9),
+ },
+ SWAP9: {
+ execute: makeSwap(9),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(10),
+ maxStack: maxSwapStack(10),
+ },
+ SWAP10: {
+ execute: makeSwap(10),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(11),
+ maxStack: maxSwapStack(11),
+ },
+ SWAP11: {
+ execute: makeSwap(11),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(12),
+ maxStack: maxSwapStack(12),
+ },
+ SWAP12: {
+ execute: makeSwap(12),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(13),
+ maxStack: maxSwapStack(13),
+ },
+ SWAP13: {
+ execute: makeSwap(13),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(14),
+ maxStack: maxSwapStack(14),
+ },
+ SWAP14: {
+ execute: makeSwap(14),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(15),
+ maxStack: maxSwapStack(15),
+ },
+ SWAP15: {
+ execute: makeSwap(15),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(16),
+ maxStack: maxSwapStack(16),
+ },
+ SWAP16: {
+ execute: makeSwap(16),
+ constantGas: GasFastestStep,
+ minStack: minSwapStack(17),
+ maxStack: maxSwapStack(17),
+ },
+ LOG0: {
+ execute: makeLog(0),
+ dynamicGas: makeGasLog(0),
+ minStack: minStack(2, 0),
+ maxStack: maxStack(2, 0),
+ memorySize: memoryLog,
+ },
+ LOG1: {
+ execute: makeLog(1),
+ dynamicGas: makeGasLog(1),
+ minStack: minStack(3, 0),
+ maxStack: maxStack(3, 0),
+ memorySize: memoryLog,
+ },
+ LOG2: {
+ execute: makeLog(2),
+ dynamicGas: makeGasLog(2),
+ minStack: minStack(4, 0),
+ maxStack: maxStack(4, 0),
+ memorySize: memoryLog,
+ },
+ LOG3: {
+ execute: makeLog(3),
+ dynamicGas: makeGasLog(3),
+ minStack: minStack(5, 0),
+ maxStack: maxStack(5, 0),
+ memorySize: memoryLog,
+ },
+ LOG4: {
+ execute: makeLog(4),
+ dynamicGas: makeGasLog(4),
+ minStack: minStack(6, 0),
+ maxStack: maxStack(6, 0),
+ memorySize: memoryLog,
+ },
+ CREATE: {
+ execute: opCreate,
+ constantGas: gasConfig.Create,
+ dynamicGas: gasCreate,
+ minStack: minStack(3, 1),
+ maxStack: maxStack(3, 1),
+ memorySize: memoryCreate,
+ },
+ CALL: {
+ execute: opCall,
+ constantGas: gasConfig.Call,
+ dynamicGas: gasCall,
+ minStack: minStack(7, 1),
+ maxStack: maxStack(7, 1),
+ memorySize: memoryCall,
+ },
+ CALLCODE: {
+ execute: opCallCode,
+ constantGas: gasConfig.Call,
+ dynamicGas: gasCall,
+ minStack: minStack(7, 1),
+ maxStack: maxStack(7, 1),
+ memorySize: memoryCall,
+ },
+ RETURN: {
+ execute: opReturn,
+ dynamicGas: gasReturn,
+ minStack: minStack(2, 0),
+ maxStack: maxStack(2, 0),
+ memorySize: memoryReturn,
+ },
+ SELFDESTRUCT: {
+ execute: opSelfdestruct,
+ constantGas: gasConfig.Selfdestruct,
+ minStack: minStack(1, 0),
+ maxStack: maxStack(1, 0),
+ },
+ }
+
+ // Fill all unassigned slots with opUndefined.
+ for i, entry := range tbl {
+ if entry == nil {
+ tbl[i] = &operation{execute: opUndefined, maxStack: maxStack(0, 0)}
+ }
+ }
+
+ return validate(tbl)
+}
+
+func copyJumpTable(source *JumpTable) *JumpTable {
+ dest := *source
+ for i, op := range source {
+ if op != nil {
+ opCopy := *op
+ dest[i] = &opCopy
+ }
+ }
+ return &dest
+}
diff --git a/evm/interpreter/memory.go b/evm/interpreter/memory.go
new file mode 100644
index 000000000..92aea95c8
--- /dev/null
+++ b/evm/interpreter/memory.go
@@ -0,0 +1,116 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "github.com/holiman/uint256"
+)
+
+// Memory implements a simple memory model for the ethereum virtual machine.
+type Memory struct {
+ store []byte
+ lastGasCost uint64
+}
+
+// NewMemory returns a new memory model.
+func NewMemory() *Memory {
+ return &Memory{}
+}
+
+// Set sets offset + size to value
+func (m *Memory) Set(offset, size uint64, value []byte) {
+ // It's possible the offset is greater than 0 and size equals 0. This is because
+ // the calcMemSize (common.go) could potentially return 0 when size is zero (NO-OP)
+ if size > 0 {
+ // length of store may never be less than offset + size.
+ // The store should be resized PRIOR to setting the memory
+ if offset+size > uint64(len(m.store)) {
+ panic("invalid memory: store empty")
+ }
+ copy(m.store[offset:offset+size], value)
+ }
+}
+
+// Set32 sets the 32 bytes starting at offset to the value of val, left-padded with zeroes to
+// 32 bytes.
+func (m *Memory) Set32(offset uint64, val *uint256.Int) {
+ // length of store may never be less than offset + size.
+ // The store should be resized PRIOR to setting the memory
+ if offset+32 > uint64(len(m.store)) {
+ panic("invalid memory: store empty")
+ }
+ // Fill in relevant bits
+ b32 := val.Bytes32()
+ copy(m.store[offset:], b32[:])
+}
+
+// Resize resizes the memory to size
+func (m *Memory) Resize(size uint64) {
+ if uint64(m.Len()) < size {
+ m.store = append(m.store, make([]byte, size-uint64(m.Len()))...)
+ }
+}
+
+// GetCopy returns offset + size as a new slice
+func (m *Memory) GetCopy(offset, size int64) (cpy []byte) {
+ if size == 0 {
+ return nil
+ }
+
+ if len(m.store) > int(offset) {
+ cpy = make([]byte, size)
+ copy(cpy, m.store[offset:offset+size])
+
+ return
+ }
+
+ return
+}
+
+// GetPtr returns the offset + size
+func (m *Memory) GetPtr(offset, size int64) []byte {
+ if size == 0 {
+ return nil
+ }
+
+ if len(m.store) > int(offset) {
+ return m.store[offset : offset+size]
+ }
+
+ return nil
+}
+
+// Len returns the length of the backing slice
+func (m *Memory) Len() int {
+ return len(m.store)
+}
+
+// Data returns the backing slice
+func (m *Memory) Data() []byte {
+ return m.store
+}
+
+// Copy copies data from the src position slice into the dst position.
+// The source and destination may overlap.
+// OBS: This operation assumes that any necessary memory expansion has already been performed,
+// and this method may panic otherwise.
+func (m *Memory) Copy(dst, src, len uint64) {
+ if len == 0 {
+ return
+ }
+ copy(m.store[dst:], m.store[src:src+len])
+}
diff --git a/evm/interpreter/memory_table.go b/evm/interpreter/memory_table.go
new file mode 100644
index 000000000..b598efc00
--- /dev/null
+++ b/evm/interpreter/memory_table.go
@@ -0,0 +1,121 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+func memoryKeccak256(stack *Stack) (uint64, bool) {
+ return calcMemSize64(stack.Back(0), stack.Back(1))
+}
+
+func memoryCallDataCopy(stack *Stack) (uint64, bool) {
+ return calcMemSize64(stack.Back(0), stack.Back(2))
+}
+
+func memoryReturnDataCopy(stack *Stack) (uint64, bool) {
+ return calcMemSize64(stack.Back(0), stack.Back(2))
+}
+
+func memoryCodeCopy(stack *Stack) (uint64, bool) {
+ return calcMemSize64(stack.Back(0), stack.Back(2))
+}
+
+func memoryExtCodeCopy(stack *Stack) (uint64, bool) {
+ return calcMemSize64(stack.Back(1), stack.Back(3))
+}
+
+func memoryMLoad(stack *Stack) (uint64, bool) {
+ return calcMemSize64WithUint(stack.Back(0), 32)
+}
+
+func memoryMStore8(stack *Stack) (uint64, bool) {
+ return calcMemSize64WithUint(stack.Back(0), 1)
+}
+
+func memoryMStore(stack *Stack) (uint64, bool) {
+ return calcMemSize64WithUint(stack.Back(0), 32)
+}
+
+func memoryMcopy(stack *Stack) (uint64, bool) {
+ mStart := stack.Back(0) // stack[0]: dest
+ if stack.Back(1).Gt(mStart) {
+ mStart = stack.Back(1) // stack[1]: source
+ }
+ return calcMemSize64(mStart, stack.Back(2)) // stack[2]: length
+}
+
+func memoryCreate(stack *Stack) (uint64, bool) {
+ return calcMemSize64(stack.Back(1), stack.Back(2))
+}
+
+func memoryCreate2(stack *Stack) (uint64, bool) {
+ return calcMemSize64(stack.Back(1), stack.Back(2))
+}
+
+func memoryCall(stack *Stack) (uint64, bool) {
+ x, overflow := calcMemSize64(stack.Back(5), stack.Back(6))
+ if overflow {
+ return 0, true
+ }
+ y, overflow := calcMemSize64(stack.Back(3), stack.Back(4))
+ if overflow {
+ return 0, true
+ }
+ if x > y {
+ return x, false
+ }
+ return y, false
+}
+func memoryDelegateCall(stack *Stack) (uint64, bool) {
+ x, overflow := calcMemSize64(stack.Back(4), stack.Back(5))
+ if overflow {
+ return 0, true
+ }
+ y, overflow := calcMemSize64(stack.Back(2), stack.Back(3))
+ if overflow {
+ return 0, true
+ }
+ if x > y {
+ return x, false
+ }
+ return y, false
+}
+
+func memoryStaticCall(stack *Stack) (uint64, bool) {
+ x, overflow := calcMemSize64(stack.Back(4), stack.Back(5))
+ if overflow {
+ return 0, true
+ }
+ y, overflow := calcMemSize64(stack.Back(2), stack.Back(3))
+ if overflow {
+ return 0, true
+ }
+ if x > y {
+ return x, false
+ }
+ return y, false
+}
+
+func memoryReturn(stack *Stack) (uint64, bool) {
+ return calcMemSize64(stack.Back(0), stack.Back(1))
+}
+
+func memoryRevert(stack *Stack) (uint64, bool) {
+ return calcMemSize64(stack.Back(0), stack.Back(1))
+}
+
+func memoryLog(stack *Stack) (uint64, bool) {
+ return calcMemSize64(stack.Back(0), stack.Back(1))
+}
diff --git a/evm/interpreter/opcodes.go b/evm/interpreter/opcodes.go
new file mode 100644
index 000000000..69df34630
--- /dev/null
+++ b/evm/interpreter/opcodes.go
@@ -0,0 +1,562 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "fmt"
+)
+
+// OpCode is an EVM opcode
+type OpCode byte
+
+// IsPush specifies if an opcode is a PUSH opcode.
+func (op OpCode) IsPush() bool {
+ return PUSH0 <= op && op <= PUSH32
+}
+
+// 0x0 range - arithmetic ops.
+const (
+ STOP OpCode = 0x0
+ ADD OpCode = 0x1
+ MUL OpCode = 0x2
+ SUB OpCode = 0x3
+ DIV OpCode = 0x4
+ SDIV OpCode = 0x5
+ MOD OpCode = 0x6
+ SMOD OpCode = 0x7
+ ADDMOD OpCode = 0x8
+ MULMOD OpCode = 0x9
+ EXP OpCode = 0xa
+ SIGNEXTEND OpCode = 0xb
+)
+
+// 0x10 range - comparison ops.
+const (
+ LT OpCode = 0x10
+ GT OpCode = 0x11
+ SLT OpCode = 0x12
+ SGT OpCode = 0x13
+ EQ OpCode = 0x14
+ ISZERO OpCode = 0x15
+ AND OpCode = 0x16
+ OR OpCode = 0x17
+ XOR OpCode = 0x18
+ NOT OpCode = 0x19
+ BYTE OpCode = 0x1a
+ SHL OpCode = 0x1b
+ SHR OpCode = 0x1c
+ SAR OpCode = 0x1d
+)
+
+// 0x20 range - crypto.
+const (
+ KECCAK256 OpCode = 0x20
+)
+
+// 0x30 range - closure state.
+const (
+ ADDRESS OpCode = 0x30
+ BALANCE OpCode = 0x31
+ ORIGIN OpCode = 0x32
+ CALLER OpCode = 0x33
+ CALLVALUE OpCode = 0x34
+ CALLDATALOAD OpCode = 0x35
+ CALLDATASIZE OpCode = 0x36
+ CALLDATACOPY OpCode = 0x37
+ CODESIZE OpCode = 0x38
+ CODECOPY OpCode = 0x39
+ GASPRICE OpCode = 0x3a
+ EXTCODESIZE OpCode = 0x3b
+ EXTCODECOPY OpCode = 0x3c
+ RETURNDATASIZE OpCode = 0x3d
+ RETURNDATACOPY OpCode = 0x3e
+ EXTCODEHASH OpCode = 0x3f
+)
+
+// 0x40 range - block operations.
+const (
+ BLOCKHASH OpCode = 0x40
+ COINBASE OpCode = 0x41
+ TIMESTAMP OpCode = 0x42
+ NUMBER OpCode = 0x43
+ DIFFICULTY OpCode = 0x44
+ RANDOM OpCode = 0x44 // Same as DIFFICULTY
+ PREVRANDAO OpCode = 0x44 // Same as DIFFICULTY
+ GASLIMIT OpCode = 0x45
+ CHAINID OpCode = 0x46
+ SELFBALANCE OpCode = 0x47
+ BASEFEE OpCode = 0x48
+ BLOBHASH OpCode = 0x49
+ BLOBBASEFEE OpCode = 0x4a
+)
+
+// 0x50 range - 'storage' and execution.
+const (
+ POP OpCode = 0x50
+ MLOAD OpCode = 0x51
+ MSTORE OpCode = 0x52
+ MSTORE8 OpCode = 0x53
+ SLOAD OpCode = 0x54
+ SSTORE OpCode = 0x55
+ JUMP OpCode = 0x56
+ JUMPI OpCode = 0x57
+ PC OpCode = 0x58
+ MSIZE OpCode = 0x59
+ GAS OpCode = 0x5a
+ JUMPDEST OpCode = 0x5b
+ TLOAD OpCode = 0x5c
+ TSTORE OpCode = 0x5d
+ MCOPY OpCode = 0x5e
+ PUSH0 OpCode = 0x5f
+)
+
+// 0x60 range - pushes.
+const (
+ PUSH1 OpCode = 0x60 + iota
+ PUSH2
+ PUSH3
+ PUSH4
+ PUSH5
+ PUSH6
+ PUSH7
+ PUSH8
+ PUSH9
+ PUSH10
+ PUSH11
+ PUSH12
+ PUSH13
+ PUSH14
+ PUSH15
+ PUSH16
+ PUSH17
+ PUSH18
+ PUSH19
+ PUSH20
+ PUSH21
+ PUSH22
+ PUSH23
+ PUSH24
+ PUSH25
+ PUSH26
+ PUSH27
+ PUSH28
+ PUSH29
+ PUSH30
+ PUSH31
+ PUSH32
+)
+
+// 0x80 range - dups.
+const (
+ DUP1 = 0x80 + iota
+ DUP2
+ DUP3
+ DUP4
+ DUP5
+ DUP6
+ DUP7
+ DUP8
+ DUP9
+ DUP10
+ DUP11
+ DUP12
+ DUP13
+ DUP14
+ DUP15
+ DUP16
+)
+
+// 0x90 range - swaps.
+const (
+ SWAP1 = 0x90 + iota
+ SWAP2
+ SWAP3
+ SWAP4
+ SWAP5
+ SWAP6
+ SWAP7
+ SWAP8
+ SWAP9
+ SWAP10
+ SWAP11
+ SWAP12
+ SWAP13
+ SWAP14
+ SWAP15
+ SWAP16
+)
+
+// 0xa0 range - logging ops.
+const (
+ LOG0 OpCode = 0xa0 + iota
+ LOG1
+ LOG2
+ LOG3
+ LOG4
+)
+
+// 0xf0 range - closures.
+const (
+ CREATE OpCode = 0xf0
+ CALL OpCode = 0xf1
+ CALLCODE OpCode = 0xf2
+ RETURN OpCode = 0xf3
+ DELEGATECALL OpCode = 0xf4
+ CREATE2 OpCode = 0xf5
+
+ STATICCALL OpCode = 0xfa
+ REVERT OpCode = 0xfd
+ INVALID OpCode = 0xfe
+ SELFDESTRUCT OpCode = 0xff
+)
+
+var opCodeToString = [256]string{
+ // 0x0 range - arithmetic ops.
+ STOP: "STOP",
+ ADD: "ADD",
+ MUL: "MUL",
+ SUB: "SUB",
+ DIV: "DIV",
+ SDIV: "SDIV",
+ MOD: "MOD",
+ SMOD: "SMOD",
+ EXP: "EXP",
+ NOT: "NOT",
+ LT: "LT",
+ GT: "GT",
+ SLT: "SLT",
+ SGT: "SGT",
+ EQ: "EQ",
+ ISZERO: "ISZERO",
+ SIGNEXTEND: "SIGNEXTEND",
+
+ // 0x10 range - bit ops.
+ AND: "AND",
+ OR: "OR",
+ XOR: "XOR",
+ BYTE: "BYTE",
+ SHL: "SHL",
+ SHR: "SHR",
+ SAR: "SAR",
+ ADDMOD: "ADDMOD",
+ MULMOD: "MULMOD",
+
+ // 0x20 range - crypto.
+ KECCAK256: "KECCAK256",
+
+ // 0x30 range - closure state.
+ ADDRESS: "ADDRESS",
+ BALANCE: "BALANCE",
+ ORIGIN: "ORIGIN",
+ CALLER: "CALLER",
+ CALLVALUE: "CALLVALUE",
+ CALLDATALOAD: "CALLDATALOAD",
+ CALLDATASIZE: "CALLDATASIZE",
+ CALLDATACOPY: "CALLDATACOPY",
+ CODESIZE: "CODESIZE",
+ CODECOPY: "CODECOPY",
+ GASPRICE: "GASPRICE",
+ EXTCODESIZE: "EXTCODESIZE",
+ EXTCODECOPY: "EXTCODECOPY",
+ RETURNDATASIZE: "RETURNDATASIZE",
+ RETURNDATACOPY: "RETURNDATACOPY",
+ EXTCODEHASH: "EXTCODEHASH",
+
+ // 0x40 range - block operations.
+ BLOCKHASH: "BLOCKHASH",
+ COINBASE: "COINBASE",
+ TIMESTAMP: "TIMESTAMP",
+ NUMBER: "NUMBER",
+ DIFFICULTY: "DIFFICULTY", // TODO (MariusVanDerWijden) rename to PREVRANDAO post merge
+ GASLIMIT: "GASLIMIT",
+ CHAINID: "CHAINID",
+ SELFBALANCE: "SELFBALANCE",
+ BASEFEE: "BASEFEE",
+ BLOBHASH: "BLOBHASH",
+ BLOBBASEFEE: "BLOBBASEFEE",
+
+ // 0x50 range - 'storage' and execution.
+ POP: "POP",
+ MLOAD: "MLOAD",
+ MSTORE: "MSTORE",
+ MSTORE8: "MSTORE8",
+ SLOAD: "SLOAD",
+ SSTORE: "SSTORE",
+ JUMP: "JUMP",
+ JUMPI: "JUMPI",
+ PC: "PC",
+ MSIZE: "MSIZE",
+ GAS: "GAS",
+ JUMPDEST: "JUMPDEST",
+ TLOAD: "TLOAD",
+ TSTORE: "TSTORE",
+ MCOPY: "MCOPY",
+ PUSH0: "PUSH0",
+
+ // 0x60 range - pushes.
+ PUSH1: "PUSH1",
+ PUSH2: "PUSH2",
+ PUSH3: "PUSH3",
+ PUSH4: "PUSH4",
+ PUSH5: "PUSH5",
+ PUSH6: "PUSH6",
+ PUSH7: "PUSH7",
+ PUSH8: "PUSH8",
+ PUSH9: "PUSH9",
+ PUSH10: "PUSH10",
+ PUSH11: "PUSH11",
+ PUSH12: "PUSH12",
+ PUSH13: "PUSH13",
+ PUSH14: "PUSH14",
+ PUSH15: "PUSH15",
+ PUSH16: "PUSH16",
+ PUSH17: "PUSH17",
+ PUSH18: "PUSH18",
+ PUSH19: "PUSH19",
+ PUSH20: "PUSH20",
+ PUSH21: "PUSH21",
+ PUSH22: "PUSH22",
+ PUSH23: "PUSH23",
+ PUSH24: "PUSH24",
+ PUSH25: "PUSH25",
+ PUSH26: "PUSH26",
+ PUSH27: "PUSH27",
+ PUSH28: "PUSH28",
+ PUSH29: "PUSH29",
+ PUSH30: "PUSH30",
+ PUSH31: "PUSH31",
+ PUSH32: "PUSH32",
+
+ // 0x80 - dups.
+ DUP1: "DUP1",
+ DUP2: "DUP2",
+ DUP3: "DUP3",
+ DUP4: "DUP4",
+ DUP5: "DUP5",
+ DUP6: "DUP6",
+ DUP7: "DUP7",
+ DUP8: "DUP8",
+ DUP9: "DUP9",
+ DUP10: "DUP10",
+ DUP11: "DUP11",
+ DUP12: "DUP12",
+ DUP13: "DUP13",
+ DUP14: "DUP14",
+ DUP15: "DUP15",
+ DUP16: "DUP16",
+
+ // 0x90 - swaps.
+ SWAP1: "SWAP1",
+ SWAP2: "SWAP2",
+ SWAP3: "SWAP3",
+ SWAP4: "SWAP4",
+ SWAP5: "SWAP5",
+ SWAP6: "SWAP6",
+ SWAP7: "SWAP7",
+ SWAP8: "SWAP8",
+ SWAP9: "SWAP9",
+ SWAP10: "SWAP10",
+ SWAP11: "SWAP11",
+ SWAP12: "SWAP12",
+ SWAP13: "SWAP13",
+ SWAP14: "SWAP14",
+ SWAP15: "SWAP15",
+ SWAP16: "SWAP16",
+
+ // 0xa0 range - logging ops.
+ LOG0: "LOG0",
+ LOG1: "LOG1",
+ LOG2: "LOG2",
+ LOG3: "LOG3",
+ LOG4: "LOG4",
+
+ // 0xf0 range - closures.
+ CREATE: "CREATE",
+ CALL: "CALL",
+ RETURN: "RETURN",
+ CALLCODE: "CALLCODE",
+ DELEGATECALL: "DELEGATECALL",
+ CREATE2: "CREATE2",
+ STATICCALL: "STATICCALL",
+ REVERT: "REVERT",
+ INVALID: "INVALID",
+ SELFDESTRUCT: "SELFDESTRUCT",
+}
+
+func (op OpCode) String() string {
+ if s := opCodeToString[op]; s != "" {
+ return s
+ }
+ return fmt.Sprintf("opcode %#x not defined", int(op))
+}
+
+var stringToOp = map[string]OpCode{
+ "STOP": STOP,
+ "ADD": ADD,
+ "MUL": MUL,
+ "SUB": SUB,
+ "DIV": DIV,
+ "SDIV": SDIV,
+ "MOD": MOD,
+ "SMOD": SMOD,
+ "EXP": EXP,
+ "NOT": NOT,
+ "LT": LT,
+ "GT": GT,
+ "SLT": SLT,
+ "SGT": SGT,
+ "EQ": EQ,
+ "ISZERO": ISZERO,
+ "SIGNEXTEND": SIGNEXTEND,
+ "AND": AND,
+ "OR": OR,
+ "XOR": XOR,
+ "BYTE": BYTE,
+ "SHL": SHL,
+ "SHR": SHR,
+ "SAR": SAR,
+ "ADDMOD": ADDMOD,
+ "MULMOD": MULMOD,
+ "KECCAK256": KECCAK256,
+ "ADDRESS": ADDRESS,
+ "BALANCE": BALANCE,
+ "ORIGIN": ORIGIN,
+ "CALLER": CALLER,
+ "CALLVALUE": CALLVALUE,
+ "CALLDATALOAD": CALLDATALOAD,
+ "CALLDATASIZE": CALLDATASIZE,
+ "CALLDATACOPY": CALLDATACOPY,
+ "CHAINID": CHAINID,
+ "BASEFEE": BASEFEE,
+ "BLOBHASH": BLOBHASH,
+ "BLOBBASEFEE": BLOBBASEFEE,
+ "DELEGATECALL": DELEGATECALL,
+ "STATICCALL": STATICCALL,
+ "CODESIZE": CODESIZE,
+ "CODECOPY": CODECOPY,
+ "GASPRICE": GASPRICE,
+ "EXTCODESIZE": EXTCODESIZE,
+ "EXTCODECOPY": EXTCODECOPY,
+ "RETURNDATASIZE": RETURNDATASIZE,
+ "RETURNDATACOPY": RETURNDATACOPY,
+ "EXTCODEHASH": EXTCODEHASH,
+ "BLOCKHASH": BLOCKHASH,
+ "COINBASE": COINBASE,
+ "TIMESTAMP": TIMESTAMP,
+ "NUMBER": NUMBER,
+ "DIFFICULTY": DIFFICULTY,
+ "GASLIMIT": GASLIMIT,
+ "SELFBALANCE": SELFBALANCE,
+ "POP": POP,
+ "MLOAD": MLOAD,
+ "MSTORE": MSTORE,
+ "MSTORE8": MSTORE8,
+ "SLOAD": SLOAD,
+ "SSTORE": SSTORE,
+ "JUMP": JUMP,
+ "JUMPI": JUMPI,
+ "PC": PC,
+ "MSIZE": MSIZE,
+ "GAS": GAS,
+ "JUMPDEST": JUMPDEST,
+ "TLOAD": TLOAD,
+ "TSTORE": TSTORE,
+ "MCOPY": MCOPY,
+ "PUSH0": PUSH0,
+ "PUSH1": PUSH1,
+ "PUSH2": PUSH2,
+ "PUSH3": PUSH3,
+ "PUSH4": PUSH4,
+ "PUSH5": PUSH5,
+ "PUSH6": PUSH6,
+ "PUSH7": PUSH7,
+ "PUSH8": PUSH8,
+ "PUSH9": PUSH9,
+ "PUSH10": PUSH10,
+ "PUSH11": PUSH11,
+ "PUSH12": PUSH12,
+ "PUSH13": PUSH13,
+ "PUSH14": PUSH14,
+ "PUSH15": PUSH15,
+ "PUSH16": PUSH16,
+ "PUSH17": PUSH17,
+ "PUSH18": PUSH18,
+ "PUSH19": PUSH19,
+ "PUSH20": PUSH20,
+ "PUSH21": PUSH21,
+ "PUSH22": PUSH22,
+ "PUSH23": PUSH23,
+ "PUSH24": PUSH24,
+ "PUSH25": PUSH25,
+ "PUSH26": PUSH26,
+ "PUSH27": PUSH27,
+ "PUSH28": PUSH28,
+ "PUSH29": PUSH29,
+ "PUSH30": PUSH30,
+ "PUSH31": PUSH31,
+ "PUSH32": PUSH32,
+ "DUP1": DUP1,
+ "DUP2": DUP2,
+ "DUP3": DUP3,
+ "DUP4": DUP4,
+ "DUP5": DUP5,
+ "DUP6": DUP6,
+ "DUP7": DUP7,
+ "DUP8": DUP8,
+ "DUP9": DUP9,
+ "DUP10": DUP10,
+ "DUP11": DUP11,
+ "DUP12": DUP12,
+ "DUP13": DUP13,
+ "DUP14": DUP14,
+ "DUP15": DUP15,
+ "DUP16": DUP16,
+ "SWAP1": SWAP1,
+ "SWAP2": SWAP2,
+ "SWAP3": SWAP3,
+ "SWAP4": SWAP4,
+ "SWAP5": SWAP5,
+ "SWAP6": SWAP6,
+ "SWAP7": SWAP7,
+ "SWAP8": SWAP8,
+ "SWAP9": SWAP9,
+ "SWAP10": SWAP10,
+ "SWAP11": SWAP11,
+ "SWAP12": SWAP12,
+ "SWAP13": SWAP13,
+ "SWAP14": SWAP14,
+ "SWAP15": SWAP15,
+ "SWAP16": SWAP16,
+ "LOG0": LOG0,
+ "LOG1": LOG1,
+ "LOG2": LOG2,
+ "LOG3": LOG3,
+ "LOG4": LOG4,
+ "CREATE": CREATE,
+ "CREATE2": CREATE2,
+ "CALL": CALL,
+ "RETURN": RETURN,
+ "CALLCODE": CALLCODE,
+ "REVERT": REVERT,
+ "INVALID": INVALID,
+ "SELFDESTRUCT": SELFDESTRUCT,
+}
+
+// StringToOp finds the opcode whose name is stored in `str`.
+func StringToOp(str string) OpCode {
+ return stringToOp[str]
+}
diff --git a/evm/interpreter/stack.go b/evm/interpreter/stack.go
new file mode 100644
index 000000000..b1cd8a96a
--- /dev/null
+++ b/evm/interpreter/stack.go
@@ -0,0 +1,82 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "sync"
+
+ "github.com/holiman/uint256"
+)
+
+var stackPool = sync.Pool{
+ New: func() interface{} {
+ return &Stack{data: make([]uint256.Int, 0, 16)}
+ },
+}
+
+// Stack is an object for basic stack operations. Items popped to the stack are
+// expected to be changed and modified. stack does not take care of adding newly
+// initialised objects.
+type Stack struct {
+ data []uint256.Int
+}
+
+func newstack() *Stack {
+ return stackPool.Get().(*Stack)
+}
+
+func returnStack(s *Stack) {
+ s.data = s.data[:0]
+ stackPool.Put(s)
+}
+
+// Data returns the underlying uint256.Int array.
+func (st *Stack) Data() []uint256.Int {
+ return st.data
+}
+
+func (st *Stack) push(d *uint256.Int) {
+ // NOTE push limit (1024) is checked in baseCheck
+ st.data = append(st.data, *d)
+}
+
+func (st *Stack) pop() (ret uint256.Int) {
+ ret = st.data[len(st.data)-1]
+ st.data = st.data[:len(st.data)-1]
+ return
+}
+
+func (st *Stack) len() int {
+ return len(st.data)
+}
+
+func (st *Stack) swap(n int) {
+ st.data[st.len()-n], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-n]
+}
+
+func (st *Stack) dup(n int) {
+ st.push(&st.data[st.len()-n])
+}
+
+func (st *Stack) peek() *uint256.Int {
+ return &st.data[st.len()-1]
+}
+
+// Back returns the n'th item in stack
+func (st *Stack) Back(n int) *uint256.Int {
+ return &st.data[st.len()-n-1]
+}
diff --git a/evm/interpreter/stack_table.go b/evm/interpreter/stack_table.go
new file mode 100644
index 000000000..26ca26479
--- /dev/null
+++ b/evm/interpreter/stack_table.go
@@ -0,0 +1,42 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "github.com/ethereum/go-ethereum/params"
+)
+
+func minSwapStack(n int) int {
+ return minStack(n, n)
+}
+func maxSwapStack(n int) int {
+ return maxStack(n, n)
+}
+
+func minDupStack(n int) int {
+ return minStack(n, n+1)
+}
+func maxDupStack(n int) int {
+ return maxStack(n, n+1)
+}
+
+func maxStack(pop, push int) int {
+ return int(params.StackLimit) + pop - push
+}
+func minStack(pops, push int) int {
+ return pops
+}
diff --git a/evm/interpreter/state_db.go b/evm/interpreter/state_db.go
new file mode 100644
index 000000000..fa79fa23c
--- /dev/null
+++ b/evm/interpreter/state_db.go
@@ -0,0 +1,32 @@
+package evm
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/multiversx/mx-chain-vm-go/executor"
+)
+
+var _ = (StateDB)((*EVMStateDB)(nil))
+
+type EVMStateDB struct {
+ executor.EVMHooks
+ transientStorage transientStorage
+}
+
+func CreateEVMStateDB(evmHooks executor.EVMHooks) *EVMStateDB {
+ return &EVMStateDB{
+ EVMHooks: evmHooks,
+ transientStorage: newTransientStorage(),
+ }
+}
+
+func (evmState *EVMStateDB) GetTransientState(address common.Address, key common.Hash) common.Hash {
+ return evmState.transientStorage.Get(address, key)
+}
+
+func (evmState *EVMStateDB) SetTransientState(address common.Address, key common.Hash, value common.Hash) {
+ prev := evmState.GetTransientState(address, key)
+ if prev == value {
+ return
+ }
+ evmState.transientStorage.Set(address, key, value)
+}
diff --git a/evm/interpreter/transient_storage.go b/evm/interpreter/transient_storage.go
new file mode 100644
index 000000000..bf27a6c77
--- /dev/null
+++ b/evm/interpreter/transient_storage.go
@@ -0,0 +1,56 @@
+// Copyright 2022 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package evm
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/state"
+)
+
+// transientStorage is a representation of EIP-1153 "Transient Storage".
+type transientStorage map[common.Address]state.Storage
+
+// newTransientStorage creates a new instance of a transientStorage.
+func newTransientStorage() transientStorage {
+ return make(transientStorage)
+}
+
+// Set sets the transient-storage `value` for `key` at the given `addr`.
+func (t transientStorage) Set(addr common.Address, key, value common.Hash) {
+ if _, ok := t[addr]; !ok {
+ t[addr] = make(state.Storage)
+ }
+ t[addr][key] = value
+}
+
+// Get gets the transient storage for `key` at the given `addr`.
+func (t transientStorage) Get(addr common.Address, key common.Hash) common.Hash {
+ val, ok := t[addr]
+ if !ok {
+ return common.Hash{}
+ }
+ return val[key]
+}
+
+// Copy does a deep copy of the transientStorage
+func (t transientStorage) Copy() transientStorage {
+ storage := make(transientStorage)
+ for key, value := range t {
+ storage[key] = value.Copy()
+ }
+ return storage
+}
diff --git a/executor/evmHooks.go b/executor/evmHooks.go
new file mode 100644
index 000000000..200232dc7
--- /dev/null
+++ b/executor/evmHooks.go
@@ -0,0 +1,73 @@
+package executor
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/holiman/uint256"
+ "math/big"
+)
+
+// EVMHooks contains all VM functions that can be called by the executor during SC execution.
+type EVMHooks interface {
+ EvmBlockchainHooks
+ EvmMeteringHooks
+ EvmOutputHooks
+ EvmRuntimeHooks
+ EvmStorageHooks
+ EvmExecutionHooks
+}
+
+type EvmBlockchainHooks interface {
+ ChainID() *big.Int
+ Random() *common.Hash
+ GetHash(number uint64) common.Hash
+ BlockNumber() *big.Int
+ Time() uint64
+ GetSelfBalance() *uint256.Int
+ GetBalance(address common.Address) *uint256.Int
+ GetCodeHash(address common.Address) common.Hash
+ GetCode(address common.Address) []byte
+ GetCodeSize(address common.Address) int
+ SaveAliasAddress() error
+}
+
+type EvmMeteringHooks interface {
+ GasLeft() uint64
+ UseGas(opCode string, gas uint64) bool
+ BlockGasLimit() uint64
+}
+
+type EvmOutputHooks interface {
+ Finish(returnData []byte)
+ FinishCreate(returnData []byte)
+ TransferBalance(destination common.Address, value *uint256.Int) error
+ SelfDestruct(destination common.Address)
+ AddLog(log *types.Log)
+}
+
+type EvmRuntimeHooks interface {
+ FailExecution(err error)
+ ReadOnly() bool
+ Origin() common.Address
+ GasPrice() *big.Int
+ CallerAddress() common.Address
+ ContractAddress() common.Address
+ CallValue() *uint256.Int
+ Arguments() [][]byte
+ CodeHash() common.Hash
+}
+
+type EvmStorageHooks interface {
+ GetState(key common.Hash) common.Hash
+ SetState(key common.Hash, value common.Hash)
+}
+
+type EvmExecutionHooks interface {
+ IsSmartContractAddress(address common.Address) bool
+ Create(code []byte, gas uint64, value *uint256.Int) ([]byte, common.Address, error)
+ Create2(code []byte, gas uint64, value *uint256.Int, salt *uint256.Int) ([]byte, common.Address, error)
+ Call(address common.Address, value *uint256.Int, input []byte, gas uint64) ([]byte, error)
+ StaticCall(address common.Address, input []byte, gas uint64) ([]byte, error)
+ DelegateCall(address common.Address, input []byte, gas uint64) ([]byte, error)
+ CallCode(address common.Address, value *uint256.Int, input []byte, gas uint64) ([]byte, error)
+}
diff --git a/executor/executor.go b/executor/executor.go
index f3c35390b..af2d7c585 100644
--- a/executor/executor.go
+++ b/executor/executor.go
@@ -22,7 +22,7 @@ type Executor interface {
check.NilInterfaceChecker
// SetOpcodeCosts sets gas costs globally inside an executor.
- SetOpcodeCosts(opcodeCosts *WASMOpcodeCost)
+ SetOpcodeCosts(opcodeCosts VMOpcodeCost)
// FunctionNames return the low-level function names provided to contracts.
FunctionNames() vmcommon.FunctionNames
diff --git a/executor/executorFactory.go b/executor/executorFactory.go
index 28b4b13d6..5e6f6cfa6 100644
--- a/executor/executorFactory.go
+++ b/executor/executorFactory.go
@@ -2,10 +2,16 @@ package executor
import "github.com/multiversx/mx-chain-core-go/core/check"
+type VMOpcodeCost struct {
+ EVMOpcodeCost *EVMOpcodeCost
+ WASMOpcodeCost *WASMOpcodeCost
+}
+
// ExecutorFactoryArgs define the Executor configurations that come from the VM, especially the hooks and the gas costs.
type ExecutorFactoryArgs struct {
+ EvmHooks EVMHooks
VMHooks VMHooks
- OpcodeCosts *WASMOpcodeCost
+ OpcodeCosts VMOpcodeCost
RkyvSerializationEnabled bool
WasmerSIGSEGVPassthrough bool
}
diff --git a/executor/executorInstance.go b/executor/executorInstance.go
index 217479a83..f618c8520 100644
--- a/executor/executorInstance.go
+++ b/executor/executorInstance.go
@@ -7,6 +7,7 @@ type Instance interface {
SetGasLimit(gasLimit uint64)
SetBreakpointValue(value uint64)
GetBreakpointValue() uint64
+ HasCompiledCode() bool
Cache() ([]byte, error)
Clean() bool
CallFunction(functionName string) error
diff --git a/executor/gasCostEVM.go b/executor/gasCostEVM.go
new file mode 100644
index 000000000..de48cd511
--- /dev/null
+++ b/executor/gasCostEVM.go
@@ -0,0 +1,51 @@
+// Code generated by vmhooks generator. DO NOT EDIT.
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!! AUTO-GENERATED FILE !!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+package executor
+
+type EVMOpcodeCost struct {
+ QuickStep uint64
+ FastestStep uint64
+ FastStep uint64
+ MidStep uint64
+ SlowStep uint64
+ ExtStep uint64
+ Ecrecover uint64
+ Sha256PerWord uint64
+ Sha256Base uint64
+ Ripemd160PerWord uint64
+ Ripemd160Base uint64
+ IdentityPerWord uint64
+ IdentityBase uint64
+ Bn256Add uint64
+ Bn256ScalarMul uint64
+ Bn256PairingBase uint64
+ Bn256PairingPerPoint uint64
+ BlobTxPointEvaluation uint64
+ Keccak256 uint64
+ Balance uint64
+ ExtcodeSize uint64
+ ExtcodeCopy uint64
+ ExtcodeHash uint64
+ Sload uint64
+ Sstore uint64
+ Jumpdest uint64
+ Tload uint64
+ Tstore uint64
+ Create uint64
+ Call uint64
+ Create2 uint64
+ Selfdestruct uint64
+ Memory uint64
+ Copy uint64
+ Log uint64
+ LogTopic uint64
+ LogData uint64
+ Keccak256Word uint64
+ InitCodeWord uint64
+ ExpByte uint64
+ Exp uint64
+}
diff --git a/executor/wrapper/wrapperExecutor.go b/executor/wrapper/wrapperExecutor.go
index a8d146dde..f07277411 100644
--- a/executor/wrapper/wrapperExecutor.go
+++ b/executor/wrapper/wrapperExecutor.go
@@ -16,7 +16,7 @@ type WrapperExecutor struct {
}
// SetOpcodeCosts wraps the call to the underlying executor.
-func (wexec *WrapperExecutor) SetOpcodeCosts(opcodeCosts *executor.WASMOpcodeCost) {
+func (wexec *WrapperExecutor) SetOpcodeCosts(opcodeCosts executor.VMOpcodeCost) {
wexec.wrappedExecutor.SetOpcodeCosts(opcodeCosts)
}
diff --git a/executor/wrapper/wrapperExecutorFactory.go b/executor/wrapper/wrapperExecutorFactory.go
index 8e64990b7..0c657ae79 100644
--- a/executor/wrapper/wrapperExecutorFactory.go
+++ b/executor/wrapper/wrapperExecutorFactory.go
@@ -31,6 +31,7 @@ func SimpleWrappedExecutorFactory(wrappedFactory executor.ExecutorAbstractFactor
// CreateExecutor creates a new Executor instance.
func (factory *WrapperExecutorFactory) CreateExecutor(args executor.ExecutorFactoryArgs) (executor.Executor, error) {
wrappedExecutor, err := factory.wrappedFactory.CreateExecutor(executor.ExecutorFactoryArgs{
+ EvmHooks: args.EvmHooks,
VMHooks: &WrapperVMHooks{
logger: factory.logger,
wrappedVMHooks: args.VMHooks,
diff --git a/executor/wrapper/wrapperInstance.go b/executor/wrapper/wrapperInstance.go
index d4fd11f1b..59eaf4b68 100644
--- a/executor/wrapper/wrapperInstance.go
+++ b/executor/wrapper/wrapperInstance.go
@@ -48,6 +48,11 @@ func (inst *WrapperInstance) GetBreakpointValue() uint64 {
return result
}
+// HasCompiledCode wraps the call to the underlying instance.
+func (inst *WrapperInstance) HasCompiledCode() bool {
+ return inst.wrappedInstance.HasCompiledCode()
+}
+
// Cache wraps the call to the underlying instance.
func (inst *WrapperInstance) Cache() ([]byte, error) {
return inst.wrappedInstance.Cache()
diff --git a/go.mod b/go.mod
index 905dbbaa9..57670eee2 100644
--- a/go.mod
+++ b/go.mod
@@ -1,44 +1,95 @@
module github.com/multiversx/mx-chain-vm-go
-go 1.23
+go 1.23.0
+
+replace (
+ github.com/multiversx/mx-chain-core-go => github.com/multiversx/mx-chain-core-sovereign-go v1.2.25-0.20251016085427-f3e9cd4fff15
+ github.com/multiversx/mx-chain-scenario-go => github.com/multiversx/mx-chain-scenario-go v1.7.1-0.20251017112020-13e0da713fbd
+ github.com/multiversx/mx-chain-vm-common-go => github.com/multiversx/mx-chain-vm-common-sovereign-go v1.5.17-0.20251017111745-78d274090d98
+)
require (
github.com/awalterschulze/gographviz v2.0.3+incompatible
github.com/btcsuite/btcd/btcec/v2 v2.3.2
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1
+ github.com/ethereum/go-ethereum v1.13.15
github.com/gogo/protobuf v1.3.2
+ github.com/holiman/uint256 v1.2.4
github.com/mitchellh/mapstructure v1.5.0
github.com/multiversx/mx-chain-core-go v1.4.0
- github.com/multiversx/mx-chain-crypto-go v1.3.0
+ github.com/multiversx/mx-chain-crypto-go v1.3.1-0.20251016113715-522462f8de2c
github.com/multiversx/mx-chain-logger-go v1.1.0
github.com/multiversx/mx-chain-scenario-go v1.6.0
github.com/multiversx/mx-chain-storage-go v1.1.0
github.com/multiversx/mx-chain-vm-common-go v1.6.0
github.com/multiversx/mx-components-big-int v1.1.0
github.com/pelletier/go-toml v1.9.3
- github.com/stretchr/testify v1.8.1
+ github.com/stretchr/testify v1.8.4
github.com/urfave/cli/v2 v2.27.1
- golang.org/x/crypto v0.3.0
+ golang.org/x/crypto v0.33.0
)
require (
+ filippo.io/edwards25519 v1.0.0 // indirect
+ github.com/DataDog/zstd v1.4.5 // indirect
+ github.com/StackExchange/wmi v1.2.1 // indirect
github.com/TwiN/go-color v1.1.0 // indirect
+ github.com/VictoriaMetrics/fastcache v1.12.1 // indirect
+ github.com/beorn7/perks v1.0.1 // indirect
+ github.com/bits-and-blooms/bitset v1.10.0 // indirect
github.com/btcsuite/btcd/btcutil v1.1.3 // indirect
+ github.com/cespare/xxhash/v2 v2.2.0 // indirect
+ github.com/cockroachdb/errors v1.8.1 // indirect
+ github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f // indirect
+ github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 // indirect
+ github.com/cockroachdb/redact v1.0.8 // indirect
+ github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 // indirect
+ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
+ github.com/consensys/bavard v0.1.13 // indirect
+ github.com/consensys/gnark-crypto v0.12.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
+ github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect
+ github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/denisbrodbeck/machineid v1.0.1 // indirect
- github.com/golang/protobuf v1.5.2 // indirect
+ github.com/ethereum/c-kzg-4844 v0.4.0 // indirect
+ github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect
+ github.com/go-ole/go-ole v1.3.0 // indirect
+ github.com/gofrs/flock v0.8.1 // indirect
+ github.com/golang/protobuf v1.5.4 // indirect
+ github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
github.com/hashicorp/golang-lru v0.6.0 // indirect
github.com/herumi/bls-go-binary v1.28.2 // indirect
- github.com/kr/pretty v0.3.0 // indirect
+ github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
+ github.com/klauspost/compress v1.15.15 // indirect
+ github.com/kr/pretty v0.3.1 // indirect
+ github.com/kr/text v0.2.0 // indirect
+ github.com/mattn/go-runewidth v0.0.13 // indirect
+ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
+ github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
+ github.com/multiversx/mx-sdk-abi-go v0.3.1-0.20250423092559-f01fdd10b35d // indirect
+ github.com/olekukonko/tablewriter v0.0.5 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/rogpeppe/go-internal v1.8.0 // indirect
+ github.com/prometheus/client_golang v1.12.0 // indirect
+ github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a // indirect
+ github.com/prometheus/common v0.32.1 // indirect
+ github.com/prometheus/procfs v0.7.3 // indirect
+ github.com/rivo/uniseg v0.2.0 // indirect
+ github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
+ github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
+ github.com/supranational/blst v0.3.11 // indirect
+ github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
+ github.com/tklauser/go-sysconf v0.3.12 // indirect
+ github.com/tklauser/numcpus v0.6.1 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
- golang.org/x/sys v0.2.0 // indirect
- google.golang.org/protobuf v1.28.0 // indirect
- gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
+ golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
+ golang.org/x/sync v0.11.0 // indirect
+ golang.org/x/sys v0.30.0 // indirect
+ google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
+ rsc.io/tmplfunc v0.0.3 // indirect
)
diff --git a/go.sum b/go.sum
index 7825dc23d..e9ff3bc11 100644
--- a/go.sum
+++ b/go.sum
@@ -1,8 +1,73 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
+filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
+github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
+github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
+github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
+github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
+github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
+github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
+github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
+github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
+github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
github.com/TwiN/go-color v1.1.0 h1:yhLAHgjp2iAxmNjDiVb6Z073NE65yoaPlcki1Q22yyQ=
github.com/TwiN/go-color v1.1.0/go.mod h1:aKVf4e1mD4ai2FtPifkDPP5iyoCwiK08YGzGwerjKo0=
+github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40=
+github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
+github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
+github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/awalterschulze/gographviz v2.0.3+incompatible h1:9sVEXJBJLwGX7EQVhLm2elIKCm7P2YHFC8v6096G09E=
github.com/awalterschulze/gographviz v2.0.3+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs=
+github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88=
+github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=
@@ -26,8 +91,47 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4=
+github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4=
+github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
+github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM=
+github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y=
+github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac=
+github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY=
+github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
+github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A=
+github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo=
+github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw=
+github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
+github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM=
+github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ=
+github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
+github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
+github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
+github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
+github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
+github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M=
+github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ=
+github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs=
+github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA=
+github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -40,161 +144,715 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeC
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
+github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
+github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY=
+github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
+github.com/ethereum/go-ethereum v1.13.15 h1:U7sSGYGo4SPjP6iNIifNoyIAiNjrmQkz6EwQG+/EZWo=
+github.com/ethereum/go-ethereum v1.13.15/go.mod h1:TN8ZiHrdJwSe8Cb6x+p0hs5CxhJZPbqB7hHkaUXcmIU=
+github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
+github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
+github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
+github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
+github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
+github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE=
+github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc=
+github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
+github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
+github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
+github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
+github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
+github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
+github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
+github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
+github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
+github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
+github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
+github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk=
+github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/herumi/bls-go-binary v1.28.2 h1:F0AezsC0M1a9aZjk7g0l2hMb1F56Xtpfku97pDndNZE=
github.com/herumi/bls-go-binary v1.28.2/go.mod h1:O4Vp1AfR4raRGwFeQpr9X/PQtncEicMoOe6BQt1oX0Y=
+github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
+github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
+github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
+github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
+github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
+github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI=
+github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
+github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
+github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
+github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk=
+github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U=
+github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw=
+github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
+github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
+github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
+github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
-github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
+github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
+github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
+github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
+github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg=
+github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ=
+github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
+github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
+github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
-github.com/multiversx/mx-chain-core-go v1.4.0 h1:p6FbfCzvMXF54kpS0B5mrjNWYpq4SEQqo0UvrMF7YVY=
-github.com/multiversx/mx-chain-core-go v1.4.0/go.mod h1:IO+vspNan+gT0WOHnJ95uvWygiziHZvfXpff6KnxV7g=
-github.com/multiversx/mx-chain-crypto-go v1.3.0 h1:0eK2bkDOMi8VbSPrB1/vGJSYT81IBtfL4zw+C4sWe/k=
-github.com/multiversx/mx-chain-crypto-go v1.3.0/go.mod h1:nPIkxxzyTP8IquWKds+22Q2OJ9W7LtusC7cAosz7ojM=
+github.com/multiversx/mx-chain-core-sovereign-go v1.2.25-0.20251016085427-f3e9cd4fff15 h1:DVjnbVio7v+4nIJ/sO32iNG+GxouPNj6rd5ixdERqCM=
+github.com/multiversx/mx-chain-core-sovereign-go v1.2.25-0.20251016085427-f3e9cd4fff15/go.mod h1:PsKbRg77qscWGVpOqH85sh3+q+wKny14Wmlziz2XXlM=
+github.com/multiversx/mx-chain-crypto-go v1.3.1-0.20251016113715-522462f8de2c h1:ZJHss4rb+I9oOplndmuyBaOmOdnwKLzoESvx1VOa+xk=
+github.com/multiversx/mx-chain-crypto-go v1.3.1-0.20251016113715-522462f8de2c/go.mod h1:uQRpb30oxGpvqsbnMzAYEBJ6vt8OzaoH8Sh3s/2MGZ4=
github.com/multiversx/mx-chain-logger-go v1.1.0 h1:97x84A6L4RfCa6YOx1HpAFxZp1cf/WI0Qh112whgZNM=
github.com/multiversx/mx-chain-logger-go v1.1.0/go.mod h1:K9XgiohLwOsNACETMNL0LItJMREuEvTH6NsoXWXWg7g=
-github.com/multiversx/mx-chain-scenario-go v1.6.0 h1:cwDFuS1pSc4YXnfiKKDTEb+QDY4fulPQaiRgIebnKxI=
-github.com/multiversx/mx-chain-scenario-go v1.6.0/go.mod h1:GrSYu1SnMvsIm9djUz1X13224HcvdY6Nb5KHNT3xZPA=
+github.com/multiversx/mx-chain-scenario-go v1.7.1-0.20251017112020-13e0da713fbd h1:1VnoyU5nTUC1xEWAm1ApzWQgDjAn96QKk4jLkA9IaOM=
+github.com/multiversx/mx-chain-scenario-go v1.7.1-0.20251017112020-13e0da713fbd/go.mod h1:fUkPC77cz1xb/J6HsD1eGzKGPA03i22BHf2AC3LEk0c=
github.com/multiversx/mx-chain-storage-go v1.1.0 h1:M1Y9DqMrJ62s7Zw31+cyuqsnPIvlG4jLBJl5WzeZLe8=
github.com/multiversx/mx-chain-storage-go v1.1.0/go.mod h1:o6Jm7cjfPmcc6XpyihYWrd6sx3sgqwurrunw3ZrfyxI=
-github.com/multiversx/mx-chain-vm-common-go v1.6.0 h1:M2zmf/ptEINciWxYCPLIkwOMTvvzWjELYYB+0MMQ5Gw=
-github.com/multiversx/mx-chain-vm-common-go v1.6.0/go.mod h1:Lc7r4VDPYRDS0CVIaWAoLtf3YQn6PZEYHv4QtaOE2Z0=
+github.com/multiversx/mx-chain-vm-common-sovereign-go v1.5.17-0.20251017111745-78d274090d98 h1:MuRpIbb1u6K6oz54/D/GvU1K0m//t3YYiy4D6dywyqI=
+github.com/multiversx/mx-chain-vm-common-sovereign-go v1.5.17-0.20251017111745-78d274090d98/go.mod h1:MAxpPWt9mbKFi1TuA/cK/yzl639Uz9CzjHEFubySMr0=
github.com/multiversx/mx-components-big-int v1.1.0 h1:7aSJKago6vJQy9JeMOBRDYKHvsrj9OmrFWOucFUV+Kg=
github.com/multiversx/mx-components-big-int v1.1.0/go.mod h1:kcWw7hDe6cSz1wcBAqj/6sFH6ouSPsNeH9P7XlpZRcw=
+github.com/multiversx/mx-sdk-abi-go v0.3.1-0.20250423092559-f01fdd10b35d h1:1GZdV0gNxxOBQG3BhJmTn0/a57o1pv2MstFL16eXbnI=
+github.com/multiversx/mx-sdk-abi-go v0.3.1-0.20250423092559-f01fdd10b35d/go.mod h1:++ds6BB47LrXl8a9N2VGRBzHCfl6kkxRCHb31a5z61g=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
+github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
+github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
+github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
+github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
+github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
+github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
+github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
-github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
+github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg=
+github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a h1:CmF68hwI0XsOQ5UwlBopMi2Ow4Pbg32akc4KIVCOm+Y=
+github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
+github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
+github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
+github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
+github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
+github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4=
+github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
+github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs=
+github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
+github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
+github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
+github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
+github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
+github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
+github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
+github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
+github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
+github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
+github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
+github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
+github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
-golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
+golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
+golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
+golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
+golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
-golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
+golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
-google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
+google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
+gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
+gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
+rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
diff --git a/integrationTests/json/scenariosEVM_test.go b/integrationTests/json/scenariosEVM_test.go
new file mode 100644
index 000000000..33701ece8
--- /dev/null
+++ b/integrationTests/json/scenariosEVM_test.go
@@ -0,0 +1,18 @@
+package vmjsonintegrationtest
+
+import (
+ "github.com/multiversx/mx-chain-vm-go/evm"
+ "github.com/multiversx/mx-chain-vm-go/scenario"
+ "testing"
+)
+
+func TestAdderEVM(t *testing.T) {
+ ScenariosTest(t).
+ Folder("evm/adder/scenarios").
+ WithExecutorFactory(evm.ExecutorFactory()).
+ WithVMType(scenario.EVMType).
+ WithOmitFunctionNameChecks(true).
+ WithOmitDefaultCodeChanges(true).
+ Run().
+ CheckNoError()
+}
diff --git a/integrationTests/json/scenariosTestCommon.go b/integrationTests/json/scenariosTestCommon.go
index 1ec5f568f..8c5593da8 100644
--- a/integrationTests/json/scenariosTestCommon.go
+++ b/integrationTests/json/scenariosTestCommon.go
@@ -46,6 +46,9 @@ type ScenariosTestBuilder struct {
enableEpochsHandler vmcommon.EnableEpochsHandler
currentError error
overrideVMType []byte
+
+ OmitFunctionNameChecks bool
+ OmitDefaultCodeChanges bool
}
// ScenariosTest will create a new ScenariosTestBuilder instance
@@ -116,6 +119,18 @@ func (mtb *ScenariosTestBuilder) WithVMType(overrideVMType []byte) *ScenariosTes
return mtb
}
+// WithOmitFunctionNameChecks overrides the OmitFunctionNameChecks
+func (mtb *ScenariosTestBuilder) WithOmitFunctionNameChecks(omitFunctionNameChecks bool) *ScenariosTestBuilder {
+ mtb.OmitFunctionNameChecks = omitFunctionNameChecks
+ return mtb
+}
+
+// WithOmitDefaultCodeChanges overrides the OmitDefaultCodeChanges
+func (mtb *ScenariosTestBuilder) WithOmitDefaultCodeChanges(omitDefaultCodeChanges bool) *ScenariosTestBuilder {
+ mtb.OmitDefaultCodeChanges = omitDefaultCodeChanges
+ return mtb
+}
+
// Run will start the testing process
func (mtb *ScenariosTestBuilder) Run() *ScenariosTestBuilder {
if check.IfNil(mtb.executorFactory) {
@@ -123,6 +138,8 @@ func (mtb *ScenariosTestBuilder) Run() *ScenariosTestBuilder {
}
vmBuilder := vmscenario.NewScenarioVMHostBuilder()
+ vmBuilder.OmitFunctionNameChecks = mtb.OmitFunctionNameChecks
+ vmBuilder.OmitDefaultCodeChanges = mtb.OmitDefaultCodeChanges
vmBuilder.OverrideVMExecutor = mtb.executorFactory
if mtb.overrideVMType != nil {
vmBuilder.VMType = mtb.overrideVMType
diff --git a/mock/context/blockChainHookStub.go b/mock/context/blockChainHookStub.go
index 308e96142..16850a906 100644
--- a/mock/context/blockChainHookStub.go
+++ b/mock/context/blockChainHookStub.go
@@ -26,6 +26,7 @@ type BlockchainHookStub struct {
CurrentTimeStampCalled func() uint64
CurrentTimeStampMsCalled func() uint64
CurrentRandomSeedCalled func() []byte
+ ChainIDCalled func() []byte
CurrentEpochCalled func() uint32
RoundTimeCalled func() uint64
EpochStartBlockTimeStampMsCalled func() uint64
@@ -46,6 +47,8 @@ type BlockchainHookStub struct {
GetSnapshotCalled func() int
RevertToSnapshotCalled func(snapshot int) error
ExecuteSmartContractCallOnOtherVMCalled func(input *vmcommon.ContractCallInput) (*vmcommon.VMOutput, error)
+ SaveAliasAddressCalled func(request *vmcommon.AliasSaveRequest) error
+ RequestAddressCalled func(request *vmcommon.AddressRequest) (*vmcommon.AddressResponse, error)
}
// NewAddress mocked method
@@ -168,6 +171,15 @@ func (b *BlockchainHookStub) CurrentRandomSeed() []byte {
return []byte("seed")
}
+// ChainID mocked method
+func (b *BlockchainHookStub) ChainID() []byte {
+ if b.ChainIDCalled != nil {
+ return b.ChainIDCalled()
+ }
+
+ return nil
+}
+
// CurrentEpoch mocked method
func (b *BlockchainHookStub) CurrentEpoch() uint32 {
if b.CurrentEpochCalled != nil {
@@ -333,6 +345,24 @@ func (b *BlockchainHookStub) ExecuteSmartContractCallOnOtherVM(input *vmcommon.C
return nil, nil
}
+// SaveAliasAddress -
+func (b *BlockchainHookStub) SaveAliasAddress(request *vmcommon.AliasSaveRequest) error {
+ if b.SaveAliasAddressCalled != nil {
+ return b.SaveAliasAddressCalled(request)
+ }
+
+ return nil
+}
+
+// RequestAddress -
+func (b *BlockchainHookStub) RequestAddress(request *vmcommon.AddressRequest) (*vmcommon.AddressResponse, error) {
+ if b.RequestAddressCalled != nil {
+ return b.RequestAddressCalled(request)
+ }
+
+ return nil, nil
+}
+
// IsInterfaceNil mocked method
func (b *BlockchainHookStub) IsInterfaceNil() bool {
return b == nil
diff --git a/mock/context/executorMock.go b/mock/context/executorMock.go
index 41d0bdcee..14a6f0d4a 100644
--- a/mock/context/executorMock.go
+++ b/mock/context/executorMock.go
@@ -56,7 +56,7 @@ func NewExecutorMock(world *worldmock.MockWorld) *ExecutorMock {
}
// SetOpcodeCosts should set gas costs, but it does nothing in the case of this mock.
-func (executorMock *ExecutorMock) SetOpcodeCosts(_ *executor.WASMOpcodeCost) {
+func (executorMock *ExecutorMock) SetOpcodeCosts(_ executor.VMOpcodeCost) {
}
// FunctionNames mocked method
diff --git a/mock/context/instanceMock.go b/mock/context/instanceMock.go
index 912e0831b..63325111f 100644
--- a/mock/context/instanceMock.go
+++ b/mock/context/instanceMock.go
@@ -101,6 +101,11 @@ func (instance *InstanceMock) GetBreakpointValue() uint64 {
return uint64(instance.BreakpointValue)
}
+// HasCompiledCode mocked method
+func (instance *InstanceMock) HasCompiledCode() bool {
+ return true
+}
+
// Cache mocked method
func (instance *InstanceMock) Cache() ([]byte, error) {
return instance.Code, nil
diff --git a/mock/context/meteringContextMock.go b/mock/context/meteringContextMock.go
index bcbc28b3c..953090d3c 100644
--- a/mock/context/meteringContextMock.go
+++ b/mock/context/meteringContextMock.go
@@ -194,8 +194,8 @@ func (m *MeteringContextMock) DeductInitialGasForDirectDeployment(_ vmhost.CodeD
}
// DeductInitialGasForIndirectDeployment mocked method
-func (m *MeteringContextMock) DeductInitialGasForIndirectDeployment(_ vmhost.CodeDeployInput) error {
- return m.Err
+func (m *MeteringContextMock) DeductInitialGasForIndirectDeployment(_ vmhost.CodeDeployInput) (uint64, error) {
+ return 0, m.Err
}
// EnableRestoreGas mocked method
diff --git a/mock/context/outputContextMock.go b/mock/context/outputContextMock.go
index 4308d0977..1c702c01a 100644
--- a/mock/context/outputContextMock.go
+++ b/mock/context/outputContextMock.go
@@ -98,6 +98,10 @@ func (o *OutputContextMock) GetOutputAccount(_ []byte) (*vmcommon.OutputAccount,
return o.OutputAccountMock, o.OutputAccountIsNew
}
+// DeleteAccount mocked method
+func (o *OutputContextMock) DeleteAccount(_ []byte) {
+}
+
// DeleteOutputAccount mocked method
func (o *OutputContextMock) DeleteOutputAccount(_ []byte) {
}
@@ -202,6 +206,14 @@ func (o *OutputContextMock) RemoveNonUpdatedStorage() {
func (o *OutputContextMock) DeployCode(_ vmhost.CodeDeployInput) {
}
+// ChangeAccountCode mocked method
+func (o *OutputContextMock) ChangeAccountCode(_ []byte, _ []byte) {
+}
+
+// SetIsCreatedInTransactionFlag mocked method
+func (o *OutputContextMock) SetIsCreatedInTransactionFlag(_ []byte) {
+}
+
// CreateVMOutputInCaseOfError mocked method
func (o *OutputContextMock) CreateVMOutputInCaseOfError(_ error) *vmcommon.VMOutput {
return o.OutputStateMock
diff --git a/mock/context/outputContextStub.go b/mock/context/outputContextStub.go
index 69f416526..84d4e46b0 100644
--- a/mock/context/outputContextStub.go
+++ b/mock/context/outputContextStub.go
@@ -12,44 +12,47 @@ var _ vmhost.OutputContext = (*OutputContextStub)(nil)
// OutputContextStub is used in tests to check the OutputContext interface method calls
type OutputContextStub struct {
- InitStateCalled func()
- PushStateCalled func()
- PopSetActiveStateCalled func()
- PopMergeActiveStateCalled func()
- PopDiscardCalled func()
- ClearStateStackCalled func()
- CopyTopOfStackToActiveStateCalled func()
- CensorVMOutputCalled func()
- GetOutputAccountsCalled func() map[string]*vmcommon.OutputAccount
- GetOutputAccountCalled func(address []byte) (*vmcommon.OutputAccount, bool)
- DeleteOutputAccountCalled func(address []byte)
- WriteLogCalled func(address []byte, topics [][]byte, data [][]byte)
- WriteLogWithIdentifierCalled func(address []byte, topics [][]byte, data [][]byte, identifier []byte)
- TransferCalled func(destination []byte, sender []byte, gasLimit uint64, gasLocked uint64, value *big.Int, asyncData []byte, input []byte) error
- TransferESDTCalled func(transfersArgs *vmhost.ESDTTransfersArgs, input *vmcommon.ContractCallInput) (uint64, error)
- GetRefundCalled func() uint64
- SetRefundCalled func(refund uint64)
- ReturnCodeCalled func() vmcommon.ReturnCode
- SetReturnCodeCalled func(returnCode vmcommon.ReturnCode)
- ReturnMessageCalled func() string
- SetReturnMessageCalled func(message string)
- ReturnDataCalled func() [][]byte
- ClearReturnDataCalled func()
- RemoveReturnDataCalled func(index uint32)
- FinishCalled func(data []byte)
- PrependFinishCalled func(data []byte)
- DeleteFirstReturnDataCalled func()
- GetVMOutputCalled func() *vmcommon.VMOutput
- AddTxValueToAccountCalled func(address []byte, value *big.Int)
- DeployCodeCalled func(input vmhost.CodeDeployInput)
- CreateVMOutputInCaseOfErrorCalled func(err error) *vmcommon.VMOutput
- AddToActiveStateCalled func(vmOutput *vmcommon.VMOutput)
- TransferValueOnlyCalled func(destination []byte, sender []byte, value *big.Int, checkPayable bool) error
- RemoveNonUpdatedStorageCalled func()
- NextOutputTransferIndexCalled func() uint32
- GetCrtTransferIndexCalled func() uint32
- SetCrtTransferIndexCalled func(index uint32)
- IsInterfaceNilCalled func() bool
+ InitStateCalled func()
+ PushStateCalled func()
+ PopSetActiveStateCalled func()
+ PopMergeActiveStateCalled func()
+ PopDiscardCalled func()
+ ClearStateStackCalled func()
+ CopyTopOfStackToActiveStateCalled func()
+ CensorVMOutputCalled func()
+ GetOutputAccountsCalled func() map[string]*vmcommon.OutputAccount
+ GetOutputAccountCalled func(address []byte) (*vmcommon.OutputAccount, bool)
+ DeleteAccountCalled func(address []byte)
+ DeleteOutputAccountCalled func(address []byte)
+ WriteLogCalled func(address []byte, topics [][]byte, data [][]byte)
+ WriteLogWithIdentifierCalled func(address []byte, topics [][]byte, data [][]byte, identifier []byte)
+ TransferCalled func(destination []byte, sender []byte, gasLimit uint64, gasLocked uint64, value *big.Int, asyncData []byte, input []byte) error
+ TransferESDTCalled func(transfersArgs *vmhost.ESDTTransfersArgs, input *vmcommon.ContractCallInput) (uint64, error)
+ GetRefundCalled func() uint64
+ SetRefundCalled func(refund uint64)
+ ReturnCodeCalled func() vmcommon.ReturnCode
+ SetReturnCodeCalled func(returnCode vmcommon.ReturnCode)
+ ReturnMessageCalled func() string
+ SetReturnMessageCalled func(message string)
+ ReturnDataCalled func() [][]byte
+ ClearReturnDataCalled func()
+ RemoveReturnDataCalled func(index uint32)
+ FinishCalled func(data []byte)
+ PrependFinishCalled func(data []byte)
+ DeleteFirstReturnDataCalled func()
+ GetVMOutputCalled func() *vmcommon.VMOutput
+ AddTxValueToAccountCalled func(address []byte, value *big.Int)
+ DeployCodeCalled func(input vmhost.CodeDeployInput)
+ ChangeAccountCodeCalled func(address []byte, contract []byte)
+ SetIsCreatedInTransactionFlagCalled func(address []byte)
+ CreateVMOutputInCaseOfErrorCalled func(err error) *vmcommon.VMOutput
+ AddToActiveStateCalled func(vmOutput *vmcommon.VMOutput)
+ TransferValueOnlyCalled func(destination []byte, sender []byte, value *big.Int, checkPayable bool) error
+ RemoveNonUpdatedStorageCalled func()
+ NextOutputTransferIndexCalled func() uint32
+ GetCrtTransferIndexCalled func() uint32
+ SetCrtTransferIndexCalled func(index uint32)
+ IsInterfaceNilCalled func() bool
}
// AddToActiveState mocked method
@@ -131,6 +134,13 @@ func (o *OutputContextStub) GetOutputAccount(address []byte) (*vmcommon.OutputAc
return nil, false
}
+// DeleteAccount mocked method
+func (o *OutputContextStub) DeleteAccount(address []byte) {
+ if o.DeleteAccountCalled != nil {
+ o.DeleteAccountCalled(address)
+ }
+}
+
// DeleteOutputAccount mocked method
func (o *OutputContextStub) DeleteOutputAccount(address []byte) {
if o.DeleteOutputAccountCalled != nil {
@@ -295,6 +305,20 @@ func (o *OutputContextStub) DeployCode(input vmhost.CodeDeployInput) {
}
}
+// ChangeAccountCode mocked method
+func (o *OutputContextStub) ChangeAccountCode(address []byte, contract []byte) {
+ if o.ChangeAccountCodeCalled != nil {
+ o.ChangeAccountCodeCalled(address, contract)
+ }
+}
+
+// SetIsCreatedInTransactionFlag mocked method
+func (o *OutputContextStub) SetIsCreatedInTransactionFlag(address []byte) {
+ if o.SetIsCreatedInTransactionFlagCalled != nil {
+ o.SetIsCreatedInTransactionFlagCalled(address)
+ }
+}
+
// CreateVMOutputInCaseOfError mocked method
func (o *OutputContextStub) CreateVMOutputInCaseOfError(err error) *vmcommon.VMOutput {
if o.CreateVMOutputInCaseOfErrorCalled != nil {
diff --git a/mock/context/runtimeContextMock.go b/mock/context/runtimeContextMock.go
index 7f6771cc6..606839d1e 100644
--- a/mock/context/runtimeContextMock.go
+++ b/mock/context/runtimeContextMock.go
@@ -16,6 +16,7 @@ type RuntimeContextMock struct {
SCAddress []byte
SCCode []byte
SCCodeSize uint64
+ SCCodeHash []byte
CallFunction string
VMType []byte
ReadOnlyFlag bool
@@ -166,6 +167,15 @@ func (r *RuntimeContextMock) SetOriginalCallerAddress(scAddress []byte) {
r.OriginalCallerAddr = scAddress
}
+// ComputeCodeHash mocked method
+func (r *RuntimeContextMock) ComputeCodeHash([]byte) []byte {
+ return make([]byte, 0)
+}
+
+// SetTrackerCode mocked method
+func (r *RuntimeContextMock) SetTrackerCode([]byte) {
+}
+
// GetSCCode mocked method
func (r *RuntimeContextMock) GetSCCode() ([]byte, error) {
return r.SCCode, r.Err
@@ -176,6 +186,14 @@ func (r *RuntimeContextMock) GetSCCodeSize() uint64 {
return r.SCCodeSize
}
+// GetSCCodeHash mocked method
+func (r *RuntimeContextMock) GetSCCodeHash() []byte {
+ return r.SCCodeHash
+}
+
+// SaveCompiledCode mocked method
+func (r *RuntimeContextMock) SaveCompiledCode() {}
+
// FunctionName mocked method
func (r *RuntimeContextMock) FunctionName() string {
return r.CallFunction
diff --git a/mock/context/runtimeContextWrapper.go b/mock/context/runtimeContextWrapper.go
index 86c1b85cc..fdd9aa945 100644
--- a/mock/context/runtimeContextWrapper.go
+++ b/mock/context/runtimeContextWrapper.go
@@ -28,10 +28,18 @@ type RuntimeContextWrapper struct {
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
SetCodeAddressFunc func(scAddress []byte)
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
+ ComputeCodeHashFunc func(contract []byte) []byte
+ // function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
+ SetTrackerCodeFunc func(contract []byte)
+ // function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
GetSCCodeFunc func() ([]byte, error)
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
GetSCCodeSizeFunc func() uint64
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
+ GetSCCodeHashFunc func() []byte
+ // function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
+ SaveCompiledCodeFunc func()
+ // function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
GetVMTypeFunc func() []byte
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
FunctionFunc func() string
@@ -156,6 +164,14 @@ func NewRuntimeContextWrapper(inputRuntimeContext *vmhost.RuntimeContext) *Runti
runtimeWrapper.runtimeContext.SetCodeAddress(scAddress)
}
+ runtimeWrapper.ComputeCodeHashFunc = func(contract []byte) []byte {
+ return runtimeWrapper.runtimeContext.ComputeCodeHash(contract)
+ }
+
+ runtimeWrapper.SetTrackerCodeFunc = func(contract []byte) {
+ runtimeWrapper.runtimeContext.SetTrackerCode(contract)
+ }
+
runtimeWrapper.GetSCCodeFunc = func() ([]byte, error) {
return runtimeWrapper.runtimeContext.GetSCCode()
}
@@ -164,6 +180,14 @@ func NewRuntimeContextWrapper(inputRuntimeContext *vmhost.RuntimeContext) *Runti
return runtimeWrapper.runtimeContext.GetSCCodeSize()
}
+ runtimeWrapper.GetSCCodeHashFunc = func() []byte {
+ return runtimeWrapper.runtimeContext.GetSCCodeHash()
+ }
+
+ runtimeWrapper.SaveCompiledCodeFunc = func() {
+ runtimeWrapper.runtimeContext.SaveCompiledCode()
+ }
+
runtimeWrapper.GetVMTypeFunc = func() []byte {
return runtimeWrapper.runtimeContext.GetVMType()
}
@@ -339,6 +363,16 @@ func (contextWrapper *RuntimeContextWrapper) SetCodeAddress(scAddress []byte) {
contextWrapper.SetCodeAddressFunc(scAddress)
}
+// ComputeCodeHash calls corresponding xxxFunc function, that by default in turn calls the original method of the wrapped RuntimeContext
+func (contextWrapper *RuntimeContextWrapper) ComputeCodeHash(contract []byte) []byte {
+ return contextWrapper.ComputeCodeHashFunc(contract)
+}
+
+// SetTrackerCode calls corresponding xxxFunc function, that by default in turn calls the original method of the wrapped RuntimeContext
+func (contextWrapper *RuntimeContextWrapper) SetTrackerCode(contract []byte) {
+ contextWrapper.SetTrackerCodeFunc(contract)
+}
+
// GetSCCode calls corresponding xxxFunc function, that by default in turn calls the original method of the wrapped RuntimeContext
func (contextWrapper *RuntimeContextWrapper) GetSCCode() ([]byte, error) {
return contextWrapper.GetSCCodeFunc()
@@ -349,6 +383,16 @@ func (contextWrapper *RuntimeContextWrapper) GetSCCodeSize() uint64 {
return contextWrapper.GetSCCodeSizeFunc()
}
+// GetSCCodeHash calls corresponding xxxFunc function, that by default in turn calls the original method of the wrapped RuntimeContext
+func (contextWrapper *RuntimeContextWrapper) GetSCCodeHash() []byte {
+ return contextWrapper.GetSCCodeHashFunc()
+}
+
+// SaveCompiledCode calls corresponding xxxFunc function, that by default in turn calls the original method of the wrapped RuntimeContext
+func (contextWrapper *RuntimeContextWrapper) SaveCompiledCode() {
+ contextWrapper.SaveCompiledCodeFunc()
+}
+
// GetVMType calls corresponding xxxFunc function, that by default in turn calls the original method of the wrapped RuntimeContext
func (contextWrapper *RuntimeContextWrapper) GetVMType() []byte {
return contextWrapper.GetVMTypeFunc()
diff --git a/mock/context/vmHostMock.go b/mock/context/vmHostMock.go
index 34ef0346f..8b7391f48 100644
--- a/mock/context/vmHostMock.go
+++ b/mock/context/vmHostMock.go
@@ -118,7 +118,7 @@ func (host *VMHostMock) CreateNewContract(_ *vmcommon.ContractCreateInput, _ int
}
// ExecuteOnSameContext mocked method
-func (host *VMHostMock) ExecuteOnSameContext(_ *vmcommon.ContractCallInput) error {
+func (host *VMHostMock) ExecuteOnSameContext(_ *vmcommon.ContractSameContextCallInput) error {
return nil
}
@@ -147,6 +147,11 @@ func (host *VMHostMock) PopState() {
func (host *VMHostMock) ClearStateStack() {
}
+// IsOutOfVMFunctionExecution mocked method
+func (host *VMHostMock) IsOutOfVMFunctionExecution(_ *vmcommon.ContractCallInput) bool {
+ return false
+}
+
// IsBuiltinFunctionName mocked method
func (host *VMHostMock) IsBuiltinFunctionName(_ string) bool {
return host.IsBuiltinFunc
diff --git a/mock/context/vmHostStub.go b/mock/context/vmHostStub.go
index 0ef8339bb..e31a6ab94 100644
--- a/mock/context/vmHostStub.go
+++ b/mock/context/vmHostStub.go
@@ -29,14 +29,15 @@ type VMHostStub struct {
GetContextsCalled func() (vmhost.ManagedTypesContext, vmhost.BlockchainContext, vmhost.MeteringContext, vmhost.OutputContext, vmhost.RuntimeContext, vmhost.AsyncContext, vmhost.StorageContext)
ManagedTypesCalled func() vmhost.ManagedTypesContext
- ExecuteESDTTransferCalled func(transfersArgs *vmhost.ESDTTransfersArgs, callType vm.CallType) (*vmcommon.VMOutput, uint64, error)
- CreateNewContractCalled func(input *vmcommon.ContractCreateInput, createContractCallType int) ([]byte, error)
- ExecuteOnSameContextCalled func(input *vmcommon.ContractCallInput) error
- ExecuteOnDestContextCalled func(input *vmcommon.ContractCallInput) (*vmcommon.VMOutput, bool, error)
- IsBuiltinFunctionNameCalled func(functionName string) bool
- IsBuiltinFunctionCallCalled func(data []byte) bool
- AreInSameShardCalled func(left []byte, right []byte) bool
- IsAllowedToExecuteCalled func(opcode string) bool
+ ExecuteESDTTransferCalled func(transfersArgs *vmhost.ESDTTransfersArgs, callType vm.CallType) (*vmcommon.VMOutput, uint64, error)
+ CreateNewContractCalled func(input *vmcommon.ContractCreateInput, createContractCallType int) ([]byte, error)
+ ExecuteOnSameContextCalled func(input *vmcommon.ContractSameContextCallInput) error
+ ExecuteOnDestContextCalled func(input *vmcommon.ContractCallInput) (*vmcommon.VMOutput, bool, error)
+ IsOutOfVMFunctionExecutionCalled func(input *vmcommon.ContractCallInput) bool
+ IsBuiltinFunctionNameCalled func(functionName string) bool
+ IsBuiltinFunctionCallCalled func(data []byte) bool
+ AreInSameShardCalled func(left []byte, right []byte) bool
+ IsAllowedToExecuteCalled func(opcode string) bool
RunSmartContractCallCalled func(input *vmcommon.ContractCallInput) (vmOutput *vmcommon.VMOutput, err error)
RunSmartContractCreateCalled func(input *vmcommon.ContractCreateInput) (vmOutput *vmcommon.VMOutput, err error)
@@ -193,7 +194,7 @@ func (vhs *VMHostStub) CreateNewContract(input *vmcommon.ContractCreateInput, cr
}
// ExecuteOnSameContext mocked method
-func (vhs *VMHostStub) ExecuteOnSameContext(input *vmcommon.ContractCallInput) error {
+func (vhs *VMHostStub) ExecuteOnSameContext(input *vmcommon.ContractSameContextCallInput) error {
if vhs.ExecuteOnSameContextCalled != nil {
return vhs.ExecuteOnSameContextCalled(input)
}
@@ -224,6 +225,14 @@ func (vhs *VMHostStub) IsAllowedToExecute(opcode string) bool {
return true
}
+// IsOutOfVMFunctionExecution mocked method
+func (vhs *VMHostStub) IsOutOfVMFunctionExecution(input *vmcommon.ContractCallInput) bool {
+ if vhs.IsOutOfVMFunctionExecutionCalled != nil {
+ return vhs.IsOutOfVMFunctionExecutionCalled(input)
+ }
+ return false
+}
+
// IsBuiltinFunctionName mocked method
func (vhs *VMHostStub) IsBuiltinFunctionName(functionName string) bool {
if vhs.IsBuiltinFunctionNameCalled != nil {
diff --git a/scenario/gasSchedules/gasScheduleEmbedGenerated.go b/scenario/gasSchedules/gasScheduleEmbedGenerated.go
index 816a12ebf..a0a8c85f4 100644
--- a/scenario/gasSchedules/gasScheduleEmbedGenerated.go
+++ b/scenario/gasSchedules/gasScheduleEmbedGenerated.go
@@ -284,6 +284,49 @@ const (
ManagedMapRemove = 10000
ManagedMapContains = 10000
+[EVMOpcodeCost]
+ QuickStep = 2
+ FastestStep = 3
+ FastStep = 5
+ MidStep = 8
+ SlowStep = 10
+ ExtStep = 10000
+ Ecrecover = 3000
+ Sha256PerWord = 1000
+ Sha256Base = 1000000
+ Ripemd160PerWord = 1000
+ Ripemd160Base = 1000000
+ IdentityPerWord = 3
+ IdentityBase = 15
+ Bn256Add = 150
+ Bn256ScalarMul = 6000
+ Bn256PairingBase = 45000
+ Bn256PairingPerPoint = 34000
+ BlobTxPointEvaluation = 50000
+ Keccak256 = 1000000
+ Balance = 7000
+ ExtcodeSize = 2500
+ ExtcodeCopy = 3000
+ ExtcodeHash = 2500
+ Sload = 1
+ Sstore = 250000
+ Jumpdest = 1
+ Tload = 100
+ Tstore = 100
+ Create = 300000
+ Call = 160000
+ Create2 = 300000
+ Selfdestruct = 5000000
+ Memory = 3
+ Copy = 3
+ Log = 3750
+ LogTopic = 320000
+ LogData = 10000
+ Keccak256Word = 1000
+ InitCodeWord = 1000
+ ExpByte = 50
+ Exp = 10
+
[WASMOpcodeCost]
AtomicFence = 10
AtomicNotify = 10
@@ -1132,6 +1175,49 @@ const (
ManagedMapRemove = 10000
ManagedMapContains = 10000
+[EVMOpcodeCost]
+ QuickStep = 2
+ FastestStep = 3
+ FastStep = 5
+ MidStep = 8
+ SlowStep = 10
+ ExtStep = 10000
+ Ecrecover = 3000
+ Sha256PerWord = 100
+ Sha256Base = 1000000
+ Ripemd160PerWord = 100
+ Ripemd160Base = 1000000
+ IdentityPerWord = 3
+ IdentityBase = 15
+ Bn256Add = 150
+ Bn256ScalarMul = 6000
+ Bn256PairingBase = 45000
+ Bn256PairingPerPoint = 34000
+ BlobTxPointEvaluation = 50000
+ Keccak256 = 1000000
+ Balance = 7000
+ ExtcodeSize = 2500
+ ExtcodeCopy = 3000
+ ExtcodeHash = 2500
+ Sload = 1
+ Sstore = 75000
+ Jumpdest = 1
+ Tload = 100
+ Tstore = 100
+ Create = 300000
+ Call = 100000
+ Create2 = 300000
+ Selfdestruct = 5000000
+ Memory = 3
+ Copy = 3
+ Log = 3750
+ LogTopic = 32000
+ LogData = 1000
+ Keccak256Word = 100
+ InitCodeWord = 100
+ ExpByte = 50
+ Exp = 10
+
[WASMOpcodeCost]
AtomicFence = 10
AtomicNotify = 10
diff --git a/scenario/gasSchedules/gasScheduleV3.toml b/scenario/gasSchedules/gasScheduleV3.toml
index 12b246604..aeaa181a2 100644
--- a/scenario/gasSchedules/gasScheduleV3.toml
+++ b/scenario/gasSchedules/gasScheduleV3.toml
@@ -272,6 +272,49 @@
ManagedMapRemove = 10000
ManagedMapContains = 10000
+[EVMOpcodeCost]
+ QuickStep = 2
+ FastestStep = 3
+ FastStep = 5
+ MidStep = 8
+ SlowStep = 10
+ ExtStep = 10000
+ Ecrecover = 3000
+ Sha256PerWord = 12
+ Sha256Base = 60
+ Ripemd160PerWord = 120
+ Ripemd160Base = 600
+ IdentityPerWord = 3
+ IdentityBase = 15
+ Bn256Add = 150
+ Bn256ScalarMul = 6000
+ Bn256PairingBase = 45000
+ Bn256PairingPerPoint = 34000
+ BlobTxPointEvaluation = 50000
+ Keccak256 = 30
+ Balance = 7000
+ ExtcodeSize = 7000
+ ExtcodeCopy = 7000
+ ExtcodeHash = 7000
+ Sload = 100000
+ Sstore = 250000
+ Jumpdest = 1
+ Tload = 100
+ Tstore = 100
+ Create = 300000
+ Call = 160000
+ Create2 = 300000
+ Selfdestruct = 150000
+ Memory = 3
+ Copy = 3
+ Log = 3750
+ LogTopic = 320000
+ LogData = 10000
+ Keccak256Word = 6
+ InitCodeWord = 2
+ ExpByte = 50
+ Exp = 10
+
[WASMOpcodeCost]
AtomicFence = 10
AtomicNotify = 10
diff --git a/scenario/gasSchedules/gasScheduleV4.toml b/scenario/gasSchedules/gasScheduleV4.toml
index 4d10c167a..fd1736032 100644
--- a/scenario/gasSchedules/gasScheduleV4.toml
+++ b/scenario/gasSchedules/gasScheduleV4.toml
@@ -274,6 +274,49 @@
ManagedMapRemove = 10000
ManagedMapContains = 10000
+[EVMOpcodeCost]
+ QuickStep = 2
+ FastestStep = 3
+ FastStep = 5
+ MidStep = 8
+ SlowStep = 10
+ ExtStep = 10000
+ Ecrecover = 3000
+ Sha256PerWord = 12
+ Sha256Base = 60
+ Ripemd160PerWord = 120
+ Ripemd160Base = 600
+ IdentityPerWord = 3
+ IdentityBase = 15
+ Bn256Add = 150
+ Bn256ScalarMul = 6000
+ Bn256PairingBase = 45000
+ Bn256PairingPerPoint = 34000
+ BlobTxPointEvaluation = 50000
+ Keccak256 = 30
+ Balance = 7000
+ ExtcodeSize = 7000
+ ExtcodeCopy = 7000
+ ExtcodeHash = 7000
+ Sload = 50000
+ Sstore = 75000
+ Jumpdest = 1
+ Tload = 100
+ Tstore = 100
+ Create = 300000
+ Call = 100000
+ Create2 = 300000
+ Selfdestruct = 100000
+ Memory = 3
+ Copy = 3
+ Log = 3750
+ LogTopic = 32000
+ LogData = 1000
+ Keccak256Word = 6
+ InitCodeWord = 2
+ ExpByte = 50
+ Exp = 10
+
[WASMOpcodeCost]
AtomicFence = 10
AtomicNotify = 10
diff --git a/scenario/vmBuilder.go b/scenario/vmBuilder.go
index 47f896851..8d96fcc7a 100644
--- a/scenario/vmBuilder.go
+++ b/scenario/vmBuilder.go
@@ -21,6 +21,9 @@ var _ scenexec.VMBuilder = (*ScenarioVMHostBuilder)(nil)
// DefaultVMType is the VM type argument we use in tests.
var DefaultVMType = []byte{5, 0}
+// EVMType is the VM type argument we use in tests for EVM.
+var EVMType = []byte{6, 0}
+
// DefaultTimeOutForSCExecutionInMilliseconds is the mainnet timeout.
var DefaultTimeOutForSCExecutionInMilliseconds uint32 = 10000
@@ -29,6 +32,9 @@ type ScenarioVMHostBuilder struct {
OverrideVMExecutor executor.ExecutorAbstractFactory
VMType []byte
TimeOutForSCExecutionInMilliseconds uint32
+
+ OmitFunctionNameChecks bool
+ OmitDefaultCodeChanges bool
}
// NewScenarioVMHostBuilder creates a default ScenarioVMHostBuilder.
@@ -83,19 +89,21 @@ func (svb *ScenarioVMHostBuilder) NewVM(
return hostCore.NewVMHost(
world,
&vmhost.VMHostParameters{
- VMType: svb.VMType,
- OverrideVMExecutor: svb.OverrideVMExecutor,
- BlockGasLimit: blockGasLimit,
- GasSchedule: gasSchedule,
- BuiltInFuncContainer: world.BuiltinFuncs.Container,
- ProtectedKeyPrefix: []byte(core.ProtectedKeyPrefix),
- ESDTTransferParser: esdtTransferParser,
- EpochNotifier: &mock.EpochNotifierStub{},
- EnableEpochsHandler: world.EnableEpochsHandler,
- WasmerSIGSEGVPassthrough: false,
- Hasher: worldmock.DefaultHasher,
- MapOpcodeAddressIsAllowed: map[string]map[string]struct{}{},
+ VMType: svb.VMType,
+ OverrideVMExecutor: svb.OverrideVMExecutor,
+ BlockGasLimit: blockGasLimit,
+ GasSchedule: gasSchedule,
+ BuiltInFuncContainer: world.BuiltinFuncs.Container,
+ ProtectedKeyPrefix: []byte(core.ProtectedKeyPrefix),
+ ESDTTransferParser: esdtTransferParser,
+ EpochNotifier: &mock.EpochNotifierStub{},
+ EnableEpochsHandler: world.EnableEpochsHandler,
+ WasmerSIGSEGVPassthrough: false,
+ Hasher: worldmock.DefaultHasher,
+ MapOpcodeAddressIsAllowed: map[string]map[string]struct{}{},
TimeOutForSCExecutionInMilliseconds: svb.TimeOutForSCExecutionInMilliseconds,
+ OmitFunctionNameChecks: svb.OmitFunctionNameChecks,
+ OmitDefaultCodeChanges: svb.OmitDefaultCodeChanges,
})
}
diff --git a/test/evm/adder/output/adder-compiled.mxsc.json b/test/evm/adder/output/adder-compiled.mxsc.json
new file mode 100644
index 000000000..9ba61a616
--- /dev/null
+++ b/test/evm/adder/output/adder-compiled.mxsc.json
@@ -0,0 +1,4 @@
+{
+ "size": 496,
+ "code": "608060405260043610610033575f3560e01c80631003e2d21461003757806345977d0314610053578063569c5f6d1461007b575b5f80fd5b610051600480360381019061004c9190610107565b6100a5565b005b34801561005e575f80fd5b5061007960048036038101906100749190610107565b6100bf565b005b348015610086575f80fd5b5061008f6100c8565b60405161009c9190610141565b60405180910390f35b805f808282546100b59190610187565b9250508190555050565b805f8190555050565b5f8054905090565b5f80fd5b5f819050919050565b6100e6816100d4565b81146100f0575f80fd5b50565b5f81359050610101816100dd565b92915050565b5f6020828403121561011c5761011b6100d0565b5b5f610129848285016100f3565b91505092915050565b61013b816100d4565b82525050565b5f6020820190506101545f830184610132565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610191826100d4565b915061019c836100d4565b92508282019050808211156101b4576101b361015a565b5b9291505056fea264697066735822122039af286dd81ddc6e16a3a4a39cd57ff0fa1a9b3398dc7fc6328fc12726282daf64736f6c63430008180033"
+}
diff --git a/test/evm/adder/output/adder.mxsc.json b/test/evm/adder/output/adder.mxsc.json
new file mode 100644
index 000000000..dd1f76d4d
--- /dev/null
+++ b/test/evm/adder/output/adder.mxsc.json
@@ -0,0 +1,4 @@
+{
+ "size": 700,
+ "code": "608060405234801561000f575f80fd5b5060405161029c38038061029c83398181016040528101906100319190610074565b805f819055505061009f565b5f80fd5b5f819050919050565b61005381610041565b811461005d575f80fd5b50565b5f8151905061006e8161004a565b92915050565b5f602082840312156100895761008861003d565b5b5f61009684828501610060565b91505092915050565b6101f0806100ac5f395ff3fe608060405260043610610033575f3560e01c80631003e2d21461003757806345977d0314610053578063569c5f6d1461007b575b5f80fd5b610051600480360381019061004c9190610107565b6100a5565b005b34801561005e575f80fd5b5061007960048036038101906100749190610107565b6100bf565b005b348015610086575f80fd5b5061008f6100c8565b60405161009c9190610141565b60405180910390f35b805f808282546100b59190610187565b9250508190555050565b805f8190555050565b5f8054905090565b5f80fd5b5f819050919050565b6100e6816100d4565b81146100f0575f80fd5b50565b5f81359050610101816100dd565b92915050565b5f6020828403121561011c5761011b6100d0565b5b5f610129848285016100f3565b91505092915050565b61013b816100d4565b82525050565b5f6020820190506101545f830184610132565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610191826100d4565b915061019c836100d4565b92508282019050808211156101b4576101b361015a565b5b9291505056fea264697066735822122039af286dd81ddc6e16a3a4a39cd57ff0fa1a9b3398dc7fc6328fc12726282daf64736f6c634300081800330000000000000000000000000000000000000000000000000000000000000005"
+}
diff --git a/test/evm/adder/scenarios/adder.scen.json b/test/evm/adder/scenarios/adder.scen.json
new file mode 100644
index 000000000..a118e84fe
--- /dev/null
+++ b/test/evm/adder/scenarios/adder.scen.json
@@ -0,0 +1,105 @@
+{
+ "name": "adder",
+ "comment": "add then check",
+ "gasSchedule": "v3",
+ "steps": [
+ {
+ "step": "setState",
+ "accounts": {
+ "address:owner": {
+ "nonce": "1",
+ "balance": "5,000,000"
+ }
+ },
+ "newAddresses": [
+ {
+ "creatorAddress": "address:owner",
+ "creatorNonce": "1",
+ "newAddress": "sc:adder"
+ }
+ ],
+ "currentBlockInfo": {
+ "blockTimestamp": "1",
+ "blockNonce": "1",
+ "blockRound": "1",
+ "blockEpoch": "1",
+ "blockRandomSeed": "0x42BA9AE77C08604DD7EB9D209488B88DD5A301D9C9F3D4A6B4B40E95AA6F4A1E20519698D3F774052F475B6877449CF3"
+ }
+ },
+ {
+ "step": "scDeploy",
+ "id": "1",
+ "tx": {
+ "from": "address:owner",
+ "contractCode": "mxsc:../output/adder.mxsc.json",
+ "arguments": [],
+ "gasLimit": "5,000,000",
+ "gasPrice": "1"
+ },
+ "expect": {
+ "out": "*",
+ "status": "",
+ "logs": "*",
+ "gas": "*",
+ "refund": "*"
+ }
+ },
+ {
+ "step": "scQuery",
+ "id": "2",
+ "tx": {
+ "to": "sc:adder",
+ "function": "569c5f6d",
+ "arguments": []
+ },
+ "expect": {
+ "out": [
+ "0x0000000000000000000000000000000000000000000000000000000000000005"
+ ],
+ "status": "",
+ "logs": []
+ }
+ },
+ {
+ "step": "scCall",
+ "id": "3",
+ "tx": {
+ "from": "address:owner",
+ "to": "sc:adder",
+ "function": "1003e2d2",
+ "arguments": [
+ "0x0000000000000000000000000000000000000000000000000000000000000003"
+ ],
+ "gasLimit": "5,000,000",
+ "gasPrice": "0"
+ },
+ "expect": {
+ "out": [],
+ "status": "",
+ "logs": "*",
+ "gas": "*",
+ "refund": "*"
+ }
+ },
+ {
+ "step": "checkState",
+ "accounts": {
+ "address:owner": {
+ "nonce": "*",
+ "balance": "0",
+ "storage": {},
+ "code": ""
+ },
+ "sc:adder": {
+ "nonce": "0",
+ "balance": "0",
+ "storage": {
+ "0x0000000000000000000000000000000000000000000000000000000000000000": "0x08"
+ },
+ "code": "mxsc:../output/adder-compiled.mxsc.json"
+ },
+ "+": {}
+ }
+ }
+ ]
+}
diff --git a/test/features/composability/scenarios/forw_raw_init_sync_accept_egld.scen.json b/test/features/composability/scenarios/forw_raw_init_sync_accept_egld.scen.json
index c9cd3868a..17d86ca05 100644
--- a/test/features/composability/scenarios/forw_raw_init_sync_accept_egld.scen.json
+++ b/test/features/composability/scenarios/forw_raw_init_sync_accept_egld.scen.json
@@ -37,8 +37,7 @@
},
"expect": {
"out": [],
- "status": "10",
- "message": "str:failed transfer (insufficient funds)",
+ "status": "*",
"logs": "*",
"gas": "*",
"refund": "*"
diff --git a/vmhost/common.go b/vmhost/common.go
index e38c7bd02..c2710477f 100644
--- a/vmhost/common.go
+++ b/vmhost/common.go
@@ -193,6 +193,8 @@ type CodeDeployInput struct {
ContractCodeMetadata []byte
ContractAddress []byte
CodeDeployerAddress []byte
+
+ OmitDefaultCodeChanges bool
}
// VMHostParameters represents the parameters to be passed to VMHost
@@ -210,6 +212,9 @@ type VMHostParameters struct {
Hasher HashComputer
TimeOutForSCExecutionInMilliseconds uint32
MapOpcodeAddressIsAllowed map[string]map[string]struct{}
+ UsePseudoAddresses bool
+ OmitFunctionNameChecks bool
+ OmitDefaultCodeChanges bool
}
// AsyncCallInfo contains the information required to handle the asynchronous call of another SmartContract
diff --git a/vmhost/contexts/async_test.go b/vmhost/contexts/async_test.go
index 579693bdc..737194873 100644
--- a/vmhost/contexts/async_test.go
+++ b/vmhost/contexts/async_test.go
@@ -2,16 +2,19 @@ package contexts
import (
"errors"
- "github.com/multiversx/mx-chain-vm-go/wasmer2"
"math/big"
"testing"
+ "github.com/multiversx/mx-chain-vm-go/wasmer2"
+
"github.com/multiversx/mx-chain-core-go/data/vm"
"github.com/multiversx/mx-chain-core-go/marshal"
"github.com/multiversx/mx-chain-scenario-go/worldmock"
vmcommon "github.com/multiversx/mx-chain-vm-common-go"
"github.com/multiversx/mx-chain-vm-common-go/builtInFunctions"
"github.com/multiversx/mx-chain-vm-common-go/parsers"
+ "github.com/stretchr/testify/require"
+
"github.com/multiversx/mx-chain-vm-go/config"
"github.com/multiversx/mx-chain-vm-go/crypto/factory"
"github.com/multiversx/mx-chain-vm-go/executor"
@@ -19,7 +22,6 @@ import (
"github.com/multiversx/mx-chain-vm-go/testcommon/testexecutor"
"github.com/multiversx/mx-chain-vm-go/vmhost"
"github.com/multiversx/mx-chain-vm-go/vmhost/vmhooks"
- "github.com/stretchr/testify/require"
)
var mockWasmerInstance *contextmock.InstanceMock
@@ -59,7 +61,8 @@ func initializeVMAndWasmerAsyncContextWithBuiltIn(tb testing.TB, isBuiltinFunc b
gasCostConfig, err := config.CreateGasConfig(gasSchedule)
require.Nil(tb, err)
wasmerExecutor, _ := wasmer2.CreateExecutor()
- wasmerExecutor.SetOpcodeCosts(gasCostConfig.WASMOpcodeCost)
+ opcodeCosts := executor.VMOpcodeCost{EVMOpcodeCost: gasCostConfig.EVMOpcodeCost, WASMOpcodeCost: gasCostConfig.WASMOpcodeCost}
+ wasmerExecutor.SetOpcodeCosts(opcodeCosts)
host := &contextmock.VMHostMock{
EnableEpochsHandlerField: &worldmock.EnableEpochsHandlerStub{},
@@ -70,14 +73,14 @@ func initializeVMAndWasmerAsyncContextWithBuiltIn(tb testing.TB, isBuiltinFunc b
host.MeteringContext = mockMetering
world := worldmock.NewMockWorld()
- host.BlockchainContext, err = NewBlockchainContext(host, world)
+ host.BlockchainContext, err = NewBlockchainContext(host, world, false)
require.Nil(tb, err)
mockWasmerInstance = contextmock.NewInstanceMock(nil)
execFactory := testexecutor.NewDefaultTestExecutorFactory(tb)
exec, err := execFactory.CreateExecutor(executor.ExecutorFactoryArgs{
VMHooks: vmhooks.NewVMHooksImpl(host),
- OpcodeCosts: gasCostConfig.WASMOpcodeCost,
+ OpcodeCosts: executor.VMOpcodeCost{EVMOpcodeCost: gasCostConfig.EVMOpcodeCost, WASMOpcodeCost: gasCostConfig.WASMOpcodeCost},
})
require.Nil(tb, err)
runtimeCtx, err := NewRuntimeContext(
@@ -86,6 +89,7 @@ func initializeVMAndWasmerAsyncContextWithBuiltIn(tb testing.TB, isBuiltinFunc b
builtInFunctions.NewBuiltInFunctionContainer(),
exec,
defaultHasher,
+ false,
)
require.Nil(tb, err)
diff --git a/vmhost/contexts/blockchain.go b/vmhost/contexts/blockchain.go
index 680e2a791..792b50abe 100644
--- a/vmhost/contexts/blockchain.go
+++ b/vmhost/contexts/blockchain.go
@@ -1,6 +1,8 @@
package contexts
import (
+ "github.com/multiversx/mx-chain-core-go/core"
+ "github.com/multiversx/mx-chain-crypto-go/address"
"math/big"
"github.com/multiversx/mx-chain-vm-go/vmhost/vmhooks"
@@ -18,12 +20,15 @@ type blockchainContext struct {
host vmhost.VMHost
blockChainHook vmcommon.BlockchainHook
stateStack []int
+
+ usePseudoAddresses bool
}
// NewBlockchainContext creates a new blockchainContext
func NewBlockchainContext(
host vmhost.VMHost,
blockChainHook vmcommon.BlockchainHook,
+ usePseudoAddresses bool,
) (*blockchainContext, error) {
if check.IfNil(host) {
return nil, vmhost.ErrNilVMHost
@@ -32,16 +37,18 @@ func NewBlockchainContext(
context := &blockchainContext{
blockChainHook: blockChainHook,
host: host,
+
+ usePseudoAddresses: usePseudoAddresses,
}
return context, nil
}
-// NewAddress returns a new address created using the provided creator address and its nonce.
-func (context *blockchainContext) NewAddress(creatorAddress []byte) ([]byte, error) {
+// GetNonceForNewAddress returns the nonce for the provided creator address.
+func (context *blockchainContext) GetNonceForNewAddress(creatorAddress []byte) (uint64, error) {
nonce, err := context.GetNonce(creatorAddress)
if err != nil {
- return nil, err
+ return 0, err
}
isIndirectDeployment := context.IsSmartContract(creatorAddress)
@@ -49,8 +56,26 @@ func (context *blockchainContext) NewAddress(creatorAddress []byte) ([]byte, err
nonce--
}
+ return nonce, nil
+}
+
+// NewAddress returns a new address created using the provided creator address and its nonce.
+func (context *blockchainContext) NewAddress(creatorAddress []byte) ([]byte, error) {
+ nonce, err := context.GetNonceForNewAddress(creatorAddress)
+ if err != nil {
+ return nil, err
+ }
+
vmType := context.host.Runtime().GetVMType()
- return context.blockChainHook.NewAddress(creatorAddress, nonce, vmType)
+ newAddress, err := context.blockChainHook.NewAddress(creatorAddress, nonce, vmType)
+ if err != nil {
+ return nil, err
+ }
+
+ if !context.usePseudoAddresses {
+ return newAddress, nil
+ }
+ return address.ConvertAddressToPseudoAddress(newAddress, core.MVXAddressIdentifier)
}
// AccountExists verifies if the provided address exists.
@@ -79,7 +104,7 @@ func (context *blockchainContext) GetBalanceBigInt(address []byte) *big.Int {
if outputAccount.Balance == nil || isBarnardActive {
account, err := context.blockChainHook.GetUserAccount(address)
if err != nil || vmhost.IfNil(account) {
- return big.NewInt(0)
+ return outputAccount.BalanceDelta
}
outputAccount.Balance = account.GetBalance()
@@ -104,7 +129,7 @@ func (context *blockchainContext) GetBalanceBigInt(address []byte) *big.Int {
func (context *blockchainContext) GetNonce(address []byte) (uint64, error) {
outputAccount, isNew := context.host.Output().GetOutputAccount(address)
- readNonceFromBlockChain := isNew || outputAccount.Nonce == 0
+ readNonceFromBlockChain := isNew || (outputAccount.Nonce == 0 && !outputAccount.IsContractCreatedInTransaction)
if !readNonceFromBlockChain {
return outputAccount.Nonce, nil
}
@@ -134,6 +159,12 @@ func (context *blockchainContext) GetESDTToken(address []byte, tokenID []byte, n
// GetCodeHash retrieves the hash of the code stored under the given address.
func (context *blockchainContext) GetCodeHash(address []byte) []byte {
+ outputAccount, isNew := context.host.Output().GetOutputAccount(address)
+ hasCodeHash := !isNew && len(outputAccount.CodeHash) > 0
+ if hasCodeHash {
+ return outputAccount.CodeHash
+ }
+
account, err := context.blockChainHook.GetUserAccount(address)
if err != nil {
return nil
@@ -143,6 +174,7 @@ func (context *blockchainContext) GetCodeHash(address []byte) []byte {
}
codeHash := account.GetCodeHash()
+ outputAccount.CodeHash = codeHash
return codeHash
}
@@ -194,6 +226,11 @@ func (context *blockchainContext) BlockHash(number uint64) []byte {
return block
}
+// ChainID returns the chain ID.
+func (context *blockchainContext) ChainID() []byte {
+ return context.blockChainHook.ChainID()
+}
+
// CurrentEpoch returns the number of the current epoch.
func (context *blockchainContext) CurrentEpoch() uint32 {
return context.blockChainHook.CurrentEpoch()
@@ -398,3 +435,13 @@ func (context *blockchainContext) ClearCompiledCodes() {
func (context *blockchainContext) ExecuteSmartContractCallOnOtherVM(input *vmcommon.ContractCallInput) (*vmcommon.VMOutput, error) {
return context.blockChainHook.ExecuteSmartContractCallOnOtherVM(input)
}
+
+// SaveAliasAddress saves the given alias address
+func (context *blockchainContext) SaveAliasAddress(request *vmcommon.AliasSaveRequest) error {
+ return context.blockChainHook.SaveAliasAddress(request)
+}
+
+// RequestAddress returns the requested address
+func (context *blockchainContext) RequestAddress(request *vmcommon.AddressRequest) (*vmcommon.AddressResponse, error) {
+ return context.blockChainHook.RequestAddress(request)
+}
diff --git a/vmhost/contexts/blockchain_test.go b/vmhost/contexts/blockchain_test.go
index 18314f674..442708703 100644
--- a/vmhost/contexts/blockchain_test.go
+++ b/vmhost/contexts/blockchain_test.go
@@ -7,9 +7,10 @@ import (
"github.com/multiversx/mx-chain-scenario-go/worldmock"
vmcommon "github.com/multiversx/mx-chain-vm-common-go"
+ "github.com/stretchr/testify/require"
+
contextmock "github.com/multiversx/mx-chain-vm-go/mock/context"
"github.com/multiversx/mx-chain-vm-go/vmhost"
- "github.com/stretchr/testify/require"
)
var errTestError = errors.New("some test error")
@@ -29,7 +30,7 @@ func TestNewBlockchainContext(t *testing.T) {
host := &contextmock.VMHostStub{}
mockWorld := worldmock.NewMockWorld()
- blockchainContext, err := NewBlockchainContext(host, mockWorld)
+ blockchainContext, err := NewBlockchainContext(host, mockWorld, false)
require.Nil(t, err)
require.NotNil(t, blockchainContext)
}
@@ -41,7 +42,7 @@ func TestBlockchainContext_AccountExists(t *testing.T) {
mockWorld := worldmock.NewMockWorld()
mockWorld.AcctMap.PutAccounts(testAccounts)
- blockchainContext, _ := NewBlockchainContext(host, mockWorld)
+ blockchainContext, _ := NewBlockchainContext(host, mockWorld, false)
require.False(t, blockchainContext.AccountExists([]byte("account_missing")))
require.False(t, blockchainContext.AccountExists([]byte("account_faulty")))
@@ -61,7 +62,7 @@ func TestBlockchainContext_GetBalance(t *testing.T) {
EnableEpochsHandlerField: &worldmock.EnableEpochsHandlerStub{},
}
host.OutputContext = mockOutput
- blockchainContext, _ := NewBlockchainContext(host, mockWorld)
+ blockchainContext, _ := NewBlockchainContext(host, mockWorld, false)
// Act as if the OutputContext has no OutputAccounts cached
// (mockOutput.GetOutputAccount() always returns "is new")
@@ -113,7 +114,7 @@ func TestBlockchainContext_GetBalance_Updates(t *testing.T) {
EnableEpochsHandlerField: &worldmock.EnableEpochsHandlerStub{},
}
host.OutputContext = mockOutput
- blockchainContext, _ := NewBlockchainContext(host, mockWorld)
+ blockchainContext, _ := NewBlockchainContext(host, mockWorld, false)
// Act as if the OutputContext has no OutputAccounts cached
// (mockOutput.GetOutputAccount() always returns "is new")
@@ -148,7 +149,7 @@ func TestBlockchainContext_GetNonceAndIncrease(t *testing.T) {
mockWorld := worldmock.NewMockWorld()
mockWorld.AcctMap.PutAccounts(testAccounts)
- blockchainContext, _ := NewBlockchainContext(host, mockWorld)
+ blockchainContext, _ := NewBlockchainContext(host, mockWorld, false)
// GetNonce: Test if error is propagated from BlockchainHook, and that the
// cached OutputAccount doesn't lose its Nonce due to the error.
@@ -203,7 +204,7 @@ func TestBlockchainContext_GetCodeHashAndSize(t *testing.T) {
host.CryptoHook = mockCrypto
host.OutputContext = outputContext
- blockchainContext, _ := NewBlockchainContext(host, mockWorld)
+ blockchainContext, _ := NewBlockchainContext(host, mockWorld, false)
address := []byte("account_with_code")
expectedCode := []byte("somecode")
@@ -275,7 +276,7 @@ func TestBlockchainContext_NewAddress(t *testing.T) {
}
// Test error propagation from GetNonce()
- blockchainContext, _ := NewBlockchainContext(host, mockWorld)
+ blockchainContext, _ := NewBlockchainContext(host, mockWorld, false)
creatorAddress := []byte("account_new")
creatorAccount := mockWorld.AcctMap.GetAccount(creatorAddress)
creatorOutputAccount := mockOutput.NewVMOutputAccountFromMockAccount(creatorAccount)
@@ -306,7 +307,7 @@ func TestBlockchainContext_NewAddress(t *testing.T) {
return []byte("new_address"), nil
},
}
- blockchainContext, _ = NewBlockchainContext(host, stubBlockchain)
+ blockchainContext, _ = NewBlockchainContext(host, stubBlockchain, false)
address, err = blockchainContext.NewAddress(creatorAddress)
require.Nil(t, err)
@@ -329,7 +330,7 @@ func TestBlockchainContext_NewAddress(t *testing.T) {
return []byte("new_address"), nil
},
}
- blockchainContext, _ = NewBlockchainContext(host, stubBlockchain)
+ blockchainContext, _ = NewBlockchainContext(host, stubBlockchain, false)
address, err = blockchainContext.NewAddress(creatorAddress)
require.Nil(t, err)
@@ -352,7 +353,7 @@ func TestBlockchainContext_NewAddress(t *testing.T) {
return nil, errTestError
},
}
- blockchainContext, _ = NewBlockchainContext(host, stubBlockchain)
+ blockchainContext, _ = NewBlockchainContext(host, stubBlockchain, false)
address, err = blockchainContext.NewAddress(creatorAddress)
require.Equal(t, errTestError, err)
@@ -365,7 +366,7 @@ func TestBlockchainContext_BlockHash(t *testing.T) {
// TODO rewrite this test to use absolute block nonces
host := &contextmock.VMHostMock{}
mockWorld := worldmock.NewMockWorld()
- blockchainContext, _ := NewBlockchainContext(host, mockWorld)
+ blockchainContext, _ := NewBlockchainContext(host, mockWorld, false)
mockWorld.Err = errTestError
hash := blockchainContext.BlockHash(42)
@@ -395,7 +396,7 @@ func TestBlockchainContext_IsPayable(t *testing.T) {
}
mockWorld.AcctMap.PutAccounts(accounts)
- bc, _ := NewBlockchainContext(host, mockWorld)
+ bc, _ := NewBlockchainContext(host, mockWorld, false)
isPayable, err := bc.IsPayable(nil, []byte("test"))
require.Nil(t, err)
@@ -413,23 +414,23 @@ func TestBlockchainContext_Getters(t *testing.T) {
mockWorld := &worldmock.MockWorld{
PreviousBlockInfo: &worldmock.BlockInfo{
- BlockTimestamp: 6749,
- BlockNonce: 90,
- BlockRound: 96,
- BlockEpoch: 3,
- RandomSeed: &randomSeed1,
+ BlockTimestampMs: 6749,
+ BlockNonce: 90,
+ BlockRound: 96,
+ BlockEpoch: 3,
+ RandomSeed: &randomSeed1,
},
CurrentBlockInfo: &worldmock.BlockInfo{
- BlockTimestamp: 6800,
- BlockNonce: 98,
- BlockRound: 99,
- BlockEpoch: 4,
- RandomSeed: &randomSeed2,
+ BlockTimestampMs: 6800,
+ BlockNonce: 98,
+ BlockRound: 99,
+ BlockEpoch: 4,
+ RandomSeed: &randomSeed2,
},
StateRootHash: []byte("root hash"),
}
- blockchainContext, _ := NewBlockchainContext(host, mockWorld)
+ blockchainContext, _ := NewBlockchainContext(host, mockWorld, false)
require.Equal(t, uint32(3), blockchainContext.LastEpoch())
require.Equal(t, uint32(4), blockchainContext.CurrentEpoch())
@@ -440,8 +441,8 @@ func TestBlockchainContext_Getters(t *testing.T) {
require.Equal(t, uint64(96), blockchainContext.LastRound())
require.Equal(t, uint64(99), blockchainContext.CurrentRound())
- require.Equal(t, uint64(6749), blockchainContext.LastTimeStamp())
- require.Equal(t, uint64(6800), blockchainContext.CurrentTimeStamp())
+ require.Equal(t, uint64(6749), blockchainContext.LastTimeStampMs())
+ require.Equal(t, uint64(6800), blockchainContext.CurrentTimeStampMs())
require.Equal(t, []byte("root hash"), blockchainContext.GetStateRootHash())
require.Equal(t, randomSeed1[:], blockchainContext.LastRandomSeed())
diff --git a/vmhost/contexts/managedType_test.go b/vmhost/contexts/managedType_test.go
index 085d22324..8469a786e 100644
--- a/vmhost/contexts/managedType_test.go
+++ b/vmhost/contexts/managedType_test.go
@@ -50,7 +50,7 @@ func TestManagedTypesContext_Randomness(t *testing.T) {
return []byte{0xf, 0xf, 0xf, 0xf, 0xa, 0xb}
},
}
- blockchainCtx, _ := NewBlockchainContext(host, mockBlockchain)
+ blockchainCtx, _ := NewBlockchainContext(host, mockBlockchain, false)
host.BlockchainContext = blockchainCtx
copyHost := host
diff --git a/vmhost/contexts/metering.go b/vmhost/contexts/metering.go
index d419df0a8..14fb4be18 100644
--- a/vmhost/contexts/metering.go
+++ b/vmhost/contexts/metering.go
@@ -525,12 +525,24 @@ func (context *meteringContext) DeductInitialGasForDirectDeployment(input vmhost
}
// DeductInitialGasForIndirectDeployment deducts gas for the deployment of a contract initiated by another SmartContract
-func (context *meteringContext) DeductInitialGasForIndirectDeployment(input vmhost.CodeDeployInput) error {
- return context.deductInitialGas(
+func (context *meteringContext) DeductInitialGasForIndirectDeployment(input vmhost.CodeDeployInput) (uint64, error) {
+ initialCost := context.calculateInitialCost(
input.ContractCode,
0,
context.gasSchedule.BaseOperationCost.CompilePerByte,
)
+ err := context.UseGasBounded(initialCost)
+ return initialCost, err
+}
+
+func (context *meteringContext) calculateInitialCost(
+ code []byte,
+ baseCost uint64,
+ costPerByte uint64,
+) uint64 {
+ codeLength := uint64(len(code))
+ codeCost := math.MulUint64(codeLength, costPerByte)
+ return math.AddUint64(baseCost, codeCost)
}
func (context *meteringContext) deductInitialGas(
@@ -539,9 +551,7 @@ func (context *meteringContext) deductInitialGas(
costPerByte uint64,
) error {
input := context.host.Runtime().GetVMInput()
- codeLength := uint64(len(code))
- codeCost := math.MulUint64(codeLength, costPerByte)
- initialCost := math.AddUint64(baseCost, codeCost)
+ initialCost := context.calculateInitialCost(code, baseCost, costPerByte)
if initialCost > input.GasProvided {
return vmhost.ErrNotEnoughGas
diff --git a/vmhost/contexts/metering_test.go b/vmhost/contexts/metering_test.go
index 595373740..43dd8f511 100644
--- a/vmhost/contexts/metering_test.go
+++ b/vmhost/contexts/metering_test.go
@@ -201,9 +201,10 @@ func TestDeductInitialGasForIndirectDeployment(t *testing.T) {
}
meteringCtx, _ := NewMeteringContext(host, config.MakeGasMapForTests(), uint64(15000))
+ meteringCtx.gasForExecution = contractCallInput.GasProvided
mockRuntime.SetPointsUsed(0)
- err := meteringCtx.DeductInitialGasForIndirectDeployment(vmhost.CodeDeployInput{ContractCode: contractCode})
+ _, err := meteringCtx.DeductInitialGasForIndirectDeployment(vmhost.CodeDeployInput{ContractCode: contractCode})
require.Nil(t, err)
remainingGas := meteringCtx.GasLeft()
require.Equal(t, gasProvided-uint64(len(contractCode)), remainingGas)
diff --git a/vmhost/contexts/output.go b/vmhost/contexts/output.go
index fb77b9141..67b22b98a 100644
--- a/vmhost/contexts/output.go
+++ b/vmhost/contexts/output.go
@@ -180,6 +180,11 @@ func (context *outputContext) GetOutputAccounts() map[string]*vmcommon.OutputAcc
return context.outputState.OutputAccounts
}
+// DeleteAccount add an account to DeletedAccounts
+func (context *outputContext) DeleteAccount(address []byte) {
+ context.outputState.DeletedAccounts = append(context.outputState.DeletedAccounts, address)
+}
+
// DeleteOutputAccount removes the given address from the output accounts and code updates
func (context *outputContext) DeleteOutputAccount(address []byte) {
delete(context.outputState.OutputAccounts, string(address))
@@ -559,12 +564,29 @@ func (context *outputContext) GetVMOutput() *vmcommon.VMOutput {
// DeployCode sets the given code to a an account, and creates a new codeUpdates entry at the accounts address.
func (context *outputContext) DeployCode(input vmhost.CodeDeployInput) {
newSCAccount, _ := context.GetOutputAccount(input.ContractAddress)
- newSCAccount.Code = input.ContractCode
newSCAccount.CodeMetadata = input.ContractCodeMetadata
newSCAccount.CodeDeployerAddress = input.CodeDeployerAddress
+ if input.OmitDefaultCodeChanges {
+ return
+ }
+ context.ChangeAccountCode(input.ContractAddress, input.ContractCode)
+}
+
+// ChangeAccountCode sets the given code to an account, and creates a new codeUpdates entry at the accounts address.
+func (context *outputContext) ChangeAccountCode(address []byte, contract []byte) {
+ newSCAccount, _ := context.GetOutputAccount(address)
+ newSCAccount.Code = contract
+ newSCAccount.CodeHash = context.host.Runtime().ComputeCodeHash(contract)
+
var empty struct{}
- context.codeUpdates[string(input.ContractAddress)] = empty
+ context.codeUpdates[string(address)] = empty
+}
+
+// SetIsCreatedInTransactionFlag sets the IsContractCreatedInTransaction flag.
+func (context *outputContext) SetIsCreatedInTransactionFlag(address []byte) {
+ account, _ := context.GetOutputAccount(address)
+ account.IsContractCreatedInTransaction = true
}
// CreateVMOutputInCaseOfError creates a new vmOutput with the given error set as return message.
@@ -592,6 +614,7 @@ func (context *outputContext) removeNonUpdatedCode() {
_, ok := context.codeUpdates[address]
if !ok {
account.Code = nil
+ account.CodeHash = nil
account.CodeMetadata = nil
account.CodeDeployerAddress = nil
}
@@ -748,12 +771,18 @@ func mergeOutputAccounts(
if len(rightAccount.Code) > 0 {
leftAccount.Code = rightAccount.Code
}
+ if len(rightAccount.CodeHash) > 0 {
+ leftAccount.CodeHash = rightAccount.CodeHash
+ }
if len(rightAccount.CodeMetadata) > 0 {
leftAccount.CodeMetadata = rightAccount.CodeMetadata
}
if rightAccount.Nonce > leftAccount.Nonce {
leftAccount.Nonce = rightAccount.Nonce
}
+ if rightAccount.IsContractCreatedInTransaction {
+ leftAccount.IsContractCreatedInTransaction = rightAccount.IsContractCreatedInTransaction
+ }
mergeTransfers(leftAccount, rightAccount, mergeAllTransfers)
diff --git a/vmhost/contexts/output_test.go b/vmhost/contexts/output_test.go
index 7532791de..e1c64faf5 100644
--- a/vmhost/contexts/output_test.go
+++ b/vmhost/contexts/output_test.go
@@ -413,7 +413,7 @@ func TestOutputContext_Transfer(t *testing.T) {
Balance: balance,
})
- blockchainContext, _ := NewBlockchainContext(host, mockWorld)
+ blockchainContext, _ := NewBlockchainContext(host, mockWorld, false)
outputContext, _ := NewOutputContext(host)
host.OutputContext = outputContext
@@ -450,7 +450,7 @@ func TestOutputContext_Transfer_Errors_And_Checks(t *testing.T) {
EnableEpochsHandlerField: &worldmock.EnableEpochsHandlerStub{},
}
outputContext, _ := NewOutputContext(host)
- blockchainContext, _ := NewBlockchainContext(host, mockWorld)
+ blockchainContext, _ := NewBlockchainContext(host, mockWorld, false)
host.RuntimeContext = &contextmock.RuntimeContextMock{VMInput: &vmcommon.ContractCallInput{}}
host.OutputContext = outputContext
@@ -519,7 +519,7 @@ func TestOutputContext_Transfer_IsAccountPayable(t *testing.T) {
EnableEpochsHandlerField: &worldmock.EnableEpochsHandlerStub{},
}
oc, _ := NewOutputContext(host)
- bc, _ := NewBlockchainContext(host, mockWorld)
+ bc, _ := NewBlockchainContext(host, mockWorld, false)
host.OutputContext = oc
host.BlockchainContext = bc
diff --git a/vmhost/contexts/runtime.go b/vmhost/contexts/runtime.go
index 40e9eb1ba..c672de492 100644
--- a/vmhost/contexts/runtime.go
+++ b/vmhost/contexts/runtime.go
@@ -75,6 +75,7 @@ func NewRuntimeContext(
builtInFuncContainer vmcommon.BuiltInFunctionContainer,
vmExecutor executor.Executor,
hasher vmhost.HashComputer,
+ omitFunctionNameChecks bool,
) (*runtimeContext, error) {
if check.IfNil(host) {
@@ -100,7 +101,7 @@ func NewRuntimeContext(
host: host,
vmType: vmType,
stateStack: make([]*runtimeContext, 0),
- validator: newWASMValidator(scAPINames, builtInFuncContainer, enableEpochsHandler),
+ validator: newWASMValidator(!omitFunctionNameChecks, scAPINames, builtInFuncContainer, enableEpochsHandler),
hasher: hasher,
errors: nil,
}
@@ -161,17 +162,13 @@ func (context *runtimeContext) StartWasmerInstance(contract []byte, gasLimit uin
return vmhost.ErrMaxInstancesReached
}
- var codeHash []byte
if newCode {
- codeHash = context.hasher.Compute(string(contract))
+ context.SetTrackerCode(contract)
} else {
- blockchain := context.host.Blockchain()
- codeHash = blockchain.GetCodeHash(context.codeAddress)
+ codeHash := context.host.Blockchain().GetCodeHash(context.codeAddress)
+ context.setTrackerState(contract, codeHash)
}
- context.iTracker.SetCodeSize(uint64(len(contract)))
- context.iTracker.SetCodeHash(codeHash)
-
defer func() {
context.iTracker.LogCounts()
logRuntime.Trace("code was new", "new", newCode)
@@ -263,8 +260,7 @@ func (context *runtimeContext) makeInstanceFromContractByteCode(contract []byte,
}
if newCode || len(context.iTracker.CodeHash()) == 0 {
- codeHash := context.hasher.Compute(string(contract))
- context.iTracker.SetCodeHash(codeHash)
+ context.SetTrackerCode(contract)
}
if newCode {
@@ -281,7 +277,7 @@ func (context *runtimeContext) makeInstanceFromContractByteCode(contract []byte,
"id", context.iTracker.Instance().ID(),
"codeHash", context.iTracker.CodeHash(),
)
- context.saveCompiledCode()
+ context.SaveCompiledCode()
return nil
}
@@ -312,6 +308,22 @@ func (context *runtimeContext) useWarmInstanceIfExists(gasLimit uint64, newCode
return true, nil
}
+// ComputeCodeHash computes the hash for the given code.
+func (context *runtimeContext) ComputeCodeHash(code []byte) []byte {
+ return context.hasher.Compute(string(code))
+}
+
+// setTrackerState sets code related details on iTracker.
+func (context *runtimeContext) setTrackerState(code []byte, codeHash []byte) {
+ context.iTracker.SetCodeHash(codeHash)
+ context.iTracker.SetCodeSize(uint64(len(code)))
+}
+
+// SetTrackerCode sets code related details on iTracker.
+func (context *runtimeContext) SetTrackerCode(code []byte) {
+ context.setTrackerState(code, context.ComputeCodeHash(code))
+}
+
// GetSCCode returns the SC code of the current SC.
func (context *runtimeContext) GetSCCode() ([]byte, error) {
blockchain := context.host.Blockchain()
@@ -329,7 +341,15 @@ func (context *runtimeContext) GetSCCodeSize() uint64 {
return context.iTracker.GetCodeSize()
}
-func (context *runtimeContext) saveCompiledCode() {
+// GetSCCodeHash returns the cached hash of the current SC code.
+func (context *runtimeContext) GetSCCodeHash() []byte {
+ return context.iTracker.CodeHash()
+}
+
+func (context *runtimeContext) SaveCompiledCode() {
+ if !context.iTracker.Instance().HasCompiledCode() {
+ return
+ }
compiledCode, err := context.iTracker.Instance().Cache()
if err != nil {
logRuntime.Error("getCompiledCode from instance", "error", err)
@@ -499,9 +519,10 @@ func (context *runtimeContext) SetVMInput(vmInput *vmcommon.ContractCallInput) {
ReturnCallAfterError: vmInput.ReturnCallAfterError,
}
context.vmInput = &vmcommon.ContractCallInput{
- VMInput: internalVMInput,
- RecipientAddr: vmInput.RecipientAddr,
- Function: vmInput.Function,
+ VMInput: internalVMInput,
+ RecipientAddr: vmInput.RecipientAddr,
+ RecipientAliasAddr: vmInput.RecipientAliasAddr,
+ Function: vmInput.Function,
}
if vmInput.CallValue != nil {
@@ -803,7 +824,7 @@ func (context *runtimeContext) CountSameContractInstancesOnStack(address []byte)
// FunctionNameChecked returns the function name, after checking that it exists in the contract.
func (context *runtimeContext) FunctionNameChecked() (string, error) {
functionName := context.FunctionName()
- err := verifyCallFunction(functionName)
+ err := context.validator.verifyCallFunction(functionName)
if err != nil {
return "", executor.ErrFuncNotFound
}
diff --git a/vmhost/contexts/runtime_test.go b/vmhost/contexts/runtime_test.go
index 8099ba7dc..1ab401e1c 100644
--- a/vmhost/contexts/runtime_test.go
+++ b/vmhost/contexts/runtime_test.go
@@ -14,6 +14,8 @@ import (
"github.com/multiversx/mx-chain-scenario-go/worldmock"
vmcommon "github.com/multiversx/mx-chain-vm-common-go"
"github.com/multiversx/mx-chain-vm-common-go/builtInFunctions"
+ "github.com/stretchr/testify/require"
+
"github.com/multiversx/mx-chain-vm-go/config"
"github.com/multiversx/mx-chain-vm-go/crypto/factory"
"github.com/multiversx/mx-chain-vm-go/executor"
@@ -21,7 +23,6 @@ import (
"github.com/multiversx/mx-chain-vm-go/testcommon/testexecutor"
"github.com/multiversx/mx-chain-vm-go/vmhost"
"github.com/multiversx/mx-chain-vm-go/vmhost/vmhooks"
- "github.com/stretchr/testify/require"
)
var defaultHasher = blake2b.NewBlake2b()
@@ -34,14 +35,15 @@ func InitializeVMAndWasmer() *contextmock.VMHostMock {
gasSchedule := config.MakeGasMapForTests()
gasCostConfig, _ := config.CreateGasConfig(gasSchedule)
wasmerExecutor, _ := wasmer2.CreateExecutor()
- wasmerExecutor.SetOpcodeCosts(gasCostConfig.WASMOpcodeCost)
+ opcodeCosts := executor.VMOpcodeCost{EVMOpcodeCost: gasCostConfig.EVMOpcodeCost, WASMOpcodeCost: gasCostConfig.WASMOpcodeCost}
+ wasmerExecutor.SetOpcodeCosts(opcodeCosts)
host := &contextmock.VMHostMock{}
mockMetering := &contextmock.MeteringContextMock{}
mockMetering.SetGasSchedule(gasSchedule)
host.MeteringContext = mockMetering
- host.BlockchainContext, _ = NewBlockchainContext(host, worldmock.NewMockWorld())
+ host.BlockchainContext, _ = NewBlockchainContext(host, worldmock.NewMockWorld(), false)
host.OutputContext, _ = NewOutputContext(host)
host.CryptoHook, _ = factory.NewVMCrypto()
return host
@@ -59,6 +61,7 @@ func makeDefaultRuntimeContext(t *testing.T, host vmhost.VMHost) *runtimeContext
builtInFunctions.NewBuiltInFunctionContainer(),
exec,
defaultHasher,
+ false,
)
require.Nil(t, err)
require.NotNil(t, runtimeCtx)
@@ -77,27 +80,27 @@ func TestNewRuntimeContextErrors(t *testing.T) {
require.Nil(t, err)
t.Run("NilHost", func(t *testing.T) {
- runtimeCtx, err := NewRuntimeContext(nil, vmType, bfc, exec, hasher)
+ runtimeCtx, err := NewRuntimeContext(nil, vmType, bfc, exec, hasher, false)
require.Nil(t, runtimeCtx)
require.ErrorIs(t, err, vmhost.ErrNilVMHost)
})
t.Run("NilVMType", func(t *testing.T) {
- runtimeCtx, err := NewRuntimeContext(host, nil, bfc, exec, hasher)
+ runtimeCtx, err := NewRuntimeContext(host, nil, bfc, exec, hasher, false)
require.Nil(t, runtimeCtx)
require.ErrorIs(t, err, vmhost.ErrNilVMType)
})
t.Run("NilBuiltinFuncContainer", func(t *testing.T) {
- runtimeCtx, err := NewRuntimeContext(host, vmType, nil, exec, hasher)
+ runtimeCtx, err := NewRuntimeContext(host, vmType, nil, exec, hasher, false)
require.Nil(t, runtimeCtx)
require.ErrorIs(t, err, vmhost.ErrNilBuiltInFunctionsContainer)
})
t.Run("NilExecutor", func(t *testing.T) {
- runtimeCtx, err := NewRuntimeContext(host, vmType, bfc, nil, hasher)
+ runtimeCtx, err := NewRuntimeContext(host, vmType, bfc, nil, hasher, false)
require.Nil(t, runtimeCtx)
require.ErrorIs(t, err, vmhost.ErrNilExecutor)
})
t.Run("NilHasher", func(t *testing.T) {
- runtimeCtx, err := NewRuntimeContext(host, vmType, bfc, exec, nil)
+ runtimeCtx, err := NewRuntimeContext(host, vmType, bfc, exec, nil, false)
require.Nil(t, runtimeCtx)
require.ErrorIs(t, err, vmhost.ErrNilHasher)
})
@@ -372,6 +375,7 @@ func TestRuntimeContext_CountContractInstancesOnStack(t *testing.T) {
builtInFunctions.NewBuiltInFunctionContainer(),
exec,
defaultHasher,
+ false,
)
vmInput := vmcommon.VMInput{
diff --git a/vmhost/contexts/validator.go b/vmhost/contexts/validator.go
index 48939e53c..76b47c9c1 100644
--- a/vmhost/contexts/validator.go
+++ b/vmhost/contexts/validator.go
@@ -30,17 +30,20 @@ var reservedFunctionsActivationFlag = map[string]core.EnableEpochFlag{
// wasmValidator is a validator for WASM SmartContracts
type wasmValidator struct {
- reserved *reservedFunctions
+ hasFunctionNameChecks bool
+ reserved *reservedFunctions
}
// newWASMValidator creates a new WASMValidator
func newWASMValidator(
+ hasFunctionNameChecks bool,
scAPINames vmcommon.FunctionNames,
builtInFuncContainer vmcommon.BuiltInFunctionContainer,
enableEpochsHandler vmcommon.EnableEpochsHandler,
) *wasmValidator {
return &wasmValidator{
- reserved: NewReservedFunctions(scAPINames, builtInFuncContainer, reservedFunctionsActivationFlag, enableEpochsHandler),
+ hasFunctionNameChecks: hasFunctionNameChecks,
+ reserved: NewReservedFunctions(scAPINames, builtInFuncContainer, reservedFunctionsActivationFlag, enableEpochsHandler),
}
}
@@ -83,7 +86,7 @@ func (validator *wasmValidator) verifyProtectedFunctions(instance executor.Insta
}
func (validator *wasmValidator) verifyValidFunctionName(functionName string) error {
- err := verifyCallFunction(functionName)
+ err := validator.verifyCallFunction(functionName)
if err != nil {
return err
}
@@ -96,7 +99,11 @@ func (validator *wasmValidator) verifyValidFunctionName(functionName string) err
return nil
}
-func verifyCallFunction(functionName string) error {
+func (validator *wasmValidator) verifyCallFunction(functionName string) error {
+ if !validator.hasFunctionNameChecks {
+ return nil
+ }
+
const maxLengthOfFunctionName = 256
errInvalidName := fmt.Errorf("%w: %s", vmhost.ErrInvalidFunctionName, functionName)
diff --git a/vmhost/contexts/validator_test.go b/vmhost/contexts/validator_test.go
index fd641457e..939da0955 100644
--- a/vmhost/contexts/validator_test.go
+++ b/vmhost/contexts/validator_test.go
@@ -25,7 +25,7 @@ func TestFunctionsGuard_isValidFunctionName(t *testing.T) {
_ = builtInFuncContainer.Add("protocolFunctionFoo", &mock.BuiltInFunctionStub{})
_ = builtInFuncContainer.Add("protocolFunctionBar", &mock.BuiltInFunctionStub{})
- validator := newWASMValidator(testImportNames(), builtInFuncContainer, worldmock.EnableEpochsHandlerStubAllFlags())
+ validator := newWASMValidator(true, testImportNames(), builtInFuncContainer, worldmock.EnableEpochsHandlerStubAllFlags())
require.Nil(t, validator.verifyValidFunctionName("foo"))
require.Nil(t, validator.verifyValidFunctionName("_"))
@@ -55,7 +55,7 @@ func TestFunctionsGuard_isValidFunctionName(t *testing.T) {
func TestFunctionsProtected(t *testing.T) {
host := InitializeVMAndWasmer()
- validator := newWASMValidator(testImportNames(), builtInFunctions.NewBuiltInFunctionContainer(), worldmock.EnableEpochsHandlerStubAllFlags())
+ validator := newWASMValidator(true, testImportNames(), builtInFunctions.NewBuiltInFunctionContainer(), worldmock.EnableEpochsHandlerStubAllFlags())
world := worldmock.NewMockWorld()
imb := contextmock.NewExecutorMock(world)
diff --git a/vmhost/evmhooks/errors.go b/vmhost/evmhooks/errors.go
new file mode 100644
index 000000000..79c961b21
--- /dev/null
+++ b/vmhost/evmhooks/errors.go
@@ -0,0 +1,7 @@
+package evmhooks
+
+import "errors"
+
+var ErrInvalidEncodedData = errors.New("invalid encoded data")
+
+var ErrInvalidReturnDataSize = errors.New("invalid return data size")
diff --git a/vmhost/evmhooks/evmBlockchainHooks.go b/vmhost/evmhooks/evmBlockchainHooks.go
new file mode 100644
index 000000000..ad5e847c6
--- /dev/null
+++ b/vmhost/evmhooks/evmBlockchainHooks.go
@@ -0,0 +1,89 @@
+package evmhooks
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/holiman/uint256"
+ "github.com/multiversx/mx-chain-core-go/core"
+ vmcommon "github.com/multiversx/mx-chain-vm-common-go"
+ "math/big"
+)
+
+func (context *EVMHooksImpl) ChainID() *big.Int {
+ return new(big.Int).SetBytes(context.GetBlockchainContext().ChainID())
+}
+
+func (context *EVMHooksImpl) Random() *common.Hash {
+ random := common.BytesToHash(context.GetBlockchainContext().CurrentRandomSeed())
+ return &random
+}
+
+func (context *EVMHooksImpl) GetHash(number uint64) common.Hash {
+ return common.BytesToHash(context.GetBlockchainContext().BlockHash(number))
+}
+
+func (context *EVMHooksImpl) BlockNumber() *big.Int {
+ return new(big.Int).SetUint64(context.GetBlockchainContext().CurrentNonce())
+}
+
+func (context *EVMHooksImpl) Time() uint64 {
+ return context.GetBlockchainContext().CurrentTimeStamp()
+}
+
+func (context *EVMHooksImpl) GetBalanceForAddress(address []byte) *uint256.Int {
+ return uint256.MustFromBig(context.GetBlockchainContext().GetBalanceBigInt(address))
+}
+
+func (context *EVMHooksImpl) GetSelfBalance() *uint256.Int {
+ return context.GetBalanceForAddress(context.ContractMvxAddress())
+}
+
+func (context *EVMHooksImpl) GetBalance(address common.Address) *uint256.Int {
+ return context.GetBalanceForAddress(context.toMVXAddress(address))
+}
+
+func (context *EVMHooksImpl) GetCodeHash(address common.Address) common.Hash {
+ codeHash := context.GetBlockchainContext().GetCodeHash(context.toMVXAddress(address))
+ return common.BytesToHash(codeHash)
+}
+
+func (context *EVMHooksImpl) GetCode(address common.Address) []byte {
+ code, _ := context.GetBlockchainContext().GetCode(context.toMVXAddress(address))
+ return code
+}
+
+func (context *EVMHooksImpl) GetCodeSize(address common.Address) int {
+ return len(context.GetCode(address))
+}
+
+func (context *EVMHooksImpl) SaveAliasAddress() error {
+ aliasAddress, err := context.requestEthereumContractAddress()
+ if err != nil {
+ return err
+ }
+
+ saveRequest := &vmcommon.AliasSaveRequest{
+ AliasAddress: aliasAddress.Bytes(),
+ AliasIdentifier: core.ETHAddressIdentifier,
+ MultiversXAddress: context.ContractMvxAddress(),
+ }
+ return context.GetBlockchainContext().SaveAliasAddress(saveRequest)
+}
+
+func (context *EVMHooksImpl) requestEthereumContractAddress() (common.Address, error) {
+ aliasAddress := context.ContractAliasAddress()
+ if aliasAddress != (common.Address{}) {
+ return aliasAddress, nil
+ }
+
+ return context.createEthereumContractAddress(context.CallerMvxAddress())
+}
+
+func (context *EVMHooksImpl) createEthereumContractAddress(creatorAddress []byte) (common.Address, error) {
+ nonce, err := context.GetBlockchainContext().GetNonceForNewAddress(creatorAddress)
+ if err != nil {
+ return common.Address{}, err
+ }
+
+ return crypto.CreateAddress(context.toEVMAddress(creatorAddress), nonce), nil
+}
diff --git a/vmhost/evmhooks/evmExecuteHooks.go b/vmhost/evmhooks/evmExecuteHooks.go
new file mode 100644
index 000000000..de1ac9eeb
--- /dev/null
+++ b/vmhost/evmhooks/evmExecuteHooks.go
@@ -0,0 +1,206 @@
+package evmhooks
+
+import (
+ "encoding/hex"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/holiman/uint256"
+ "github.com/multiversx/mx-chain-core-go/core"
+ vmcommon "github.com/multiversx/mx-chain-vm-common-go"
+ "github.com/multiversx/mx-chain-vm-common-go/parsers"
+
+ "github.com/multiversx/mx-chain-vm-go/vmhost/vmhooks"
+)
+
+const evmCallExpectedReturnDataSize = 1
+
+const evmCallExpectedReturnDataPosition = 0
+
+const nonEvmCallFunctionNameInputPosition = 0
+
+const nonEvmCallArgumentsInputPositionStart = 1
+
+func (context *EVMHooksImpl) IsSmartContractAddress(address common.Address) bool {
+ return core.IsSmartContractAddress(context.toMVXAddress(address))
+}
+
+func (context *EVMHooksImpl) Create(code []byte, gas uint64, value *uint256.Int) ([]byte, common.Address, error) {
+ aliasAddress, err := context.createEthereumContractAddress(context.ContractMvxAddress())
+ if err != nil {
+ return nil, common.Address{}, err
+ }
+
+ return context.createContract(code, gas, value, aliasAddress)
+}
+
+func (context *EVMHooksImpl) Create2(code []byte, gas uint64, value *uint256.Int, salt *uint256.Int) ([]byte, common.Address, error) {
+ aliasAddress := crypto.CreateAddress2(context.ContractAddress(), salt.Bytes32(), crypto.Keccak256Hash(code).Bytes())
+ return context.createContract(code, gas, value, aliasAddress)
+}
+
+func (context *EVMHooksImpl) Call(address common.Address, value *uint256.Int, input []byte, gas uint64) ([]byte, error) {
+ destination := context.toMVXAddress(address)
+ isNonEvmCall := context.isNonEvmCall(destination)
+ functionName, arguments, err := parseInput(input, isNonEvmCall)
+ if err != nil {
+ return nil, err
+ }
+
+ returnDataLength := context.returnDataLength()
+ _, err = vmhooks.ExecuteOnDestContextUnmetered(
+ context.host,
+ int64(gas),
+ value.ToBig(),
+ functionName,
+ destination,
+ arguments,
+ 0,
+ false,
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ return context.parseReturnData(isNonEvmCall, returnDataLength)
+}
+
+func (context *EVMHooksImpl) StaticCall(address common.Address, input []byte, gas uint64) ([]byte, error) {
+ destination := context.toMVXAddress(address)
+ isNonEvmCall := context.isNonEvmCall(destination)
+ functionName, arguments, err := parseInput(input, isNonEvmCall)
+ if err != nil {
+ return nil, err
+ }
+
+ returnDataLength := context.returnDataLength()
+ _, err = vmhooks.ExecuteReadOnlyUnmetered(
+ context.host,
+ int64(gas),
+ functionName,
+ context.toMVXAddress(address),
+ arguments,
+ 0,
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ return context.parseReturnData(isNonEvmCall, returnDataLength)
+}
+
+func (context *EVMHooksImpl) CallCode(address common.Address, value *uint256.Int, input []byte, gas uint64) ([]byte, error) {
+ sender := context.ContractMvxAddress()
+ return context.executeOnSameContext(sender, sender, address, value, input, gas, true)
+}
+
+func (context *EVMHooksImpl) DelegateCall(address common.Address, input []byte, gas uint64) ([]byte, error) {
+ sender := context.CallerMvxAddress()
+ receiver := context.ContractMvxAddress()
+ return context.executeOnSameContext(sender, receiver, address, context.CallValue(), input, gas, false)
+}
+
+func (context *EVMHooksImpl) createContract(code []byte, gas uint64, value *uint256.Int, aliasAddress common.Address) ([]byte, common.Address, error) {
+ sender := context.ContractMvxAddress()
+ returnDataLength := context.returnDataLength()
+ codeMetadata := vmcommon.GetEVMContractCodeMetadata()
+ _, err := vmhooks.CreateContractWithAddress(
+ sender,
+ [][]byte{},
+ value.ToBig(),
+ int64(gas),
+ code,
+ codeMetadata.ToBytes(),
+ context.host,
+ vmhooks.CreateContract,
+ aliasAddress.Bytes(),
+ )
+ if err != nil {
+ return nil, common.Address{}, err
+ }
+
+ returnData, err := context.parseReturnData(false, returnDataLength)
+ if err != nil {
+ return nil, common.Address{}, err
+ }
+
+ return returnData, aliasAddress, err
+}
+
+func (context *EVMHooksImpl) executeOnSameContext(sender []byte, receiver []byte, codeAddress common.Address, value *uint256.Int, input []byte, gas uint64, doTransfer bool) ([]byte, error) {
+ returnDataLength := context.returnDataLength()
+ functionName, arguments, err := parseInput(input, false)
+ if err != nil {
+ return nil, err
+ }
+
+ _, err = vmhooks.ExecuteOnSameContextUnmetered(
+ context.host,
+ int64(gas),
+ value.ToBig(),
+ functionName,
+ receiver,
+ arguments,
+ sender,
+ 0,
+ context.toMVXAddress(codeAddress),
+ doTransfer,
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ return context.parseReturnData(false, returnDataLength)
+}
+
+func (context *EVMHooksImpl) isNonEvmCall(destination []byte) bool {
+ return context.host.IsOutOfVMFunctionExecution(&vmcommon.ContractCallInput{RecipientAddr: destination})
+}
+
+func (context *EVMHooksImpl) returnDataLength() int {
+ return len(context.GetOutputContext().ReturnData())
+}
+
+func (context *EVMHooksImpl) extractReturnData(previousReturnDataLength int) [][]byte {
+ returnData := context.GetOutputContext().ReturnData()
+ context.GetOutputContext().ClearReturnData()
+ if len(returnData) > previousReturnDataLength {
+ return returnData[previousReturnDataLength:]
+ }
+ return nil
+}
+
+func (context *EVMHooksImpl) parseReturnData(isNonEvmCall bool, oldLength int) ([]byte, error) {
+ returnData := context.extractReturnData(oldLength)
+ if returnData == nil {
+ return nil, nil
+ }
+ if isNonEvmCall {
+ return lengthPrefixEncode(returnData), nil
+ }
+ if len(returnData) != evmCallExpectedReturnDataSize {
+ return nil, ErrInvalidReturnDataSize
+ }
+ return returnData[evmCallExpectedReturnDataPosition], nil
+}
+
+func parseInput(input []byte, isNonEvmCall bool) ([]byte, [][]byte, error) {
+ if isNonEvmCall {
+ decodedArguments, err := lengthPrefixDecode(input)
+ if err != nil {
+ return nil, nil, err
+ }
+ return decodedArguments[nonEvmCallFunctionNameInputPosition], decodedArguments[nonEvmCallArgumentsInputPositionStart:], nil
+ }
+
+ functionName, arguments, err := parsers.ParseEthereumCallInput(input)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ functionNameHex := []byte(hex.EncodeToString(functionName))
+ if len(arguments) > 0 {
+ return functionNameHex, [][]byte{arguments}, nil
+ }
+ return functionNameHex, nil, nil
+}
diff --git a/vmhost/evmhooks/evmHooksImpl.go b/vmhost/evmhooks/evmHooksImpl.go
new file mode 100644
index 000000000..017f9e573
--- /dev/null
+++ b/vmhost/evmhooks/evmHooksImpl.go
@@ -0,0 +1,86 @@
+package evmhooks
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/multiversx/mx-chain-core-go/core"
+ vmcommon "github.com/multiversx/mx-chain-vm-common-go"
+
+ "github.com/multiversx/mx-chain-vm-go/crypto"
+ "github.com/multiversx/mx-chain-vm-go/vmhost"
+ "github.com/multiversx/mx-chain-vm-go/vmhost/vmhooks"
+)
+
+type EVMHooksImpl struct {
+ host vmhost.VMHost
+}
+
+// NewEVMHooksImpl creates a new EVMHooksImpl instance.
+func NewEVMHooksImpl(host vmhost.VMHost) *EVMHooksImpl {
+ return &EVMHooksImpl{host: host}
+}
+
+// GetBlockchainContext returns the blockchain context
+func (context *EVMHooksImpl) GetBlockchainContext() vmhost.BlockchainContext {
+ return context.host.Blockchain()
+}
+
+// GetRuntimeContext returns the runtime context
+func (context *EVMHooksImpl) GetRuntimeContext() vmhost.RuntimeContext {
+ return context.host.Runtime()
+}
+
+// GetCryptoContext returns the crypto context
+func (context *EVMHooksImpl) GetCryptoContext() crypto.VMCrypto {
+ return context.host.Crypto()
+}
+
+// GetManagedTypesContext returns the big int context
+func (context *EVMHooksImpl) GetManagedTypesContext() vmhost.ManagedTypesContext {
+ return context.host.ManagedTypes()
+}
+
+// GetOutputContext returns the output context
+func (context *EVMHooksImpl) GetOutputContext() vmhost.OutputContext {
+ return context.host.Output()
+}
+
+// GetMeteringContext returns the metering context
+func (context *EVMHooksImpl) GetMeteringContext() vmhost.MeteringContext {
+ return context.host.Metering()
+}
+
+// GetStorageContext returns the storage context
+func (context *EVMHooksImpl) GetStorageContext() vmhost.StorageContext {
+ return context.host.Storage()
+}
+
+// FailExecution fails the execution with the provided error
+func (context *EVMHooksImpl) FailExecution(err error) {
+ vmhooks.FailExecution(context.host, err)
+}
+
+func (context *EVMHooksImpl) toEVMAddress(address []byte) common.Address {
+ addressResponse, err := context.GetBlockchainContext().RequestAddress(&vmcommon.AddressRequest{
+ SourceAddress: address,
+ SourceIdentifier: core.MVXAddressIdentifier,
+ RequestedIdentifier: core.ETHAddressIdentifier,
+ SaveOnGenerate: true,
+ })
+ if err != nil {
+ panic(err)
+ }
+ return common.BytesToAddress(addressResponse.RequestedAddress)
+}
+
+func (context *EVMHooksImpl) toMVXAddress(address common.Address) []byte {
+ addressResponse, err := context.GetBlockchainContext().RequestAddress(&vmcommon.AddressRequest{
+ SourceAddress: address.Bytes(),
+ SourceIdentifier: core.ETHAddressIdentifier,
+ RequestedIdentifier: core.MVXAddressIdentifier,
+ SaveOnGenerate: true,
+ })
+ if err != nil {
+ panic(err)
+ }
+ return addressResponse.RequestedAddress
+}
diff --git a/vmhost/evmhooks/evmMeteringHooks.go b/vmhost/evmhooks/evmMeteringHooks.go
new file mode 100644
index 000000000..530a352d5
--- /dev/null
+++ b/vmhost/evmhooks/evmMeteringHooks.go
@@ -0,0 +1,14 @@
+package evmhooks
+
+func (context *EVMHooksImpl) GasLeft() uint64 {
+ return context.GetMeteringContext().GasLeft()
+}
+
+func (context *EVMHooksImpl) UseGas(opCode string, gas uint64) bool {
+ err := context.GetMeteringContext().UseGasBoundedAndAddTracedGas(opCode, gas)
+ return err == nil
+}
+
+func (context *EVMHooksImpl) BlockGasLimit() uint64 {
+ return context.GetMeteringContext().BlockGasLimit()
+}
diff --git a/vmhost/evmhooks/evmOutputHooks.go b/vmhost/evmhooks/evmOutputHooks.go
new file mode 100644
index 000000000..ba74fad4e
--- /dev/null
+++ b/vmhost/evmhooks/evmOutputHooks.go
@@ -0,0 +1,55 @@
+package evmhooks
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/holiman/uint256"
+)
+
+func (context *EVMHooksImpl) Finish(returnData []byte) {
+ context.GetOutputContext().ClearReturnData()
+ if returnData != nil {
+ context.GetOutputContext().Finish(returnData)
+ }
+}
+
+func (context *EVMHooksImpl) FinishCreate(returnData []byte) {
+ context.saveCompiledCode(returnData)
+ context.Finish(returnData)
+}
+
+func (context *EVMHooksImpl) TransferBalance(destination common.Address, value *uint256.Int) error {
+ sender := context.ContractMvxAddress()
+ return context.GetOutputContext().TransferValueOnly(context.toMVXAddress(destination), sender, value.ToBig(), true)
+}
+
+func (context *EVMHooksImpl) SelfDestruct(destination common.Address) {
+ err := context.TransferBalance(destination, context.GetSelfBalance())
+ if err != nil {
+ context.FailExecution(err)
+ contract := context.ContractMvxAddress()
+ context.GetOutputContext().DeleteAccount(contract)
+ }
+}
+
+func (context *EVMHooksImpl) AddLog(log *types.Log) {
+ var data [][]byte
+ if len(log.Data) > 0 {
+ data = [][]byte{log.Data}
+ }
+
+ topics := make([][]byte, len(log.Topics))
+ for i, topic := range log.Topics {
+ topics[i] = topic.Bytes()
+ }
+
+ contract := context.ContractMvxAddress()
+ context.GetOutputContext().WriteLog(contract, topics, data)
+}
+
+func (context *EVMHooksImpl) saveCompiledCode(contract []byte) {
+ runtime, output := context.GetRuntimeContext(), context.GetOutputContext()
+ runtime.SetTrackerCode(contract)
+ runtime.SaveCompiledCode()
+ output.ChangeAccountCode(context.ContractMvxAddress(), contract)
+}
diff --git a/vmhost/evmhooks/evmRuntimeHooks.go b/vmhost/evmhooks/evmRuntimeHooks.go
new file mode 100644
index 000000000..4f0f8d4ea
--- /dev/null
+++ b/vmhost/evmhooks/evmRuntimeHooks.go
@@ -0,0 +1,56 @@
+package evmhooks
+
+import (
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/holiman/uint256"
+)
+
+//func (context *EVMHooksImpl) FailExecution(err error) {
+// context.GetRuntimeContext().FailExecution(err)
+//}
+
+func (context *EVMHooksImpl) ReadOnly() bool {
+ return context.GetRuntimeContext().ReadOnly()
+}
+
+func (context *EVMHooksImpl) Origin() common.Address {
+ return context.toEVMAddress(context.GetRuntimeContext().GetOriginalCallerAddress())
+}
+
+func (context *EVMHooksImpl) GasPrice() *big.Int {
+ return new(big.Int).SetUint64(context.GetRuntimeContext().GetVMInput().GasPrice)
+}
+
+func (context *EVMHooksImpl) CallerMvxAddress() []byte {
+ return context.GetRuntimeContext().GetVMInput().CallerAddr
+}
+
+func (context *EVMHooksImpl) CallerAddress() common.Address {
+ return context.toEVMAddress(context.CallerMvxAddress())
+}
+
+func (context *EVMHooksImpl) CallValue() *uint256.Int {
+ return uint256.MustFromBig(context.GetRuntimeContext().GetVMInput().CallValue)
+}
+
+func (context *EVMHooksImpl) ContractMvxAddress() []byte {
+ return context.GetRuntimeContext().GetContextAddress()
+}
+
+func (context *EVMHooksImpl) ContractAddress() common.Address {
+ return context.toEVMAddress(context.ContractMvxAddress())
+}
+
+func (context *EVMHooksImpl) ContractAliasAddress() common.Address {
+ return common.BytesToAddress(context.GetRuntimeContext().GetVMInput().RecipientAliasAddr)
+}
+
+func (context *EVMHooksImpl) Arguments() [][]byte {
+ return context.GetRuntimeContext().Arguments()
+}
+
+func (context *EVMHooksImpl) CodeHash() common.Hash {
+ return common.BytesToHash(context.GetRuntimeContext().GetSCCodeHash())
+}
diff --git a/vmhost/evmhooks/evmStorageHooks.go b/vmhost/evmhooks/evmStorageHooks.go
new file mode 100644
index 000000000..2dff34313
--- /dev/null
+++ b/vmhost/evmhooks/evmStorageHooks.go
@@ -0,0 +1,40 @@
+package evmhooks
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+)
+
+const getState = "getState"
+
+func (context *EVMHooksImpl) GetState(key common.Hash) common.Hash {
+ value, trieDepth, usedCache, err := context.GetStorageContext().GetStorage(key.Bytes())
+ if err != nil {
+ context.FailExecution(err)
+ return common.Hash{}
+ }
+
+ loadCost := context.GetMeteringContext().GasSchedule().EVMOpcodeCost.Sload
+ err = context.GetStorageContext().UseGasForStorageLoad(getState, int64(trieDepth), loadCost, usedCache)
+ if err != nil {
+ context.FailExecution(err)
+ return common.Hash{}
+ }
+
+ return common.BytesToHash(value)
+}
+
+func (context *EVMHooksImpl) SetState(key common.Hash, value common.Hash) {
+ _, err := context.GetStorageContext().SetStorage(key.Bytes(), trimValue(value))
+ if err != nil {
+ context.FailExecution(err)
+ }
+}
+
+func trimValue(hash common.Hash) []byte {
+ for currentPosition, currentByte := range hash {
+ if currentByte != 0 {
+ return hash.Bytes()[currentPosition:]
+ }
+ }
+ return make([]byte, 0)
+}
diff --git a/vmhost/evmhooks/nonEvmCallEncoder.go b/vmhost/evmhooks/nonEvmCallEncoder.go
new file mode 100644
index 000000000..e333b7065
--- /dev/null
+++ b/vmhost/evmhooks/nonEvmCallEncoder.go
@@ -0,0 +1,47 @@
+package evmhooks
+
+import (
+ "encoding/binary"
+)
+
+const lengthPrefixSize = 4
+
+func lengthPrefixEncode(arguments [][]byte) []byte {
+ totalLength := 0
+ for _, argument := range arguments {
+ totalLength += lengthPrefixSize + len(argument)
+ }
+
+ currentOffset := 0
+ encoded := make([]byte, totalLength)
+ for _, argument := range arguments {
+ argumentStart := currentOffset + lengthPrefixSize
+ binary.BigEndian.PutUint32(encoded[currentOffset:argumentStart], uint32(len(argument)))
+ copy(encoded[argumentStart:], argument)
+ currentOffset = argumentStart + len(argument)
+ }
+ return encoded
+}
+
+func lengthPrefixDecode(encoded []byte) ([][]byte, error) {
+ currentOffset := 0
+ var arguments [][]byte
+ for currentOffset < len(encoded) {
+ argumentStart := currentOffset + lengthPrefixSize
+ if argumentStart > len(encoded) {
+ return nil, ErrInvalidEncodedData
+ }
+
+ length := binary.BigEndian.Uint32(encoded[currentOffset:argumentStart])
+ argumentEnd := argumentStart + int(length)
+ if argumentEnd > len(encoded) {
+ return nil, ErrInvalidEncodedData
+ }
+
+ currentArgument := encoded[argumentStart:argumentEnd]
+ arguments = append(arguments, currentArgument)
+
+ currentOffset = argumentEnd
+ }
+ return arguments, nil
+}
diff --git a/vmhost/hostCore/execution.go b/vmhost/hostCore/execution.go
index eb1bf9f21..5d91860df 100644
--- a/vmhost/hostCore/execution.go
+++ b/vmhost/hostCore/execution.go
@@ -52,13 +52,15 @@ func (host *vmHost) doRunSmartContractCreate(input *vmcommon.ContractCreateInput
metering.InitStateFromContractCallInput(&input.VMInput)
output.AddTxValueToAccount(address, input.CallValue)
+ output.SetIsCreatedInTransactionFlag(address)
storage.SetAddress(runtime.GetContextAddress())
codeDeployInput := vmhost.CodeDeployInput{
- ContractCode: input.ContractCode,
- ContractCodeMetadata: input.ContractCodeMetadata,
- ContractAddress: address,
- CodeDeployerAddress: input.CallerAddr,
+ ContractCode: input.ContractCode,
+ ContractCodeMetadata: input.ContractCodeMetadata,
+ ContractAddress: address,
+ CodeDeployerAddress: input.CallerAddr,
+ OmitDefaultCodeChanges: host.omitDefaultCodeChanges,
}
vmOutput, err = host.performCodeDeploymentAtContractCreate(codeDeployInput)
@@ -153,10 +155,11 @@ func (host *vmHost) doRunSmartContractUpgrade(input *vmcommon.ContractCallInput)
}
codeDeployInput := vmhost.CodeDeployInput{
- ContractCode: code,
- ContractCodeMetadata: codeMetadata,
- ContractAddress: input.RecipientAddr,
- CodeDeployerAddress: input.CallerAddr,
+ ContractCode: code,
+ ContractCodeMetadata: codeMetadata,
+ ContractAddress: input.RecipientAddr,
+ CodeDeployerAddress: input.CallerAddr,
+ OmitDefaultCodeChanges: host.omitDefaultCodeChanges,
}
vmOutput, err = host.performCodeDeploymentAtContractUpgrade(codeDeployInput)
@@ -570,7 +573,8 @@ func (host *vmHost) finishExecuteOnDestContext(executeErr error) *vmcommon.VMOut
// ExecuteOnSameContext executes the contract call with the given input
// on the same runtime context. Some other contexts are backed up.
-func (host *vmHost) ExecuteOnSameContext(input *vmcommon.ContractCallInput) error {
+func (host *vmHost) ExecuteOnSameContext(sameContextCallInput *vmcommon.ContractSameContextCallInput) error {
+ input := &sameContextCallInput.ContractCallInput
log.Trace("ExecuteOnSameContext", "function", input.Function)
if host.IsBuiltinFunctionName(input.Function) {
@@ -585,14 +589,10 @@ func (host *vmHost) ExecuteOnSameContext(input *vmcommon.ContractCallInput) erro
managedTypes.InitState()
output.PushState()
- librarySCAddress := make([]byte, len(input.RecipientAddr))
- copy(librarySCAddress, input.RecipientAddr)
-
- input.RecipientAddr = input.CallerAddr
copyTxHashesFromContext(runtime, input)
runtime.PushState()
runtime.InitStateFromContractCallInput(input)
- runtime.SetCodeAddress(librarySCAddress)
+ runtime.SetCodeAddress(sameContextCallInput.CodeAddress)
metering.PushState()
metering.InitStateFromContractCallInput(&input.VMInput)
@@ -601,14 +601,18 @@ func (host *vmHost) ExecuteOnSameContext(input *vmcommon.ContractCallInput) erro
var err error
- defer host.finishExecuteOnSameContext(err)
+ defer func() {
+ host.finishExecuteOnSameContext(err)
+ }()
- // Perform a value transfer to the called SC. If the execution fails, this
- // transfer will not persist.
- err = output.TransferValueOnly(input.RecipientAddr, input.CallerAddr, input.CallValue, false)
- if err != nil {
- runtime.AddError(err, input.Function)
- return err
+ if sameContextCallInput.DoTransfer {
+ // Perform a value transfer to the called SC. If the execution fails, this
+ // transfer will not persist.
+ err = output.TransferValueOnly(input.RecipientAddr, input.CallerAddr, input.CallValue, false)
+ if err != nil {
+ runtime.AddError(err, input.Function)
+ return err
+ }
}
output.WriteLogWithIdentifier(
input.CallerAddr,
@@ -699,15 +703,17 @@ func (host *vmHost) CreateNewContract(input *vmcommon.ContractCreateInput, creat
_, blockchain, metering, output, runtime, _, _ := host.GetContexts()
codeDeployInput := vmhost.CodeDeployInput{
- ContractCode: input.ContractCode,
- ContractCodeMetadata: input.ContractCodeMetadata,
- ContractAddress: nil,
- CodeDeployerAddress: input.CallerAddr,
+ ContractCode: input.ContractCode,
+ ContractCodeMetadata: input.ContractCodeMetadata,
+ ContractAddress: nil,
+ CodeDeployerAddress: input.CallerAddr,
+ OmitDefaultCodeChanges: false,
}
- err = metering.DeductInitialGasForIndirectDeployment(codeDeployInput)
+ initialCost, err := metering.DeductInitialGasForIndirectDeployment(codeDeployInput)
if err != nil {
return
}
+ input.GasProvided -= initialCost
if runtime.ReadOnly() {
err = vmhost.ErrInvalidCallOnReadOnlyMode
@@ -726,6 +732,7 @@ func (host *vmHost) CreateNewContract(input *vmcommon.ContractCreateInput, creat
codeDeployInput.ContractAddress = newContractAddress
output.DeployCode(codeDeployInput)
+ output.SetIsCreatedInTransactionFlag(newContractAddress)
defer func() {
if err != nil {
@@ -736,10 +743,11 @@ func (host *vmHost) CreateNewContract(input *vmcommon.ContractCreateInput, creat
runtime.MustVerifyNextContractCode()
initCallInput := &vmcommon.ContractCallInput{
- RecipientAddr: newContractAddress,
- Function: vmhost.InitFunctionName,
- AllowInitFunction: true,
- VMInput: input.VMInput,
+ RecipientAddr: newContractAddress,
+ RecipientAliasAddr: input.AliasAddress,
+ Function: vmhost.InitFunctionName,
+ AllowInitFunction: true,
+ VMInput: input.VMInput,
}
var isChildComplete bool
@@ -803,10 +811,11 @@ func (host *vmHost) executeUpgrade(input *vmcommon.ContractCallInput) error {
}
codeDeployInput := vmhost.CodeDeployInput{
- ContractCode: code,
- ContractCodeMetadata: codeMetadata,
- ContractAddress: input.RecipientAddr,
- CodeDeployerAddress: input.CallerAddr,
+ ContractCode: code,
+ ContractCodeMetadata: codeMetadata,
+ ContractAddress: input.RecipientAddr,
+ CodeDeployerAddress: input.CallerAddr,
+ OmitDefaultCodeChanges: host.omitDefaultCodeChanges,
}
err = metering.DeductInitialGasForDirectDeployment(codeDeployInput)
diff --git a/vmhost/hostCore/host.go b/vmhost/hostCore/host.go
index b2a3fdffc..dccf48721 100644
--- a/vmhost/hostCore/host.go
+++ b/vmhost/hostCore/host.go
@@ -2,6 +2,7 @@ package hostCore
import (
"context"
+ "github.com/multiversx/mx-chain-vm-go/vmhost/evmhooks"
"math"
"runtime/debug"
"sync"
@@ -74,6 +75,8 @@ type vmHost struct {
transferLogIdentifiers map[string]bool
mapOpcodeAddressIsAllowed map[string]map[string]struct{}
+
+ omitDefaultCodeChanges bool
}
// NewVMHost creates a new VM vmHost
@@ -133,13 +136,14 @@ func NewVMHost(
executionTimeout: minExecutionTimeout,
enableEpochsHandler: hostParameters.EnableEpochsHandler,
mapOpcodeAddressIsAllowed: hostParameters.MapOpcodeAddressIsAllowed,
+ omitDefaultCodeChanges: hostParameters.OmitDefaultCodeChanges,
}
newExecutionTimeout := time.Duration(hostParameters.TimeOutForSCExecutionInMilliseconds) * time.Millisecond
if newExecutionTimeout > minExecutionTimeout {
host.executionTimeout = newExecutionTimeout
}
- host.blockchainContext, err = contexts.NewBlockchainContext(host, blockChainHook)
+ host.blockchainContext, err = contexts.NewBlockchainContext(host, blockChainHook, hostParameters.UsePseudoAddresses)
if err != nil {
return nil, err
}
@@ -155,6 +159,7 @@ func NewVMHost(
host.builtInFuncContainer,
vmExecutor,
hostParameters.Hasher,
+ hostParameters.OmitFunctionNameChecks,
)
if err != nil {
return nil, err
@@ -205,6 +210,7 @@ func NewVMHost(
// Creates a new executor instance. Should only be called once per VM host instantiation.
func (host *vmHost) createExecutor(hostParameters *vmhost.VMHostParameters) (executor.Executor, error) {
+ evmHooks := evmhooks.NewEVMHooksImpl(host)
vmHooks := vmhooks.NewVMHooksImpl(host)
gasCostConfig, err := config.CreateGasConfig(host.gasSchedule)
if err != nil {
@@ -218,9 +224,11 @@ func (host *vmHost) createExecutor(hostParameters *vmhost.VMHostParameters) (exe
} else {
vmExecutorFactory = wasmer2.ExecutorFactory()
}
+ opcodeCosts := executor.VMOpcodeCost{EVMOpcodeCost: gasCostConfig.EVMOpcodeCost, WASMOpcodeCost: gasCostConfig.WASMOpcodeCost}
vmExecutorFactoryArgs := executor.ExecutorFactoryArgs{
+ EvmHooks: evmHooks,
VMHooks: vmHooks,
- OpcodeCosts: gasCostConfig.WASMOpcodeCost,
+ OpcodeCosts: opcodeCosts,
RkyvSerializationEnabled: true,
WasmerSIGSEGVPassthrough: hostParameters.WasmerSIGSEGVPassthrough,
}
@@ -358,7 +366,8 @@ func (host *vmHost) GasScheduleChange(newGasSchedule config.GasScheduleMap) {
return
}
- host.runtimeContext.GetVMExecutor().SetOpcodeCosts(gasCostConfig.WASMOpcodeCost)
+ opcodeCosts := executor.VMOpcodeCost{EVMOpcodeCost: gasCostConfig.EVMOpcodeCost, WASMOpcodeCost: gasCostConfig.WASMOpcodeCost}
+ host.runtimeContext.GetVMExecutor().SetOpcodeCosts(opcodeCosts)
host.meteringContext.SetGasSchedule(newGasSchedule)
host.runtimeContext.ClearWarmInstanceCache()
diff --git a/vmhost/hosttest/contracts_deploy_test.go b/vmhost/hosttest/contracts_deploy_test.go
index ee8c5dc1f..e16ab70ee 100644
--- a/vmhost/hosttest/contracts_deploy_test.go
+++ b/vmhost/hosttest/contracts_deploy_test.go
@@ -46,11 +46,13 @@ func TestDeployFromSource_Success(t *testing.T) {
deployedCodeLen := uint64(len(deployedCode))
runDeployFromSourceTest(t, &testConfig, func(world *worldmock.MockWorld, verify *test.VMOutputVerifier) {
newContractAddress := verify.VmOutput.ReturnData[0]
+ parentCodeLen := uint64(len(test.ParentAddress))
verify.
Ok().
Code(newContractAddress, deployedCode).
GasRemaining(testConfig.GasProvided -
testConfig.GasUsedByInit -
+ parentCodeLen*testConfig.AoTPreparePerByteCost -
deployedCodeLen*testConfig.CompilePerByteCost -
deployedCodeLen*testConfig.AoTPreparePerByteCost)
})
diff --git a/vmhost/hosttest/execution_test.go b/vmhost/hosttest/execution_test.go
index a0121545b..a1a4e9c07 100644
--- a/vmhost/hosttest/execution_test.go
+++ b/vmhost/hosttest/execution_test.go
@@ -3085,11 +3085,13 @@ func TestExecution_CreateNewContract_Success(t *testing.T) {
childCode := test.GetTestSCCode("init-correct", "../../")
childAddress := []byte("newAddress")
l := len(childCode)
+ parentCodeCost := uint64(0)
+ parentCode := test.GetTestSCCode("deployer", "../../")
test.BuildInstanceCallTest(t).
WithContracts(
test.CreateInstanceContract(test.ParentAddress).
- WithCode(test.GetTestSCCode("deployer", "../../")).
+ WithCode(parentCode).
WithBalance(1000),
).
WithInput(test.CreateTestContractCallInputBuilder().
@@ -3100,6 +3102,8 @@ func TestExecution_CreateNewContract_Success(t *testing.T) {
WithCurrentTxHash([]byte("txhash")).
Build()).
WithSetup(func(host vmhost.VMHost, stubBlockchainHook *contextmock.BlockchainHookStub) {
+ gasSchedule := host.Metering().GasSchedule()
+ parentCodeCost = uint64(len(parentCode))*gasSchedule.BaseOperationCost.AoTPreparePerByte + gasSchedule.BaseOperationCost.GetCode
stubBlockchainHook.GetStorageDataCalled = func(address []byte, key []byte) ([]byte, uint32, error) {
if bytes.Equal(address, test.ParentAddress) {
if bytes.Equal(key, []byte{'A'}) {
@@ -3113,8 +3117,8 @@ func TestExecution_CreateNewContract_Success(t *testing.T) {
AndAssertResults(func(host vmhost.VMHost, stubBlockchainHook *contextmock.BlockchainHookStub, verify *test.VMOutputVerifier) {
verify.Ok().
Balance(test.ParentAddress, 1000).
- GasUsed(test.ParentAddress, 16395).
- GasRemaining(983015).
+ GasUsed(test.ParentAddress, 16395+parentCodeCost).
+ GasRemaining(983015-parentCodeCost).
BalanceDelta(childAddress, 42).
Code(childAddress, childCode).
CodeMetadata(childAddress, []byte{1, 0}).
diff --git a/vmhost/interface.go b/vmhost/interface.go
index 1f12afbfa..435294e73 100644
--- a/vmhost/interface.go
+++ b/vmhost/interface.go
@@ -44,8 +44,9 @@ type VMHost interface {
ExecuteESDTTransfer(transfersArgs *ESDTTransfersArgs, callType vm.CallType) (*vmcommon.VMOutput, uint64, error)
CreateNewContract(input *vmcommon.ContractCreateInput, createContractCallType int) ([]byte, error)
- ExecuteOnSameContext(input *vmcommon.ContractCallInput) error
+ ExecuteOnSameContext(input *vmcommon.ContractSameContextCallInput) error
ExecuteOnDestContext(input *vmcommon.ContractCallInput) (*vmcommon.VMOutput, bool, error)
+ IsOutOfVMFunctionExecution(input *vmcommon.ContractCallInput) bool
IsBuiltinFunctionName(functionName string) bool
IsBuiltinFunctionCall(data []byte) bool
AreInSameShard(leftAddress []byte, rightAddress []byte) bool
@@ -69,11 +70,13 @@ type VMHost interface {
type BlockchainContext interface {
StateStack
+ GetNonceForNewAddress(creatorAddress []byte) (uint64, error)
NewAddress(creatorAddress []byte) ([]byte, error)
AccountExists(addr []byte) bool
GetBalance(addr []byte) []byte
GetBalanceBigInt(addr []byte) *big.Int
GetNonce(addr []byte) (uint64, error)
+ ChainID() []byte
CurrentEpoch() uint32
GetStateRootHash() []byte
LastTimeStamp() uint64
@@ -111,6 +114,8 @@ type BlockchainContext interface {
RevertToSnapshot(snapshot int)
ClearCompiledCodes()
ExecuteSmartContractCallOnOtherVM(input *vmcommon.ContractCallInput) (*vmcommon.VMOutput, error)
+ SaveAliasAddress(request *vmcommon.AliasSaveRequest) error
+ RequestAddress(request *vmcommon.AddressRequest) (*vmcommon.AddressResponse, error)
}
// RuntimeContext defines the functionality needed for interacting with the runtime context
@@ -126,8 +131,12 @@ type RuntimeContext interface {
GetContextAddress() []byte
GetOriginalCallerAddress() []byte
SetCodeAddress(scAddress []byte)
+ ComputeCodeHash(contract []byte) []byte
+ SetTrackerCode(contract []byte)
GetSCCode() ([]byte, error)
GetSCCodeSize() uint64
+ GetSCCodeHash() []byte
+ SaveCompiledCode()
GetVMType() []byte
FunctionName() string
Arguments() [][]byte
@@ -236,6 +245,7 @@ type OutputContext interface {
GetOutputAccount(address []byte) (*vmcommon.OutputAccount, bool)
GetOutputAccounts() map[string]*vmcommon.OutputAccount
+ DeleteAccount(address []byte)
DeleteOutputAccount(address []byte)
WriteLog(address []byte, topics [][]byte, data [][]byte)
WriteLogWithIdentifier(address []byte, topics [][]byte, data [][]byte, identifier []byte)
@@ -258,6 +268,8 @@ type OutputContext interface {
RemoveNonUpdatedStorage()
AddTxValueToAccount(address []byte, value *big.Int)
DeployCode(input CodeDeployInput)
+ ChangeAccountCode(address []byte, contract []byte)
+ SetIsCreatedInTransactionFlag(address []byte)
CreateVMOutputInCaseOfError(err error) *vmcommon.VMOutput
NextOutputTransferIndex() uint32
GetCrtTransferIndex() uint32
@@ -286,7 +298,7 @@ type MeteringContext interface {
BlockGasLimit() uint64
DeductInitialGasForExecution(contract []byte) error
DeductInitialGasForDirectDeployment(input CodeDeployInput) error
- DeductInitialGasForIndirectDeployment(input CodeDeployInput) error
+ DeductInitialGasForIndirectDeployment(input CodeDeployInput) (uint64, error)
ComputeExtraGasLockedForAsync() uint64
UseGasForAsyncStep() error
UseGasBounded(gasToUse uint64) error
diff --git a/vmhost/mock/blockchainContextMock.go b/vmhost/mock/blockchainContextMock.go
index 7310c83e4..6b858fb2e 100644
--- a/vmhost/mock/blockchainContextMock.go
+++ b/vmhost/mock/blockchainContextMock.go
@@ -35,6 +35,11 @@ func (b *BlockchainContextMock) PopDiscard() {
func (b *BlockchainContextMock) ClearStateStack() {
}
+// GetNonceForNewAddress -
+func (b *BlockchainContextMock) GetNonceForNewAddress(_ []byte) (uint64, error) {
+ return 0, nil
+}
+
// NewAddress -
func (b *BlockchainContextMock) NewAddress(creatorAddress []byte) ([]byte, error) {
return creatorAddress, nil
@@ -60,6 +65,11 @@ func (b *BlockchainContextMock) GetNonce(_ []byte) (uint64, error) {
return 0, nil
}
+// ChainID -
+func (b *BlockchainContextMock) ChainID() []byte {
+ return make([]byte, 0)
+}
+
// CurrentEpoch -
func (b *BlockchainContextMock) CurrentEpoch() uint32 {
return 0
@@ -240,3 +250,13 @@ func (b *BlockchainContextMock) ClearCompiledCodes() {
func (b *BlockchainContextMock) ExecuteSmartContractCallOnOtherVM(input *vmcommon.ContractCallInput) (*vmcommon.VMOutput, error) {
return nil, nil
}
+
+// SaveAliasAddress -
+func (b *BlockchainContextMock) SaveAliasAddress(_ *vmcommon.AliasSaveRequest) error {
+ return nil
+}
+
+// RequestAddress -
+func (b *BlockchainContextMock) RequestAddress(_ *vmcommon.AddressRequest) (*vmcommon.AddressResponse, error) {
+ return nil, nil
+}
diff --git a/vmhost/vmhooks/baseOps.go b/vmhost/vmhooks/baseOps.go
index c2e1f2aa8..ac82ef1df 100644
--- a/vmhost/vmhooks/baseOps.go
+++ b/vmhost/vmhooks/baseOps.go
@@ -13,6 +13,7 @@ import (
logger "github.com/multiversx/mx-chain-logger-go"
vmcommon "github.com/multiversx/mx-chain-vm-common-go"
"github.com/multiversx/mx-chain-vm-common-go/parsers"
+
"github.com/multiversx/mx-chain-vm-go/executor"
"github.com/multiversx/mx-chain-vm-go/math"
"github.com/multiversx/mx-chain-vm-go/vmhost"
@@ -3141,7 +3142,28 @@ func ExecuteOnSameContextWithTypedArgs(
}
sender := runtime.GetContextAddress()
+ result, err := ExecuteOnSameContextUnmetered(host, gasLimit, value, function, sender, args, sender, gasToUse, dest, true)
+ if err != nil {
+ FailExecution(host, err)
+ return -1
+ }
+ return result
+}
+
+// ExecuteOnSameContextUnmetered - executeOnSameContext unmetered
+func ExecuteOnSameContextUnmetered(
+ host vmhost.VMHost,
+ gasLimit int64,
+ value *big.Int,
+ function []byte,
+ dest []byte,
+ args [][]byte,
+ sender []byte,
+ gasToUse uint64,
+ codeAddress []byte,
+ doTransfer bool,
+) (int32, error) {
contractCallInput, err := prepareIndirectContractCallInput(
host,
sender,
@@ -3154,22 +3176,24 @@ func ExecuteOnSameContextWithTypedArgs(
true,
)
if err != nil {
- FailExecution(host, err)
- return -1
+ return -1, err
}
if host.IsBuiltinFunctionName(contractCallInput.Function) {
- FailExecution(host, vmhost.ErrInvalidBuiltInFunctionCall)
- return 1
+ return 1, err
}
- err = host.ExecuteOnSameContext(contractCallInput)
+ sameContextInput := vmcommon.ContractSameContextCallInput{
+ ContractCallInput: *contractCallInput,
+ DoTransfer: doTransfer,
+ CodeAddress: codeAddress,
+ }
+ err = host.ExecuteOnSameContext(&sameContextInput)
if err != nil {
- FailExecution(host, err)
- return -1
+ return -1, err
}
- return 0
+ return 0, nil
}
// ExecuteOnDestContext VMHooks implementation.
@@ -3252,6 +3276,28 @@ func ExecuteOnDestContextWithTypedArgs(
return -1
}
+ result, err := ExecuteOnDestContextUnmetered(host, gasLimit, value, function, dest, args, gasToUse, failExecution)
+ if err != nil {
+ FailExecution(host, err)
+ return 1
+ }
+
+ return result
+}
+
+// ExecuteOnDestContextUnmetered - executeOnDestContext unmetered
+func ExecuteOnDestContextUnmetered(
+ host vmhost.VMHost,
+ gasLimit int64,
+ value *big.Int,
+ function []byte,
+ dest []byte,
+ args [][]byte,
+ gasToUse uint64,
+ failExecution bool,
+) (int32, error) {
+ runtime := host.Runtime()
+
sender := runtime.GetContextAddress()
contractCallInput, err := prepareIndirectContractCallInput(
@@ -3266,22 +3312,21 @@ func ExecuteOnDestContextWithTypedArgs(
true,
)
if err != nil {
- FailExecution(host, err)
- return 1
+ return 1, err
}
vmOutput, err := executeOnDestContextFromAPI(host, contractCallInput)
if err != nil {
if vmOutput == nil || failExecution {
- FailExecution(host, err)
+ return 1, err
}
- return 1
+ return 1, nil
}
host.CompleteLogEntriesWithCallType(vmOutput, vmhost.ExecuteOnDestContextString)
- return 0
+ return 0, nil
}
// ExecuteReadOnly VMHooks implementation.
@@ -3347,7 +3392,6 @@ func ExecuteReadOnlyWithTypedArguments(
dest []byte,
args [][]byte,
) int32 {
- runtime := host.Runtime()
metering := host.Metering()
gasToUse := metering.GasSchedule().BaseOpsAPICost.ExecuteReadOnly
@@ -3357,6 +3401,26 @@ func ExecuteReadOnlyWithTypedArguments(
return -1
}
+ result, err := ExecuteReadOnlyUnmetered(host, gasLimit, function, dest, args, gasToUse)
+ if err != nil {
+ FailExecution(host, err)
+ return -1
+ }
+
+ return result
+}
+
+// ExecuteReadOnlyUnmetered - executeReadOnly unmetered
+func ExecuteReadOnlyUnmetered(
+ host vmhost.VMHost,
+ gasLimit int64,
+ function []byte,
+ dest []byte,
+ args [][]byte,
+ gasToUse uint64,
+) (int32, error) {
+ runtime := host.Runtime()
+
sender := runtime.GetContextAddress()
contractCallInput, err := prepareIndirectContractCallInput(
@@ -3371,13 +3435,11 @@ func ExecuteReadOnlyWithTypedArguments(
true,
)
if err != nil {
- FailExecution(host, err)
- return -1
+ return -1, err
}
if host.IsBuiltinFunctionName(contractCallInput.Function) {
- FailExecution(host, vmhost.ErrInvalidBuiltInFunctionCall)
- return 1
+ return 1, vmhost.ErrInvalidBuiltInFunctionCall
}
wasReadOnly := runtime.ReadOnly()
@@ -3386,11 +3448,10 @@ func ExecuteReadOnlyWithTypedArguments(
runtime.SetReadOnly(wasReadOnly)
if err != nil {
- FailExecution(host, err)
- return -1
+ return -1, err
}
- return 0
+ return 0, nil
}
// CreateContract VMHooks implementation.
@@ -3613,6 +3674,20 @@ func createContract(
codeMetadata []byte,
host vmhost.VMHost,
createContractCallType CreateContractCallType,
+) ([]byte, error) {
+ return CreateContractWithAddress(sender, data, value, gasLimit, code, codeMetadata, host, createContractCallType, nil)
+}
+
+func CreateContractWithAddress(
+ sender []byte,
+ data [][]byte,
+ value *big.Int,
+ gasLimit int64,
+ code []byte,
+ codeMetadata []byte,
+ host vmhost.VMHost,
+ createContractCallType CreateContractCallType,
+ aliasAddress []byte,
) ([]byte, error) {
originalCaller := host.Runtime().GetOriginalCallerAddress()
metering := host.Metering()
@@ -3625,6 +3700,7 @@ func createContract(
GasPrice: 0,
GasProvided: metering.BoundGasLimit(gasLimit),
},
+ AliasAddress: aliasAddress,
ContractCode: code,
ContractCodeMetadata: codeMetadata,
}
diff --git a/vmhost/vmhooks/generate/cmd/eiGenMain.go b/vmhost/vmhooks/generate/cmd/eiGenMain.go
index 7a8cbb682..0e8672e6e 100644
--- a/vmhost/vmhooks/generate/cmd/eiGenMain.go
+++ b/vmhost/vmhooks/generate/cmd/eiGenMain.go
@@ -64,9 +64,13 @@ func main() {
fmt.Printf("Generated code for %d executor callback methods.\n", len(eiMetadata.AllFunctions))
writeExecutorOpcodeCosts()
+ writeEVMExecutorOpcodeCosts()
writeWasmer2OpcodeCost()
+ writeEVMOpcodeCost()
writeWASMOpcodeCostFuncHelpers()
+ writeEVMOpcodeCostFuncHelpers()
writeWASMOpcodeCostConfigHelpers()
+ writeEVMOpcodeCostConfigHelpers()
writeOpcodeCostFuncHelpers()
writeRustOpcodeCost()
writeRustWasmerMeteringHelpers()
@@ -179,24 +183,48 @@ func writeExecutorOpcodeCosts() {
eapigen.WriteExecutorOpcodeCost(out)
}
+func writeEVMExecutorOpcodeCosts() {
+ out := eapigen.NewEIGenWriter(pathToApiPackage, "../../executor/gasCostEVM.go")
+ defer out.Close()
+ eapigen.WriteEVMExecutorOpcodeCost(out)
+}
+
func writeWASMOpcodeCostFuncHelpers() {
out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/FillGasMap_WASMOpcodeCosts.txt")
defer out.Close()
eapigen.WriteWASMOpcodeCostFuncHelpers(out)
}
+func writeEVMOpcodeCostFuncHelpers() {
+ out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/FillGasMap_EVMOpcodeCosts.txt")
+ defer out.Close()
+ eapigen.WriteEVMOpcodeCostFuncHelpers(out)
+}
+
func writeWASMOpcodeCostConfigHelpers() {
out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/config.txt")
defer out.Close()
eapigen.WriteWASMOpcodeCostConfigHelpers(out)
}
+func writeEVMOpcodeCostConfigHelpers() {
+ out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/evm_config.txt")
+ defer out.Close()
+ eapigen.WriteEVMOpcodeCostConfigHelpers(out)
+}
+
func writeWasmer2OpcodeCost() {
out := eapigen.NewEIGenWriter(pathToApiPackage, "../../wasmer2/opcodeCost.go")
defer out.Close()
eapigen.WriteWasmer2OpcodeCost(out)
}
+func writeEVMOpcodeCost() {
+ out := eapigen.NewEIGenWriter(pathToApiPackage, "../../evm/interpreter/gas_config.go")
+ defer out.Close()
+ eapigen.WriteEVMOpcodeCost(out)
+}
+
func writeOpcodeCostFuncHelpers() {
out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/extractOpcodeCost.txt")
defer out.Close()
diff --git a/vmhost/vmhooks/generate/cmd/input/evm_opcodes.txt b/vmhost/vmhooks/generate/cmd/input/evm_opcodes.txt
new file mode 100644
index 000000000..44e401974
--- /dev/null
+++ b/vmhost/vmhooks/generate/cmd/input/evm_opcodes.txt
@@ -0,0 +1,41 @@
+QuickStep
+FastestStep
+FastStep
+MidStep
+SlowStep
+ExtStep
+Ecrecover
+Sha256PerWord
+Sha256Base
+Ripemd160PerWord
+Ripemd160Base
+IdentityPerWord
+IdentityBase
+Bn256Add
+Bn256ScalarMul
+Bn256PairingBase
+Bn256PairingPerPoint
+BlobTxPointEvaluation
+Keccak256
+Balance
+ExtcodeSize
+ExtcodeCopy
+ExtcodeHash
+Sload
+Sstore
+Jumpdest
+Tload
+Tstore
+Create
+Call
+Create2
+Selfdestruct
+Memory
+Copy
+Log
+LogTopic
+LogData
+Keccak256Word
+InitCodeWord
+ExpByte
+Exp
diff --git a/vmhost/vmhooks/generate/eiGenWriteEVMOpcodeCost.go b/vmhost/vmhooks/generate/eiGenWriteEVMOpcodeCost.go
new file mode 100644
index 000000000..6bebcaa65
--- /dev/null
+++ b/vmhost/vmhooks/generate/eiGenWriteEVMOpcodeCost.go
@@ -0,0 +1,35 @@
+package vmhooksgenerate
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+)
+
+// WriteEVMExecutorOpcodeCost generates code for executor/gasCostEVM.go
+func WriteEVMExecutorOpcodeCost(out *eiGenWriter) {
+ out.WriteString(`// Code generated by vmhooks generator. DO NOT EDIT.
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!! AUTO-GENERATED FILE !!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+`)
+ out.WriteString("package executor\n\n")
+ out.WriteString("type EVMOpcodeCost struct {\n")
+
+ readFile, err := os.Open("generate/cmd/input/evm_opcodes.txt")
+ if err != nil {
+ panic(err)
+ }
+ defer readFile.Close()
+
+ fileScanner := bufio.NewScanner(readFile)
+ fileScanner.Split(bufio.ScanLines)
+
+ for fileScanner.Scan() {
+ opcode := fileScanner.Text()
+ out.WriteString(fmt.Sprintf("\t%-30suint64\n", opcode))
+ }
+ out.WriteString("}\n")
+}
diff --git a/vmhost/vmhooks/generate/eiGenWriteEVMOpcodeCostConfigHelpers.go b/vmhost/vmhooks/generate/eiGenWriteEVMOpcodeCostConfigHelpers.go
new file mode 100644
index 000000000..df8cb51ca
--- /dev/null
+++ b/vmhost/vmhooks/generate/eiGenWriteEVMOpcodeCostConfigHelpers.go
@@ -0,0 +1,35 @@
+package vmhooksgenerate
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+)
+
+// WriteEVMOpcodeCostConfigHelpers generates code for config.txt
+// (to be copied manually in config/config.toml)
+func WriteEVMOpcodeCostConfigHelpers(out *eiGenWriter) {
+ out.WriteString(`// Code generated by vmhooks generator. DO NOT EDIT.
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!! AUTO-GENERATED FILE !!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+// !!!!!!!!!!!!!!!!!! USE IN config/config.toml !!!!!!!!!!!!!!!!!!!!
+
+`)
+ out.WriteString("[EVMOpcodeCost]\n")
+ readFile, err := os.Open("generate/cmd/input/evm_opcodes.txt")
+ if err != nil {
+ panic(err)
+ }
+ defer readFile.Close()
+
+ fileScanner := bufio.NewScanner(readFile)
+ fileScanner.Split(bufio.ScanLines)
+
+ for fileScanner.Scan() {
+ opcode := fileScanner.Text()
+ out.WriteString(fmt.Sprintf(" %s = 1\n", opcode))
+ }
+}
diff --git a/vmhost/vmhooks/generate/eiGenWriteEVMOpcodeCostFuncHelpers.go b/vmhost/vmhooks/generate/eiGenWriteEVMOpcodeCostFuncHelpers.go
new file mode 100644
index 000000000..14db7a6ed
--- /dev/null
+++ b/vmhost/vmhooks/generate/eiGenWriteEVMOpcodeCostFuncHelpers.go
@@ -0,0 +1,39 @@
+package vmhooksgenerate
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+)
+
+// WriteEVMOpcodeCostHelpers generates code for FillGasMap_EVMOpcodeCosts.txt
+// (to be copied manually in config/gasSchedule.go)
+func WriteEVMOpcodeCostFuncHelpers(out *eiGenWriter) {
+ out.WriteString(`// Code generated by vmhooks generator. DO NOT EDIT.
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!! AUTO-GENERATED FILE !!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+// !!!!!!!!!!!!!!!!!! USE IN config/gasSchedule.go !!!!!!!!!!!!!!!!!
+
+`)
+ out.WriteString("func FillGasMap_EVMOpcodeCosts(value uint64) map[string]uint64 {\n")
+ out.WriteString("\tgasMap := make(map[string]uint64)\n\n")
+
+ readFile, err := os.Open("generate/cmd/input/evm_opcodes.txt")
+ if err != nil {
+ panic(err)
+ }
+ defer readFile.Close()
+
+ fileScanner := bufio.NewScanner(readFile)
+ fileScanner.Split(bufio.ScanLines)
+
+ for fileScanner.Scan() {
+ opcode := fileScanner.Text()
+ out.WriteString(fmt.Sprintf("\tgasMap[\"%s\"] = value\n", opcode))
+ }
+ out.WriteString("\n\treturn gasMap\n")
+ out.WriteString("}\n")
+}
diff --git a/vmhost/vmhooks/generate/eiGenWriteEVMSpecificOpcodeCost.go b/vmhost/vmhooks/generate/eiGenWriteEVMSpecificOpcodeCost.go
new file mode 100644
index 000000000..b874d10c0
--- /dev/null
+++ b/vmhost/vmhooks/generate/eiGenWriteEVMSpecificOpcodeCost.go
@@ -0,0 +1,35 @@
+package vmhooksgenerate
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+)
+
+// WriteEVMOpcodeCost generates EVM code for evm/interpreter/gas_config.go
+func WriteEVMOpcodeCost(out *eiGenWriter) {
+ out.WriteString(`// Code generated by vmhooks generator. DO NOT EDIT.
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!! AUTO-GENERATED FILE !!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+`)
+ out.WriteString("package evm\n\n")
+ out.WriteString("type GasConfig struct {\n")
+
+ readFile, err := os.Open("generate/cmd/input/evm_opcodes.txt")
+ if err != nil {
+ panic(err)
+ }
+ defer readFile.Close()
+
+ fileScanner := bufio.NewScanner(readFile)
+ fileScanner.Split(bufio.ScanLines)
+
+ for fileScanner.Scan() {
+ opcode := fileScanner.Text()
+ out.WriteString(fmt.Sprintf("\t%-30suint64\n", opcode))
+ }
+ out.WriteString("}\n")
+}
diff --git a/wasmer2/wasmer2Executor.go b/wasmer2/wasmer2Executor.go
index 159b0d567..d3691fd8e 100644
--- a/wasmer2/wasmer2Executor.go
+++ b/wasmer2/wasmer2Executor.go
@@ -49,9 +49,9 @@ func CreateExecutor() (*Wasmer2Executor, error) {
}
// SetOpcodeCosts sets gas costs globally inside the Wasmer executor.
-func (wasmerExecutor *Wasmer2Executor) SetOpcodeCosts(wasmOps *executor.WASMOpcodeCost) {
+func (wasmerExecutor *Wasmer2Executor) SetOpcodeCosts(wasmOps executor.VMOpcodeCost) {
// extract only wasmer2 opcodes
- wasmerExecutor.opcodeCost = wasmerExecutor.extractOpcodeCost(wasmOps)
+ wasmerExecutor.opcodeCost = wasmerExecutor.extractOpcodeCost(wasmOps.WASMOpcodeCost)
cWasmerExecutorSetOpcodeCost(
wasmerExecutor.cgoExecutor,
(*cWasmerOpcodeCostT)(unsafe.Pointer(wasmerExecutor.opcodeCost)),
diff --git a/wasmer2/wasmer2ExecutorFactory.go b/wasmer2/wasmer2ExecutorFactory.go
index b3b28a549..c344e48de 100644
--- a/wasmer2/wasmer2ExecutorFactory.go
+++ b/wasmer2/wasmer2ExecutorFactory.go
@@ -25,7 +25,7 @@ func (wef *Wasmer2ExecutorFactory) CreateExecutor(args executor.ExecutorFactoryA
return nil, err
}
executor.initVMHooks(args.VMHooks)
- if args.OpcodeCosts != nil {
+ if args.OpcodeCosts.WASMOpcodeCost != nil {
// opcode costs are sometimes not initialized at this point in certain tests
executor.SetOpcodeCosts(args.OpcodeCosts)
}
diff --git a/wasmer2/wasmer2Instance.go b/wasmer2/wasmer2Instance.go
index bd904a7dd..2f88449ec 100644
--- a/wasmer2/wasmer2Instance.go
+++ b/wasmer2/wasmer2Instance.go
@@ -87,6 +87,11 @@ func (instance *Wasmer2Instance) GetBreakpointValue() uint64 {
return cWasmerInstanceGetBreakpointValue(instance.cgoInstance)
}
+// HasCompiledCode specifies if the code is compiled
+func (instance *Wasmer2Instance) HasCompiledCode() bool {
+ return true
+}
+
// Cache caches the instance
func (instance *Wasmer2Instance) Cache() ([]byte, error) {
var cacheBytes *cUchar