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  }