github.com/cheng762/platon-go@v1.8.17-0.20190529111256-7deff2d7be26/core/vm/interpreter_life.go (about)

     1  package vm
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  	"github.com/PlatONnetwork/PlatON-Go/common"
     9  	"github.com/PlatONnetwork/PlatON-Go/common/math"
    10  	"github.com/PlatONnetwork/PlatON-Go/core/lru"
    11  	"github.com/PlatONnetwork/PlatON-Go/life/utils"
    12  	"github.com/PlatONnetwork/PlatON-Go/log"
    13  	"github.com/PlatONnetwork/PlatON-Go/rlp"
    14  	"math/big"
    15  	"reflect"
    16  	"runtime"
    17  	"strings"
    18  
    19  	"github.com/PlatONnetwork/PlatON-Go/life/exec"
    20  	"github.com/PlatONnetwork/PlatON-Go/life/resolver"
    21  )
    22  
    23  var (
    24  	errReturnInvalidRlpFormat = errors.New("interpreter_life: invalid rlp format.")
    25  	errReturnInsufficientParams = errors.New("interpreter_life: invalid input. ele must greater than 2")
    26  	errReturnInvalidAbi = errors.New("interpreter_life: invalid abi, encoded fail.")
    27  )
    28  
    29  const (
    30  	CALL_CANTRACT_FLAG = 9
    31  )
    32  
    33  var DEFAULT_VM_CONFIG = exec.VMConfig{
    34  	EnableJIT:          false,
    35  	DefaultMemoryPages: exec.DefaultMemoryPages,
    36  	DynamicMemoryPages: exec.DynamicMemoryPages,
    37  }
    38  
    39  // WASMInterpreter represents an WASM interpreter
    40  type WASMInterpreter struct {
    41  	evm         *EVM
    42  	cfg         Config
    43  	wasmStateDB *WasmStateDB
    44  	WasmLogger  log.Logger
    45  	resolver    exec.ImportResolver
    46  	returnData  []byte
    47  }
    48  
    49  // NewWASMInterpreter returns a new instance of the Interpreter
    50  func NewWASMInterpreter(evm *EVM, cfg Config) *WASMInterpreter {
    51  
    52  	wasmStateDB := &WasmStateDB{
    53  		StateDB: evm.StateDB,
    54  		evm:     evm,
    55  		cfg:     &cfg,
    56  	}
    57  	return &WASMInterpreter{
    58  		evm:         evm,
    59  		cfg:         cfg,
    60  		WasmLogger:  NewWasmLogger(cfg, log.WasmRoot()),
    61  		wasmStateDB: wasmStateDB,
    62  		resolver:    resolver.NewResolver(0x01),
    63  	}
    64  }
    65  
    66  // Run loops and evaluates the contract's code with the given input data and returns.
    67  // the return byte-slice and an error if one occurred
    68  //
    69  // It's important to note that any errors returned by the interpreter should be
    70  // considered a revert-and-consume-all-gas operations except for
    71  // errExecutionReverted which means revert-and-keep-gas-lfet.
    72  func (in *WASMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) {
    73  	defer func() {
    74  		if er := recover(); er != nil {
    75  			fmt.Println(stack())
    76  			ret, err = nil, fmt.Errorf("VM execute fail: %v", er)
    77  		}
    78  	}()
    79  	in.evm.depth++
    80  	defer func() {
    81  		in.evm.depth--
    82  		if in.evm.depth == 0 {
    83  			logger, ok := in.WasmLogger.(*WasmLogger)
    84  			if ok {
    85  				logger.Flush()
    86  			}
    87  		}
    88  	}()
    89  
    90  	if len(contract.Code) == 0 {
    91  		return nil, nil
    92  	}
    93  	_, abi, code, er := parseRlpData(contract.Code)
    94  	if er != nil {
    95  		return nil, er
    96  	}
    97  
    98  	context := &exec.VMContext{
    99  		Config:   DEFAULT_VM_CONFIG,
   100  		Addr:     contract.Address(),
   101  		GasLimit: contract.Gas,
   102  		StateDB:  NewWasmStateDB(in.wasmStateDB, contract),
   103  		Log:      in.WasmLogger,
   104  	}
   105  
   106  	var lvm *exec.VirtualMachine
   107  	var module *lru.WasmModule
   108  	module, ok := lru.WasmCache().Get(contract.Address())
   109  
   110  	if !ok {
   111  		module = &lru.WasmModule{}
   112  		module.Module, module.FunctionCode, err = exec.ParseModuleAndFunc(code, nil)
   113  		if err != nil {
   114  			return nil, err
   115  		}
   116  		lru.WasmCache().Add(contract.Address(), module)
   117  	}
   118  
   119  	lvm, err = exec.NewVirtualMachineWithModule(module.Module, module.FunctionCode, context, in.resolver, nil)
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	defer func() {
   124  		lvm.Stop()
   125  	}()
   126  
   127  	contract.Input = input
   128  	var (
   129  		funcName   string
   130  		txType     int
   131  		params     []int64
   132  		returnType string
   133  	)
   134  
   135  	if input == nil {
   136  		funcName = "init" // init function.
   137  	} else {
   138  		// parse input.
   139  		txType, funcName, params, returnType, err = parseInputFromAbi(lvm, input, abi)
   140  		if err != nil {
   141  			if err == errReturnInsufficientParams && txType == 0 { // transfer to contract address.
   142  				return nil, nil
   143  			}
   144  			return nil, err
   145  		}
   146  		if txType == 0 {
   147  			return nil, nil
   148  		}
   149  	}
   150  	entryID, ok := lvm.GetFunctionExport(funcName)
   151  	if !ok {
   152  		return nil, fmt.Errorf("entryId not found.")
   153  	}
   154  	res, err := lvm.RunWithGasLimit(entryID, int(context.GasLimit), params...)
   155  	if err != nil {
   156  		fmt.Println("throw exception:", err.Error())
   157  		return nil, err
   158  	}
   159  	if contract.Gas > context.GasUsed {
   160  		contract.Gas = contract.Gas - context.GasUsed
   161  	} else {
   162  		return nil, fmt.Errorf("out of gas.")
   163  	}
   164  
   165  	if input == nil {
   166  		return contract.Code, nil
   167  	}
   168  
   169  	// todo: more type need to be completed
   170  	switch returnType {
   171  	case "void", "int8", "int", "int32", "int64":
   172  		if txType == CALL_CANTRACT_FLAG {
   173  			return utils.Int64ToBytes(res), nil
   174  		}
   175  		bigRes := new(big.Int)
   176  		bigRes.SetInt64(res)
   177  		finalRes := utils.Align32Bytes(math.U256(bigRes).Bytes())
   178  		return finalRes, nil
   179  	case "uint8", "uint16", "uint32", "uint64":
   180  		if txType == CALL_CANTRACT_FLAG {
   181  			return utils.Uint64ToBytes(uint64(res)), nil
   182  		}
   183  		finalRes := utils.Align32Bytes(utils.Uint64ToBytes((uint64(res))))
   184  		return finalRes, nil
   185  	case "string":
   186  		returnBytes := make([]byte, 0)
   187  		copyData := lvm.Memory.Memory[res:]
   188  		for _, v := range copyData {
   189  			if v == 0 {
   190  				break
   191  			}
   192  			returnBytes = append(returnBytes, v)
   193  		}
   194  		if txType == CALL_CANTRACT_FLAG {
   195  			return returnBytes, nil
   196  		}
   197  		strHash := common.BytesToHash(common.Int32ToBytes(32))
   198  		sizeHash := common.BytesToHash(common.Int64ToBytes(int64((len(returnBytes)))))
   199  		var dataRealSize = len(returnBytes)
   200  		if (dataRealSize % 32) != 0 {
   201  			dataRealSize = dataRealSize + (32 - (dataRealSize % 32))
   202  		}
   203  		dataByt := make([]byte, dataRealSize)
   204  		copy(dataByt[0:], returnBytes)
   205  
   206  		finalData := make([]byte, 0)
   207  		finalData = append(finalData, strHash.Bytes()...)
   208  		finalData = append(finalData, sizeHash.Bytes()...)
   209  		finalData = append(finalData, dataByt...)
   210  
   211  		//fmt.Println("CallReturn:", string(returnBytes))
   212  		return finalData, nil
   213  	}
   214  	return nil, nil
   215  }
   216  
   217  // CanRun tells if the contract, passed as an argument, can be run
   218  // by the current interpreter
   219  func (in *WASMInterpreter) CanRun(code []byte) bool {
   220  	return true
   221  }
   222  
   223  // parse input(payload)
   224  func parseInputFromAbi(vm *exec.VirtualMachine, input []byte, abi []byte) (txType int, funcName string, params []int64, returnType string, err error) {
   225  	if input == nil || len(input) <= 1 {
   226  		return -1, "", nil, "", fmt.Errorf("invalid input.")
   227  	}
   228  	// [txType][funcName][args1][args2]
   229  	// rlp decode
   230  	ptr := new(interface{})
   231  	err = rlp.Decode(bytes.NewReader(input), &ptr)
   232  	if err != nil {
   233  		return -1, "", nil, "", err
   234  	}
   235  	rlpList := reflect.ValueOf(ptr).Elem().Interface()
   236  
   237  	if _, ok := rlpList.([]interface{}); !ok {
   238  		return -1, "", nil, "", errReturnInvalidRlpFormat
   239  	}
   240  
   241  	iRlpList := rlpList.([]interface{})
   242  	if len(iRlpList) < 2 {
   243  		if len(iRlpList) != 0 {
   244  			if v, ok := iRlpList[0].([]byte); ok {
   245  				txType = int(common.BytesToInt64(v))
   246  			}
   247  		} else {
   248  			txType = -1
   249  		}
   250  		return txType, "", nil, "", errReturnInsufficientParams
   251  	}
   252  
   253  	wasmabi := new(utils.WasmAbi)
   254  	err = wasmabi.FromJson(abi)
   255  	if err != nil {
   256  		return -1, "", nil, "", errReturnInvalidAbi
   257  	}
   258  
   259  	params = make([]int64, 0)
   260  	if v, ok := iRlpList[0].([]byte); ok {
   261  		txType = int(common.BytesToInt64(v))
   262  	}
   263  	if v, ok := iRlpList[1].([]byte); ok {
   264  		funcName = string(v)
   265  	}
   266  
   267  	var args []utils.InputParam
   268  	for _, v := range wasmabi.AbiArr {
   269  		if strings.EqualFold(funcName, v.Name) && strings.EqualFold(v.Type, "function") {
   270  			args = v.Inputs
   271  			if len(v.Outputs) != 0 {
   272  				returnType = v.Outputs[0].Type
   273  			} else {
   274  				returnType = "void"
   275  			}
   276  			break
   277  		}
   278  	}
   279  	argsRlp := iRlpList[2:]
   280  	if len(args) != len(argsRlp) {
   281  		return -1, "", nil, returnType, fmt.Errorf("invalid input or invalid abi.")
   282  	}
   283  	// uint64 uint32  uint16 uint8 int64 int32  int16 int8 float32 float64 string void
   284  	for i, v := range args {
   285  		bts := argsRlp[i].([]byte)
   286  		switch v.Type {
   287  		case "string":
   288  			pos := resolver.MallocString(vm, string(bts))
   289  			params = append(params, pos)
   290  		case "int8":
   291  			params = append(params, int64(bts[0]))
   292  		case "int16":
   293  			params = append(params, int64(binary.BigEndian.Uint16(bts)))
   294  		case "int32", "int":
   295  			params = append(params, int64(binary.BigEndian.Uint32(bts)))
   296  		case "int64":
   297  			params = append(params, int64(binary.BigEndian.Uint64(bts)))
   298  		case "uint8":
   299  			params = append(params, int64(bts[0]))
   300  		case "uint32", "uint":
   301  			params = append(params, int64(binary.BigEndian.Uint32(bts)))
   302  		case "uint64":
   303  			params = append(params, int64(binary.BigEndian.Uint64(bts)))
   304  		case "bool":
   305  			params = append(params, int64(bts[0]))
   306  		}
   307  	}
   308  	return txType, funcName, params, returnType, nil
   309  }
   310  
   311  // rlpData=RLP([txType][code][abi])
   312  func parseRlpData(rlpData []byte) (int64, []byte, []byte, error) {
   313  	ptr := new(interface{})
   314  	err := rlp.Decode(bytes.NewReader(rlpData), &ptr)
   315  	if err != nil {
   316  		return -1, nil, nil, err
   317  	}
   318  	rlpList := reflect.ValueOf(ptr).Elem().Interface()
   319  
   320  	if _, ok := rlpList.([]interface{}); !ok {
   321  		return -1, nil, nil, fmt.Errorf("invalid rlp format.")
   322  	}
   323  
   324  	iRlpList := rlpList.([]interface{})
   325  	if len(iRlpList) <= 2 {
   326  		return -1, nil, nil, fmt.Errorf("invalid input. ele must greater than 2")
   327  	}
   328  	var (
   329  		txType int64
   330  		code   []byte
   331  		abi    []byte
   332  	)
   333  	if v, ok := iRlpList[0].([]byte); ok {
   334  		txType = utils.BytesToInt64(v)
   335  	}
   336  	if v, ok := iRlpList[1].([]byte); ok {
   337  		code = v
   338  		//fmt.Println("dstCode: ", common.Bytes2Hex(code))
   339  	}
   340  	if v, ok := iRlpList[2].([]byte); ok {
   341  		abi = v
   342  		//fmt.Println("dstAbi:", common.Bytes2Hex(abi))
   343  	}
   344  	return txType, abi, code, nil
   345  }
   346  
   347  func stack() string {
   348  	var buf [2 << 10]byte
   349  	return string(buf[:runtime.Stack(buf[:], true)])
   350  }