github.com/aergoio/aergo@v1.3.1/contract/vm.go (about) 1 /** 2 * @file 3 * @copyright defined in aergo/LICENSE.txt 4 */ 5 6 package contract 7 8 /* 9 #cgo CFLAGS: -I${SRCDIR}/../libtool/include/luajit-2.1 -I${SRCDIR}/../libtool/include 10 #cgo !windows CFLAGS: -DLJ_TARGET_POSIX 11 #cgo darwin LDFLAGS: ${SRCDIR}/../libtool/lib/libluajit-5.1.a ${SRCDIR}/../libtool/lib/libgmp.dylib -lm 12 #cgo windows LDFLAGS: ${SRCDIR}/../libtool/lib/libluajit-5.1.a ${SRCDIR}/../libtool/bin/libgmp-10.dll -lm 13 #cgo !darwin,!windows LDFLAGS: ${SRCDIR}/../libtool/lib/libluajit-5.1.a ${SRCDIR}/../libtool/lib/libgmp.so -lm 14 15 #include <stdlib.h> 16 #include <string.h> 17 #include "vm.h" 18 #include "lgmp.h" 19 */ 20 import "C" 21 import ( 22 "bytes" 23 "encoding/binary" 24 "encoding/hex" 25 "encoding/json" 26 "errors" 27 "fmt" 28 "math/big" 29 "math/rand" 30 "os" 31 "reflect" 32 "strings" 33 "sync" 34 "time" 35 "unsafe" 36 37 "github.com/aergoio/aergo-lib/log" 38 "github.com/aergoio/aergo/fee" 39 "github.com/aergoio/aergo/internal/enc" 40 "github.com/aergoio/aergo/state" 41 "github.com/aergoio/aergo/types" 42 ) 43 44 const ( 45 maxStateSet = 20 46 callMaxInstLimit = C.int(5000000) 47 queryMaxInstLimit = callMaxInstLimit * C.int(10) 48 dbUpdateMaxLimit = fee.StateDbMaxUpdateSize 49 maxCallDepth = 5 50 ) 51 52 var ( 53 ctrLog *log.Logger 54 curStateSet [maxStateSet]*StateSet 55 lastQueryIndex int 56 querySync sync.Mutex 57 zeroFee *big.Int 58 ) 59 60 type ChainAccessor interface { 61 GetBlockByNo(blockNo types.BlockNo) (*types.Block, error) 62 GetBestBlock() (*types.Block, error) 63 } 64 65 type CallState struct { 66 ctrState *state.ContractState 67 prevState *types.State 68 curState *types.State 69 tx Tx 70 } 71 72 type ContractInfo struct { 73 callState *CallState 74 sender []byte 75 contractId []byte 76 rp uint64 77 amount *big.Int 78 } 79 80 type StateSet struct { 81 curContract *ContractInfo 82 bs *state.BlockState 83 cdb ChainAccessor 84 origin []byte 85 txHash []byte 86 blockHeight uint64 87 timestamp int64 88 node string 89 confirmed bool 90 isQuery bool 91 prevBlockHash []byte 92 service C.int 93 callState map[types.AccountID]*CallState 94 lastRecoveryEntry *recoveryEntry 95 dbUpdateTotalSize int64 96 seed *rand.Rand 97 events []*types.Event 98 eventCount int32 99 callDepth int32 100 traceFile *os.File 101 } 102 103 type recoveryEntry struct { 104 seq int 105 amount *big.Int 106 senderState *types.State 107 senderNonce uint64 108 callState *CallState 109 onlySend bool 110 sqlSaveName *string 111 stateRevision state.Snapshot 112 prev *recoveryEntry 113 } 114 115 type LState = C.struct_lua_State 116 117 type Executor struct { 118 L *LState 119 code []byte 120 err error 121 numArgs C.int 122 stateSet *StateSet 123 jsonRet string 124 isView bool 125 } 126 127 func init() { 128 ctrLog = log.NewLogger("contract") 129 lastQueryIndex = ChainService 130 zeroFee = big.NewInt(0) 131 } 132 133 func newContractInfo(callState *CallState, sender, contractId []byte, rp uint64, amount *big.Int) *ContractInfo { 134 return &ContractInfo{ 135 callState, 136 sender, 137 contractId, 138 rp, 139 amount, 140 } 141 } 142 143 func getTraceFile(blkno uint64, tx []byte) *os.File { 144 f, _ := os.OpenFile(fmt.Sprintf("%s%s%d.trace", os.TempDir(), string(os.PathSeparator), blkno), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644) 145 if f != nil { 146 _, _ = f.WriteString(fmt.Sprintf("[START TX]: %s\n", enc.ToString(tx))) 147 } 148 return f 149 } 150 151 func NewContext(blockState *state.BlockState, cdb ChainAccessor, sender, reciever *state.V, 152 contractState *state.ContractState, senderID []byte, txHash []byte, blockHeight uint64, 153 timestamp int64, prevBlockHash []byte, node string, confirmed bool, 154 query bool, rp uint64, service int, amount *big.Int) *StateSet { 155 156 callState := &CallState{ctrState: contractState, curState: reciever.State()} 157 158 stateSet := &StateSet{ 159 curContract: newContractInfo(callState, senderID, reciever.ID(), rp, amount), 160 bs: blockState, 161 cdb: cdb, 162 origin: senderID, 163 txHash: txHash, 164 node: node, 165 confirmed: confirmed, 166 isQuery: query, 167 blockHeight: blockHeight, 168 timestamp: timestamp, 169 prevBlockHash: prevBlockHash, 170 service: C.int(service), 171 } 172 stateSet.callState = make(map[types.AccountID]*CallState) 173 stateSet.callState[reciever.AccountID()] = callState 174 if sender != nil { 175 stateSet.callState[sender.AccountID()] = &CallState{curState: sender.State()} 176 } 177 if TraceBlockNo != 0 && TraceBlockNo == blockHeight { 178 stateSet.traceFile = getTraceFile(blockHeight, txHash) 179 } 180 181 return stateSet 182 } 183 184 func NewContextQuery(blockState *state.BlockState, cdb ChainAccessor, receiverId []byte, 185 contractState *state.ContractState, node string, confirmed bool, 186 rp uint64) *StateSet { 187 188 callState := &CallState{ctrState: contractState, curState: contractState.State} 189 190 stateSet := &StateSet{ 191 curContract: newContractInfo(callState, nil, receiverId, rp, big.NewInt(0)), 192 bs: blockState, 193 cdb: cdb, 194 node: node, 195 confirmed: confirmed, 196 timestamp: time.Now().UnixNano(), 197 isQuery: true, 198 } 199 stateSet.callState = make(map[types.AccountID]*CallState) 200 stateSet.callState[types.ToAccountID(receiverId)] = callState 201 202 return stateSet 203 } 204 205 func (s *StateSet) usedFee() *big.Int { 206 if fee.IsZeroFee() { 207 return zeroFee 208 } 209 size := fee.PaymentDataSize(s.dbUpdateTotalSize) 210 return new(big.Int).Mul(big.NewInt(size), fee.AerPerByte) 211 } 212 213 func NewLState() *LState { 214 return C.vm_newstate() 215 } 216 217 func (L *LState) Close() { 218 if L != nil { 219 C.lua_close(L) 220 } 221 } 222 223 func resolveFunction(contractState *state.ContractState, name string, constructor bool) (*types.Function, error) { 224 abi, err := GetABI(contractState) 225 if err != nil { 226 return nil, err 227 } 228 var defaultFunc *types.Function 229 for _, f := range abi.Functions { 230 if f.Name == name { 231 return f, nil 232 } 233 if f.Name == "default" { 234 defaultFunc = f 235 } 236 } 237 if constructor { 238 return nil, nil 239 } 240 if len(name) == 0 && defaultFunc != nil { 241 return defaultFunc, nil 242 } 243 return nil, errors.New("not found function: " + name) 244 } 245 246 func newExecutor( 247 contract []byte, 248 contractId []byte, 249 stateSet *StateSet, 250 ci *types.CallInfo, 251 amount *big.Int, 252 isCreate bool, 253 ctrState *state.ContractState, 254 ) *Executor { 255 256 if stateSet.callDepth > maxCallDepth { 257 ce := &Executor{ 258 code: contract, 259 stateSet: stateSet, 260 } 261 ce.err = errors.New(fmt.Sprintf("exceeded the maximum call depth(%d)", maxCallDepth)) 262 return ce 263 } 264 stateSet.callDepth++ 265 ce := &Executor{ 266 code: contract, 267 L: GetLState(), 268 stateSet: stateSet, 269 } 270 if ce.L == nil { 271 ce.err = newVmStartError() 272 ctrLog.Error().Err(ce.err).Str("contract", types.EncodeAddress(contractId)).Msg("new AergoLua executor") 273 return ce 274 } 275 backupService := stateSet.service 276 stateSet.service = -1 277 hexId := C.CString(hex.EncodeToString(contractId)) 278 defer C.free(unsafe.Pointer(hexId)) 279 if cErrMsg := C.vm_loadbuff( 280 ce.L, 281 (*C.char)(unsafe.Pointer(&contract[0])), 282 C.size_t(len(contract)), 283 hexId, 284 &stateSet.service, 285 ); cErrMsg != nil { 286 errMsg := C.GoString(cErrMsg) 287 ce.err = errors.New(errMsg) 288 ctrLog.Error().Err(ce.err).Str("contract", types.EncodeAddress(contractId)).Msg("failed to load code") 289 return ce 290 } 291 stateSet.service = backupService 292 293 if isCreate { 294 f, err := resolveFunction(ctrState, "constructor", isCreate) 295 if err != nil { 296 ce.err = err 297 ctrLog.Error().Err(ce.err).Str("contract", types.EncodeAddress(contractId)).Msg("not found function") 298 return ce 299 } 300 if f == nil { 301 f = &types.Function{ 302 Name: "constructor", 303 Payable: false, 304 } 305 } 306 err = checkPayable(f, amount) 307 if err != nil { 308 ce.err = err 309 ctrLog.Error().Err(ce.err).Str("contract", types.EncodeAddress(contractId)).Msg("check payable function") 310 return ce 311 } 312 ce.isView = f.View 313 C.vm_get_constructor(ce.L) 314 if C.vm_isnil(ce.L, C.int(-1)) == 1 { 315 ce.close() 316 return nil 317 } 318 ce.numArgs = C.int(len(ci.Args)) 319 } else { 320 C.vm_remove_constructor(ce.L) 321 f, err := resolveFunction(ctrState, ci.Name, isCreate) 322 if err != nil { 323 ce.err = err 324 ctrLog.Error().Err(ce.err).Str("contract", types.EncodeAddress(contractId)).Msg("not found function") 325 return ce 326 } 327 err = checkPayable(f, amount) 328 if err != nil { 329 ce.err = err 330 ctrLog.Error().Err(ce.err).Str("contract", types.EncodeAddress(contractId)).Msg("check payable function") 331 return ce 332 } 333 ce.isView = f.View 334 resolvedName := C.CString(f.Name) 335 C.vm_get_abi_function(ce.L, resolvedName) 336 C.free(unsafe.Pointer(resolvedName)) 337 ce.numArgs = C.int(len(ci.Args) + 1) 338 } 339 ce.processArgs(ci) 340 if ce.err != nil { 341 ctrLog.Error().Err(ce.err).Str("contract", types.EncodeAddress(contractId)).Msg("invalid argument") 342 } 343 return ce 344 } 345 346 func (ce *Executor) processArgs(ci *types.CallInfo) { 347 for _, v := range ci.Args { 348 if err := pushValue(ce.L, v); err != nil { 349 ce.err = err 350 return 351 } 352 } 353 } 354 355 func (ce *Executor) getEvents() []*types.Event { 356 if ce == nil || ce.stateSet == nil { 357 return nil 358 } 359 return ce.stateSet.events 360 } 361 362 func pushValue(L *LState, v interface{}) error { 363 switch arg := v.(type) { 364 case string: 365 argC := C.CBytes([]byte(arg)) 366 C.lua_pushlstring(L, (*C.char)(argC), C.size_t(len(arg))) 367 C.free(argC) 368 case float64: 369 if arg == float64(int64(arg)) { 370 C.lua_pushinteger(L, C.lua_Integer(arg)) 371 } else { 372 C.lua_pushnumber(L, C.double(arg)) 373 } 374 case bool: 375 var b int 376 if arg { 377 b = 1 378 } 379 C.lua_pushboolean(L, C.int(b)) 380 381 case json.Number: 382 str := arg.String() 383 intVal, err := arg.Int64() 384 if err == nil { 385 C.lua_pushinteger(L, C.lua_Integer(intVal)) 386 } else { 387 ftVal, err := arg.Float64() 388 if err != nil { 389 return errors.New("unsupported number type:" + str) 390 } 391 C.lua_pushnumber(L, C.double(ftVal)) 392 } 393 394 case nil: 395 C.lua_pushnil(L) 396 case []interface{}: 397 err := toLuaArray(L, arg) 398 if err != nil { 399 return err 400 } 401 case map[string]interface{}: 402 err := toLuaTable(L, arg) 403 if err != nil { 404 return err 405 } 406 default: 407 return errors.New("unsupported type:" + reflect.TypeOf(v).Name()) 408 } 409 return nil 410 } 411 412 func toLuaArray(L *LState, arr []interface{}) error { 413 C.lua_createtable(L, C.int(len(arr)), C.int(0)) 414 n := C.lua_gettop(L) 415 for i, v := range arr { 416 if err := pushValue(L, v); err != nil { 417 return err 418 } 419 C.lua_rawseti(L, n, C.int(i+1)) 420 } 421 return nil 422 } 423 424 func toLuaTable(L *LState, tab map[string]interface{}) error { 425 C.lua_createtable(L, C.int(0), C.int(len(tab))) 426 n := C.lua_gettop(L) 427 for k, v := range tab { 428 if len(tab) == 1 && strings.EqualFold(k, "_bignum") { 429 if arg, ok := v.(string); ok { 430 C.lua_settop(L, -2) 431 argC := C.CString(arg) 432 msg := C.lua_set_bignum(L, argC) 433 C.free(unsafe.Pointer(argC)) 434 if msg != nil { 435 return errors.New(C.GoString(msg)) 436 } 437 return nil 438 } 439 } 440 // push a key 441 key := C.CString(k) 442 C.lua_pushstring(L, key) 443 C.free(unsafe.Pointer(key)) 444 445 if err := pushValue(L, v); err != nil { 446 return err 447 } 448 C.lua_rawset(L, n) 449 } 450 return nil 451 } 452 453 func checkPayable(callee *types.Function, amount *big.Int) error { 454 if amount.Cmp(big.NewInt(0)) <= 0 || callee.Payable { 455 return nil 456 } 457 return fmt.Errorf("'%s' is not payable", callee.Name) 458 } 459 460 func (ce *Executor) call(target *LState) C.int { 461 if ce.err != nil { 462 return 0 463 } 464 if ce.isView == true { 465 oldIsQuery := ce.stateSet.isQuery 466 ce.stateSet.isQuery = true 467 defer func() { 468 ce.stateSet.isQuery = oldIsQuery 469 }() 470 } 471 nret := C.int(0) 472 if cErrMsg := C.vm_pcall(ce.L, ce.numArgs, &nret); cErrMsg != nil { 473 errMsg := C.GoString(cErrMsg) 474 if target != nil { 475 if C.luaL_hasuncatchablerror(ce.L) != C.int(0) { 476 C.luaL_setuncatchablerror(target) 477 } 478 //if C.luaL_hassyserror(ce.L) != C.int(0) { 479 // C.luaL_setsyserror(target) 480 //} 481 } 482 if C.luaL_hassyserror(ce.L) != C.int(0) { 483 ce.err = newVmSystemError(errors.New(errMsg)) 484 } else { 485 ce.err = errors.New(errMsg) 486 } 487 ctrLog.Warn().Err(ce.err).Str( 488 "contract", 489 types.EncodeAddress(ce.stateSet.curContract.contractId), 490 ).Msg("contract is failed") 491 return 0 492 } 493 if target == nil { 494 var errRet C.int 495 retMsg := C.GoString(C.vm_get_json_ret(ce.L, nret, &errRet)) 496 if errRet == 1 { 497 ce.err = errors.New(retMsg) 498 } else { 499 ce.jsonRet = retMsg 500 } 501 } else { 502 C.luaL_disablemaxmem(target) 503 if cErrMsg := C.vm_copy_result(ce.L, target, nret); cErrMsg != nil { 504 errMsg := C.GoString(cErrMsg) 505 ce.err = errors.New(errMsg) 506 ctrLog.Warn().Err(ce.err).Str( 507 "contract", 508 types.EncodeAddress(ce.stateSet.curContract.contractId), 509 ).Msg("failed to move results") 510 } 511 C.luaL_enablemaxmem(target) 512 } 513 if ce.stateSet.traceFile != nil { 514 address := types.EncodeAddress(ce.stateSet.curContract.contractId) 515 codeFile := fmt.Sprintf("%s%s%s.code", os.TempDir(), string(os.PathSeparator), address) 516 if _, err := os.Stat(codeFile); os.IsNotExist(err) { 517 f, err := os.OpenFile(codeFile, os.O_WRONLY|os.O_CREATE, 0644) 518 if err == nil { 519 _, _ = f.Write(ce.code) 520 _ = f.Close() 521 } 522 } 523 _, _ = ce.stateSet.traceFile.WriteString(fmt.Sprintf("contract %s used fee: %s\n", 524 address, ce.stateSet.usedFee().String())) 525 } 526 return nret 527 } 528 529 func (ce *Executor) commitCalledContract() error { 530 stateSet := ce.stateSet 531 532 if stateSet == nil || stateSet.callState == nil { 533 return nil 534 } 535 536 bs := stateSet.bs 537 rootContract := stateSet.curContract.callState.ctrState 538 539 var err error 540 for k, v := range stateSet.callState { 541 if v.tx != nil { 542 err = v.tx.Release() 543 if err != nil { 544 return newVmError(err) 545 } 546 } 547 if v.ctrState == rootContract { 548 continue 549 } 550 if v.ctrState != nil { 551 err = bs.StageContractState(v.ctrState) 552 if err != nil { 553 return newDbSystemError(err) 554 } 555 } 556 /* For Sender */ 557 if v.prevState == nil { 558 continue 559 } 560 err = bs.PutState(k, v.curState) 561 if err != nil { 562 return newDbSystemError(err) 563 } 564 } 565 566 if stateSet.traceFile != nil { 567 _, _ = ce.stateSet.traceFile.WriteString("[Put State Balance]\n") 568 for k, v := range stateSet.callState { 569 _, _ = ce.stateSet.traceFile.WriteString(fmt.Sprintf("%s : nonce=%d ammount=%s\n", 570 k.String(), v.curState.GetNonce(), v.curState.GetBalanceBigInt().String())) 571 } 572 } 573 574 return nil 575 } 576 577 func (ce *Executor) rollbackToSavepoint() error { 578 stateSet := ce.stateSet 579 580 if stateSet == nil || stateSet.callState == nil { 581 return nil 582 } 583 584 var err error 585 for _, v := range stateSet.callState { 586 if v.tx == nil { 587 continue 588 } 589 err = v.tx.RollbackToSavepoint() 590 if err != nil { 591 return newVmError(err) 592 } 593 } 594 return nil 595 } 596 597 func (ce *Executor) close() { 598 if ce != nil { 599 if ce.stateSet != nil { 600 ce.stateSet.callDepth-- 601 } 602 FreeLState(ce.L) 603 } 604 } 605 606 func getCallInfo(ci interface{}, args []byte, contractAddress []byte) error { 607 d := json.NewDecoder(bytes.NewReader(args)) 608 d.UseNumber() 609 d.DisallowUnknownFields() 610 err := d.Decode(ci) 611 if err != nil { 612 ctrLog.Warn().AnErr("error", err).Str( 613 "contract", 614 types.EncodeAddress(contractAddress), 615 ).Msg("invalid calling information") 616 } 617 return err 618 } 619 620 func Call(contractState *state.ContractState, code, contractAddress []byte, 621 stateSet *StateSet) (string, []*types.Event, *big.Int, error) { 622 623 var err error 624 var ci types.CallInfo 625 contract := getContract(contractState, nil) 626 if contract != nil { 627 if len(code) > 0 { 628 err = getCallInfo(&ci, code, contractAddress) 629 } 630 } else { 631 addr := types.EncodeAddress(contractAddress) 632 ctrLog.Warn().Str("error", "not found contract").Str("contract", addr).Msg("call") 633 err = fmt.Errorf("not found contract %s", addr) 634 } 635 if err != nil { 636 return "", nil, stateSet.usedFee(), err 637 } 638 if ctrLog.IsDebugEnabled() { 639 ctrLog.Debug().Str("abi", string(code)).Str("contract", types.EncodeAddress(contractAddress)).Msg("call") 640 } 641 642 curStateSet[stateSet.service] = stateSet 643 ce := newExecutor(contract, contractAddress, stateSet, &ci, stateSet.curContract.amount, false, contractState) 644 defer ce.close() 645 ce.setCountHook(callMaxInstLimit) 646 647 ce.call(nil) 648 err = ce.err 649 if err != nil { 650 if dbErr := ce.rollbackToSavepoint(); dbErr != nil { 651 logger.Error().Err(dbErr).Str("contract", types.EncodeAddress(contractAddress)).Msg("rollback state") 652 err = dbErr 653 } 654 if stateSet.traceFile != nil { 655 _, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[error] : %s\n", err)) 656 _, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[usedFee] : %s\n", stateSet.usedFee().String())) 657 evs := ce.getEvents() 658 if evs != nil { 659 _, _ = stateSet.traceFile.WriteString("[Event]\n") 660 for _, ev := range evs { 661 eb, _ := ev.MarshalJSON() 662 _, _ = stateSet.traceFile.Write(eb) 663 _, _ = stateSet.traceFile.WriteString("\n") 664 } 665 } 666 _, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[CALL END] : %s(%s)\n", 667 types.EncodeAddress(contractAddress), types.ToAccountID(contractAddress))) 668 } 669 return "", ce.getEvents(), stateSet.usedFee(), err 670 } 671 err = ce.commitCalledContract() 672 if err != nil { 673 logger.Error().Err(err).Str("contract", types.EncodeAddress(contractAddress)).Msg("commit state") 674 return "", ce.getEvents(), stateSet.usedFee(), err 675 } 676 if stateSet.traceFile != nil { 677 _, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[ret] : %s\n", ce.jsonRet)) 678 _, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[usedFee] : %s\n", stateSet.usedFee().String())) 679 evs := ce.getEvents() 680 if evs != nil { 681 _, _ = stateSet.traceFile.WriteString("[Event]\n") 682 for _, ev := range evs { 683 eb, _ := ev.MarshalJSON() 684 _, _ = stateSet.traceFile.Write(eb) 685 _, _ = stateSet.traceFile.WriteString("\n") 686 } 687 } 688 _, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[CALL END] : %s(%s)\n", 689 types.EncodeAddress(contractAddress), types.ToAccountID(contractAddress))) 690 } 691 return ce.jsonRet, ce.getEvents(), stateSet.usedFee(), nil 692 } 693 694 func setRandomSeed(stateSet *StateSet) { 695 var randSrc rand.Source 696 if stateSet.isQuery { 697 randSrc = rand.NewSource(stateSet.timestamp) 698 } else { 699 b, _ := new(big.Int).SetString(enc.ToString(stateSet.prevBlockHash[:7]), 62) 700 t, _ := new(big.Int).SetString(enc.ToString(stateSet.txHash[:7]), 62) 701 b.Add(b, t) 702 randSrc = rand.NewSource(b.Int64()) 703 } 704 stateSet.seed = rand.New(randSrc) 705 } 706 707 func PreCall(ce *Executor, bs *state.BlockState, sender *state.V, contractState *state.ContractState, 708 blockNo uint64, ts int64, rp uint64, prevBlockHash []byte) (string, []*types.Event, *big.Int, error) { 709 var err error 710 711 defer ce.close() 712 713 stateSet := ce.stateSet 714 stateSet.bs = bs 715 callState := stateSet.curContract.callState 716 callState.ctrState = contractState 717 callState.curState = contractState.State 718 stateSet.callState[sender.AccountID()] = &CallState{curState: sender.State()} 719 720 stateSet.blockHeight = blockNo 721 stateSet.timestamp = ts 722 stateSet.curContract.rp = rp 723 stateSet.prevBlockHash = prevBlockHash 724 725 if TraceBlockNo != 0 && TraceBlockNo == blockNo { 726 stateSet.traceFile = getTraceFile(blockNo, stateSet.txHash) 727 if stateSet.traceFile != nil { 728 defer func() { 729 _ = stateSet.traceFile.Close() 730 }() 731 } 732 } 733 curStateSet[stateSet.service] = stateSet 734 ce.call(nil) 735 err = ce.err 736 if err == nil { 737 err = ce.commitCalledContract() 738 if err != nil { 739 ctrLog.Error().Err(err).Str( 740 "contract", 741 types.EncodeAddress(stateSet.curContract.contractId), 742 ).Msg("pre-call") 743 } 744 } else { 745 if dbErr := ce.rollbackToSavepoint(); dbErr != nil { 746 ctrLog.Error().Err(dbErr).Str( 747 "contract", 748 types.EncodeAddress(stateSet.curContract.contractId), 749 ).Msg("pre-call") 750 err = dbErr 751 } 752 } 753 if stateSet.traceFile != nil { 754 contractId := stateSet.curContract.contractId 755 _, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[ret] : %s\n", ce.jsonRet)) 756 _, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[usedFee] : %s\n", stateSet.usedFee().String())) 757 evs := ce.getEvents() 758 if evs != nil { 759 _, _ = stateSet.traceFile.WriteString("[Event]\n") 760 for _, ev := range evs { 761 eb, _ := ev.MarshalJSON() 762 _, _ = stateSet.traceFile.Write(eb) 763 _, _ = stateSet.traceFile.WriteString("\n") 764 } 765 } 766 _, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[PRECALL END] : %s(%s)\n", 767 types.EncodeAddress(contractId), types.ToAccountID(contractId))) 768 } 769 return ce.jsonRet, ce.getEvents(), stateSet.usedFee(), err 770 } 771 772 func PreloadEx(bs *state.BlockState, contractState *state.ContractState, contractAid types.AccountID, code, contractAddress []byte, 773 stateSet *StateSet) (*Executor, error) { 774 775 var err error 776 var ci types.CallInfo 777 var contractCode []byte 778 779 if bs != nil { 780 contractCode = bs.CodeMap.Get(contractAid) 781 } 782 if contractCode == nil { 783 contractCode = getContract(contractState, nil) 784 if contractCode != nil && bs != nil { 785 bs.CodeMap.Add(contractAid, contractCode) 786 } 787 } 788 789 if contractCode != nil { 790 if len(code) > 0 { 791 err = getCallInfo(&ci, code, contractAddress) 792 } 793 } else { 794 addr := types.EncodeAddress(contractAddress) 795 ctrLog.Warn().Str("error", "not found contract").Str("contract", addr).Msg("preload") 796 err = fmt.Errorf("not found contract %s", addr) 797 } 798 if err != nil { 799 return nil, err 800 } 801 if ctrLog.IsDebugEnabled() { 802 ctrLog.Debug().Str("abi", string(code)).Str("contract", types.EncodeAddress(contractAddress)).Msg("preload") 803 } 804 ce := newExecutor(contractCode, contractAddress, stateSet, &ci, stateSet.curContract.amount, false, contractState) 805 ce.setCountHook(callMaxInstLimit) 806 807 return ce, nil 808 809 } 810 811 func setContract(contractState *state.ContractState, contractAddress, code []byte) ([]byte, uint32, error) { 812 if len(code) <= 4 { 813 err := fmt.Errorf("invalid code (%d bytes is too short)", len(code)) 814 ctrLog.Warn().Err(err).Str("contract", types.EncodeAddress(contractAddress)).Msg("deploy") 815 return nil, 0, err 816 } 817 codeLen := codeLength(code[0:]) 818 if uint32(len(code)) < codeLen { 819 err := fmt.Errorf("invalid code (expected %d bytes, actual %d bytes)", codeLen, len(code)) 820 ctrLog.Warn().Err(err).Str("contract", types.EncodeAddress(contractAddress)).Msg("deploy") 821 return nil, 0, err 822 } 823 sCode := code[4:codeLen] 824 825 err := contractState.SetCode(sCode) 826 if err != nil { 827 return nil, 0, err 828 } 829 contract := getContract(contractState, sCode) 830 if contract == nil { 831 err = fmt.Errorf("cannot deploy contract %s", types.EncodeAddress(contractAddress)) 832 ctrLog.Warn().Str("error", "cannot load contract").Str( 833 "contract", 834 types.EncodeAddress(contractAddress), 835 ).Msg("deploy") 836 return nil, 0, err 837 } 838 839 return contract, codeLen, nil 840 } 841 842 func Create(contractState *state.ContractState, code, contractAddress []byte, 843 stateSet *StateSet) (string, []*types.Event, *big.Int, error) { 844 if len(code) == 0 { 845 return "", nil, stateSet.usedFee(), errors.New("contract code is required") 846 } 847 848 if ctrLog.IsDebugEnabled() { 849 ctrLog.Debug().Str("contract", types.EncodeAddress(contractAddress)).Msg("deploy") 850 } 851 contract, codeLen, err := setContract(contractState, contractAddress, code) 852 if err != nil { 853 return "", nil, stateSet.usedFee(), err 854 } 855 err = contractState.SetData(creatorMetaKey, []byte(types.EncodeAddress(stateSet.curContract.sender))) 856 if err != nil { 857 return "", nil, stateSet.usedFee(), err 858 } 859 var ci types.CallInfo 860 if len(code) != int(codeLen) { 861 err = getCallInfo(&ci.Args, code[codeLen:], contractAddress) 862 if err != nil { 863 logger.Warn().Err(err).Str("contract", types.EncodeAddress(contractAddress)).Msg("invalid constructor argument") 864 errMsg, _ := json.Marshal("constructor call error:" + err.Error()) 865 return string(errMsg), nil, stateSet.usedFee(), nil 866 } 867 } 868 869 curStateSet[stateSet.service] = stateSet 870 871 // create a sql database for the contract 872 db := LuaGetDbHandle(&stateSet.service) 873 if db == nil { 874 return "", nil, stateSet.usedFee(), newVmError(errors.New("can't open a database connection")) 875 } 876 877 ce := newExecutor(contract, contractAddress, stateSet, &ci, stateSet.curContract.amount, true, contractState) 878 if ce == nil { 879 return "", nil, stateSet.usedFee(), nil 880 } 881 defer ce.close() 882 ce.setCountHook(callMaxInstLimit) 883 884 ce.call(nil) 885 err = ce.err 886 if err != nil { 887 logger.Warn().Msg("constructor is failed") 888 if dbErr := ce.rollbackToSavepoint(); dbErr != nil { 889 logger.Error().Err(dbErr).Msg("rollback state") 890 err = dbErr 891 } 892 893 if stateSet.traceFile != nil { 894 _, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[error] : %s\n", err)) 895 _, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[usedFee] : %s\n", stateSet.usedFee().String())) 896 evs := ce.getEvents() 897 if evs != nil { 898 _, _ = stateSet.traceFile.WriteString("[Event]\n") 899 for _, ev := range evs { 900 eb, _ := ev.MarshalJSON() 901 _, _ = stateSet.traceFile.Write(eb) 902 _, _ = stateSet.traceFile.WriteString("\n") 903 } 904 } 905 _, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[CREATE END] : %s(%s)\n", 906 types.EncodeAddress(contractAddress), types.ToAccountID(contractAddress))) 907 } 908 return "", ce.getEvents(), stateSet.usedFee(), err 909 } 910 err = ce.commitCalledContract() 911 if err != nil { 912 logger.Warn().Msg("constructor is failed") 913 logger.Error().Err(err).Msg("commit state") 914 return "", ce.getEvents(), stateSet.usedFee(), err 915 } 916 if stateSet.traceFile != nil { 917 _, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[ret] : %s\n", ce.jsonRet)) 918 _, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[usedFee] : %s\n", stateSet.usedFee().String())) 919 evs := ce.getEvents() 920 if evs != nil { 921 _, _ = stateSet.traceFile.WriteString("[Event]\n") 922 for _, ev := range evs { 923 eb, _ := ev.MarshalJSON() 924 _, _ = stateSet.traceFile.Write(eb) 925 _, _ = stateSet.traceFile.WriteString("\n") 926 } 927 } 928 _, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[CREATE END] : %s(%s)\n", 929 types.EncodeAddress(contractAddress), types.ToAccountID(contractAddress))) 930 } 931 return ce.jsonRet, ce.getEvents(), stateSet.usedFee(), nil 932 } 933 934 func setQueryContext(stateSet *StateSet) { 935 querySync.Lock() 936 defer querySync.Unlock() 937 startIndex := lastQueryIndex 938 index := startIndex 939 for { 940 index++ 941 if index == maxStateSet { 942 index = ChainService + 1 943 } 944 if curStateSet[index] == nil { 945 stateSet.service = C.int(index) 946 curStateSet[index] = stateSet 947 lastQueryIndex = index 948 return 949 } 950 if index == startIndex { 951 querySync.Unlock() 952 time.Sleep(100 * time.Millisecond) 953 querySync.Lock() 954 } 955 } 956 } 957 958 func Query(contractAddress []byte, bs *state.BlockState, cdb ChainAccessor, contractState *state.ContractState, queryInfo []byte) (res []byte, err error) { 959 var ci types.CallInfo 960 contract := getContract(contractState, nil) 961 if contract != nil { 962 err = getCallInfo(&ci, queryInfo, contractAddress) 963 } else { 964 addr := types.EncodeAddress(contractAddress) 965 ctrLog.Warn().Str("error", "not found contract").Str("contract", addr).Msg("query") 966 err = fmt.Errorf("not found contract %s", addr) 967 } 968 if err != nil { 969 return 970 } 971 972 stateSet := NewContextQuery(bs, cdb, contractAddress, contractState, "", true, 973 contractState.SqlRecoveryPoint) 974 975 setQueryContext(stateSet) 976 if ctrLog.IsDebugEnabled() { 977 ctrLog.Debug().Str("abi", string(queryInfo)).Str("contract", types.EncodeAddress(contractAddress)).Msg("query") 978 } 979 ce := newExecutor(contract, contractAddress, stateSet, &ci, stateSet.curContract.amount, false, contractState) 980 defer ce.close() 981 defer func() { 982 if dbErr := ce.rollbackToSavepoint(); dbErr != nil { 983 err = dbErr 984 } 985 }() 986 ce.setCountHook(queryMaxInstLimit) 987 ce.call(nil) 988 989 curStateSet[stateSet.service] = nil 990 return []byte(ce.jsonRet), ce.err 991 } 992 993 func getContract(contractState *state.ContractState, code []byte) []byte { 994 var val []byte 995 val = code 996 if val == nil { 997 var err error 998 val, err = contractState.GetCode() 999 1000 if err != nil { 1001 return nil 1002 } 1003 } 1004 valLen := len(val) 1005 if valLen <= 4 { 1006 return nil 1007 } 1008 l := codeLength(val[0:]) 1009 if 4+l > uint32(valLen) { 1010 return nil 1011 } 1012 return val[4 : 4+l] 1013 } 1014 1015 func GetABI(contractState *state.ContractState) (*types.ABI, error) { 1016 val, err := contractState.GetCode() 1017 if err != nil { 1018 return nil, err 1019 } 1020 valLen := len(val) 1021 if valLen == 0 { 1022 return nil, errors.New("cannot find contract") 1023 } 1024 if valLen <= 4 { 1025 return nil, errors.New("cannot find abi") 1026 } 1027 l := codeLength(val) 1028 if 4+l >= uint32(len(val)) { 1029 return nil, errors.New("cannot find abi") 1030 } 1031 abi := new(types.ABI) 1032 if err := json.Unmarshal(val[4+l:], abi); err != nil { 1033 return nil, err 1034 } 1035 return abi, nil 1036 } 1037 1038 func codeLength(val []byte) uint32 { 1039 return binary.LittleEndian.Uint32(val[0:]) 1040 } 1041 1042 func (re *recoveryEntry) recovery() error { 1043 var zero big.Int 1044 callState := re.callState 1045 if re.amount.Cmp(&zero) > 0 { 1046 if re.senderState != nil { 1047 re.senderState.Balance = new(big.Int).Add(re.senderState.GetBalanceBigInt(), re.amount).Bytes() 1048 } 1049 if callState != nil { 1050 callState.curState.Balance = new(big.Int).Sub(callState.curState.GetBalanceBigInt(), re.amount).Bytes() 1051 } 1052 } 1053 if re.onlySend { 1054 return nil 1055 } 1056 if re.senderState != nil { 1057 re.senderState.Nonce = re.senderNonce 1058 } 1059 1060 if callState == nil { 1061 return nil 1062 } 1063 if re.stateRevision != -1 { 1064 err := callState.ctrState.Rollback(re.stateRevision) 1065 if err != nil { 1066 return newDbSystemError(err) 1067 } 1068 } 1069 if callState.tx != nil { 1070 if re.sqlSaveName == nil { 1071 err := callState.tx.RollbackToSavepoint() 1072 if err != nil { 1073 return newDbSystemError(err) 1074 } 1075 callState.tx = nil 1076 } else { 1077 err := callState.tx.RollbackToSubSavepoint(*re.sqlSaveName) 1078 if err != nil { 1079 return newDbSystemError(err) 1080 } 1081 } 1082 } 1083 return nil 1084 }