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 }