github.com/aergoio/aergo@v1.3.1/contract/vm_callback.go (about)

     1  package contract
     2  
     3  /*
     4  #cgo CFLAGS: -I${SRCDIR}/../libtool/include/luajit-2.1
     5  #cgo LDFLAGS: ${SRCDIR}/../libtool/lib/libluajit-5.1.a -lm
     6  
     7  #include <stdlib.h>
     8  #include <string.h>
     9  #include "vm.h"
    10  #include "lgmp.h"
    11  
    12  struct proof {
    13  	void *data;
    14  	size_t len;
    15  };
    16  */
    17  import "C"
    18  import (
    19  	"bytes"
    20  	"encoding/hex"
    21  	"errors"
    22  	"fmt"
    23  	"github.com/aergoio/aergo/internal/common"
    24  	"index/suffixarray"
    25  	"math/big"
    26  	"regexp"
    27  	"strconv"
    28  	"strings"
    29  	"unsafe"
    30  
    31  	luacUtil "github.com/aergoio/aergo/cmd/aergoluac/util"
    32  	"github.com/aergoio/aergo/contract/name"
    33  	"github.com/aergoio/aergo/contract/system"
    34  	"github.com/aergoio/aergo/internal/enc"
    35  	"github.com/aergoio/aergo/state"
    36  	"github.com/aergoio/aergo/types"
    37  	"github.com/btcsuite/btcd/btcec"
    38  	"github.com/minio/sha256-simd"
    39  )
    40  
    41  var (
    42  	mulAergo, mulGaer, zeroBig *big.Int
    43  	creatorMetaKey             = []byte("Creator")
    44  )
    45  
    46  const (
    47  	maxEventCnt       = 50
    48  	maxEventNameSize  = 64
    49  	maxEventArgSize   = 4096
    50  	luaCallCountDeduc = 1000
    51  )
    52  
    53  func init() {
    54  	mulAergo, _ = new(big.Int).SetString("1000000000000000000", 10)
    55  	mulGaer, _ = new(big.Int).SetString("1000000000", 10)
    56  	zeroBig = big.NewInt(0)
    57  }
    58  
    59  func addUpdateSize(s *StateSet, updateSize int64) error {
    60  	if s.dbUpdateTotalSize+updateSize > dbUpdateMaxLimit {
    61  		return errors.New("exceeded size of updates in the state database")
    62  	}
    63  	s.dbUpdateTotalSize += updateSize
    64  	return nil
    65  }
    66  
    67  //export LuaSetDB
    68  func LuaSetDB(L *LState, service *C.int, key unsafe.Pointer, keyLen C.int, value *C.char) *C.char {
    69  	stateSet := curStateSet[*service]
    70  	if stateSet == nil {
    71  		return C.CString("[System.LuaSetDB] contract state not found")
    72  	}
    73  	if stateSet.isQuery == true {
    74  		return C.CString("[System.LuaSetDB] set not permitted in query")
    75  	}
    76  	val := []byte(C.GoString(value))
    77  	if err := stateSet.curContract.callState.ctrState.SetData(C.GoBytes(key, keyLen), val); err != nil {
    78  		return C.CString(err.Error())
    79  	}
    80  	if err := addUpdateSize(stateSet, int64(types.HashIDLength+len(val))); err != nil {
    81  		C.luaL_setuncatchablerror(L)
    82  		return C.CString(err.Error())
    83  	}
    84  	if stateSet.traceFile != nil {
    85  		_, _ = stateSet.traceFile.WriteString("[Set]\n")
    86  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("Key=%s Len=%v byte=%v\n",
    87  			string(C.GoBytes(key, keyLen)), keyLen, C.GoBytes(key, keyLen)))
    88  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("Data=%s Len=%d byte=%v\n",
    89  			string(val), len(val), val))
    90  	}
    91  	return nil
    92  }
    93  
    94  //export LuaGetDB
    95  func LuaGetDB(L *LState, service *C.int, key unsafe.Pointer, keyLen C.int, blkno *C.char) (*C.char, *C.char) {
    96  	stateSet := curStateSet[*service]
    97  	if stateSet == nil {
    98  		return nil, C.CString("[System.LuaGetDB] contract state not found")
    99  	}
   100  	if blkno != nil {
   101  		bigNo, _ := new(big.Int).SetString(strings.TrimSpace(C.GoString(blkno)), 10)
   102  		if bigNo == nil || bigNo.Sign() < 0 {
   103  			return nil, C.CString("[System.LuaGetDB] invalid blockheight value :" + C.GoString(blkno))
   104  		}
   105  		blkNo := bigNo.Uint64()
   106  
   107  		chainBlockHeight := stateSet.blockHeight
   108  		if chainBlockHeight == 0 {
   109  			bestBlock, err := stateSet.cdb.GetBestBlock()
   110  			if err != nil {
   111  				return nil, C.CString("[System.LuaGetDB] get best block error")
   112  			}
   113  			chainBlockHeight = bestBlock.GetHeader().GetBlockNo()
   114  		}
   115  		if blkNo < chainBlockHeight {
   116  			blk, err := stateSet.cdb.GetBlockByNo(blkNo)
   117  			if err != nil {
   118  				return nil, C.CString(err.Error())
   119  			}
   120  			accountId := types.ToAccountID(stateSet.curContract.contractId)
   121  			contractProof, err := stateSet.bs.GetAccountAndProof(accountId[:], blk.GetHeader().GetBlocksRootHash(), false)
   122  			if err != nil {
   123  				return nil, C.CString("[System.LuaGetDB] failed to get snapshot state for account")
   124  			} else if contractProof.Inclusion {
   125  				trieKey := common.Hasher(C.GoBytes(key, keyLen))
   126  				varProof, err := stateSet.bs.GetVarAndProof(trieKey, contractProof.GetState().GetStorageRoot(), false)
   127  				if err != nil {
   128  					return nil, C.CString("[System.LuaGetDB] failed to get snapshot state variable in contract")
   129  				}
   130  				if varProof.Inclusion {
   131  					if len(varProof.GetValue()) == 0 {
   132  						return nil, nil
   133  					}
   134  					return C.CString(string(varProof.GetValue())), nil
   135  				}
   136  			}
   137  			return nil, nil
   138  		}
   139  	}
   140  
   141  	data, err := stateSet.curContract.callState.ctrState.GetData(C.GoBytes(key, keyLen))
   142  	if err != nil {
   143  		return nil, C.CString(err.Error())
   144  	}
   145  	if data == nil {
   146  		return nil, nil
   147  	}
   148  	return C.CString(string(data)), nil
   149  }
   150  
   151  //export LuaDelDB
   152  func LuaDelDB(L *LState, service *C.int, key unsafe.Pointer, keyLen C.int) *C.char {
   153  	stateSet := curStateSet[*service]
   154  	if stateSet == nil {
   155  		return C.CString("[System.LuaDelDB] contract state not found")
   156  	}
   157  	if stateSet.isQuery {
   158  		return C.CString("[System.LuaDelDB] delete not permitted in query")
   159  	}
   160  	if err := stateSet.curContract.callState.ctrState.DeleteData(C.GoBytes(key, keyLen)); err != nil {
   161  		return C.CString(err.Error())
   162  	}
   163  	if err := addUpdateSize(stateSet, int64(32)); err != nil {
   164  		C.luaL_setuncatchablerror(L)
   165  		return C.CString(err.Error())
   166  	}
   167  	if stateSet.traceFile != nil {
   168  		_, _ = stateSet.traceFile.WriteString("[Del]\n")
   169  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("Key=%s Len=%v byte=%v\n",
   170  			string(C.GoBytes(key, keyLen)), keyLen, C.GoBytes(key, keyLen)))
   171  	}
   172  	return nil
   173  }
   174  
   175  func getCallState(stateSet *StateSet, aid types.AccountID) (*CallState, error) {
   176  	callState := stateSet.callState[aid]
   177  	if callState == nil {
   178  		bs := stateSet.bs
   179  
   180  		prevState, err := bs.GetAccountState(aid)
   181  		if err != nil {
   182  			return nil, err
   183  		}
   184  
   185  		curState := types.Clone(*prevState).(types.State)
   186  		callState =
   187  			&CallState{prevState: prevState, curState: &curState}
   188  		stateSet.callState[aid] = callState
   189  	}
   190  	return callState, nil
   191  }
   192  
   193  func getCtrState(stateSet *StateSet, aid types.AccountID) (*CallState, error) {
   194  	callState, err := getCallState(stateSet, aid)
   195  	if err != nil {
   196  		return nil, err
   197  	}
   198  	if callState.ctrState == nil {
   199  		callState.ctrState, err = stateSet.bs.OpenContractState(aid, callState.curState)
   200  	}
   201  	return callState, err
   202  }
   203  
   204  func setInstCount(parent *LState, child *LState) {
   205  	C.luaL_setinstcount(parent, C.luaL_instcount(child))
   206  }
   207  
   208  func setInstMinusCount(L *LState, deduc C.int) {
   209  	C.luaL_setinstcount(L, minusCallCount(C.luaL_instcount(L), deduc))
   210  }
   211  
   212  func minusCallCount(curCount C.int, deduc C.int) C.int {
   213  	remain := curCount - deduc
   214  	if remain <= 0 {
   215  		remain = 1
   216  	}
   217  	return remain
   218  }
   219  
   220  //export LuaCallContract
   221  func LuaCallContract(L *LState, service *C.int, contractId *C.char, fname *C.char, args *C.char,
   222  	amount *C.char, gas uint64) (C.int, *C.char) {
   223  	fnameStr := C.GoString(fname)
   224  	argsStr := C.GoString(args)
   225  
   226  	stateSet := curStateSet[*service]
   227  	if stateSet == nil {
   228  		return -1, C.CString("[Contract.LuaCallContract] contract state not found")
   229  	}
   230  	contractAddress := C.GoString(contractId)
   231  	cid, err := getAddressNameResolved(contractAddress, stateSet.bs)
   232  	if err != nil {
   233  		return -1, C.CString("[Contract.LuaCallContract] invalid contractId: " + err.Error())
   234  	}
   235  	aid := types.ToAccountID(cid)
   236  	amountBig, err := transformAmount(C.GoString(amount))
   237  	if err != nil {
   238  		return -1, C.CString("[Contract.LuaCallContract] invalid amount: " + err.Error())
   239  	}
   240  
   241  	callState, err := getCtrState(stateSet, aid)
   242  	if err != nil {
   243  		return -1, C.CString("[Contract.LuaCallContract] getAccount error: " + err.Error())
   244  	}
   245  
   246  	callee := getContract(callState.ctrState, nil)
   247  	if callee == nil {
   248  		return -1, C.CString("[Contract.LuaCallContract] cannot find contract " + C.GoString(contractId))
   249  	}
   250  
   251  	prevContractInfo := stateSet.curContract
   252  
   253  	var ci types.CallInfo
   254  	ci.Name = fnameStr
   255  	err = getCallInfo(&ci.Args, []byte(argsStr), cid)
   256  	if err != nil {
   257  		return -1, C.CString("[Contract.LuaCallContract] invalid arguments: " + err.Error())
   258  	}
   259  
   260  	ce := newExecutor(callee, cid, stateSet, &ci, amountBig, false, callState.ctrState)
   261  	defer ce.close()
   262  
   263  	if ce.err != nil {
   264  		return -1, C.CString("[Contract.LuaCallContract] newExecutor error: " + ce.err.Error())
   265  	}
   266  
   267  	senderState := prevContractInfo.callState.curState
   268  	if amountBig.Cmp(zeroBig) > 0 {
   269  		if stateSet.isQuery == true {
   270  			return -1, C.CString("[Contract.LuaCallContract] send not permitted in query")
   271  		}
   272  		if r := sendBalance(L, senderState, callState.curState, amountBig); r != nil {
   273  			return -1, r
   274  		}
   275  	}
   276  	seq, err := setRecoveryPoint(aid, stateSet, senderState, callState, amountBig, false)
   277  	if stateSet.traceFile != nil {
   278  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[CALL Contract %v(%v) %v]\n",
   279  			contractAddress, aid.String(), fnameStr))
   280  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("snapshot set %d\n", seq))
   281  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("SendBalance: %s\n", amountBig.String()))
   282  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("After sender: %s receiver: %s\n",
   283  			senderState.GetBalanceBigInt().String(), callState.curState.GetBalanceBigInt().String()))
   284  	}
   285  	if err != nil {
   286  		return -1, C.CString("[System.LuaCallContract] database error: " + err.Error())
   287  	}
   288  	stateSet.curContract = newContractInfo(callState, prevContractInfo.contractId, cid,
   289  		callState.curState.SqlRecoveryPoint, amountBig)
   290  	defer func() {
   291  		stateSet.curContract = prevContractInfo
   292  	}()
   293  	ce.setCountHook(minusCallCount(C.luaL_instcount(L), luaCallCountDeduc))
   294  	defer setInstCount(L, ce.L)
   295  
   296  	ret := ce.call(L)
   297  	if ce.err != nil {
   298  		err := clearRecovery(L, stateSet, seq, true)
   299  		if err != nil {
   300  			return -1, C.CString("[Contract.LuaCallContract] recovery err: " + err.Error())
   301  		}
   302  		if stateSet.traceFile != nil {
   303  			_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("recovery snapshot: %d\n", seq))
   304  		}
   305  		return -1, C.CString("[Contract.LuaCallContract] call err: " + ce.err.Error())
   306  	}
   307  	if seq == 1 {
   308  		err := clearRecovery(L, stateSet, seq, false)
   309  		if err != nil {
   310  			return -1, C.CString("[Contract.LuaCallContract] recovery err: " + err.Error())
   311  		}
   312  	}
   313  	return ret, nil
   314  }
   315  
   316  func getOnlyContractState(stateSet *StateSet, aid types.AccountID) (*state.ContractState, error) {
   317  	callState := stateSet.callState[aid]
   318  	if callState == nil || callState.ctrState == nil {
   319  		return stateSet.bs.OpenContractStateAccount(aid)
   320  	}
   321  	return callState.ctrState, nil
   322  }
   323  
   324  //export LuaDelegateCallContract
   325  func LuaDelegateCallContract(L *LState, service *C.int, contractId *C.char,
   326  	fname *C.char, args *C.char, gas uint64) (C.int, *C.char) {
   327  	contractIdStr := C.GoString(contractId)
   328  	fnameStr := C.GoString(fname)
   329  	argsStr := C.GoString(args)
   330  
   331  	stateSet := curStateSet[*service]
   332  	if stateSet == nil {
   333  		return -1, C.CString("[Contract.LuaDelegateCallContract] contract state not found")
   334  	}
   335  	cid, err := getAddressNameResolved(contractIdStr, stateSet.bs)
   336  	if err != nil {
   337  		return -1, C.CString("[Contract.LuaDelegateCallContract] invalid contractId: " + err.Error())
   338  	}
   339  	aid := types.ToAccountID(cid)
   340  	contractState, err := getOnlyContractState(stateSet, aid)
   341  	if err != nil {
   342  		return -1, C.CString("[Contract.LuaDelegateCallContract]getContractState error" + err.Error())
   343  	}
   344  	contract := getContract(contractState, nil)
   345  	if contract == nil {
   346  		return -1, C.CString("[Contract.LuaDelegateCallContract] cannot find contract " + contractIdStr)
   347  	}
   348  
   349  	var ci types.CallInfo
   350  	ci.Name = fnameStr
   351  	err = getCallInfo(&ci.Args, []byte(argsStr), cid)
   352  	if err != nil {
   353  		return -1, C.CString("[Contract.LuaDelegateCallContract] invalid arguments: " + err.Error())
   354  	}
   355  
   356  	ce := newExecutor(contract, cid, stateSet, &ci, zeroBig, false, contractState)
   357  	defer ce.close()
   358  
   359  	if ce.err != nil {
   360  		return -1, C.CString("[Contract.LuaDelegateCallContract] newExecutor error: " + ce.err.Error())
   361  	}
   362  
   363  	seq, err := setRecoveryPoint(aid, stateSet, nil, stateSet.curContract.callState, zeroBig, false)
   364  	if err != nil {
   365  		return -1, C.CString("[System.LuaDelegateCallContract] database error: " + err.Error())
   366  	}
   367  	if stateSet.traceFile != nil {
   368  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[DELEGATECALL Contract %v %v]\n", contractIdStr, fnameStr))
   369  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("snapshot set %d\n", seq))
   370  	}
   371  	ce.setCountHook(minusCallCount(C.luaL_instcount(L), luaCallCountDeduc))
   372  	defer setInstCount(L, ce.L)
   373  
   374  	ret := ce.call(L)
   375  	if ce.err != nil {
   376  		err := clearRecovery(L, stateSet, seq, true)
   377  		if err != nil {
   378  			return -1, C.CString("[Contract.LuaDelegateCallContract] recovery error: " + err.Error())
   379  		}
   380  		if stateSet.traceFile != nil {
   381  			_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("recovery snapshot: %d\n", seq))
   382  		}
   383  		return -1, C.CString("[Contract.LuaDelegateCallContract] call error: " + ce.err.Error())
   384  	}
   385  	if seq == 1 {
   386  		err := clearRecovery(L, stateSet, seq, false)
   387  		if err != nil {
   388  			return -1, C.CString("[Contract.LuaDelegateCallContract] recovery error: " + err.Error())
   389  		}
   390  	}
   391  	return ret, nil
   392  }
   393  
   394  func getAddressNameResolved(account string, bs *state.BlockState) ([]byte, error) {
   395  	accountLen := len(account)
   396  	if accountLen == types.EncodedAddressLength {
   397  		return types.DecodeAddress(account)
   398  	} else if accountLen == types.NameLength {
   399  		cid := name.Resolve(bs, []byte(account))
   400  		if cid == nil {
   401  			return nil, errors.New("name not founded :" + account)
   402  		}
   403  		return cid, nil
   404  	}
   405  	return nil, errors.New("invalid account length:" + account)
   406  }
   407  
   408  //export LuaSendAmount
   409  func LuaSendAmount(L *LState, service *C.int, contractId *C.char, amount *C.char) *C.char {
   410  	stateSet := curStateSet[*service]
   411  	if stateSet == nil {
   412  		return C.CString("[Contract.LuaSendAmount] contract state not found")
   413  	}
   414  	amountBig, err := transformAmount(C.GoString(amount))
   415  	if err != nil {
   416  		return C.CString("[Contract.LuaSendAmount] invalid amount: " + err.Error())
   417  	}
   418  	if stateSet.isQuery == true && amountBig.Cmp(zeroBig) > 0 {
   419  		return C.CString("[Contract.LuaSendAmount] send not permitted in query")
   420  	}
   421  	cid, err := getAddressNameResolved(C.GoString(contractId), stateSet.bs)
   422  	if err != nil {
   423  		return C.CString("[Contract.LuaSendAmount] invalid contractId: " + err.Error())
   424  	}
   425  
   426  	aid := types.ToAccountID(cid)
   427  	callState, err := getCallState(stateSet, aid)
   428  	if err != nil {
   429  		return C.CString("[Contract.LuaSendAmount] getAccount error: " + err.Error())
   430  	}
   431  
   432  	senderState := stateSet.curContract.callState.curState
   433  	if len(callState.curState.GetCodeHash()) > 0 {
   434  		if callState.ctrState == nil {
   435  			callState.ctrState, err = stateSet.bs.OpenContractState(aid, callState.curState)
   436  			if err != nil {
   437  				return C.CString("[Contract.LuaSendAmount] getContractState error: " + err.Error())
   438  			}
   439  		}
   440  		var ci types.CallInfo
   441  		ci.Name = "default"
   442  		code := getContract(callState.ctrState, nil)
   443  		if code == nil {
   444  			return C.CString("[Contract.LuaSendAmount] cannot find contract:" + C.GoString(contractId))
   445  		}
   446  
   447  		ce := newExecutor(code, cid, stateSet, &ci, amountBig, false, callState.ctrState)
   448  		defer ce.close()
   449  		if ce.err != nil {
   450  			return C.CString("[Contract.LuaSendAmount] newExecutor error: " + ce.err.Error())
   451  		}
   452  
   453  		if amountBig.Cmp(zeroBig) > 0 {
   454  			if r := sendBalance(L, senderState, callState.curState, amountBig); r != nil {
   455  				return r
   456  			}
   457  		}
   458  		seq, err := setRecoveryPoint(aid, stateSet, senderState, callState, amountBig, false)
   459  		if err != nil {
   460  			return C.CString("[System.LuaSendAmount] database error: " + err.Error())
   461  		}
   462  		if stateSet.traceFile != nil {
   463  			_, _ = stateSet.traceFile.WriteString(
   464  				fmt.Sprintf("[Send Call default] %s(%s) : %s\n", types.EncodeAddress(cid), aid.String(), amountBig.String()))
   465  			_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("After sender: %s receiver: %s\n",
   466  				senderState.GetBalanceBigInt().String(), callState.curState.GetBalanceBigInt().String()))
   467  			_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("snapshot set %d\n", seq))
   468  		}
   469  		prevContractInfo := stateSet.curContract
   470  		stateSet.curContract = newContractInfo(callState, prevContractInfo.contractId, cid,
   471  			callState.curState.SqlRecoveryPoint, amountBig)
   472  		defer func() {
   473  			stateSet.curContract = prevContractInfo
   474  		}()
   475  		ce.setCountHook(minusCallCount(C.luaL_instcount(L), luaCallCountDeduc))
   476  		defer setInstCount(L, ce.L)
   477  
   478  		ce.call(L)
   479  		if ce.err != nil {
   480  			err := clearRecovery(L, stateSet, seq, true)
   481  			if err != nil {
   482  				return C.CString("[Contract.LuaSendAmount] recovery err: " + err.Error())
   483  			}
   484  			if stateSet.traceFile != nil {
   485  				_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("recovery snapshot: %d\n", seq))
   486  			}
   487  			return C.CString("[Contract.LuaSendAmount] call err: " + ce.err.Error())
   488  		}
   489  		if seq == 1 {
   490  			err := clearRecovery(L, stateSet, seq, false)
   491  			if err != nil {
   492  				return C.CString("[Contract.LuaSendAmount] recovery err: " + err.Error())
   493  			}
   494  		}
   495  		return nil
   496  	}
   497  	if amountBig.Cmp(zeroBig) == 0 {
   498  		return nil
   499  	}
   500  
   501  	if r := sendBalance(L, senderState, callState.curState, amountBig); r != nil {
   502  		return r
   503  	}
   504  	if stateSet.lastRecoveryEntry != nil {
   505  		_, _ = setRecoveryPoint(aid, stateSet, senderState, callState, amountBig, true)
   506  	}
   507  	if stateSet.traceFile != nil {
   508  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[Send] %s(%s) : %s\n",
   509  			types.EncodeAddress(cid), aid.String(), amountBig.String()))
   510  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("After sender: %s receiver: %s\n",
   511  			senderState.GetBalanceBigInt().String(), callState.curState.GetBalanceBigInt().String()))
   512  	}
   513  	return nil
   514  }
   515  
   516  func sendBalance(L *LState, sender *types.State, receiver *types.State, amount *big.Int) *C.char {
   517  	if sender == receiver {
   518  		return nil
   519  	}
   520  	if sender.GetBalanceBigInt().Cmp(amount) < 0 {
   521  		return C.CString("[Contract.sendBalance] insufficient balance: " +
   522  			sender.GetBalanceBigInt().String() + " : " + amount.String())
   523  	} else {
   524  		sender.Balance = new(big.Int).Sub(sender.GetBalanceBigInt(), amount).Bytes()
   525  	}
   526  	receiver.Balance = new(big.Int).Add(receiver.GetBalanceBigInt(), amount).Bytes()
   527  
   528  	return nil
   529  }
   530  
   531  //export LuaPrint
   532  func LuaPrint(L *LState, service *C.int, args *C.char) {
   533  	stateSet := curStateSet[*service]
   534  	setInstMinusCount(L, 1000)
   535  	logger.Info().Str("Contract SystemPrint", types.EncodeAddress(stateSet.curContract.contractId)).Msg(C.GoString(args))
   536  }
   537  
   538  func setRecoveryPoint(aid types.AccountID, stateSet *StateSet, senderState *types.State,
   539  	callState *CallState, amount *big.Int, isSend bool) (int, error) {
   540  	var seq int
   541  	prev := stateSet.lastRecoveryEntry
   542  	if prev != nil {
   543  		seq = prev.seq + 1
   544  	} else {
   545  		seq = 1
   546  	}
   547  	recoveryEntry := &recoveryEntry{
   548  		seq,
   549  		amount,
   550  		senderState,
   551  		senderState.GetNonce(),
   552  		callState,
   553  		isSend,
   554  		nil,
   555  		-1,
   556  		prev,
   557  	}
   558  	stateSet.lastRecoveryEntry = recoveryEntry
   559  	if isSend {
   560  		return seq, nil
   561  	}
   562  	recoveryEntry.stateRevision = callState.ctrState.Snapshot()
   563  	tx := callState.tx
   564  	if tx != nil {
   565  		saveName := fmt.Sprintf("%s_%p", aid.String(), &recoveryEntry)
   566  		err := tx.SubSavepoint(saveName)
   567  		if err != nil {
   568  			return seq, err
   569  		}
   570  		recoveryEntry.sqlSaveName = &saveName
   571  	}
   572  	return seq, nil
   573  }
   574  
   575  //export LuaSetRecoveryPoint
   576  func LuaSetRecoveryPoint(L *LState, service *C.int) (C.int, *C.char) {
   577  	stateSet := curStateSet[*service]
   578  	if stateSet == nil {
   579  		return -1, C.CString("[Contract.pcall] contract state not found")
   580  	}
   581  	if stateSet.isQuery == true {
   582  		return 0, nil
   583  	}
   584  	curContract := stateSet.curContract
   585  	seq, err := setRecoveryPoint(types.ToAccountID(curContract.contractId), stateSet, nil,
   586  		curContract.callState, zeroBig, false)
   587  	if err != nil {
   588  		return -1, C.CString("[Contract.pcall] database error: " + err.Error())
   589  	}
   590  	if stateSet.traceFile != nil {
   591  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[Pcall] snapshot set %d\n", seq))
   592  	}
   593  	return C.int(seq), nil
   594  }
   595  
   596  func clearRecovery(L *LState, stateSet *StateSet, start int, error bool) error {
   597  	item := stateSet.lastRecoveryEntry
   598  	for {
   599  		if error {
   600  			if item.recovery() != nil {
   601  				return errors.New("database error")
   602  			}
   603  		}
   604  		if item.seq == start {
   605  			if error || item.prev == nil {
   606  				stateSet.lastRecoveryEntry = item.prev
   607  			}
   608  			return nil
   609  		}
   610  		item = item.prev
   611  		if item == nil {
   612  			return errors.New("internal error")
   613  		}
   614  	}
   615  }
   616  
   617  //export LuaClearRecovery
   618  func LuaClearRecovery(L *LState, service *C.int, start int, error bool) *C.char {
   619  	stateSet := curStateSet[*service]
   620  	if stateSet == nil {
   621  		return C.CString("[Contract.pcall] contract state not found")
   622  	}
   623  	err := clearRecovery(L, stateSet, start, error)
   624  	if err != nil {
   625  		return C.CString(err.Error())
   626  	}
   627  	if stateSet.traceFile != nil && error == true {
   628  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("pcall recovery snapshot : %d\n", start))
   629  	}
   630  	return nil
   631  }
   632  
   633  //export LuaGetBalance
   634  func LuaGetBalance(L *LState, service *C.int, contractId *C.char) (*C.char, *C.char) {
   635  	stateSet := curStateSet[*service]
   636  	if contractId == nil {
   637  		return C.CString(stateSet.curContract.callState.ctrState.GetBalanceBigInt().String()), nil
   638  	}
   639  	cid, err := getAddressNameResolved(C.GoString(contractId), stateSet.bs)
   640  	if err != nil {
   641  		return nil, C.CString("[Contract.LuaGetBalance] invalid contractId: " + err.Error())
   642  	}
   643  	aid := types.ToAccountID(cid)
   644  	callState := stateSet.callState[aid]
   645  	if callState == nil {
   646  		bs := stateSet.bs
   647  
   648  		as, err := bs.GetAccountState(aid)
   649  		if err != nil {
   650  			return nil, C.CString("[Contract.LuaGetBalance] getAccount error: " + err.Error())
   651  		}
   652  		return C.CString(as.GetBalanceBigInt().String()), nil
   653  	}
   654  	return C.CString(callState.curState.GetBalanceBigInt().String()), nil
   655  }
   656  
   657  //export LuaGetSender
   658  func LuaGetSender(L *LState, service *C.int) *C.char {
   659  	stateSet := curStateSet[*service]
   660  	setInstMinusCount(L, 1000)
   661  	return C.CString(types.EncodeAddress(stateSet.curContract.sender))
   662  }
   663  
   664  //export LuaGetHash
   665  func LuaGetHash(L *LState, service *C.int) *C.char {
   666  	stateSet := curStateSet[*service]
   667  	return C.CString(enc.ToString(stateSet.txHash))
   668  }
   669  
   670  //export LuaGetBlockNo
   671  func LuaGetBlockNo(L *LState, service *C.int) C.lua_Integer {
   672  	stateSet := curStateSet[*service]
   673  	return C.lua_Integer(stateSet.blockHeight)
   674  }
   675  
   676  //export LuaGetTimeStamp
   677  func LuaGetTimeStamp(L *LState, service *C.int) C.lua_Integer {
   678  	stateSet := curStateSet[*service]
   679  	return C.lua_Integer(stateSet.timestamp / 1e9)
   680  }
   681  
   682  //export LuaGetContractId
   683  func LuaGetContractId(L *LState, service *C.int) *C.char {
   684  	stateSet := curStateSet[*service]
   685  	setInstMinusCount(L, 1000)
   686  	return C.CString(types.EncodeAddress(stateSet.curContract.contractId))
   687  }
   688  
   689  //export LuaGetAmount
   690  func LuaGetAmount(L *LState, service *C.int) *C.char {
   691  	stateSet := curStateSet[*service]
   692  	return C.CString(stateSet.curContract.amount.String())
   693  }
   694  
   695  //export LuaGetOrigin
   696  func LuaGetOrigin(L *LState, service *C.int) *C.char {
   697  	stateSet := curStateSet[*service]
   698  	setInstMinusCount(L, 1000)
   699  	return C.CString(types.EncodeAddress(stateSet.origin))
   700  }
   701  
   702  //export LuaGetPrevBlockHash
   703  func LuaGetPrevBlockHash(L *LState, service *C.int) *C.char {
   704  	stateSet := curStateSet[*service]
   705  	return C.CString(enc.ToString(stateSet.prevBlockHash))
   706  }
   707  
   708  //export LuaGetDbHandle
   709  func LuaGetDbHandle(service *C.int) *C.sqlite3 {
   710  	stateSet := curStateSet[*service]
   711  	curContract := stateSet.curContract
   712  	callState := curContract.callState
   713  	if callState.tx != nil {
   714  		return callState.tx.GetHandle()
   715  	}
   716  	var tx Tx
   717  	var err error
   718  
   719  	aid := types.ToAccountID(curContract.contractId)
   720  	if stateSet.isQuery == true {
   721  		tx, err = BeginReadOnly(aid.String(), curContract.rp)
   722  	} else {
   723  		tx, err = BeginTx(aid.String(), curContract.rp)
   724  	}
   725  	if err != nil {
   726  		logger.Error().Err(err).Msg("Begin SQL Transaction")
   727  		return nil
   728  	}
   729  	if stateSet.isQuery == false {
   730  		err = tx.Savepoint()
   731  		if err != nil {
   732  			logger.Error().Err(err).Msg("Begin SQL Transaction")
   733  			return nil
   734  		}
   735  	}
   736  	callState.tx = tx
   737  	return callState.tx.GetHandle()
   738  }
   739  
   740  func checkHexString(data string) bool {
   741  	if len(data) >= 2 && data[0] == '0' && (data[1] == 'x' || data[1] == 'X') {
   742  		return true
   743  	}
   744  	return false
   745  }
   746  
   747  //export LuaCryptoSha256
   748  func LuaCryptoSha256(L *LState, arg unsafe.Pointer, argLen C.int) (*C.char, *C.char) {
   749  	data := C.GoBytes(arg, argLen)
   750  	if checkHexString(string(data)) {
   751  		dataStr := data[2:]
   752  		var err error
   753  		data, err = hex.DecodeString(string(dataStr))
   754  		if err != nil {
   755  			return nil, C.CString("[Contract.LuaCryptoSha256] hex decoding error: " + err.Error())
   756  		}
   757  	}
   758  	h := sha256.New()
   759  	h.Write(data)
   760  	resultHash := h.Sum(nil)
   761  
   762  	return C.CString("0x" + hex.EncodeToString(resultHash)), nil
   763  }
   764  
   765  func decodeHex(hexStr string) ([]byte, error) {
   766  	if checkHexString(hexStr) {
   767  		hexStr = hexStr[2:]
   768  	}
   769  	return hex.DecodeString(hexStr)
   770  }
   771  
   772  //export LuaECVerify
   773  func LuaECVerify(L *LState, msg *C.char, sig *C.char, addr *C.char) (C.int, *C.char) {
   774  	bMsg, err := decodeHex(C.GoString(msg))
   775  	if err != nil {
   776  		return -1, C.CString("[Contract.LuaEcVerify] invalid message format: " + err.Error())
   777  	}
   778  	bSig, err := decodeHex(C.GoString(sig))
   779  	if err != nil {
   780  		return -1, C.CString("[Contract.LuaEcVerify] invalid signature format: " + err.Error())
   781  	}
   782  	address := C.GoString(addr)
   783  	setInstMinusCount(L, 10000)
   784  
   785  	var pubKey *btcec.PublicKey
   786  	var verifyResult bool
   787  	isAergo := len(address) == types.EncodedAddressLength
   788  
   789  	/*Aergo Address*/
   790  	if isAergo {
   791  		bAddress, err := types.DecodeAddress(address)
   792  		if err != nil {
   793  			return -1, C.CString("[Contract.LuaEcVerify] invalid aergo address: " + err.Error())
   794  		}
   795  		pubKey, err = btcec.ParsePubKey(bAddress, btcec.S256())
   796  		if err != nil {
   797  			return -1, C.CString("[Contract.LuaEcVerify] error parsing pubKey: " + err.Error())
   798  		}
   799  	}
   800  
   801  	// CompactSign
   802  	if len(bSig) == 65 {
   803  		// ethereum
   804  		if !isAergo {
   805  			btcsig := make([]byte, 65)
   806  			btcsig[0] = bSig[64] + 27
   807  			copy(btcsig[1:], bSig)
   808  			bSig = btcsig
   809  		}
   810  		pub, _, err := btcec.RecoverCompact(btcec.S256(), bSig, bMsg)
   811  		if err != nil {
   812  			return -1, C.CString("[Contract.LuaEcVerify] error recoverCompact: " + err.Error())
   813  		}
   814  		if pubKey != nil {
   815  			verifyResult = pubKey.IsEqual(pub)
   816  		} else {
   817  			bAddress, err := decodeHex(address)
   818  			if err != nil {
   819  				return -1, C.CString("[Contract.LuaEcVerify] invalid Ethereum address: " + err.Error())
   820  			}
   821  			bPub := pub.SerializeUncompressed()
   822  			h := sha256.New()
   823  			h.Write(bPub[1:])
   824  			signAddress := h.Sum(nil)[12:]
   825  			verifyResult = bytes.Equal(bAddress, signAddress)
   826  		}
   827  	} else {
   828  		sign, err := btcec.ParseSignature(bSig, btcec.S256())
   829  		if err != nil {
   830  			return -1, C.CString("[Contract.LuaEcVerify] error parsing signature: " + err.Error())
   831  		}
   832  		if pubKey == nil {
   833  			return -1, C.CString("[Contract.LuaEcVerify] error recovering pubKey")
   834  		}
   835  		verifyResult = sign.Verify(bMsg, pubKey)
   836  	}
   837  	if verifyResult {
   838  		return C.int(1), nil
   839  	}
   840  	return C.int(0), nil
   841  }
   842  
   843  func luaCryptoToBytes(data unsafe.Pointer, dataLen C.int) ([]byte, bool) {
   844  	var d []byte
   845  	b := C.GoBytes(data, dataLen)
   846  	isHex := checkHexString(string(b))
   847  	if isHex {
   848  		var err error
   849  		d, err = hex.DecodeString(string(b[2:]))
   850  		if err != nil {
   851  			isHex = false
   852  		}
   853  	}
   854  	if !isHex {
   855  		d = b
   856  	}
   857  	return d, isHex
   858  }
   859  
   860  //export LuaCryptoVerifyProof
   861  func LuaCryptoVerifyProof(
   862  	key unsafe.Pointer, keyLen C.int,
   863  	value unsafe.Pointer, valueLen C.int,
   864  	hash unsafe.Pointer, hashLen C.int,
   865  	proof unsafe.Pointer, nProof C.int,
   866  ) C.int {
   867  	k, _ := luaCryptoToBytes(key, keyLen)
   868  	v, _ := luaCryptoToBytes(value, valueLen)
   869  	h, _ := luaCryptoToBytes(hash, hashLen)
   870  	cProof := (*[1 << 30]C.struct_proof)(proof)[:nProof:nProof]
   871  	bProof := make([][]byte, int(nProof))
   872  	for i, p := range cProof {
   873  		bProof[i], _ = luaCryptoToBytes(p.data, C.int(p.len))
   874  	}
   875  	if verifyEthStorageProof(k, v, h, bProof) {
   876  		return C.int(1)
   877  	}
   878  	return C.int(0)
   879  }
   880  
   881  //export LuaCryptoKeccak256
   882  func LuaCryptoKeccak256(data unsafe.Pointer, dataLen C.int) (unsafe.Pointer, int) {
   883  	d, isHex := luaCryptoToBytes(data, dataLen)
   884  	h := keccak256(d)
   885  	if isHex {
   886  		hex := []byte("0x" + hex.EncodeToString(h))
   887  		return C.CBytes(hex), len(hex)
   888  	} else {
   889  		return C.CBytes(h), len(h)
   890  	}
   891  }
   892  
   893  func transformAmount(amountStr string) (*big.Int, error) {
   894  	var ret *big.Int
   895  	var prev int
   896  	if len(amountStr) == 0 {
   897  		return zeroBig, nil
   898  	}
   899  	index := suffixarray.New([]byte(amountStr))
   900  	r := regexp.MustCompile("(?i)aergo|gaer|aer")
   901  
   902  	res := index.FindAllIndex(r, -1)
   903  	for _, pair := range res {
   904  		amountBig, _ := new(big.Int).SetString(strings.TrimSpace(amountStr[prev:pair[0]]), 10)
   905  		if amountBig == nil {
   906  			return nil, errors.New("converting error for BigNum: " + amountStr[prev:])
   907  		}
   908  		cmp := amountBig.Cmp(zeroBig)
   909  		if cmp < 0 {
   910  			return nil, errors.New("negative amount not allowed")
   911  		} else if cmp == 0 {
   912  			prev = pair[1]
   913  			continue
   914  		}
   915  		switch pair[1] - pair[0] {
   916  		case 3:
   917  		case 4:
   918  			amountBig = new(big.Int).Mul(amountBig, mulGaer)
   919  		case 5:
   920  			amountBig = new(big.Int).Mul(amountBig, mulAergo)
   921  		}
   922  		if ret != nil {
   923  			ret = new(big.Int).Add(ret, amountBig)
   924  		} else {
   925  			ret = amountBig
   926  		}
   927  		prev = pair[1]
   928  	}
   929  
   930  	if prev >= len(amountStr) {
   931  		if ret != nil {
   932  			return ret, nil
   933  		} else {
   934  			return zeroBig, nil
   935  		}
   936  	}
   937  	num := strings.TrimSpace(amountStr[prev:])
   938  	if len(num) == 0 {
   939  		if ret != nil {
   940  			return ret, nil
   941  		} else {
   942  			return zeroBig, nil
   943  		}
   944  	}
   945  
   946  	amountBig, _ := new(big.Int).SetString(num, 10)
   947  
   948  	if amountBig == nil {
   949  		return nil, errors.New("converting error for Integer: " + amountStr[prev:])
   950  	}
   951  	if amountBig.Cmp(zeroBig) < 0 {
   952  		return nil, errors.New("negative amount not allowed")
   953  	}
   954  	if ret != nil {
   955  		ret = new(big.Int).Add(ret, amountBig)
   956  	} else {
   957  		ret = amountBig
   958  	}
   959  	return ret, nil
   960  }
   961  
   962  //export LuaDeployContract
   963  func LuaDeployContract(
   964  	L *LState,
   965  	service *C.int,
   966  	contract *C.char,
   967  	args *C.char,
   968  	amount *C.char,
   969  ) (C.int, *C.char) {
   970  
   971  	argsStr := C.GoString(args)
   972  	contractStr := C.GoString(contract)
   973  
   974  	stateSet := curStateSet[*service]
   975  	if stateSet == nil {
   976  		return -1, C.CString("[Contract.LuaDeployContract]not found contract state")
   977  	}
   978  	if stateSet.isQuery == true {
   979  		return -1, C.CString("[Contract.LuaDeployContract]send not permitted in query")
   980  	}
   981  	bs := stateSet.bs
   982  
   983  	// get code
   984  	var code []byte
   985  
   986  	cid, err := getAddressNameResolved(contractStr, bs)
   987  	if err == nil {
   988  		aid := types.ToAccountID(cid)
   989  		contractState, err := getOnlyContractState(stateSet, aid)
   990  		if err != nil {
   991  			return -1, C.CString("[Contract.LuaDeployContract]" + err.Error())
   992  		}
   993  		code, err = contractState.GetCode()
   994  		if err != nil {
   995  			return -1, C.CString("[Contract.LuaDeployContract]" + err.Error())
   996  		} else if len(code) == 0 {
   997  			return -1, C.CString("[Contract.LuaDeployContract]: not found code")
   998  		}
   999  	}
  1000  
  1001  	if len(code) == 0 {
  1002  		l := luacUtil.NewLState()
  1003  		if l == nil {
  1004  			return -1, C.CString("[Contract.LuaDeployContract] get luaState error")
  1005  		}
  1006  		defer luacUtil.CloseLState(l)
  1007  		code, err = luacUtil.Compile(l, contractStr)
  1008  		if err != nil {
  1009  			return -1, C.CString("[Contract.LuaDeployContract]compile error:" + err.Error())
  1010  		}
  1011  	}
  1012  
  1013  	err = addUpdateSize(stateSet, int64(len(code)))
  1014  	if err != nil {
  1015  		return -1, C.CString("[Contract.LuaDeployContract]:" + err.Error())
  1016  	}
  1017  
  1018  	// create account
  1019  	prevContractInfo := stateSet.curContract
  1020  	creator := prevContractInfo.callState.curState
  1021  	newContract, err := bs.CreateAccountStateV(CreateContractID(prevContractInfo.contractId, creator.GetNonce()))
  1022  	if err != nil {
  1023  		return -1, C.CString("[Contract.LuaDeployContract]:" + err.Error())
  1024  	}
  1025  	contractState, err := bs.OpenContractState(newContract.AccountID(), newContract.State())
  1026  	if err != nil {
  1027  		return -1, C.CString("[Contract.LuaDeployContract]:" + err.Error())
  1028  	}
  1029  
  1030  	callState := &CallState{ctrState: contractState, prevState: &types.State{}, curState: newContract.State()}
  1031  	stateSet.callState[newContract.AccountID()] = callState
  1032  
  1033  	amountBig, err := transformAmount(C.GoString(amount))
  1034  	if err != nil {
  1035  		return -1, C.CString("[Contract.LuaDeployContract]value not proper format:" + err.Error())
  1036  	}
  1037  	var ci types.CallInfo
  1038  	err = getCallInfo(&ci.Args, []byte(argsStr), newContract.ID())
  1039  	if err != nil {
  1040  		return -1, C.CString("[Contract.LuaDeployContract] invalid args:" + err.Error())
  1041  	}
  1042  	runCode := getContract(contractState, code)
  1043  
  1044  	senderState := prevContractInfo.callState.curState
  1045  	if amountBig.Cmp(zeroBig) > 0 {
  1046  		if rv := sendBalance(L, senderState, callState.curState, amountBig); rv != nil {
  1047  			return -1, rv
  1048  		}
  1049  	}
  1050  
  1051  	seq, err := setRecoveryPoint(newContract.AccountID(), stateSet, senderState, callState, amountBig, false)
  1052  	if err != nil {
  1053  		return -1, C.CString("[System.LuaDeployContract] DB err:" + err.Error())
  1054  	}
  1055  	if stateSet.traceFile != nil {
  1056  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[DEPLOY] %s(%s)\n",
  1057  			types.EncodeAddress(newContract.ID()), newContract.AccountID().String()))
  1058  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("deploy snapshot set %d\n", seq))
  1059  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("SendBalance : %s\n", amountBig.String()))
  1060  		_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("After sender: %s receiver: %s\n",
  1061  			senderState.GetBalanceBigInt().String(), callState.curState.GetBalanceBigInt().String()))
  1062  	}
  1063  	stateSet.curContract = newContractInfo(callState, prevContractInfo.contractId, newContract.ID(),
  1064  		callState.curState.SqlRecoveryPoint, amountBig)
  1065  	defer func() {
  1066  		stateSet.curContract = prevContractInfo
  1067  	}()
  1068  
  1069  	err = contractState.SetCode(code)
  1070  	if err != nil {
  1071  		return -1, C.CString("[Contract.LuaDeployContract]:" + err.Error())
  1072  	}
  1073  	err = contractState.SetData(creatorMetaKey, []byte(types.EncodeAddress(prevContractInfo.contractId)))
  1074  	if err != nil {
  1075  		return -1, C.CString("[Contract.LuaDeployContract]:" + err.Error())
  1076  	}
  1077  
  1078  	ce := newExecutor(runCode, newContract.ID(), stateSet, &ci, amountBig, true, contractState)
  1079  	if ce != nil {
  1080  		defer ce.close()
  1081  		if ce.err != nil {
  1082  			return -1, C.CString("[Contract.LuaDeployContract]newExecutor Error :" + ce.err.Error())
  1083  		}
  1084  	}
  1085  
  1086  	// create a sql database for the contract
  1087  	db := LuaGetDbHandle(&stateSet.service)
  1088  	if db == nil {
  1089  		return -1, C.CString("[System.LuaDeployContract] DB err: cannot open a database")
  1090  	}
  1091  	senderState.Nonce += 1
  1092  
  1093  	addr := C.CString(types.EncodeAddress(newContract.ID()))
  1094  	ret := C.int(1)
  1095  	if ce != nil {
  1096  		ce.setCountHook(minusCallCount(C.luaL_instcount(L), luaCallCountDeduc))
  1097  		defer setInstCount(L, ce.L)
  1098  
  1099  		ret += ce.call(L)
  1100  		if ce.err != nil {
  1101  			err := clearRecovery(L, stateSet, seq, true)
  1102  			if err != nil {
  1103  				return -1, C.CString("[Contract.LuaDeployContract] recovery error: " + err.Error())
  1104  			}
  1105  			if stateSet.traceFile != nil {
  1106  				_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("recovery snapshot: %d\n", seq))
  1107  			}
  1108  			return -1, C.CString("[Contract.LuaDeployContract] call err:" + ce.err.Error())
  1109  		}
  1110  	}
  1111  	if seq == 1 {
  1112  		err := clearRecovery(L, stateSet, seq, false)
  1113  		if err != nil {
  1114  			return -1, C.CString("[Contract.LuaDeployContract] recovery error: " + err.Error())
  1115  		}
  1116  	}
  1117  	return ret, addr
  1118  }
  1119  
  1120  //export IsPublic
  1121  func IsPublic() C.int {
  1122  	if PubNet {
  1123  		return C.int(1)
  1124  	} else {
  1125  		return C.int(0)
  1126  	}
  1127  }
  1128  
  1129  //export LuaRandomInt
  1130  func LuaRandomInt(min, max, service C.int) C.int {
  1131  	stateSet := curStateSet[service]
  1132  	if stateSet.seed == nil {
  1133  		setRandomSeed(stateSet)
  1134  	}
  1135  	return C.int(stateSet.seed.Intn(int(max+C.int(1)-min)) + int(min))
  1136  }
  1137  
  1138  //export LuaEvent
  1139  func LuaEvent(L *LState, service *C.int, eventName *C.char, args *C.char) *C.char {
  1140  	stateSet := curStateSet[*service]
  1141  	if stateSet.isQuery == true {
  1142  		return C.CString("[Contract.Event] event not permitted in query")
  1143  	}
  1144  	if stateSet.eventCount >= maxEventCnt {
  1145  		return C.CString(fmt.Sprintf("[Contract.Event] exceeded the maximum number of events(%d)", maxEventCnt))
  1146  	}
  1147  	if len(C.GoString(eventName)) > maxEventNameSize {
  1148  		return C.CString(fmt.Sprintf("[Contract.Event] exceeded the maximum length of event name(%d)", maxEventNameSize))
  1149  	}
  1150  	if len(C.GoString(args)) > maxEventArgSize {
  1151  		return C.CString(fmt.Sprintf("[Contract.Event] exceeded the maximum length of event args(%d)", maxEventArgSize))
  1152  	}
  1153  	stateSet.events = append(
  1154  		stateSet.events,
  1155  		&types.Event{
  1156  			ContractAddress: stateSet.curContract.contractId,
  1157  			EventIdx:        stateSet.eventCount,
  1158  			EventName:       C.GoString(eventName),
  1159  			JsonArgs:        C.GoString(args),
  1160  		},
  1161  	)
  1162  	stateSet.eventCount++
  1163  	return nil
  1164  }
  1165  
  1166  //export LuaIsContract
  1167  func LuaIsContract(L *LState, service *C.int, contractId *C.char) (C.int, *C.char) {
  1168  	stateSet := curStateSet[*service]
  1169  	if stateSet == nil {
  1170  		return -1, C.CString("[Contract.LuaIsContract] contract state not found")
  1171  	}
  1172  	cid, err := getAddressNameResolved(C.GoString(contractId), stateSet.bs)
  1173  	if err != nil {
  1174  		return -1, C.CString("[Contract.LuaIsContract] invalid contractId: " + err.Error())
  1175  	}
  1176  
  1177  	aid := types.ToAccountID(cid)
  1178  	callState, err := getCallState(stateSet, aid)
  1179  	if err != nil {
  1180  		return -1, C.CString("[Contract.LuaIsContract] getAccount error: " + err.Error())
  1181  	}
  1182  	return C.int(len(callState.curState.GetCodeHash())), nil
  1183  }
  1184  
  1185  //export LuaGovernance
  1186  func LuaGovernance(L *LState, service *C.int, gType C.char, arg *C.char) *C.char {
  1187  	stateSet := curStateSet[*service]
  1188  	if stateSet == nil {
  1189  		return C.CString("[Contract.LuaGovernance] contract state not found")
  1190  	}
  1191  	var amountBig *big.Int
  1192  	var payload []byte
  1193  
  1194  	if gType != 'V' {
  1195  		var err error
  1196  		amountBig, err = transformAmount(C.GoString(arg))
  1197  		if err != nil {
  1198  			return C.CString("[Contract.LuaGovernance] invalid amount: " + err.Error())
  1199  		}
  1200  		if stateSet.isQuery == true && amountBig.Cmp(zeroBig) > 0 {
  1201  			return C.CString("[Contract.LuaGovernance] governance not permitted in query")
  1202  		}
  1203  		if gType == 'S' {
  1204  			payload = []byte(fmt.Sprintf(`{"Name":"%s"}`, types.Stake))
  1205  		} else {
  1206  			payload = []byte(fmt.Sprintf(`{"Name":"%s"}`, types.Unstake))
  1207  		}
  1208  	} else {
  1209  		amountBig = zeroBig
  1210  		payload = []byte(fmt.Sprintf(`{"Name":"%s","Args":%s}`, types.VoteBP, C.GoString(arg)))
  1211  	}
  1212  	aid := types.ToAccountID([]byte(types.AergoSystem))
  1213  	scsState, err := getCtrState(stateSet, aid)
  1214  	if err != nil {
  1215  		return C.CString("[Contract.LuaGovernance] getAccount error: " + err.Error())
  1216  	}
  1217  	curContract := stateSet.curContract
  1218  
  1219  	senderState := stateSet.curContract.callState.curState
  1220  	sender := stateSet.bs.InitAccountStateV(curContract.contractId,
  1221  		curContract.callState.prevState, curContract.callState.curState)
  1222  	receiver := stateSet.bs.InitAccountStateV([]byte(types.AergoSystem), scsState.prevState, scsState.curState)
  1223  	txBody := types.TxBody{
  1224  		Amount:  amountBig.Bytes(),
  1225  		Payload: payload,
  1226  	}
  1227  	err = types.ValidateSystemTx(&txBody)
  1228  	if err != nil {
  1229  		return C.CString("[Contract.LuaGovernance] error: " + err.Error())
  1230  	}
  1231  	seq, err := setRecoveryPoint(aid, stateSet, senderState, scsState, zeroBig, false)
  1232  	if err != nil {
  1233  		return C.CString("[Contract.LuaGovernance] database error: " + err.Error())
  1234  	}
  1235  	evs, err := system.ExecuteSystemTx(scsState.ctrState, &txBody, sender, receiver, stateSet.blockHeight)
  1236  	if err != nil {
  1237  		rErr := clearRecovery(L, stateSet, seq, true)
  1238  		if rErr != nil {
  1239  			return C.CString("[Contract.LuaGovernance] recovery error: " + rErr.Error())
  1240  		}
  1241  		return C.CString("[Contract.LuaGovernance] error: " + err.Error())
  1242  	}
  1243  	if seq == 1 {
  1244  		err := clearRecovery(L, stateSet, seq, false)
  1245  		if err != nil {
  1246  			return C.CString("[Contract.LuaGovernance] recovery error: " + err.Error())
  1247  		}
  1248  	}
  1249  	stateSet.eventCount += int32(len(evs))
  1250  	stateSet.events = append(stateSet.events, evs...)
  1251  
  1252  	if stateSet.lastRecoveryEntry != nil {
  1253  		if gType == 'S' {
  1254  			seq, _ = setRecoveryPoint(aid, stateSet, senderState, scsState, amountBig, true)
  1255  			if stateSet.traceFile != nil {
  1256  				_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[GOVERNANCE]aid(%s)\n", aid.String()))
  1257  				_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("snapshot set %d\n", seq))
  1258  				_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("staking : %s\n", amountBig.String()))
  1259  				_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("After sender: %s receiver: %s\n",
  1260  					senderState.GetBalanceBigInt().String(), scsState.curState.GetBalanceBigInt().String()))
  1261  			}
  1262  		} else if gType == 'U' {
  1263  			seq, _ = setRecoveryPoint(aid, stateSet, scsState.curState, stateSet.curContract.callState, amountBig, true)
  1264  			if stateSet.traceFile != nil {
  1265  				_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("[GOVERNANCE]aid(%s)\n", aid.String()))
  1266  				_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("snapshot set %d\n", seq))
  1267  				_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("unstaking : %s\n", amountBig.String()))
  1268  				_, _ = stateSet.traceFile.WriteString(fmt.Sprintf("After sender: %s receiver: %s\n",
  1269  					senderState.GetBalanceBigInt().String(), scsState.curState.GetBalanceBigInt().String()))
  1270  			}
  1271  		}
  1272  	}
  1273  	return nil
  1274  }
  1275  
  1276  //export LuaGetDbHandleSnap
  1277  func LuaGetDbHandleSnap(service *C.int, snap *C.char) *C.char {
  1278  	stateSet := curStateSet[*service]
  1279  	curContract := stateSet.curContract
  1280  	callState := curContract.callState
  1281  
  1282  	if stateSet.isQuery != true {
  1283  		return C.CString("[Contract.LuaSetDbSnap] not permitted in transaction")
  1284  	}
  1285  	if callState.tx != nil {
  1286  		return C.CString("[Contract.LuaSetDbSnap] transaction already started")
  1287  	}
  1288  	rp, err := strconv.ParseUint(C.GoString(snap), 10, 64)
  1289  	if err != nil {
  1290  		return C.CString("[Contract.LuaSetDbSnap] snapshot is not valid" + C.GoString(snap))
  1291  	}
  1292  	aid := types.ToAccountID(curContract.contractId)
  1293  	tx, err := BeginReadOnly(aid.String(), rp)
  1294  	if err != nil {
  1295  		return C.CString("Error Begin SQL Transaction")
  1296  	}
  1297  	callState.tx = tx
  1298  	return nil
  1299  }
  1300  
  1301  //export LuaGetDbSnapshot
  1302  func LuaGetDbSnapshot(service *C.int) *C.char {
  1303  	stateSet := curStateSet[*service]
  1304  	curContract := stateSet.curContract
  1305  
  1306  	return C.CString(strconv.FormatUint(curContract.rp, 10))
  1307  }