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 }