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 }