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