github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/core/wavm/runtime.go (about)

     1  // Copyright 2019 The go-vnt Authors
     2  // This file is part of the go-vnt library.
     3  //
     4  // The go-vnt library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-vnt library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-vnt library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package wavm
    18  
    19  import (
    20  	"bytes"
    21  	"errors"
    22  	"fmt"
    23  	"math/big"
    24  	"reflect"
    25  	"regexp"
    26  
    27  	"github.com/vntchain/go-vnt/accounts/abi"
    28  	"github.com/vntchain/go-vnt/common"
    29  	"github.com/vntchain/go-vnt/common/math"
    30  	mat "github.com/vntchain/go-vnt/common/math"
    31  	"github.com/vntchain/go-vnt/core/vm"
    32  	"github.com/vntchain/go-vnt/core/wavm/gas"
    33  	"github.com/vntchain/go-vnt/core/wavm/utils"
    34  	"github.com/vntchain/go-vnt/log"
    35  	"github.com/vntchain/vnt-wasm/exec"
    36  	"github.com/vntchain/vnt-wasm/validate"
    37  	"github.com/vntchain/vnt-wasm/vnt"
    38  	"github.com/vntchain/vnt-wasm/wasm"
    39  )
    40  
    41  const maximum_linear_memory = 33 * 1024 * 1024 //bytes
    42  const maximum_mutable_globals = 1024           //bytes
    43  const maximum_table_elements = 1024            //elements
    44  const maximum_linear_memory_init = 64 * 1024   //bytes
    45  const maximum_func_local_bytes = 8192          //bytes
    46  const wasm_page_size = 64 * 1024
    47  
    48  const kPageSize = 64 * 1024
    49  const AddressLength = 20
    50  
    51  const FallBackFunctionName = "Fallback"
    52  const FallBackPayableFunctionName = "$Fallback"
    53  
    54  type InvalidFunctionNameError string
    55  
    56  func (e InvalidFunctionNameError) Error() string {
    57  	return fmt.Sprintf("Exec wasm error: Invalid function name \"%s\"", string(e))
    58  }
    59  
    60  type InvalidPayableFunctionError string
    61  
    62  func (e InvalidPayableFunctionError) Error() string {
    63  	return fmt.Sprintf("Exec wasm error: Invalid payable function: %s", string(e))
    64  }
    65  
    66  type IllegalInputError string
    67  
    68  func (e IllegalInputError) Error() string {
    69  	return fmt.Sprintf("Exec wasm error: Illegal input")
    70  }
    71  
    72  type UnknownABITypeError string
    73  
    74  func (e UnknownABITypeError) Error() string {
    75  	return fmt.Sprintf("Exec wasm error: Unknown abi type \"%s\"", string(e))
    76  }
    77  
    78  type UnknownTypeError string
    79  
    80  func (e UnknownTypeError) Error() string {
    81  	return fmt.Sprintf("Exec wasm error: Unknown type")
    82  }
    83  
    84  type NoFunctionError string
    85  
    86  func (e NoFunctionError) Error() string {
    87  	return fmt.Sprintf("Exec wasm error: Can't find function %s in abi", string(e))
    88  }
    89  
    90  type MismatchMutableFunctionError struct {
    91  	parent  int
    92  	current int
    93  }
    94  
    95  func (e MismatchMutableFunctionError) Error() string {
    96  	parentStr := "unmutable"
    97  	if e.parent == 1 {
    98  		parentStr = "mutable"
    99  	}
   100  	currentStr := "unmutable"
   101  	if e.current == 1 {
   102  		currentStr = "mutable"
   103  	}
   104  	return fmt.Sprintf("Mismatch mutable type, parent function type : %s, current function type : %s", parentStr, currentStr)
   105  }
   106  
   107  type Wavm struct {
   108  	VM              *exec.Interpreter
   109  	Module          *wasm.Module
   110  	ChainContext    ChainContext
   111  	GasRules        gas.Gas
   112  	WavmConfig      Config
   113  	IsCreated       bool
   114  	currentFuncName string
   115  	MutableList     Mutable
   116  	tempGasLeft     uint64
   117  }
   118  
   119  // type InstanceContext struct {
   120  // 	memory *MemoryInstance
   121  // }
   122  
   123  func NewWavm(chainctx ChainContext, wavmConfig Config, iscreated bool) *Wavm {
   124  	return &Wavm{
   125  		ChainContext: chainctx,
   126  		WavmConfig:   wavmConfig,
   127  		IsCreated:    iscreated,
   128  	}
   129  }
   130  
   131  func (wavm *Wavm) ResolveImports(name string) (*wasm.Module, error) {
   132  	envModule := EnvModule{}
   133  	envModule.InitModule(&wavm.ChainContext)
   134  	return envModule.GetModule(), nil
   135  }
   136  
   137  func (wavm *Wavm) captureOp(pc uint64, op byte) error {
   138  	if wavm.WavmConfig.Debug {
   139  		wavm.Tracer().CaptureState(wavm.ChainContext.Wavm, pc, OpCode{Op: op}, wavm.ChainContext.Contract.Gas, 0, wavm.ChainContext.Contract, wavm.ChainContext.Wavm.depth, nil)
   140  	}
   141  	return nil
   142  }
   143  
   144  func (wavm *Wavm) captureEnvFunctionStart(pc uint64, funcName string) error {
   145  	wavm.tempGasLeft = wavm.ChainContext.Contract.Gas
   146  	return nil
   147  }
   148  
   149  func (wavm *Wavm) captureEnvFunctionEnd(pc uint64, funcName string) error {
   150  	if wavm.WavmConfig.Debug {
   151  		gas := wavm.tempGasLeft - wavm.ChainContext.Contract.Gas
   152  		wavm.Tracer().CaptureState(wavm.ChainContext.Wavm, pc, OpCode{FuncName: funcName}, wavm.ChainContext.Contract.Gas, gas, wavm.ChainContext.Contract, wavm.ChainContext.Wavm.depth, nil)
   153  	}
   154  	return nil
   155  }
   156  
   157  func (wavm *Wavm) captrueFault(pc uint64, err error) error {
   158  	if wavm.WavmConfig.Debug {
   159  		wavm.Tracer().CaptureState(wavm.ChainContext.Wavm, pc, OpCode{FuncName: "error"}, wavm.ChainContext.Contract.Gas, 0, wavm.ChainContext.Contract, wavm.ChainContext.Wavm.depth, err)
   160  	}
   161  	return nil
   162  }
   163  
   164  func (wavm *Wavm) Tracer() vm.Tracer {
   165  	return wavm.ChainContext.Wavm.wavmConfig.Tracer
   166  }
   167  
   168  func instantiateMemory(m *vnt.WavmMemory, module *wasm.Module) error {
   169  	if module.Data != nil {
   170  		var index int
   171  		for _, v := range module.Data.Entries {
   172  			expr, _ := module.ExecInitExpr(v.Offset)
   173  			offset, ok := expr.(int32)
   174  			if !ok {
   175  				return wasm.InvalidValueTypeInitExprError{Wanted: reflect.Int32, Got: reflect.TypeOf(offset).Kind()}
   176  			}
   177  			index = int(offset) + len(v.Data)
   178  			if bytes.Contains(v.Data, []byte{byte(0)}) {
   179  				split := bytes.Split(v.Data, []byte{byte(0)})
   180  				var tmpoffset = int(offset)
   181  				for _, tmp := range split {
   182  					tmplen := len(tmp)
   183  					b, res := utils.IsAddress(tmp)
   184  					if b == true {
   185  						tmp = common.HexToAddress(string(res)).Bytes()
   186  					}
   187  					b, res = utils.IsU256(tmp)
   188  					if b == true {
   189  
   190  						bigint := utils.GetU256(res)
   191  						tmp = []byte(bigint.String())
   192  					}
   193  					m.Set(uint64(tmpoffset), uint64(len(tmp)), tmp)
   194  					tmpoffset += tmplen + 1
   195  				}
   196  			} else {
   197  				m.Set(uint64(offset), uint64(len(v.Data)), v.Data)
   198  			}
   199  		}
   200  		m.Pos = index
   201  	} else {
   202  		m.Pos = 0
   203  	}
   204  	return nil
   205  }
   206  
   207  func (wavm *Wavm) InstantiateModule(code []byte, memory []uint8) error {
   208  	wasm.SetDebugMode(false)
   209  	buf := bytes.NewReader(code)
   210  	m, err := wasm.ReadModule(buf, wavm.ResolveImports)
   211  	if err != nil {
   212  		log.Error("could not read module", "err", err)
   213  		return err
   214  	}
   215  	if wavm.IsCreated == true {
   216  		err = validate.VerifyModule(m)
   217  		if err != nil {
   218  			log.Error("could not verify module", "err", err)
   219  			return err
   220  		}
   221  	}
   222  	if m.Export == nil {
   223  		log.Error("module has no export section", "export", "nil")
   224  		return errors.New("module has no export section")
   225  	}
   226  	wavm.Module = m
   227  	// m.PrintDetails()
   228  	return nil
   229  }
   230  
   231  func (wavm *Wavm) Apply(input []byte, compiled []vnt.Compiled, mutable Mutable) (res []byte, err error) {
   232  	// Catch all the panic and transform it into an error
   233  	defer func() {
   234  		if r := recover(); r != nil {
   235  			log.Error("Got error during wasm execution.", "err", r)
   236  			res = nil
   237  			err = fmt.Errorf("%s", r)
   238  			if wavm.WavmConfig.Debug == true {
   239  				if wavm.VM == nil {
   240  					wavm.captrueFault(uint64(0), err)
   241  				} else {
   242  					wavm.captrueFault(uint64(wavm.VM.Pc()), err)
   243  				}
   244  			}
   245  		}
   246  	}()
   247  	wavm.MutableList = mutable
   248  
   249  	//initialize the gas cost for initial memory when create contract before create Interpreter
   250  	//todo memory grow内存消耗
   251  	if wavm.ChainContext.IsCreated == true {
   252  		memSize := uint64(1)
   253  		if len(wavm.Module.Memory.Entries) != 0 {
   254  			memSize = uint64(wavm.Module.Memory.Entries[0].Limits.Initial)
   255  		}
   256  		wavm.ChainContext.GasCounter.GasInitialMemory(memSize)
   257  	}
   258  
   259  	var vm *exec.Interpreter
   260  	vm, err = exec.NewInterpreter(wavm.Module, compiled, instantiateMemory, wavm.captureOp, wavm.captureEnvFunctionStart, wavm.captureEnvFunctionEnd, wavm.WavmConfig.Debug)
   261  	if err != nil {
   262  		log.Error("Could not create VM: ", "error", err)
   263  		return nil, fmt.Errorf("Could not create VM: %s", err)
   264  	}
   265  
   266  	wavm.VM = vm
   267  	// gas := wavm.ChainContext.Contract.Gas
   268  	// adjustedGas := uint64(gas * exec.WasmCostsOpcodesDiv / exec.WasmCostsOpcodesMul)
   269  	// if adjustedGas > math.MaxUint64 {
   270  	// 	return nil, fmt.Errorf("Wasm interpreter cannot run contracts with gas (wasm adjusted) >= 2^64")
   271  	// }
   272  	//
   273  	// vm.Contract.Gas = adjustedGas
   274  
   275  	res, err = wavm.ExecCodeWithFuncName(input)
   276  	if err != nil {
   277  		return nil, err
   278  	}
   279  	return res, err
   280  }
   281  
   282  func (wavm *Wavm) GetFallBackFunction() (int64, string) {
   283  	index := int64(-1)
   284  	for name, e := range wavm.VM.Module().Export.Entries {
   285  		if name == FallBackFunctionName {
   286  			index = int64(e.Index)
   287  			return index, FallBackFunctionName
   288  		}
   289  		if name == FallBackPayableFunctionName {
   290  			index = int64(e.Index)
   291  			return index, FallBackPayableFunctionName
   292  		}
   293  	}
   294  	return index, ""
   295  }
   296  
   297  func (wavm *Wavm) ExecCodeWithFuncName(input []byte) ([]byte, error) {
   298  	wavm.ChainContext.Wavm.depth++
   299  	defer func() { wavm.ChainContext.Wavm.depth-- }()
   300  	index := int64(0)
   301  	matched := false
   302  	funcName := ""
   303  	VM := wavm.VM
   304  	module := VM.Module()
   305  	Abi := wavm.ChainContext.Abi
   306  	if wavm.ChainContext.IsCreated == true {
   307  		val := Abi.Constructor
   308  		for name, e := range module.Export.Entries {
   309  			if name == val.Name {
   310  				index = int64(e.Index)
   311  				funcName = val.Name
   312  				matched = true
   313  			}
   314  		}
   315  	} else {
   316  		//TODO: do optimization on function searching
   317  		if len(input) < 4 {
   318  			matched = false
   319  		} else {
   320  			sig := input[:4]
   321  			input = input[4:]
   322  			for name, e := range module.Export.Entries {
   323  				if val, ok := Abi.Methods[name]; ok {
   324  					res := val.Id()
   325  					if bytes.Equal(sig, res) {
   326  						matched = true
   327  						funcName = name
   328  						index = int64(e.Index)
   329  						break
   330  					}
   331  				}
   332  			}
   333  		}
   334  	}
   335  
   336  	if matched == false {
   337  		//查找是否有fallback方法
   338  		index, funcName = wavm.GetFallBackFunction()
   339  		if index == -1 {
   340  			return nil, InvalidFunctionNameError(funcName)
   341  		}
   342  	}
   343  
   344  	if wavm.payable(funcName) != true {
   345  		if wavm.ChainContext.Contract.Value().Cmp(new(big.Int).SetUint64(0)) > 0 {
   346  			return nil, InvalidPayableFunctionError(funcName)
   347  		}
   348  	}
   349  	wavm.currentFuncName = funcName
   350  	log.Debug("wavm", "exec function name", wavm.currentFuncName)
   351  	var method abi.Method
   352  	if wavm.ChainContext.IsCreated == true {
   353  		method = Abi.Constructor
   354  	} else {
   355  		method = Abi.Methods[funcName]
   356  	}
   357  	var args []uint64
   358  
   359  	// if funcName == InitFuntionName {
   360  	// 	input = vm.ChainContext.Input
   361  	// }
   362  
   363  	for i, v := range method.Inputs {
   364  		if len(input) < 32*(i+1) {
   365  			return nil, IllegalInputError("")
   366  		}
   367  		arg := input[(32 * i):(32 * (i + 1))]
   368  		switch v.Type.T {
   369  		case abi.StringTy: // variable arrays are written at the end of the return bytes
   370  			output := input[:]
   371  			begin, end, err := lengthPrefixPointsTo(i*32, output)
   372  			if err != nil {
   373  				return nil, err
   374  			}
   375  			value := output[begin : begin+end]
   376  			offset := VM.Memory.SetBytes(value)
   377  			VM.AddHeapPointer(uint64(len(value)))
   378  			args = append(args, uint64(offset))
   379  		case abi.IntTy, abi.UintTy:
   380  			a := readInteger(v.Type.Kind, arg)
   381  			val := reflect.ValueOf(a)
   382  			if val.Kind() == reflect.Ptr { //uint256
   383  				u256 := math.U256(a.(*big.Int))
   384  				value := []byte(u256.String())
   385  				// args = append(args, a.(uint64))
   386  				offset := VM.Memory.SetBytes(value)
   387  				VM.AddHeapPointer(uint64(len(value)))
   388  				args = append(args, uint64(offset))
   389  			} else {
   390  				args = append(args, a.(uint64))
   391  			}
   392  		case abi.BoolTy:
   393  			res, err := readBool(arg)
   394  			if err != nil {
   395  				return nil, err
   396  			}
   397  			args = append(args, res)
   398  		case abi.AddressTy:
   399  			addr := common.BytesToAddress(arg)
   400  			idx := VM.Memory.SetBytes(addr.Bytes())
   401  			VM.AddHeapPointer(uint64(len(addr.Bytes())))
   402  			args = append(args, uint64(idx))
   403  		default:
   404  			return nil, UnknownABITypeError(v.Type.String())
   405  		}
   406  	}
   407  	if wavm.ChainContext.IsCreated == true {
   408  		*VM.Mutable = true
   409  	} else if funcName == FallBackFunctionName || funcName == FallBackPayableFunctionName {
   410  		*VM.Mutable = true
   411  	} else {
   412  		if v, ok := wavm.MutableList[uint32(index)]; ok {
   413  			*VM.Mutable = v
   414  		} else {
   415  			*VM.Mutable = false
   416  		}
   417  	}
   418  	if wavm.ChainContext.Wavm.mutable == -1 {
   419  		if *VM.Mutable == true {
   420  			wavm.ChainContext.Wavm.mutable = 1
   421  		} else {
   422  			wavm.ChainContext.Wavm.mutable = 0
   423  		}
   424  	} else {
   425  		if wavm.ChainContext.Wavm.mutable == 0 && *VM.Mutable == true {
   426  			return nil, MismatchMutableFunctionError{0, 1}
   427  		}
   428  	}
   429  
   430  	res, err := VM.ExecContractCode(index, args...)
   431  	if err != nil {
   432  		return nil, err
   433  	}
   434  
   435  	// vm.GetGasCost()
   436  	funcType := module.GetFunction(int(index)).Sig
   437  	if len(funcType.ReturnTypes) == 0 {
   438  		return nil, nil
   439  	}
   440  
   441  	if val, ok := Abi.Methods[funcName]; ok {
   442  		outputs := val.Outputs
   443  		if len(outputs) != 0 {
   444  			output := outputs[0].Type.T
   445  			switch output {
   446  			case abi.StringTy:
   447  				v := VM.Memory.GetPtr(res)
   448  				l, err := packNum(reflect.ValueOf(32))
   449  				if err != nil {
   450  					return nil, err
   451  				}
   452  				s, err := packBytesSlice(v, len(v))
   453  				if err != nil {
   454  					return nil, err
   455  				}
   456  				return append(l, s...), nil
   457  			case abi.UintTy, abi.IntTy:
   458  				if outputs[0].Type.Kind == reflect.Ptr {
   459  					mem := VM.Memory.GetPtr(res)
   460  					bigint := utils.GetU256(mem)
   461  					return abi.U256(bigint), nil
   462  				} else if output == abi.UintTy {
   463  					return abi.U256(new(big.Int).SetUint64(res)), nil
   464  				} else {
   465  					if outputs[0].Type.Size == 32 {
   466  						return abi.U256(big.NewInt(int64(int32(res)))), nil
   467  					} else {
   468  						return abi.U256(big.NewInt(int64(res))), nil
   469  					}
   470  				}
   471  			case abi.BoolTy:
   472  				if res != 0 {
   473  					return mat.PaddedBigBytes(common.Big1, 32), nil
   474  				}
   475  				return mat.PaddedBigBytes(common.Big0, 32), nil
   476  			case abi.AddressTy:
   477  				v := VM.Memory.GetPtr(res)
   478  				return common.LeftPadBytes(v, 32), nil
   479  			default:
   480  				//todo 所有类型处理
   481  				return nil, UnknownTypeError("")
   482  			}
   483  		} else { //无返回类型
   484  			return utils.I32ToBytes(0), nil
   485  		}
   486  	}
   487  	return nil, NoFunctionError(funcName)
   488  }
   489  
   490  func (wavm *Wavm) GetFuncName() string {
   491  	return wavm.currentFuncName
   492  }
   493  
   494  func (wavm *Wavm) SetFuncName(name string) {
   495  	wavm.currentFuncName = name
   496  }
   497  
   498  func (wavm *Wavm) payable(funcName string) bool {
   499  	reg := regexp.MustCompile(`^\$`)
   500  	res := reg.FindAllString(funcName, -1)
   501  	if len(res) != 0 {
   502  		return true
   503  	}
   504  	return false
   505  }