From b4540a0363441b1f45acbb69598e47170415908b Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 15 Jun 2022 20:08:07 -0300 Subject: [PATCH 001/182] [contract] composable transactions --- chain/chainhandle.go | 18 +++- contract/contract.go | 24 +++-- contract/vm.go | 57 ++++++++-- contract/vm_multicall.go | 216 ++++++++++++++++++++++++++++++++++++++ contract/vm_multicall.lua | 196 ++++++++++++++++++++++++++++++++++ state/contract.go | 13 +++ types/blockchain.pb.go | 3 + types/transaction.go | 7 +- 8 files changed, 511 insertions(+), 23 deletions(-) create mode 100644 contract/vm_multicall.go create mode 100644 contract/vm_multicall.lua diff --git a/chain/chainhandle.go b/chain/chainhandle.go index 3c8620f67..47010d0ee 100644 --- a/chain/chainhandle.go +++ b/chain/chainhandle.go @@ -919,12 +919,21 @@ func executeTx( return err } - if recipient, err = name.Resolve(bs, txBody.Recipient, isQuirkTx); err != nil { - return err + isMultiCall := (txBody.Type == types.TxType_MULTICALL) + + if isMultiCall { + recipient = account + } else { + if recipient, err = name.Resolve(bs, txBody.Recipient, isQuirkTx); err != nil { + return err + } } + var receiver *state.V status := "SUCCESS" - if len(recipient) > 0 { + if isMultiCall { + receiver = sender + } else if len(recipient) > 0 { receiver, err = bs.GetAccountStateV(recipient) if receiver != nil && txBody.Type == types.TxType_REDEPLOY { status = "RECREATED" @@ -941,8 +950,9 @@ func executeTx( var txFee *big.Int var rv string var events []*types.Event + switch txBody.Type { - case types.TxType_NORMAL, types.TxType_REDEPLOY, types.TxType_TRANSFER, types.TxType_CALL, types.TxType_DEPLOY: + case types.TxType_NORMAL, types.TxType_TRANSFER, types.TxType_CALL, types.TxType_MULTICALL, types.TxType_DEPLOY, types.TxType_REDEPLOY: rv, events, txFee, err = contract.Execute(bs, cdb, tx.GetTx(), sender, receiver, bi, preLoadService, false) sender.SubBalance(txFee) case types.TxType_GOVERNANCE: diff --git a/contract/contract.go b/contract/contract.go index 1be92f8d5..18a46836e 100644 --- a/contract/contract.go +++ b/contract/contract.go @@ -71,6 +71,7 @@ func Execute( isFeeDelegation bool, ) (rv string, events []*types.Event, usedFee *big.Int, err error) { txBody := tx.GetBody() + isMultiCall := (txBody.Type == types.TxType_MULTICALL) usedFee = txFee(len(txBody.GetPayload()), bs.GasPrice, bi.Version) @@ -84,7 +85,7 @@ func Execute( receiver.AddBalance(txBody.GetAmountBigInt()) } - if !receiver.IsDeploy() && len(receiver.State().CodeHash) == 0 { + if !isMultiCall && !receiver.IsDeploy() && len(receiver.State().CodeHash) == 0 { // Before the chain version 3, any tx with no code hash is // unconditionally executed as a simple Aergo transfer. Since this // causes confusion, emit error for call-type tx with a wrong address @@ -127,10 +128,16 @@ func Execute( } } - contractState, err := bs.OpenContractState(receiver.AccountID(), receiver.State()) + var contractState *state.ContractState + if isMultiCall { + contractState = bs.GetMultiCallState(sender.AccountID(), sender.State()) + } else { + contractState, err = bs.OpenContractState(receiver.AccountID(), receiver.State()) + } if err != nil { return } + if receiver.IsRedeploy() { if err = checkRedeploy(sender, receiver, contractState); err != nil { return @@ -163,7 +170,7 @@ func Execute( } else { ctx := newVmContext(bs, cdb, sender, receiver, contractState, sender.ID(), tx.GetHash(), bi, "", true, false, receiver.RP(), - preLoadService, txBody.GetAmountBigInt(), gasLimit, isFeeDelegation) + preLoadService, txBody.GetAmountBigInt(), gasLimit, isFeeDelegation, isMultiCall) if receiver.IsDeploy() { rv, events, ctrFee, err = Create(contractState, txBody.Payload, receiver.ID(), ctx) @@ -196,9 +203,11 @@ func Execute( } } - err = bs.StageContractState(contractState) - if err != nil { - return "", events, usedFee, err + if !isMultiCall { + err = bs.StageContractState(contractState) + if err != nil { + return "", events, usedFee, err + } } return rv, events, usedFee, nil @@ -269,7 +278,8 @@ func preLoadWorker() { ctx := newVmContext(bs, nil, nil, receiver, contractState, txBody.GetAccount(), tx.GetHash(), reqInfo.bi, "", false, false, receiver.RP(), reqInfo.preLoadService, txBody.GetAmountBigInt(), txBody.GetGasLimit(), - txBody.Type == types.TxType_FEEDELEGATION) + txBody.Type == types.TxType_FEEDELEGATION, + txBody.Type == types.TxType_MULTICALL) ex, err := PreloadEx(bs, contractState, txBody.Payload, receiver.ID(), ctx) if ex == nil && ctx.traceFile != nil { diff --git a/contract/vm.go b/contract/vm.go index eb0f2ca53..50d90747f 100644 --- a/contract/vm.go +++ b/contract/vm.go @@ -93,6 +93,7 @@ type vmContext struct { isQuery bool nestedView int32 isFeeDelegation bool + isMultiCall bool service C.int callState map[types.AccountID]*callState lastRecoveryEntry *recoveryEntry @@ -169,14 +170,14 @@ func getTraceFile(blkno uint64, tx []byte) *os.File { return f } -func newVmContext(blockState *state.BlockState, cdb ChainAccessor, sender, reciever *state.V, +func newVmContext(blockState *state.BlockState, cdb ChainAccessor, sender, receiver *state.V, contractState *state.ContractState, senderID []byte, txHash []byte, bi *types.BlockHeaderInfo, node string, confirmed bool, - query bool, rp uint64, service int, amount *big.Int, gasLimit uint64, feeDelegation bool) *vmContext { + query bool, rp uint64, service int, amount *big.Int, gasLimit uint64, feeDelegation bool, isMultiCall bool) *vmContext { - cs := &callState{ctrState: contractState, curState: reciever.State()} + cs := &callState{ctrState: contractState, curState: receiver.State()} ctx := &vmContext{ - curContract: newContractInfo(cs, senderID, reciever.ID(), rp, amount), + curContract: newContractInfo(cs, senderID, receiver.ID(), rp, amount), bs: blockState, cdb: cdb, origin: senderID, @@ -189,10 +190,11 @@ func newVmContext(blockState *state.BlockState, cdb ChainAccessor, sender, recie gasLimit: gasLimit, remainedGas: gasLimit, isFeeDelegation: feeDelegation, + isMultiCall: isMultiCall, } ctx.callState = make(map[types.AccountID]*callState) - ctx.callState[reciever.AccountID()] = cs - if sender != nil { + ctx.callState[receiver.AccountID()] = cs + if sender != nil && sender != receiver { ctx.callState[sender.AccountID()] = &callState{curState: sender.State()} } if TraceBlockNo != 0 && TraceBlockNo == ctx.blockInfo.No { @@ -759,6 +761,13 @@ func refreshGas(ctx *vmContext, L *LState) { } } +func getMultiCallInfo(ci *types.CallInfo, payload []byte) error { + payload = append([]byte{'['}, payload...) + payload = append(payload, ']') + ci.Name = "execute" + return getCallInfo(&ci.Args, payload, []byte("multicall")) +} + func getCallInfo(ci interface{}, args []byte, contractAddress []byte) error { d := json.NewDecoder(bytes.NewReader(args)) d.UseNumber() @@ -775,16 +784,26 @@ func getCallInfo(ci interface{}, args []byte, contractAddress []byte) error { func Call( contractState *state.ContractState, - code, contractAddress []byte, + payload, contractAddress []byte, ctx *vmContext, ) (string, []*types.Event, *big.Int, error) { var err error var ci types.CallInfo - contract := getContract(contractState, ctx.bs) + var contract []byte + + if ctx.isMultiCall { + contract = getMultiCallContract(contractState) + } else { + contract = getContract(contractState, ctx.bs) + } if contract != nil { - if len(code) > 0 { - err = getCallInfo(&ci, code, contractAddress) + if ctx.isMultiCall { + err = getMultiCallInfo(&ci, payload) + } else { + if len(payload) > 0 { + err = getCallInfo(&ci, payload, contractAddress) + } } } else { addr := types.EncodeAddress(contractAddress) @@ -795,7 +814,7 @@ func Call( return "", nil, ctx.usedFee(), err } if ctrLgr.IsDebugEnabled() { - ctrLgr.Debug().Str("abi", string(code)).Str("contract", types.EncodeAddress(contractAddress)).Msg("call") + ctrLgr.Debug().Str("abi", string(payload)).Str("contract", types.EncodeAddress(contractAddress)).Msg("call") } contexts[ctx.service] = ctx @@ -825,11 +844,13 @@ func Call( } return "", ce.getEvents(), ctx.usedFee(), err } + err = ce.commitCalledContract() if err != nil { ctrLgr.Error().Err(err).Str("contract", types.EncodeAddress(contractAddress)).Msg("commit state") return "", ce.getEvents(), ctx.usedFee(), err } + if ctx.traceFile != nil { _, _ = ctx.traceFile.WriteString(fmt.Sprintf("[ret] : %s\n", ce.jsonRet)) _, _ = ctx.traceFile.WriteString(fmt.Sprintf("[usedFee] : %s\n", ctx.usedFee().String())) @@ -845,6 +866,7 @@ func Call( _, _ = ctx.traceFile.WriteString(fmt.Sprintf("[CALL END] : %s(%s)\n", types.EncodeAddress(contractAddress), types.ToAccountID(contractAddress))) } + return ce.jsonRet, ce.getEvents(), ctx.usedFee(), nil } @@ -1227,6 +1249,9 @@ func getCode(contractState *state.ContractState, bs *state.BlockState) ([]byte, } func getContract(contractState *state.ContractState, bs *state.BlockState) []byte { + if len(contractState.GetCodeHash()) == 0 { + return nil + } code, err := getCode(contractState, bs) if err != nil { return nil @@ -1234,6 +1259,16 @@ func getContract(contractState *state.ContractState, bs *state.BlockState) []byt return luacUtil.LuaCode(code).ByteCode() } +func getMultiCallContract(contractState *state.ContractState) []byte { + code := luacUtil.LuaCode(multicall_payload) + if !code.IsValidFormat() { + ctrLgr.Warn().Msg("multicall_payload") + return nil + } + contractState.SetMultiCallCode(multicall_payload) + return code.ByteCode() +} + func GetABI(contractState *state.ContractState, bs *state.BlockState) (*types.ABI, error) { var abi *types.ABI diff --git a/contract/vm_multicall.go b/contract/vm_multicall.go new file mode 100644 index 000000000..f353a1df3 --- /dev/null +++ b/contract/vm_multicall.go @@ -0,0 +1,216 @@ +package contract + +var multicall_payload = []byte { + 0xd4,0x0c,0x00,0x00,0x1b,0x4c,0x4a,0x02,0x0a,0x25,0x02,0x00,0x03,0x00,0x02, + 0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00, + 0x00,0x00,0x09,0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63,0x74, + 0x37,0x02,0x01,0x04,0x00,0x03,0x00,0x07,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01, + 0x39,0x01,0x02,0x01,0x12,0x03,0x00,0x00,0x42,0x01,0x02,0x02,0x47,0x03,0x01,0x00, + 0x43,0x01,0x00,0x00,0x0a,0x76,0x61,0x6c,0x75,0x65,0x09,0x63,0x61,0x6c,0x6c,0x0d, + 0x63,0x6f,0x6e,0x74,0x72,0x61,0x63,0x74,0x41,0x02,0x00,0x05,0x00,0x03,0x01,0x08, + 0x34,0x00,0x03,0x00,0x36,0x01,0x00,0x00,0x36,0x03,0x01,0x00,0x39,0x03,0x02,0x03, + 0x47,0x04,0x00,0x00,0x41,0x01,0x01,0x00,0x3f,0x01,0x00,0x00,0x4c,0x00,0x02,0x00, + 0x09,0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63,0x74,0x0a,0x70, + 0x63,0x61,0x6c,0x6c,0x03,0x80,0x80,0xc0,0x99,0x04,0x53,0x02,0x01,0x07,0x00,0x04, + 0x01,0x0b,0x34,0x01,0x03,0x00,0x36,0x02,0x00,0x00,0x36,0x04,0x01,0x00,0x39,0x04, + 0x02,0x04,0x39,0x04,0x03,0x04,0x12,0x06,0x00,0x00,0x42,0x04,0x02,0x02,0x47,0x05, + 0x01,0x00,0x41,0x02,0x01,0x00,0x3f,0x02,0x00,0x00,0x4c,0x01,0x02,0x00,0x0a,0x76, + 0x61,0x6c,0x75,0x65,0x09,0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61, + 0x63,0x74,0x0a,0x70,0x63,0x61,0x6c,0x6c,0x03,0x80,0x80,0xc0,0x99,0x04,0x28,0x00, + 0x01,0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03, + 0x00,0x00,0x44,0x01,0x02,0x00,0x0c,0x62,0x61,0x6c,0x61,0x6e,0x63,0x65,0x0d,0x63, + 0x6f,0x6e,0x74,0x72,0x61,0x63,0x74,0x29,0x00,0x02,0x06,0x00,0x02,0x00,0x05,0x36, + 0x02,0x00,0x00,0x39,0x02,0x01,0x02,0x12,0x04,0x00,0x00,0x12,0x05,0x01,0x00,0x44, + 0x02,0x03,0x00,0x09,0x73,0x65,0x6e,0x64,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63, + 0x74,0x18,0x00,0x02,0x03,0x00,0x01,0x00,0x03,0x36,0x02,0x00,0x00,0x3c,0x01,0x00, + 0x02,0x4b,0x00,0x01,0x00,0x09,0x76,0x61,0x72,0x73,0x2c,0x00,0x01,0x03,0x00,0x02, + 0x00,0x05,0x36,0x01,0x00,0x00,0x36,0x02,0x00,0x00,0x39,0x02,0x01,0x02,0x3c,0x02, + 0x00,0x01,0x4b,0x00,0x01,0x00,0x10,0x6c,0x61,0x73,0x74,0x5f,0x72,0x65,0x73,0x75, + 0x6c,0x74,0x09,0x76,0x61,0x72,0x73,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x38, + 0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x0f,0x00,0x03,0x03,0x00,0x00,0x00,0x02,0x3c, + 0x02,0x01,0x00,0x4b,0x00,0x01,0x00,0x28,0x02,0x00,0x03,0x00,0x02,0x00,0x05,0x36, + 0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x41,0x00,0x00,0x01,0x4b, + 0x00,0x01,0x00,0x0b,0x69,0x6e,0x73,0x65,0x72,0x74,0x0a,0x74,0x61,0x62,0x6c,0x65, + 0x28,0x02,0x00,0x03,0x00,0x02,0x00,0x05,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00, + 0x47,0x02,0x00,0x00,0x41,0x00,0x00,0x01,0x4b,0x00,0x01,0x00,0x0b,0x72,0x65,0x6d, + 0x6f,0x76,0x65,0x0a,0x74,0x61,0x62,0x6c,0x65,0x0f,0x00,0x02,0x03,0x00,0x00,0x00, + 0x02,0x20,0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00, + 0x02,0x21,0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00, + 0x02,0x22,0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00, + 0x02,0x23,0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00, + 0x02,0x25,0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00, + 0x02,0x24,0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x23,0x00,0x01,0x04,0x00,0x02,0x00, + 0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03,0x00,0x00,0x44,0x01,0x02, + 0x00,0x09,0x73,0x71,0x72,0x74,0x0b,0x62,0x69,0x67,0x6e,0x75,0x6d,0x25,0x02,0x00, + 0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00, + 0x00,0x43,0x00,0x00,0x00,0x0b,0x66,0x6f,0x72,0x6d,0x61,0x74,0x0b,0x73,0x74,0x72, + 0x69,0x6e,0x67,0x22,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00,0x00,0x39, + 0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x08,0x73,0x75,0x62,0x0b, + 0x73,0x74,0x72,0x69,0x6e,0x67,0x24,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00, + 0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x0a,0x6d, + 0x61,0x74,0x63,0x68,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x23,0x02,0x00,0x03,0x00, + 0x02,0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43, + 0x00,0x00,0x00,0x09,0x67,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x25, + 0x00,0x01,0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12, + 0x03,0x00,0x00,0x44,0x01,0x02,0x00,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x0b,0x62, + 0x69,0x67,0x6e,0x75,0x6d,0x1c,0x00,0x01,0x04,0x00,0x01,0x00,0x03,0x36,0x01,0x00, + 0x00,0x12,0x03,0x00,0x00,0x44,0x01,0x02,0x00,0x0d,0x74,0x6f,0x6e,0x75,0x6d,0x62, + 0x65,0x72,0x1c,0x00,0x01,0x04,0x00,0x01,0x00,0x03,0x36,0x01,0x00,0x00,0x12,0x03, + 0x00,0x00,0x44,0x01,0x02,0x00,0x0d,0x74,0x6f,0x73,0x74,0x72,0x69,0x6e,0x67,0x23, + 0x00,0x01,0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12, + 0x03,0x00,0x00,0x44,0x01,0x02,0x00,0x0b,0x65,0x6e,0x63,0x6f,0x64,0x65,0x09,0x6a, + 0x73,0x6f,0x6e,0x23,0x00,0x01,0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00,0x39, + 0x01,0x01,0x01,0x12,0x03,0x00,0x00,0x44,0x01,0x02,0x00,0x0b,0x64,0x65,0x63,0x6f, + 0x64,0x65,0x09,0x6a,0x73,0x6f,0x6e,0x70,0x02,0x00,0x08,0x00,0x05,0x01,0x0e,0x36, + 0x00,0x00,0x00,0x36,0x02,0x01,0x00,0x47,0x04,0x00,0x00,0x41,0x02,0x00,0x02,0x27, + 0x03,0x02,0x00,0x36,0x04,0x03,0x00,0x39,0x04,0x04,0x04,0x34,0x06,0x03,0x00,0x47, + 0x07,0x00,0x00,0x3f,0x07,0x00,0x00,0x42,0x04,0x02,0x02,0x26,0x03,0x04,0x03,0x42, + 0x00,0x03,0x01,0x4b,0x00,0x01,0x00,0x0b,0x65,0x6e,0x63,0x6f,0x64,0x65,0x09,0x6a, + 0x73,0x6f,0x6e,0x17,0x61,0x73,0x73,0x65,0x72,0x74,0x69,0x6f,0x6e,0x20,0x66,0x61, + 0x69,0x6c,0x65,0x64,0x3a,0x20,0x09,0x65,0x76,0x61,0x6c,0x0b,0x61,0x73,0x73,0x65, + 0x72,0x74,0x03,0x80,0x80,0xc0,0x99,0x04,0x80,0x08,0x00,0x01,0x17,0x00,0x19,0x01, + 0xd6,0x01,0x2b,0x01,0x02,0x00,0x2b,0x02,0x01,0x00,0x2c,0x03,0x09,0x00,0x29,0x0a, + 0x01,0x00,0x15,0x0b,0x00,0x00,0x03,0x0a,0x0b,0x00,0x58,0x0b,0xce,0x80,0x55,0x0b, + 0xcd,0x80,0x38,0x0b,0x0a,0x00,0x34,0x0c,0x00,0x00,0x36,0x0d,0x00,0x00,0x12,0x0f, + 0x0b,0x00,0x42,0x0d,0x02,0x04,0x58,0x10,0x01,0x80,0x3c,0x11,0x10,0x0c,0x45,0x10, + 0x03,0x03,0x52,0x10,0xfd,0x7f,0x36,0x0d,0x00,0x00,0x12,0x0f,0x0c,0x00,0x42,0x0d, + 0x02,0x04,0x58,0x10,0x29,0x80,0x29,0x12,0x01,0x00,0x01,0x12,0x10,0x00,0x58,0x12, + 0x26,0x80,0x36,0x12,0x01,0x00,0x12,0x14,0x11,0x00,0x42,0x12,0x02,0x02,0x07,0x12, + 0x02,0x00,0x58,0x12,0x21,0x80,0x15,0x12,0x11,0x00,0x29,0x13,0x03,0x00,0x03,0x13, + 0x12,0x00,0x58,0x12,0x1d,0x80,0x36,0x12,0x02,0x00,0x39,0x12,0x03,0x12,0x12,0x14, + 0x11,0x00,0x29,0x15,0x01,0x00,0x29,0x16,0x01,0x00,0x42,0x12,0x04,0x02,0x07,0x12, + 0x04,0x00,0x58,0x12,0x15,0x80,0x36,0x12,0x02,0x00,0x39,0x12,0x03,0x12,0x12,0x14, + 0x11,0x00,0x29,0x15,0xff,0xff,0x29,0x16,0xff,0xff,0x42,0x12,0x04,0x02,0x07,0x12, + 0x04,0x00,0x58,0x12,0x0d,0x80,0x36,0x12,0x02,0x00,0x39,0x12,0x03,0x12,0x12,0x14, + 0x11,0x00,0x29,0x15,0x02,0x00,0x29,0x16,0xfe,0xff,0x42,0x12,0x04,0x02,0x36,0x13, + 0x05,0x00,0x38,0x13,0x12,0x13,0x0a,0x13,0x00,0x00,0x58,0x13,0x03,0x80,0x36,0x13, + 0x05,0x00,0x38,0x13,0x12,0x13,0x3c,0x13,0x10,0x0c,0x45,0x10,0x03,0x03,0x52,0x10, + 0xd5,0x7f,0x36,0x0d,0x06,0x00,0x39,0x0d,0x07,0x0d,0x12,0x0f,0x0c,0x00,0x29,0x10, + 0x01,0x00,0x42,0x0d,0x03,0x02,0x36,0x0e,0x08,0x00,0x38,0x0e,0x0d,0x0e,0x0f,0x00, + 0x0e,0x00,0x58,0x0f,0x0e,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x0c,0x80,0x12,0x0f, + 0x0e,0x00,0x36,0x11,0x09,0x00,0x12,0x13,0x0c,0x00,0x42,0x11,0x02,0x00,0x41,0x0f, + 0x00,0x02,0x36,0x10,0x0a,0x00,0x38,0x10,0x0d,0x10,0x0e,0x00,0x10,0x00,0x58,0x10, + 0x7f,0x80,0x36,0x10,0x05,0x00,0x3d,0x0f,0x0b,0x10,0x58,0x0f,0x7c,0x80,0x07,0x0d, + 0x0c,0x00,0x58,0x0f,0x08,0x80,0x36,0x0f,0x0d,0x00,0x36,0x11,0x09,0x00,0x12,0x13, + 0x0c,0x00,0x42,0x11,0x02,0x00,0x41,0x0f,0x00,0x02,0x12,0x01,0x0f,0x00,0x12,0x02, + 0x01,0x00,0x58,0x0f,0x72,0x80,0x07,0x0d,0x0e,0x00,0x58,0x0f,0x0e,0x80,0x0f,0x00, + 0x01,0x00,0x58,0x0f,0x02,0x80,0x2b,0x01,0x01,0x00,0x58,0x0f,0x6c,0x80,0x0e,0x00, + 0x02,0x00,0x58,0x0f,0x6a,0x80,0x36,0x0f,0x0d,0x00,0x36,0x11,0x09,0x00,0x12,0x13, + 0x0c,0x00,0x42,0x11,0x02,0x00,0x41,0x0f,0x00,0x02,0x12,0x01,0x0f,0x00,0x12,0x02, + 0x01,0x00,0x58,0x0f,0x62,0x80,0x07,0x0d,0x0f,0x00,0x58,0x0f,0x08,0x80,0x0e,0x00, + 0x01,0x00,0x58,0x0f,0x02,0x80,0x13,0x01,0x02,0x00,0x58,0x0f,0x5c,0x80,0x2b,0x01, + 0x01,0x00,0x58,0x0f,0x01,0x80,0x2b,0x01,0x02,0x00,0x58,0x0f,0x58,0x80,0x07,0x0d, + 0x10,0x00,0x58,0x0f,0x02,0x80,0x2b,0x01,0x02,0x00,0x58,0x0f,0x54,0x80,0x07,0x0d, + 0x11,0x00,0x58,0x0f,0x0b,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x09,0x80,0x12,0x03, + 0x0a,0x00,0x27,0x05,0x12,0x00,0x3a,0x04,0x01,0x0c,0x3a,0x06,0x02,0x0c,0x29,0x07, + 0x01,0x00,0x36,0x0f,0x05,0x00,0x38,0x10,0x07,0x06,0x3c,0x10,0x04,0x0f,0x58,0x0f, + 0x47,0x80,0x07,0x0d,0x13,0x00,0x58,0x0f,0x0e,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f, + 0x0c,0x80,0x12,0x03,0x0a,0x00,0x27,0x05,0x14,0x00,0x3a,0x04,0x01,0x0c,0x3a,0x08, + 0x03,0x0c,0x3a,0x0f,0x04,0x0c,0x0c,0x09,0x0f,0x00,0x58,0x10,0x01,0x80,0x29,0x09, + 0x01,0x00,0x36,0x0f,0x05,0x00,0x3a,0x10,0x02,0x0c,0x3c,0x10,0x04,0x0f,0x58,0x0f, + 0x37,0x80,0x07,0x0d,0x15,0x00,0x58,0x0f,0x25,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f, + 0x23,0x80,0x07,0x05,0x12,0x00,0x58,0x0f,0x09,0x80,0x16,0x07,0x00,0x07,0x15,0x0f, + 0x06,0x00,0x03,0x07,0x0f,0x00,0x58,0x0f,0x2d,0x80,0x36,0x0f,0x05,0x00,0x38,0x10, + 0x07,0x06,0x3c,0x10,0x04,0x0f,0x12,0x0a,0x03,0x00,0x58,0x0f,0x28,0x80,0x07,0x05, + 0x14,0x00,0x58,0x0f,0x26,0x80,0x36,0x0f,0x05,0x00,0x36,0x10,0x05,0x00,0x38,0x10, + 0x04,0x10,0x20,0x10,0x09,0x10,0x3c,0x10,0x04,0x0f,0x29,0x0f,0x00,0x00,0x01,0x0f, + 0x09,0x00,0x58,0x0f,0x04,0x80,0x36,0x0f,0x05,0x00,0x38,0x0f,0x04,0x0f,0x00,0x08, + 0x0f,0x00,0x58,0x0f,0x1a,0x80,0x29,0x0f,0x00,0x00,0x01,0x09,0x0f,0x00,0x58,0x0f, + 0x05,0x80,0x36,0x0f,0x05,0x00,0x38,0x0f,0x04,0x0f,0x01,0x0f,0x08,0x00,0x58,0x0f, + 0x01,0x80,0x58,0x0f,0x12,0x80,0x12,0x0a,0x03,0x00,0x58,0x0f,0x10,0x80,0x07,0x0d, + 0x16,0x00,0x58,0x0f,0x06,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x04,0x80,0x36,0x0f, + 0x09,0x00,0x12,0x11,0x0c,0x00,0x44,0x0f,0x02,0x00,0x58,0x0f,0x08,0x80,0x0f,0x00, + 0x01,0x00,0x58,0x0f,0x06,0x80,0x36,0x0f,0x17,0x00,0x2b,0x11,0x01,0x00,0x27,0x12, + 0x18,0x00,0x12,0x13,0x0d,0x00,0x26,0x12,0x13,0x12,0x42,0x0f,0x03,0x01,0x16,0x0a, + 0x00,0x0a,0x58,0x0b,0x2f,0x7f,0x4b,0x00,0x01,0x00,0x18,0x63,0x6f,0x6d,0x6d,0x61, + 0x6e,0x64,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x3a,0x20,0x0b,0x61, + 0x73,0x73,0x65,0x72,0x74,0x0b,0x72,0x65,0x74,0x75,0x72,0x6e,0x09,0x6c,0x6f,0x6f, + 0x70,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x08,0x66,0x6f,0x72,0x09,0x65,0x61,0x63, + 0x68,0x0c,0x66,0x6f,0x72,0x65,0x61,0x63,0x68,0x08,0x65,0x6e,0x64,0x09,0x65,0x6c, + 0x73,0x65,0x09,0x65,0x6c,0x69,0x66,0x09,0x65,0x76,0x61,0x6c,0x07,0x69,0x66,0x10, + 0x6c,0x61,0x73,0x74,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x09,0x73,0x6b,0x69,0x70, + 0x0b,0x75,0x6e,0x70,0x61,0x63,0x6b,0x0b,0x61,0x63,0x74,0x69,0x6f,0x6e,0x0b,0x72, + 0x65,0x6d,0x6f,0x76,0x65,0x0a,0x74,0x61,0x62,0x6c,0x65,0x09,0x76,0x61,0x72,0x73, + 0x06,0x25,0x08,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x09,0x74,0x79, + 0x70,0x65,0x0b,0x69,0x70,0x61,0x69,0x72,0x73,0x02,0xc7,0x04,0x02,0x00,0x0d,0x00, + 0x0f,0x01,0x7b,0x34,0x00,0x03,0x00,0x47,0x01,0x00,0x00,0x3f,0x01,0x00,0x00,0x3a, + 0x01,0x01,0x00,0x3a,0x02,0x02,0x00,0x3a,0x03,0x03,0x00,0x2b,0x04,0x01,0x00,0x2b, + 0x05,0x01,0x00,0x36,0x06,0x00,0x00,0x39,0x06,0x01,0x06,0x12,0x08,0x02,0x00,0x29, + 0x09,0x01,0x00,0x29,0x0a,0x01,0x00,0x42,0x06,0x04,0x02,0x07,0x06,0x02,0x00,0x58, + 0x06,0x07,0x80,0x2b,0x04,0x02,0x00,0x36,0x06,0x00,0x00,0x39,0x06,0x01,0x06,0x12, + 0x08,0x02,0x00,0x29,0x09,0x02,0x00,0x42,0x06,0x03,0x02,0x12,0x02,0x06,0x00,0x0b, + 0x01,0x00,0x00,0x58,0x06,0x03,0x80,0x06,0x02,0x03,0x00,0x58,0x06,0x01,0x80,0x58, + 0x06,0x3b,0x80,0x07,0x02,0x03,0x00,0x58,0x06,0x06,0x80,0x04,0x01,0x03,0x00,0x58, + 0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58, + 0x06,0x33,0x80,0x07,0x02,0x04,0x00,0x58,0x06,0x06,0x80,0x00,0x03,0x01,0x00,0x58, + 0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58, + 0x06,0x2b,0x80,0x07,0x02,0x05,0x00,0x58,0x06,0x06,0x80,0x02,0x03,0x01,0x00,0x58, + 0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58, + 0x06,0x23,0x80,0x07,0x02,0x06,0x00,0x58,0x06,0x06,0x80,0x00,0x01,0x03,0x00,0x58, + 0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58, + 0x06,0x1b,0x80,0x07,0x02,0x07,0x00,0x58,0x06,0x06,0x80,0x02,0x01,0x03,0x00,0x58, + 0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58, + 0x06,0x13,0x80,0x07,0x02,0x08,0x00,0x58,0x06,0x0b,0x80,0x36,0x06,0x00,0x00,0x39, + 0x06,0x08,0x06,0x12,0x08,0x01,0x00,0x12,0x09,0x03,0x00,0x42,0x06,0x03,0x02,0x0b, + 0x06,0x00,0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b, + 0x05,0x02,0x00,0x58,0x06,0x06,0x80,0x36,0x06,0x09,0x00,0x2b,0x08,0x01,0x00,0x27, + 0x09,0x0a,0x00,0x12,0x0a,0x02,0x00,0x26,0x09,0x0a,0x09,0x42,0x06,0x03,0x01,0x0f, + 0x00,0x04,0x00,0x58,0x06,0x01,0x80,0x13,0x05,0x05,0x00,0x15,0x06,0x00,0x00,0x29, + 0x07,0x03,0x00,0x01,0x07,0x06,0x00,0x58,0x06,0x1c,0x80,0x3a,0x02,0x04,0x00,0x36, + 0x06,0x0b,0x00,0x36,0x08,0x0c,0x00,0x12,0x0a,0x00,0x00,0x29,0x0b,0x05,0x00,0x15, + 0x0c,0x00,0x00,0x42,0x08,0x04,0x00,0x41,0x06,0x00,0x02,0x07,0x02,0x0d,0x00,0x58, + 0x07,0x05,0x80,0x0d,0x07,0x05,0x00,0x58,0x07,0x01,0x80,0x12,0x07,0x06,0x00,0x4c, + 0x07,0x02,0x00,0x58,0x07,0x0d,0x80,0x07,0x02,0x0e,0x00,0x58,0x07,0x05,0x80,0x0c, + 0x07,0x05,0x00,0x58,0x07,0x01,0x80,0x12,0x07,0x06,0x00,0x4c,0x07,0x02,0x00,0x58, + 0x07,0x06,0x80,0x36,0x07,0x09,0x00,0x2b,0x09,0x01,0x00,0x27,0x0a,0x0a,0x00,0x12, + 0x0b,0x02,0x00,0x26,0x0a,0x0b,0x0a,0x42,0x07,0x03,0x01,0x4c,0x05,0x02,0x00,0x07, + 0x6f,0x72,0x08,0x61,0x6e,0x64,0x0b,0x75,0x6e,0x70,0x61,0x63,0x6b,0x09,0x65,0x76, + 0x61,0x6c,0x19,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x20,0x6e,0x6f,0x74,0x20, + 0x6b,0x6e,0x6f,0x77,0x6e,0x3a,0x20,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x0a,0x6d, + 0x61,0x74,0x63,0x68,0x07,0x3c,0x3d,0x06,0x3c,0x07,0x3e,0x3d,0x06,0x3e,0x06,0x3d, + 0x06,0x21,0x08,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x03,0x80,0x80, + 0xc0,0x99,0x04,0xd3,0x04,0x03,0x00,0x03,0x00,0x45,0x00,0x49,0x34,0x00,0x00,0x00, + 0x37,0x00,0x00,0x00,0x35,0x00,0x01,0x00,0x37,0x00,0x02,0x00,0x35,0x00,0x04,0x00, + 0x33,0x01,0x03,0x00,0x3d,0x01,0x05,0x00,0x33,0x01,0x06,0x00,0x3d,0x01,0x07,0x00, + 0x33,0x01,0x08,0x00,0x3d,0x01,0x09,0x00,0x33,0x01,0x0a,0x00,0x3d,0x01,0x0b,0x00, + 0x33,0x01,0x0c,0x00,0x3d,0x01,0x0d,0x00,0x33,0x01,0x0e,0x00,0x3d,0x01,0x0f,0x00, + 0x33,0x01,0x10,0x00,0x3d,0x01,0x11,0x00,0x33,0x01,0x12,0x00,0x3d,0x01,0x13,0x00, + 0x33,0x01,0x14,0x00,0x3d,0x01,0x15,0x00,0x33,0x01,0x16,0x00,0x3d,0x01,0x17,0x00, + 0x33,0x01,0x18,0x00,0x3d,0x01,0x19,0x00,0x33,0x01,0x1a,0x00,0x3d,0x01,0x1b,0x00, + 0x33,0x01,0x1c,0x00,0x3d,0x01,0x1d,0x00,0x33,0x01,0x1e,0x00,0x3d,0x01,0x1f,0x00, + 0x33,0x01,0x20,0x00,0x3d,0x01,0x21,0x00,0x33,0x01,0x22,0x00,0x3d,0x01,0x23,0x00, + 0x33,0x01,0x24,0x00,0x3d,0x01,0x25,0x00,0x33,0x01,0x26,0x00,0x3d,0x01,0x27,0x00, + 0x33,0x01,0x28,0x00,0x3d,0x01,0x29,0x00,0x33,0x01,0x2a,0x00,0x3d,0x01,0x2b,0x00, + 0x33,0x01,0x2c,0x00,0x3d,0x01,0x2d,0x00,0x33,0x01,0x2e,0x00,0x3d,0x01,0x2f,0x00, + 0x33,0x01,0x30,0x00,0x3d,0x01,0x31,0x00,0x33,0x01,0x32,0x00,0x3d,0x01,0x33,0x00, + 0x33,0x01,0x34,0x00,0x3d,0x01,0x35,0x00,0x33,0x01,0x36,0x00,0x3d,0x01,0x37,0x00, + 0x33,0x01,0x38,0x00,0x3d,0x01,0x39,0x00,0x33,0x01,0x3a,0x00,0x3d,0x01,0x3b,0x00, + 0x33,0x01,0x3c,0x00,0x3d,0x01,0x3d,0x00,0x37,0x00,0x3e,0x00,0x33,0x00,0x3f,0x00, + 0x37,0x00,0x40,0x00,0x33,0x00,0x41,0x00,0x37,0x00,0x42,0x00,0x36,0x00,0x43,0x00, + 0x39,0x00,0x44,0x00,0x36,0x02,0x40,0x00,0x42,0x00,0x02,0x01,0x4b,0x00,0x01,0x00, + 0x0d,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x08,0x61,0x62,0x69,0x09,0x65,0x76, + 0x61,0x6c,0x00,0x0c,0x65,0x78,0x65,0x63,0x75,0x74,0x65,0x00,0x0b,0x61,0x63,0x74, + 0x69,0x6f,0x6e,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x00,0x0d,0x66,0x72,0x6f,0x6d, + 0x6a,0x73,0x6f,0x6e,0x00,0x0b,0x74,0x6f,0x6a,0x73,0x6f,0x6e,0x00,0x0d,0x74,0x6f, + 0x73,0x74,0x72,0x69,0x6e,0x67,0x00,0x0d,0x74,0x6f,0x6e,0x75,0x6d,0x62,0x65,0x72, + 0x00,0x0d,0x74,0x6f,0x62,0x69,0x67,0x6e,0x75,0x6d,0x00,0x0c,0x72,0x65,0x70,0x6c, + 0x61,0x63,0x65,0x00,0x09,0x66,0x69,0x6e,0x64,0x00,0x0b,0x73,0x75,0x62,0x73,0x74, + 0x72,0x00,0x0b,0x66,0x6f,0x72,0x6d,0x61,0x74,0x00,0x09,0x73,0x71,0x72,0x74,0x00, + 0x08,0x6d,0x6f,0x64,0x00,0x08,0x70,0x6f,0x77,0x00,0x08,0x64,0x69,0x76,0x00,0x08, + 0x6d,0x75,0x6c,0x00,0x08,0x73,0x75,0x62,0x00,0x08,0x61,0x64,0x64,0x00,0x0b,0x72, + 0x65,0x6d,0x6f,0x76,0x65,0x00,0x0b,0x69,0x6e,0x73,0x65,0x72,0x74,0x00,0x08,0x73, + 0x65,0x74,0x00,0x08,0x67,0x65,0x74,0x00,0x0a,0x73,0x74,0x6f,0x72,0x65,0x00,0x08, + 0x6c,0x65,0x74,0x00,0x09,0x73,0x65,0x6e,0x64,0x00,0x0c,0x62,0x61,0x6c,0x61,0x6e, + 0x63,0x65,0x00,0x0f,0x70,0x63,0x61,0x6c,0x6c,0x2d,0x73,0x65,0x6e,0x64,0x00,0x0a, + 0x70,0x63,0x61,0x6c,0x6c,0x00,0x0e,0x63,0x61,0x6c,0x6c,0x2d,0x73,0x65,0x6e,0x64, + 0x00,0x09,0x63,0x61,0x6c,0x6c,0x01,0x00,0x00,0x00,0x09,0x73,0x6b,0x69,0x70,0x01, + 0x00,0x05,0x0b,0x69,0x6e,0x73,0x65,0x72,0x74,0x02,0x08,0x6c,0x65,0x74,0x02,0x0a, + 0x73,0x74,0x6f,0x72,0x65,0x02,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x02,0x08,0x73, + 0x65,0x74,0x02,0x09,0x76,0x61,0x72,0x73,0x00,0x7b,0x22,0x76,0x65,0x72,0x73,0x69, + 0x6f,0x6e,0x22,0x3a,0x22,0x30,0x2e,0x32,0x22,0x2c,0x22,0x6c,0x61,0x6e,0x67,0x75, + 0x61,0x67,0x65,0x22,0x3a,0x22,0x6c,0x75,0x61,0x22,0x2c,0x22,0x66,0x75,0x6e,0x63, + 0x74,0x69,0x6f,0x6e,0x73,0x22,0x3a,0x5b,0x7b,0x22,0x6e,0x61,0x6d,0x65,0x22,0x3a, + 0x22,0x65,0x78,0x65,0x63,0x75,0x74,0x65,0x22,0x2c,0x22,0x61,0x72,0x67,0x75,0x6d, + 0x65,0x6e,0x74,0x73,0x22,0x3a,0x5b,0x7b,0x22,0x6e,0x61,0x6d,0x65,0x22,0x3a,0x22, + 0x63,0x61,0x6c,0x6c,0x73,0x22,0x7d,0x5d,0x7d,0x5d,0x7d, +} diff --git a/contract/vm_multicall.lua b/contract/vm_multicall.lua new file mode 100644 index 000000000..e0ec420f2 --- /dev/null +++ b/contract/vm_multicall.lua @@ -0,0 +1,196 @@ +------------------------------------------------------------------- +-- COMPOSABLE EXECUTION +------------------------------------------------------------------- + +vars = {} + +skip = {store=true,let=true,set=true,insert=true,assert=true} + +action = { + + -- contract call + call = function (...) return contract.call(...) end, + ["call-send"] = function (amount,...) return contract.call.value(amount)(...) end, + ["pcall"] = function (...) return {pcall(contract.call,...)} end, + ["pcall-send"] = function (amount,...) return {pcall(contract.call.value(amount),...)} end, + + -- aergo balance and transfer + balance = function (address) return contract.balance(address) end, + send = function (address,amount) return contract.send(address, amount) end, + + -- variables + let = function (x,y) vars[x] = y end, + store = function (n) vars[n] = vars['last_result'] end, + + -- tables + get = function (o,k) return o[k] end, + set = function (o,k,v) o[k] = v end, + insert = function (...) table.insert(...) end, -- inserts at the end if no pos informed + remove = function (...) table.remove(...) end, + + -- math + add = function (x,y) return x+y end, + sub = function (x,y) return x-y end, + mul = function (x,y) return x*y end, + div = function (x,y) return x/y end, + pow = function (x,y) return x^y end, + mod = function (x,y) return x%y end, + sqrt = function (x) return bignum.sqrt(x) end, -- use pow(0.5) for numbers + + -- strings + format = function (...) return string.format(...) end, -- for concat: ['format','%s%s','%val1%','%val2%'] + substr = function (...) return string.sub(...) end, + find = function (...) return string.match(...) end, + replace = function (...) return string.gsub(...) end, + + -- conversions + tobignum = function (x) return bignum.number(x) end, + tonumber = function (x) return tonumber(x) end, + tostring = function (x) return tostring(x) end, -- bignum to string + tojson = function (x) return json.encode(x) end, + fromjson = function (x) return json.decode(x) end, -- create tables + + -- assertion + assert = function (...) assert(eval(...),"assertion failed: " .. json.encode({...})) end, + +} + +function execute(calls) + + local if_on = true + local if_done = false + + local for_cmdpos + local for_var, for_type + local for_list, for_pos + local for_last, for_increment + + local cmdpos = 1 + while cmdpos <= #calls do + local call = calls[cmdpos] + local args = {} -- use a copy of the list because of loops + for i,v in ipairs(call) do args[i] = v end + + -- process variables + for i,item in ipairs(args) do + if i > 1 and type(item) == 'string' and #item >= 3 and + string.sub(item, 1, 1) == '%' and string.sub(item, -1, -1) == '%' then + local varname = string.sub(item, 2, -2) + if vars[varname] ~= nil then + args[i] = vars[varname] + end + end + end + + -- process the command + local cmd = table.remove(args, 1) + local fn = action[cmd] + if fn and if_on then + local result = fn(unpack(args)) + if not skip[cmd] then + vars['last_result'] = result + end + + -- if elif else end + elseif cmd == "if" then + if_on = eval(unpack(args)) + if_done = if_on + elseif cmd == "elif" then + if if_on then + if_on = false + elseif not if_done then + if_on = eval(unpack(args)) + if_done = if_on + end + elseif cmd == "else" then + if_on = (not if_on) and (not if_done) + elseif cmd == "end" then + if_on = true + + -- for foreach loop + elseif cmd == "foreach" and if_on then + for_cmdpos = cmdpos + for_type = "each" + for_var = args[1] + for_list = args[2] + for_pos = 1 + vars[for_var] = for_list[for_pos] + elseif cmd == "for" and if_on then + for_cmdpos = cmdpos + for_type = "number" + for_var = args[1] + for_last = args[3] + for_increment = args[4] or 1 + vars[for_var] = args[2] + elseif cmd == "loop" and if_on then + if for_type == "each" then + for_pos = for_pos + 1 + if for_pos <= #for_list then + vars[for_var] = for_list[for_pos] + cmdpos = for_cmdpos + end + elseif for_type == "number" then + vars[for_var] = vars[for_var] + for_increment + if (for_increment > 0 and vars[for_var] > for_last) or (for_increment < 0 and vars[for_var] < for_last) then + -- quit loop (continue to the next command) + else + cmdpos = for_cmdpos + end + end + + -- return + elseif cmd == "return" and if_on then + return unpack(args) -- or the array itself + elseif if_on then + assert(false, "command not found: " .. cmd) + end + + cmdpos = cmdpos + 1 + end + +end + +function eval(...) + local args = {...} + local v1 = args[1] + local op = args[2] + local v2 = args[3] + local neg = false + local matches = false + if string.sub(op,1,1) == "!" then + neg = true + op = string.sub(op, 2) + end + if v1 == nil and op ~= "=" then + -- does not match + elseif op == "=" then + matches = v1 == v2 + elseif op == ">" then + matches = v1 > v2 + elseif op == ">=" then + matches = v1 >= v2 + elseif op == "<" then + matches = v1 < v2 + elseif op == "<=" then + matches = v1 <= v2 + elseif op == "match" then + matches = string.match(v1, v2) ~= nil + else + assert(false, "operator not known: " .. op) + end + if neg then matches = not matches end + if #args > 3 then + op = args[4] + local matches2 = eval(unpack(args, 5, #args)) + if op == "and" then + return (matches and matches2) + elseif op == "or" then + return (matches or matches2) + else + assert(false, "operator not known: " .. op) + end + end + return matches +end + +abi.register(execute) diff --git a/state/contract.go b/state/contract.go index f51d233bf..7f5c9f937 100644 --- a/state/contract.go +++ b/state/contract.go @@ -9,6 +9,14 @@ import ( "github.com/golang/protobuf/proto" ) +func (states *StateDB) GetMultiCallState(aid types.AccountID, st *types.State) (*ContractState) { + res := &ContractState{ + State: st, + account: aid, + } + return res +} + func (states *StateDB) OpenContractStateAccount(aid types.AccountID) (*ContractState, error) { st, err := states.GetAccountState(aid) if err != nil { @@ -85,6 +93,11 @@ func (st *ContractState) SetCode(code []byte) error { return nil } +func (st *ContractState) SetMultiCallCode(code []byte) { + // no codeHash means it is not a contract + st.code = code +} + func (st *ContractState) GetCode() ([]byte, error) { if st.code != nil { // already loaded. diff --git a/types/blockchain.pb.go b/types/blockchain.pb.go index 425c3703e..6a31eff26 100644 --- a/types/blockchain.pb.go +++ b/types/blockchain.pb.go @@ -28,6 +28,7 @@ const ( TxType_TRANSFER TxType = 4 TxType_CALL TxType = 5 TxType_DEPLOY TxType = 6 + TxType_MULTICALL TxType = 7 ) var TxType_name = map[int32]string{ @@ -38,6 +39,7 @@ var TxType_name = map[int32]string{ 4: "TRANSFER", 5: "CALL", 6: "DEPLOY", + 7: "MULTICALL", } var TxType_value = map[string]int32{ "NORMAL": 0, @@ -47,6 +49,7 @@ var TxType_value = map[string]int32{ "TRANSFER": 4, "CALL": 5, "DEPLOY": 6, + "MULTICALL": 7, } func (x TxType) String() string { diff --git a/types/transaction.go b/types/transaction.go index e8e77ff92..bb9573af8 100644 --- a/types/transaction.go +++ b/types/transaction.go @@ -159,13 +159,18 @@ func (tx *transaction) Validate(chainidhash []byte, isPublic bool) error { if tx.GetBody().GetRecipient() == nil { return ErrTxInvalidRecipient } - case TxType_DEPLOY: + case TxType_DEPLOY, TxType_MULTICALL: if tx.GetBody().GetRecipient() != nil { return ErrTxInvalidRecipient } if len(tx.GetBody().GetPayload()) == 0 { return ErrTxFormatInvalid } + if tx.GetBody().Type == TxType_MULTICALL { + if amount.Cmp(big.NewInt(0)) != 0 { + return ErrTxInvalidAmount + } + } default: return ErrTxInvalidType } From 7c3cff71e2d12d33dbe63dced141267119bd94a3 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 15 Jun 2022 21:53:25 -0300 Subject: [PATCH 002/182] [brick] add multicall command --- cmd/brick/exec/multicall.go | 114 ++++++++++++++++++++++++++++++++++++ contract/vm_dummy.go | 69 ++++++++++++++++++---- 2 files changed, 172 insertions(+), 11 deletions(-) create mode 100644 cmd/brick/exec/multicall.go diff --git a/cmd/brick/exec/multicall.go b/cmd/brick/exec/multicall.go new file mode 100644 index 000000000..3825ec79e --- /dev/null +++ b/cmd/brick/exec/multicall.go @@ -0,0 +1,114 @@ +package exec + +import ( + "fmt" + + "github.com/rs/zerolog" + + "github.com/aergoio/aergo/cmd/brick/context" + "github.com/aergoio/aergo/contract" + "github.com/aergoio/aergo/types" +) + +func init() { + registerExec(&multicall{}) +} + +type multicall struct{} + +func (c *multicall) Command() string { + return "multicall" +} + +func (c *multicall) Syntax() string { + return fmt.Sprintf("%s %s %s %s", context.AccountSymbol, + context.ContractArgsSymbol, + context.ExpectedErrSymbol, context.ExpectedSymbol) +} + +func (c *multicall) Usage() string { + return fmt.Sprintf("multicall `[call_json_str]` `[expected_error_str]` `[expected_result_str]`") +} + +func (c *multicall) Describe() string { + return "composable call to multiple smart contracts" +} + +func (c *multicall) Validate(args string) error { + + // is chain is loaded? + if context.Get() == nil { + return fmt.Errorf("load chain first") + } + + _, _, _, _, err := c.parse(args) + + return err +} + +func (c *multicall) parse(args string) (string, string, string, string, error) { + splitArgs := context.SplitSpaceAndAccent(args, false) + if len(splitArgs) < 2 { + return "", "", "", "", fmt.Errorf("need at least 2 arguments. usage: %s", c.Usage()) + } + + callCode := splitArgs[1].Text + expectedError := "" + expectedRes := "" + + if len(splitArgs) >= 3 { + expectedError = splitArgs[2].Text + } + if len(splitArgs) == 4 { + expectedRes = splitArgs[3].Text + } else if len(splitArgs) > 4 { + return "", "", "", "", fmt.Errorf("too many arguments. usage: %s", c.Usage()) + } + + return splitArgs[0].Text, //accountName + callCode, + expectedError, + expectedRes, + nil +} + +func (c *multicall) Run(args string) (string, uint64, []*types.Event, error) { + + accountName, payload, expectedError, expectedRes, _ := c.parse(args) + + multicallTx := contract.NewLuaTxMultiCall(accountName, payload) + + logLevel := zerolog.GlobalLevel() + + if expectedError != "" { + multicallTx.Fail(expectedError) + zerolog.SetGlobalLevel(zerolog.ErrorLevel) // turn off log + } + err := context.Get().ConnectBlock(multicallTx) + + if expectedError != "" { + zerolog.SetGlobalLevel(logLevel) // restore log level + } + if err != nil { + return "", 0, nil, err + } + + if expectedError != "" { + Index(context.ExpectedErrSymbol, expectedError) + return "call a smart contract successfully", 0, nil, nil + } + + receipt := context.Get().GetReceipt(multicallTx.Hash()) + + if expectedRes != "" && expectedRes != receipt.Ret { + err = fmt.Errorf("expected: %s, but got: %s", expectedRes, receipt.Ret) + return "", 0, nil, err + } + + result := "success" + if expectedRes == "" && len(receipt.Ret) > 0 { + result += ": " + receipt.Ret + } + return result, receipt.GasUsed, context.Get().GetEvents(multicallTx.Hash()), nil + +} diff --git a/contract/vm_dummy.go b/contract/vm_dummy.go index fe3218fa8..b0b021049 100644 --- a/contract/vm_dummy.go +++ b/contract/vm_dummy.go @@ -294,6 +294,7 @@ type luaTxContract interface { amount() *big.Int code() []byte isFeeDelegate() bool + isMultiCall() bool } type luaTxContractCommon struct { @@ -303,6 +304,7 @@ type luaTxContractCommon struct { _code []byte txId uint64 feeDelegate bool + multiCall bool } func (l *luaTxContractCommon) Hash() []byte { @@ -329,6 +331,10 @@ func (l *luaTxContractCommon) isFeeDelegate() bool { return l.feeDelegate } +func (l *luaTxContractCommon) isMultiCall() bool { + return l.multiCall +} + func hash(id uint64) []byte { h := sha256.New() h.Write([]byte(strconv.FormatUint(id, 10))) @@ -390,15 +396,27 @@ func contractFrame(l luaTxContract, bs *state.BlockState, cdb ChainAccessor, rec } contractId := types.ToAccountID(l.contract()) - contractState, err := bs.GetAccountStateV(l.contract()) + + var contractState *state.V + if l.isMultiCall() { + contractState = creatorState + } else { + contractState, err = bs.GetAccountStateV(l.contract()) + } if err != nil { return err } - eContractState, err := bs.OpenContractState(contractId, contractState.State()) + var eContractState *state.ContractState + if l.isMultiCall() { + eContractState = bs.GetMultiCallState(creatorId, creatorState.State()) + } else { + eContractState, err = bs.OpenContractState(contractId, contractState.State()) + } if err != nil { return err } + usedFee := txFee(len(l.code()), new(big.Int).SetUint64(1), 2) if l.isFeeDelegate() { @@ -417,9 +435,14 @@ func contractFrame(l luaTxContract, bs *state.BlockState, cdb ChainAccessor, rec return types.ErrNotAllowedFeeDelegation } } - creatorState.SubBalance(l.amount()) - contractState.AddBalance(l.amount()) + + if contractId != creatorId { + creatorState.SubBalance(l.amount()) + contractState.AddBalance(l.amount()) + } + rv, evs, cFee, err := run(creatorState, contractState, contractId, eContractState) + if cFee != nil { usedFee.Add(usedFee, cFee) } @@ -428,6 +451,7 @@ func contractFrame(l luaTxContract, bs *state.BlockState, cdb ChainAccessor, rec status = "ERROR" rv = err.Error() } + r := types.NewReceipt(l.contract(), status, rv) r.TxHash = l.Hash() r.GasUsed = usedFee.Uint64() @@ -454,10 +478,13 @@ func contractFrame(l luaTxContract, bs *state.BlockState, cdb ChainAccessor, rec } creatorState.SubBalance(usedFee) } + bs.PutState(creatorId, creatorState.State()) - bs.PutState(contractId, contractState.State()) - return nil + if contractId != creatorId { + bs.PutState(contractId, contractState.State()) + } + return nil } func (l *luaTxDef) run(bs *state.BlockState, bc *DummyChain, bi *types.BlockHeaderInfo, receiptTx db.Transaction) error { @@ -469,7 +496,7 @@ func (l *luaTxDef) run(bs *state.BlockState, bc *DummyChain, bi *types.BlockHead contract.State().SqlRecoveryPoint = 1 ctx := newVmContext(bs, nil, sender, contract, eContractState, sender.ID(), l.Hash(), bi, "", true, - false, contract.State().SqlRecoveryPoint, BlockFactory, l.amount(), math.MaxUint64, false) + false, contract.State().SqlRecoveryPoint, BlockFactory, l.amount(), math.MaxUint64, false, false) if traceState { ctx.traceFile, _ = @@ -526,6 +553,19 @@ func NewLuaTxCallFeeDelegate(sender, contract string, amount uint64, code string } } +func NewLuaTxMultiCall(sender, code string) *luaTxCall { + return &luaTxCall{ + luaTxContractCommon: luaTxContractCommon{ + _sender: strHash(sender), + _contract: strHash(""), + _amount: new(big.Int).SetUint64(0), + _code: []byte(code), + txId: newTxId(), + multiCall: true, + }, + } +} + func (l *luaTxCall) Fail(expectedErr string) *luaTxCall { l.expectedErr = expectedErr return l @@ -534,21 +574,28 @@ func (l *luaTxCall) Fail(expectedErr string) *luaTxCall { func (l *luaTxCall) run(bs *state.BlockState, bc *DummyChain, bi *types.BlockHeaderInfo, receiptTx db.Transaction) error { err := contractFrame(l, bs, bc, receiptTx, func(sender, contract *state.V, contractId types.AccountID, eContractState *state.ContractState) (string, []*types.Event, *big.Int, error) { + ctx := newVmContext(bs, bc, sender, contract, eContractState, sender.ID(), l.Hash(), bi, "", true, - false, contract.State().SqlRecoveryPoint, BlockFactory, l.amount(), math.MaxUint64, l.feeDelegate) + false, contract.State().SqlRecoveryPoint, BlockFactory, l.amount(), math.MaxUint64, l.feeDelegate, l.multiCall) + if traceState { ctx.traceFile, _ = os.OpenFile("test.trace", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644) defer ctx.traceFile.Close() } + rv, evs, ctrFee, err := Call(eContractState, l.code(), l.contract(), ctx) if err != nil { return "", nil, ctrFee, err } - err = bs.StageContractState(eContractState) - if err != nil { - return "", nil, ctrFee, err + + if !ctx.isMultiCall { + err = bs.StageContractState(eContractState) + if err != nil { + return "", nil, ctrFee, err + } } + return rv, evs, ctrFee, nil }, ) From 001cac167cce1cffc4a30e8057f14668c4110441 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 16 Jun 2022 05:06:16 -0300 Subject: [PATCH 003/182] [contract] add tests for composable transactions --- contract/vm_test.go | 1066 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1066 insertions(+) diff --git a/contract/vm_test.go b/contract/vm_test.go index 2be0abddf..1a8a949dd 100644 --- a/contract/vm_test.go +++ b/contract/vm_test.go @@ -6155,4 +6155,1070 @@ abi.register(stmt_exec, stmt_exec_pcall, get)` } } + +////////////////////////////////////////////////////////////////////// +// COMPOSABLE TRANSACTIONS +////////////////////////////////////////////////////////////////////// + +func multicall(t *testing.T, bc *DummyChain, params ...string) { + var expectedError, expectedResult string + account := params[0] + payload := params[1] + if len(params) > 2 { + expectedError = params[2] + } + if len(params) > 3 { + expectedResult = params[3] + } + + tx := NewLuaTxMultiCall(account, payload).Fail(expectedError) + + err := bc.ConnectBlock(tx) + if err != nil { + t.Error(err) + } + + if expectedError == "" && expectedResult != "" { + receipt := bc.GetReceipt(tx.Hash()) + if receipt.GetRet() != expectedResult { + t.Errorf("multicall invalid result - expected: %s got: %s", expectedResult, receipt.GetRet()) + } + } + +} + +func call(t *testing.T, bc *DummyChain, + account string, amount uint64, + contract string, function string, args string, + expectedError string, expectedResult string) { + + callinfo := fmt.Sprintf(`{"Name":"%s", "Args":%s}`, function, args) + + tx := NewLuaTxCall(account, contract, amount, callinfo).Fail(expectedError) + + err := bc.ConnectBlock(tx) + if err != nil { + t.Error(err) + } + + if expectedError == "" && expectedResult != "" { + receipt := bc.GetReceipt(tx.Hash()) + if receipt.GetRet() != expectedResult { + t.Errorf("call invalid result - expected: %s got: %s", expectedResult, receipt.GetRet()) + } + } + +} + +func TestComposableTransactions(t *testing.T) { + bc, err := LoadDummyChain() + if err != nil { + t.Errorf("failed to create test database: %v", err) + } + defer bc.Release() + + definition := ` +state.var { + name = state.value(), + last = state.value(), + dict = state.map() +} + +function get_dict() + return {one = 1, two = 2, three = 3} +end + +function get_list() + return {'first', 'second', 'third', 123, 12.5, true} +end + +function get_table() + return { name = "Test", second = 'Te"st', number = 123, bool = true, array = {11,22,33} } +end + +function works() + return 123 +end + +function fails() + assert(false, "this call should fail") +end + +function hello(name) + return 'hello ' .. name +end + +function set_name(val) + name:set(val) + assert(type(val)=='string', "must be string") +end + +function get_name() + return name:get() +end + +function set(key, value) + dict[key] = value +end + +function add(value) + local key = (last:get() or 0) + 1 + dict[tostring(key)] = value + last:set(key) +end + +function get(key) + return dict[key] +end + +abi.register(add, set, set_name) +abi.register_view(get_dict, get_list, get_table, works, fails, get, get_name, hello) + +function call(...) + return contract.call(...) +end + +function is_contract(address) + return system.isContract(address) +end + +function sender() + return system.getSender() +end + +function origin() + return system.getOrigin() +end + +abi.register(call) +abi.register_view(is_contract, sender, origin) + +function recv_aergo() + -- does nothing +end + +abi.payable(recv_aergo) +` + + err = bc.ConnectBlock( + NewLuaTxAccount("ac0", 10000000000000000000), + NewLuaTxAccount("ac1", 10000000000000000000), + NewLuaTxAccount("ac2", 10000000000000000000), + NewLuaTxAccount("ac3", 10000000000000000000), + NewLuaTxAccount("ac4", 10000000000000000000), + NewLuaTxAccount("ac5", 10000000000000000000), + NewLuaTxDef("ac0", "tables", 0, definition), + NewLuaTxDef("ac0", "c1", 0, definition), + NewLuaTxDef("ac0", "c2", 0, definition), + NewLuaTxDef("ac0", "c3", 0, definition), + ) + if err != nil { + t.Error(err) + } + + + multicall(t, bc, "ac1", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_dict"], + ["store","dict"], + ["set","%dict%","two",22], + ["set","%dict%","four",4], + ["set","%dict%","one",null], + ["get","%dict%","two"], + ["set","%dict%","copy","%last_result%"], + ["return","%dict%"] + ]`, ``, `{"copy":22,"four":4,"three":3,"two":22}`) + + multicall(t, bc, "ac1", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_list"], + ["store","array"], + ["set","%array%",2,"2nd"], + ["insert","%array%",1,"zero"], + ["insert","%array%","last"], + ["return","%array%"] + ]`, ``, `["zero","first","2nd","third",123,12.5,true,"last"]`) + + multicall(t, bc, "ac1", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_list"], + ["store","array"], + ["remove","%array%",3], + ["return","%array%"] + ]`, ``, `["first","second",123,12.5,true]`) + + + // create new dict or array using fromjson + + multicall(t, bc, "ac1", `[ + ["fromjson","{\"one\":1,\"two\":2}"], + ["set","%last_result%","three",3], + ["return","%last_result%"] + ]`, ``, `{"one":1,"three":3,"two":2}`) + + + // define dict or list using let + + multicall(t, bc, "ac1", `[ + ["let","obj",{"one":1,"two":2}], + ["set","%obj%","three",3], + ["return","%obj%"] + ]`, ``, `{"one":1,"three":3,"two":2}`) + + multicall(t, bc, "ac1", `[ + ["let","list",["one",1,"two",2,2.5,true,false]], + ["set","%list%",4,"three"], + ["insert","%list%",1,"first"], + ["insert","%list%","last"], + ["return","%list%"] + ]`, ``, `["first","one",1,"two","three",2.5,true,false,"last"]`) + + multicall(t, bc, "ac1", `[ + ["let","list",["one",22,3.3,true,false]], + ["get","%list%",1], + ["assert","%last_result%","=","one"], + ["get","%list%",2], + ["assert","%last_result%","=",22], + ["get","%list%",3], + ["assert","%last_result%","=",3.3], + ["get","%list%",4], + ["assert","%last_result%","=",true], + ["get","%list%",5], + ["assert","%last_result%","=",false], + ["return","%list%"] + ]`, ``, `["one",22,3.3,true,false]`) + + + + // BIGNUM + + multicall(t, bc, "ac1", `[ + ["tobignum",123], + ["store","a"], + ["tobignum",123], + ["store","b"], + ["mul","%a%","%b%"], + ["return","%last_result%"] + ]`, ``, `{"_bignum":"15129"}`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","100000"], + ["store","b"], + ["div","%a%","%b%"], + ["return","%last_result%"] + ]`, ``, `{"_bignum":"5000000000000000"}`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","100000"], + ["store","b"], + ["div","%a%","%b%"], + ["tostring","%last_result%"], + ["return","%last_result%"] + ]`, ``, `"5000000000000000"`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + + ["tobignum","100000"], + ["div","%a%","%last_result%"], + ["store","a"], + + ["tobignum","1000000000000000"], + ["sub","%a%","%last_result%"], + ["store","a"], + + ["tobignum","1234"], + ["add","%a%","%last_result%"], + ["store","a"], + + ["tobignum","2"], + ["pow","%a%","%last_result%"], + ["sqrt","%last_result%"], + ["store","a"], + + ["tobignum","2"], + ["mod","%a%","10000"], + + ["return","%last_result%"] + ]`, ``, `{"_bignum":"1234"}`) + + multicall(t, bc, "ac1", `[ + ["let","a",25], + ["sqrt","%a%"], + ["return","%last_result%"] + ]`, ``, `{"_bignum":"5"}`) + + multicall(t, bc, "ac1", `[ + ["let","a",25], + ["pow","%a%",0.5], + ["return","%last_result%"] + ]`, ``, `5`) + + + + // STRINGS + + multicall(t, bc, "ac1", `[ + ["format","%s%s%s","hello"," ","world"], + ["return","%last_result%"] + ]`, ``, `"hello world"`) + + multicall(t, bc, "ac1", `[ + ["let","s","hello world"], + ["substr","%s%",1,4], + ["return","%last_result%"] + ]`, ``, `"hell"`) + + multicall(t, bc, "ac1", `[ + ["let","s","hello world"], + ["substr","%s%",-2,-1], + ["return","%last_result%"] + ]`, ``, `"ld"`) + + multicall(t, bc, "ac1", `[ + ["let","s","the amount is 12345"], + ["find","%s%","%d+"], + ["tonumber","%last_result%"], + ["return","%last_result%"] + ]`, ``, `12345`) + + multicall(t, bc, "ac1", `[ + ["let","s","rate: 55 10%"], + ["find","%s%","(%d+)%%"], + ["tonumber","%last_result%"], + ["return","%last_result%"] + ]`, ``, `10`) + + multicall(t, bc, "ac1", `[ + ["let","s","rate: 12%"], + ["find","%s%","%s*(%d+)%%"], + ["tonumber","%last_result%"], + ["return","%last_result%"] + ]`, ``, `12`) + + multicall(t, bc, "ac1", `[ + ["let","s","hello world"], + ["replace","%s%","hello","good bye"], + ["return","%last_result%"] + ]`, ``, `"good bye world"`) + + multicall(t, bc, "ac1", `[ + ["fromjson","{\"name\":\"ticket\",\"value\":12.5,\"amount\":10}"], + ["replace","name = $name, value = $value, amount = $amount","%$(%w+)","%last_result%"], + ["return","%last_result%"] + ]`, ``, `"name = ticket, value = 12.5, amount = 10"`) + + + // IF THEN ELSE + + multicall(t, bc, "ac1", `[ + ["let","s",20], + ["if","%s%",">=",20], + ["let","b","big"], + ["elif","%s%",">=",10], + ["let","b","medium"], + ["else"], + ["let","b","low"], + ["end"], + ["let","c","after"], + ["return","%b%","%c%"] + ]`, ``, `["big","after"]`) + + multicall(t, bc, "ac1", `[ + ["let","s",10], + ["if","%s%",">=",20], + ["let","b","big"], + ["elif","%s%",">=",10], + ["let","b","medium"], + ["else"], + ["let","b","low"], + ["end"], + ["let","c","after"], + ["return","%b%","%c%"] + ]`, ``, `["medium","after"]`) + + multicall(t, bc, "ac1", `[ + ["let","s",5], + ["if","%s%",">=",20], + ["let","b","big"], + ["elif","%s%",">=",10], + ["let","b","medium"], + ["else"], + ["let","b","low"], + ["end"], + ["let","c","after"], + ["return","%b%","%c%"] + ]`, ``, `["low","after"]`) + + multicall(t, bc, "ac1", `[ + ["let","s",20], + ["if","%s%",">=",20], + ["return","big"], + ["elif","%s%",">=",10], + ["return","medium"], + ["else"], + ["return","low"], + ["end"], + ["return","after"] + ]`, ``, `"big"`) + + multicall(t, bc, "ac1", `[ + ["let","s",10], + ["if","%s%",">=",20], + ["return","big"], + ["elif","%s%",">=",10], + ["return","medium"], + ["else"], + ["return","low"], + ["end"], + ["return","after"] + ]`, ``, `"medium"`) + + multicall(t, bc, "ac1", `[ + ["let","s",5], + ["if","%s%",">=",20], + ["return","big"], + ["elif","%s%",">=",10], + ["return","medium"], + ["else"], + ["return","low"], + ["end"], + ["return","after"] + ]`, ``, `"low"`) + + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","500000000000000000000"], + ["store","b"], + ["if","%a%","=","%b%"], + ["let","b","equal"], + ["else"], + ["let","b","diff"], + ["end"], + ["return","%b%"] + ]`, ``, `"equal"`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","500000000000000000001"], + ["store","b"], + ["if","%a%","=","%b%"], + ["let","b","equal"], + ["else"], + ["let","b","diff"], + ["end"], + ["return","%b%"] + ]`, ``, `"diff"`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000001"], + ["store","a"], + ["tobignum","500000000000000000000"], + ["store","b"], + ["if","%a%",">","%b%"], + ["let","b","bigger"], + ["else"], + ["let","b","lower"], + ["end"], + ["return","%b%"] + ]`, ``, `"bigger"`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","500000000000000000001"], + ["store","b"], + ["if","%a%",">","%b%"], + ["let","b","bigger"], + ["else"], + ["let","b","lower"], + ["end"], + ["return","%b%"] + ]`, ``, `"lower"`) + + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","500000000000000000001"], + ["store","b"], + ["if","%a%","<","%b%","and","1","=","0"], + ["let","b","wrong 1"], + ["elif","%a%","<","%b%","and","1","=","1"], + ["let","b","correct"], + ["else"], + ["let","b","wrong 2"], + ["end"], + ["return","%b%"] + ]`, ``, `"correct"`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","500000000000000000001"], + ["store","b"], + ["if","%a%","<","%b%","and",1,"=",0], + ["let","b","wrong 1"], + ["elif","%a%","<","%b%","and",1,"=",1], + ["let","b","correct"], + ["else"], + ["let","b","wrong 2"], + ["end"], + ["return","%b%"] + ]`, ``, `"correct"`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","500000000000000000001"], + ["store","b"], + ["tobignum","400000000000000000000"], + ["store","c"], + ["if","%a%","<","%b%","and","%a%","<","%c%"], + ["let","b","wrong 1"], + ["elif","%a%",">","%b%","and","%a%",">","%c%"], + ["let","b","wrong 2"], + ["elif","%a%","<","%b%","and","%a%",">","%c%"], + ["let","b","correct"], + ["else"], + ["let","b","wrong 3"], + ["end"], + ["return","%b%"] + ]`, ``, `"correct"`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","500000000000000000001"], + ["store","b"], + ["tobignum","400000000000000000000"], + ["store","c"], + ["tostring",0], + + ["if","%a%",">","%b%","or","%a%","<","%c%"], + ["format","%s%s","%last_result%","1"], + ["end"], + + ["if","%a%","=","%b%","or","%a%","=","%c%"], + ["format","%s%s","%last_result%","2"], + ["end"], + + ["if","%a%","<","%b%","or","%a%","<","%c%"], + ["format","%s%s","%last_result%","3"], + ["end"], + + ["if","%a%",">","%b%","or","%a%",">","%c%"], + ["format","%s%s","%last_result%","4"], + ["end"], + + ["if","%a%","<","%b%","or","%a%",">","%c%"], + ["format","%s%s","%last_result%","5"], + ["end"], + + ["if","%a%","!=","%b%","or","%a%","=","%c%"], + ["format","%s%s","%last_result%","6"], + ["end"], + + ["if","%a%","=","%b%","or","%a%","!=","%c%"], + ["format","%s%s","%last_result%","7"], + ["end"], + + + ["if","%a%",">=","%b%","and","%a%","<=","%c%"], + ["format","%s%s","%last_result%","8"], + ["end"], + + ["if","%a%",">=","%c%","and","%a%","<=","%b%"], + ["format","%s%s","%last_result%","9"], + ["end"], + + ["if","%b%",">=","%a%","and","%b%","<=","%c%"], + ["format","%s%s","%last_result%","A"], + ["end"], + + ["if","%b%",">=","%c%","and","%b%","<=","%a%"], + ["format","%s%s","%last_result%","B"], + ["end"], + + ["if","%c%",">=","%a%","and","%c%","<=","%b%"], + ["format","%s%s","%last_result%","C"], + ["end"], + + ["if","%c%",">=","%b%","and","%c%","<=","%a%"], + ["format","%s%s","%last_result%","D"], + ["end"], + + + ["if","%a%",">=","%b%","and","%a%","<=","%c%","or",1,"=",0], + ["format","%s%s","%last_result%","E"], + ["end"], + + ["if","%a%",">=","%b%","and","%a%","<=","%c%","or",1,"=",1], + ["format","%s%s","%last_result%","F"], + ["end"], + + ["if","%a%",">=","%b%","and","%a%","<=","%c%","and",1,"=",0], + ["format","%s%s","%last_result%","G"], + ["end"], + + ["if","%a%",">=","%b%","and","%a%","<=","%c%","and",1,"=",1], + ["format","%s%s","%last_result%","H"], + ["end"], + + + ["if","%a%",">=","%c%","and","%a%","<=","%b%","or",1,"=",0], + ["format","%s%s","%last_result%","I"], + ["end"], + + ["if","%a%",">=","%c%","and","%a%","<=","%b%","or",1,"=",1], + ["format","%s%s","%last_result%","J"], + ["end"], + + ["if","%a%",">=","%c%","and","%a%","<=","%b%","and",1,"=",0], + ["format","%s%s","%last_result%","K"], + ["end"], + + ["if","%a%",">=","%c%","and","%a%","<=","%b%","and",1,"=",1], + ["format","%s%s","%last_result%","L"], + ["end"], + + + ["if",1,"=",0,"or","%a%",">=","%b%","and","%a%","<=","%c%"], + ["format","%s%s","%last_result%","M"], + ["end"], + + ["if",1,"=",1,"or","%a%",">=","%b%","and","%a%","<=","%c%"], + ["format","%s%s","%last_result%","N"], + ["end"], + + ["if",1,"=",0,"or","%a%",">=","%c%","and","%a%","<=","%b%"], + ["format","%s%s","%last_result%","O"], + ["end"], + + ["if",1,"=",1,"or","%a%",">=","%c%","and","%a%","<=","%b%"], + ["format","%s%s","%last_result%","P"], + ["end"], + + + ["return","%last_result%"] + ]`, ``, `"0345679IJLNOP"`) + + + + + // FOR + + multicall(t, bc, "ac1", `[ + ["for","n",1,5], + ["loop"], + ["return","%n%"] + ]`, ``, `6`) + + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",1,5], + ["add","%last_result%",1], + ["loop"], + ["return","%last_result%"] + ]`, ``, `5`) + + multicall(t, bc, "ac1", `[ + ["tobignum","10000000000000000001"], + ["store","to_add"], + ["tobignum","100000000000000000000"], + + ["for","n",1,3], + ["add","%last_result%","%to_add%"], + ["loop"], + + ["tostring","%last_result%"], + ["return","%last_result%"] + ]`, ``, `"130000000000000000003"`) + + + // FOR "BREAK" + + multicall(t, bc, "ac1", `[ + ["let","c",0], + ["for","n",1,10], + ["add","%c%",1], + ["store","c"], + ["if","%n%","=",5], + ["let","n",500], + ["end"], + ["loop"], + ["return","%c%"] + ]`, ``, `5`) + + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["let","c",0], + ["for","n",1,10], + ["add","%last_result%",1], + ["if","%n%","=",5], + ["let","n",500], + ["end"], + ["loop"], + ["return","%last_result%"] + ]`, ``, `5`) + + + // FOREACH + + multicall(t, bc, "ac1", `[ + ["let","list",[11,22,33]], + ["let","r",0], + ["foreach","item","%list%"], + ["add","%r%","%item%"], + ["store","r"], + ["loop"], + ["return","%r%"] + ]`, ``, `66`) + + multicall(t, bc, "ac1", `[ + ["let","list",[10,21,32]], + ["let","r",0], + ["foreach","item","%list%"], + ["if","%item%","<",30], + ["add","%r%","%item%"], + ["store","r"], + ["end"], + ["loop"], + ["return","%r%"] + ]`, ``, `31`) + + + // RETURN before the end + + multicall(t, bc, "ac1", `[ + ["let","v",123], + ["if","%v%",">",100], + ["return"], + ["end"], + ["let","v",500], + ["return","%v%"] + ]`, ``, ``) + + multicall(t, bc, "ac1", `[ + ["let","v",123], + ["if","%v%",">",200], + ["return"], + ["end"], + ["let","v",500], + ["return","%v%"] + ]`, ``, `500`) + + + + // CALLS + + multicall(t, bc, "ac1", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","works"], + ["assert","%last_result%","=",123], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","works"], + ["return","%last_result%"] + ]`, ``, `123`) + + multicall(t, bc, "ac1", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","works"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","fails"] + ]`, `this call should fail`) + + + multicall(t, bc, "ac3", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set_name","test"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_name"], + ["assert","%last_result%","=","test"] + ]`) + + multicall(t, bc, "ac3", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set_name","wrong"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_name"], + ["assert","%last_result%","=","wrong"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set_name",123] + ]`, `must be string`) + + multicall(t, bc, "ac3", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_name"], + ["assert","%last_result%","=","test"], + ["return","%last_result%"] + ]`, ``, `"test"`) + + + multicall(t, bc, "ac3", `[ + ["let","c","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA"], + ["call","%c%","set_name","test2"], + ["call","%c%","get_name"], + ["assert","%last_result%","=","test2"] + ]`) + + + // CALL LOOP + + multicall(t, bc, "ac3", `[ + ["let","list",["first","second","third"]], + ["foreach","item","%list%"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","add","%item%"], + ["loop"] + ]`) + + multicall(t, bc, "ac1", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","1"], + ["assert","%last_result%","=","first"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","2"], + ["assert","%last_result%","=","second"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","3"], + ["assert","%last_result%","=","third"] + ]`) + + multicall(t, bc, "ac3", `[ + ["let","list",["1st","2nd","3rd"]], + ["let","n",1], + ["foreach","item","%list%"], + ["tostring","%n%"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set","%last_result%","%item%"], + ["add","%n%",1], + ["store","n"], + ["loop"] + ]`) + + multicall(t, bc, "ac1", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","1"], + ["assert","%last_result%","=","1st"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","2"], + ["assert","%last_result%","=","2nd"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","3"], + ["assert","%last_result%","=","3rd"] + ]`) + + + + // PCALL + + multicall(t, bc, "ac1", `[ + ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","works"], + ["get","%last_result%",1], + ["assert","%last_result%","=",true], + ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","fails"], + ["get","%last_result%",1], + ["assert","%last_result%","=",false] + ]`) + + multicall(t, bc, "ac3", `[ + ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set_name","1st"], + ["get","%last_result%",1], + ["assert","%last_result%","=",true], + + ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_name"], + ["store","ret"], + ["get","%ret%",1], + ["assert","%last_result%","=",true], + ["get","%ret%",2], + ["assert","%last_result%","=","1st"], + + ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set_name",22], + ["get","%last_result%",1], + ["assert","%last_result%","=",false], + + ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_name"], + ["store","ret"], + ["get","%ret%",1], + ["assert","%last_result%","=",true], + ["get","%ret%",2], + ["assert","%last_result%","=","1st"], + + ["return","%last_result%"] + ]`, ``, `"1st"`) + + + + // MULTICALL ON ACCOUNT ------------------------------------------ + + + //deploy ac0 0 c1 test.lua + //deploy ac0 0 c2 test.lua + //deploy ac0 0 c3 test.lua + + // c1: AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9 + // c2: Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4 + // c3: AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK + + multicall(t, bc, "ac0", `[ + ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","set_name","testing multicall"], + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","set_name","contract 2"], + ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","set_name","third one"] + ]`) + + multicall(t, bc, "ac0", `[ + ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","get_name"], + ["assert","%last_result%","=","testing multicall"], + ["store","r1"], + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","get_name"], + ["assert","%last_result%","=","contract 2"], + ["store","r2"], + ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","get_name"], + ["assert","%last_result%","=","third one"], + ["store","r3"], + ["return","%r1%","%r2%","%r3%"] + ]`, ``, `["testing multicall","contract 2","third one"]`) + + multicall(t, bc, "ac0", `[ + ["fromjson","{}"], + ["store","res"], + ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","get_name"], + ["set","%res%","r1","%last_result%"], + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","get_name"], + ["set","%res%","r2","%last_result%"], + ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","get_name"], + ["set","%res%","r3","%last_result%"], + ["return","%res%"] + ]`, ``, `{"r1":"testing multicall","r2":"contract 2","r3":"third one"}`) + + + multicall(t, bc, "ac0", `[ + ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","set_name","wohooooooo"], + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","set_name","it works!"], + ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","set_name","it really works!"] + ]`) + + multicall(t, bc, "ac0", `[ + ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","get_name"], + ["assert","%last_result%","=","wohooooooo"], + ["store","r1"], + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","get_name"], + ["assert","%last_result%","=","it works!"], + ["store","r2"], + ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","get_name"], + ["assert","%last_result%","=","it really works!"], + ["store","r3"], + ["return","%r1%","%r2%","%r3%"] + ]`, ``, `["wohooooooo","it works!","it really works!"]`) + + multicall(t, bc, "ac0", `[ + ["fromjson","{}"], + ["store","res"], + ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","get_name"], + ["set","%res%","r1","%last_result%"], + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","get_name"], + ["set","%res%","r2","%last_result%"], + ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","get_name"], + ["set","%res%","r3","%last_result%"], + ["return","%res%"] + ]`, ``, `{"r1":"wohooooooo","r2":"it works!","r3":"it really works!"}`) + + + + // aergo balance and send + + multicall(t, bc, "ac5", `[ + ["balance"], + ["tostring","%last_result%"], + ["assert","%last_result%","=","10000000000000000000"], + ["return","%last_result%"] + ]`, ``, `"10000000000000000000"`) + + multicall(t, bc, "ac2", `[ + ["balance"], + ["tostring","%last_result%"], + ["assert","%last_result%","=","10000000000000000000"], + + ["balance","AmgHyfkUt5iuXJKZNTrdthtXWLLJCrKWdJ6H6Yshn6ZR285Wr2Hc"], + ["tostring","%last_result%"], + ["assert","%last_result%","=","0"], + + ["send","AmgHyfkUt5iuXJKZNTrdthtXWLLJCrKWdJ6H6Yshn6ZR285Wr2Hc","3000000000000000000"], + + ["balance","AmgHyfkUt5iuXJKZNTrdthtXWLLJCrKWdJ6H6Yshn6ZR285Wr2Hc"], + ["tostring","%last_result%"], + ["assert","%last_result%","=","3000000000000000000"], + + ["balance"], + ["tostring","%last_result%"], + ["assert","%last_result%","=","7000000000000000000"], + + ["return","%last_result%"] + ]`, ``, `"7000000000000000000"`) + + + + // SECURITY CHECKS + + // it should not be possible to call the code from another account + + // a. from an account (via multicall, using the 'call' command) + + multicall(t, bc, "ac1", `[ + ["call","AmgeSw3M3V3orBMjf1j98kGne4WycnmQWVTJe6MYNrQ2wuVz3Li2","execute",[["add",11,22],["return","%last_result%"]]], + ["return","%last_result%"] + ]`, `nd contract`) + + + // b. from an account (via a call tx) + + call(t, bc, "ac1", 0, "ac1", "execute", `[[["add",11,22],["return","%last_result%"]]]`, `nd contract`, ``) + + call(t, bc, "ac1", 0, "ac2", "execute", `[[["add",11,22],["return","%last_result%"]]]`, `nd contract`, ``) + + + // c. from a contract (calling back) + + multicall(t, bc, "ac1", `[ + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","call","AmgMPiyZYr19kQ1kHFNiGenez1CRTBqNWqppj6gGZGEP6qszDGe1","execute",[["add",11,22],["return","%last_result%"]]], + ["return","%last_result%"] + ]`, `nd contract`) + + + // d. from a contract (calling another account) + + multicall(t, bc, "ac1", `[ + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","call","AmgeSw3M3V3orBMjf1j98kGne4WycnmQWVTJe6MYNrQ2wuVz3Li2","execute",[["add",11,22],["return","%last_result%"]]], + ["return","%last_result%"] + ]`, `nd contract`) + + + // e. from a contract (via a call txn) + + call(t, bc, "ac1", 0, "c2", "call", `["AmgMPiyZYr19kQ1kHFNiGenez1CRTBqNWqppj6gGZGEP6qszDGe1","execute",[["add",11,22],["return","%last_result%"]]]`, `nd contract`, ``) + + call(t, bc, "ac1", 0, "c2", "call", `["AmgeSw3M3V3orBMjf1j98kGne4WycnmQWVTJe6MYNrQ2wuVz3Li2","execute",[["add",11,22],["return","%last_result%"]]]`, `nd contract`, ``) + + + // system.isContract() should return false on user accounts + + call(t, bc, "ac1", 0, "c2", "is_contract", `["AmgMPiyZYr19kQ1kHFNiGenez1CRTBqNWqppj6gGZGEP6qszDGe1"]`, ``, `false`) + + call(t, bc, "ac1", 0, "c2", "is_contract", `["AmgeSw3M3V3orBMjf1j98kGne4WycnmQWVTJe6MYNrQ2wuVz3Li2"]`, ``, `false`) + + multicall(t, bc, "ac1", `[ + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","is_contract","AmgMPiyZYr19kQ1kHFNiGenez1CRTBqNWqppj6gGZGEP6qszDGe1"], + ["assert","%last_result%","=",false], + ["return","%last_result%"] + ]`, ``, `false`) + + multicall(t, bc, "ac1", `[ + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","is_contract","AmgeSw3M3V3orBMjf1j98kGne4WycnmQWVTJe6MYNrQ2wuVz3Li2"], + ["assert","%last_result%","=",false], + ["return","%last_result%"] + ]`, ``, `false`) + + + // on a contract called by multicall, the system.getSender() and system.getOrigin() must be the same + + multicall(t, bc, "ac1", `[ + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","sender"], + ["store","sender"], + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","origin"], + ["store","origin"], + ["assert","%sender%","=","%origin%"], + ["return","%sender%"] + ]`, ``, `"AmgMPiyZYr19kQ1kHFNiGenez1CRTBqNWqppj6gGZGEP6qszDGe1"`) + + +} + // end of test-cases From 19d246446b246e0a02f6c844ae64b63f434ca710 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 23 Jun 2022 02:47:24 -0300 Subject: [PATCH 004/182] [contract] decimal amounts on send, call, deploy, gov --- contract/vm_callback.go | 48 +++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/contract/vm_callback.go b/contract/vm_callback.go index 6bc3c79c0..5a11784e2 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -257,7 +257,7 @@ func luaCallContract(L *LState, service C.int, contractId *C.char, fname *C.char return -1, C.CString("[Contract.LuaCallContract] invalid contractId: " + err.Error()) } aid := types.ToAccountID(cid) - amountBig, err := transformAmount(C.GoString(amount)) + amountBig, err := transformAmount(C.GoString(amount), ctx) if err != nil { return -1, C.CString("[Contract.LuaCallContract] invalid amount: " + err.Error()) } @@ -444,7 +444,7 @@ func luaSendAmount(L *LState, service C.int, contractId *C.char, amount *C.char) if ctx == nil { return C.CString("[Contract.LuaSendAmount] contract state not found") } - amountBig, err := transformAmount(C.GoString(amount)) + amountBig, err := transformAmount(C.GoString(amount), ctx) if err != nil { return C.CString("[Contract.LuaSendAmount] invalid amount: " + err.Error()) } @@ -946,7 +946,33 @@ func luaCryptoKeccak256(data unsafe.Pointer, dataLen C.int) (unsafe.Pointer, int } } -func transformAmount(amountStr string) (*big.Int, error) { +func parseDecimalAmount(str string, digits int) string { + idx := strings.Index(str, ".") + if idx == -1 { + return str + } + p1 := str[0:idx] + p2 := str[idx+1:] + if strings.Index(p2, ".") != -1 { + return "error" + } + + to_add := digits - len(p2) + if to_add > 0 { + p2 = p2 + strings.Repeat("0", to_add) + } else if to_add < 0 { + p2 = p2[0:digits] + } + str = p1 + p2 + + str = strings.TrimLeft(str, "0") + if str == "" { + str = "0" + } + return str +} + +func transformAmount(amountStr string, ctx *vmContext) (*big.Int, error) { var ret *big.Int var prev int if len(amountStr) == 0 { @@ -957,7 +983,17 @@ func transformAmount(amountStr string) (*big.Int, error) { res := index.FindAllIndex(r, -1) for _, pair := range res { - amountBig, _ := new(big.Int).SetString(strings.TrimSpace(amountStr[prev:pair[0]]), 10) + parsedAmount := strings.TrimSpace(amountStr[prev:pair[0]]) + if HardforkConfig.IsV3Fork(ctx.blockInfo.No) { + if strings.Contains(parsedAmount,".") && pair[1] - pair[0] == 5 { + parsedAmount = parseDecimalAmount(parsedAmount, 18) + if parsedAmount == "error" { + return nil, errors.New(amountStr[prev:]) + } + pair[0] += 2 // from aergo to aer + } + } + amountBig, _ := new(big.Int).SetString(parsedAmount, 10) if amountBig == nil { return nil, errors.New("converting error for BigNum: " + amountStr[prev:]) } @@ -1092,7 +1128,7 @@ func luaDeployContract( cs := &callState{ctrState: contractState, prevState: &types.State{}, curState: newContract.State()} ctx.callState[newContract.AccountID()] = cs - amountBig, err := transformAmount(C.GoString(amount)) + amountBig, err := transformAmount(C.GoString(amount), ctx) if err != nil { return -1, C.CString("[Contract.LuaDeployContract]value not proper format:" + err.Error()) } @@ -1261,7 +1297,7 @@ func luaGovernance(L *LState, service C.int, gType C.char, arg *C.char) *C.char switch gType { case 'S', 'U': var err error - amountBig, err = transformAmount(C.GoString(arg)) + amountBig, err = transformAmount(C.GoString(arg), ctx) if err != nil { return C.CString("[Contract.LuaGovernance] invalid amount: " + err.Error()) } From a77c5d5366ce986ebb5017d5087877855ca21713 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 23 Jun 2022 14:40:10 -0300 Subject: [PATCH 005/182] [brick] decimal amounts --- cmd/brick/context/util.go | 37 +++++++++++++++++++++++++++++++ cmd/brick/exec/callContract.go | 3 ++- cmd/brick/exec/debug.go | 4 ++-- cmd/brick/exec/deployContract.go | 3 ++- cmd/brick/exec/getstateAccount.go | 6 ++++- cmd/brick/exec/injectAccount.go | 3 ++- cmd/brick/exec/sendCoin.go | 5 +++-- 7 files changed, 53 insertions(+), 8 deletions(-) diff --git a/cmd/brick/context/util.go b/cmd/brick/context/util.go index e97810ecf..fa42c17e2 100644 --- a/cmd/brick/context/util.go +++ b/cmd/brick/context/util.go @@ -17,6 +17,43 @@ func ParseFirstWord(input string) (string, string) { return strings.ToLower(splitedStr[0]), strings.Join(splitedStr[1:], " ") } +func ParseDecimalAmount(str string, digits int) string { + + idx := strings.Index(str, ".") + + str = strings.ToLower(str) + if strings.HasSuffix(str, " aergo") { + str = str[:len(str)-6] + if idx == -1 { + return str + strings.Repeat("0", digits) + } + } + + if idx == -1 { + return str + } + p1 := str[0:idx] + p2 := str[idx+1:] + if strings.Index(p2, ".") != -1 { + return "error" + } + + to_add := digits - len(p2) + if to_add > 0 { + p2 = p2 + strings.Repeat("0", to_add) + } else if to_add < 0 { + //p2 = p2[0:digits] + return "error" + } + str = p1 + p2 + + str = strings.TrimLeft(str, "0") + if str == "" { + str = "0" + } + return str +} + type Chunk struct { Accent bool Text string diff --git a/cmd/brick/exec/callContract.go b/cmd/brick/exec/callContract.go index 75a1737c5..b270bcae0 100644 --- a/cmd/brick/exec/callContract.go +++ b/cmd/brick/exec/callContract.go @@ -53,7 +53,8 @@ func (c *callContract) parse(args string) (string, *big.Int, string, string, str return "", nil, "", "", "", "", fmt.Errorf("need at least 4 arguments. usage: %s", c.Usage()) } - amount, success := new(big.Int).SetString(splitArgs[1].Text, 10) + amountStr := context.ParseDecimalAmount(splitArgs[1].Text, 18) + amount, success := new(big.Int).SetString(amountStr, 10) if success == false { return "", nil, "", "", "", "", fmt.Errorf("fail to parse number %s", splitArgs[1].Text) } diff --git a/cmd/brick/exec/debug.go b/cmd/brick/exec/debug.go index fcbe3efa1..8d9264338 100644 --- a/cmd/brick/exec/debug.go +++ b/cmd/brick/exec/debug.go @@ -60,7 +60,7 @@ func (c *setb) parse(args string) (uint64, string, error) { line, err := strconv.ParseUint(splitArgs[0].Text, 10, 64) if err != nil { - return 0, "", fmt.Errorf("fail to parse number %s: %s", splitArgs[1].Text, err.Error()) + return 0, "", fmt.Errorf("fail to parse number %s: %s", splitArgs[0].Text, err.Error()) } contractIDHex := contract.PlainStrToHexAddr(splitArgs[1].Text) @@ -118,7 +118,7 @@ func (c *delb) parse(args string) (uint64, string, error) { line, err := strconv.ParseUint(splitArgs[0].Text, 10, 64) if err != nil { - return 0, "", fmt.Errorf("fail to parse number %s: %s", splitArgs[1].Text, err.Error()) + return 0, "", fmt.Errorf("fail to parse number %s: %s", splitArgs[0].Text, err.Error()) } contractIDHex := contract.PlainStrToHexAddr(splitArgs[1].Text) diff --git a/cmd/brick/exec/deployContract.go b/cmd/brick/exec/deployContract.go index 5dcc4af3d..af6c4dc35 100644 --- a/cmd/brick/exec/deployContract.go +++ b/cmd/brick/exec/deployContract.go @@ -86,7 +86,8 @@ func (c *deployContract) parse(args string) (string, *big.Int, string, string, s return "", nil, "", "", "", fmt.Errorf("need 4 arguments. usage: %s", c.Usage()) } - amount, success := new(big.Int).SetString(splitArgs[1].Text, 10) + amountStr := context.ParseDecimalAmount(splitArgs[1].Text, 18) + amount, success := new(big.Int).SetString(amountStr, 10) if success == false { return "", nil, "", "", "", fmt.Errorf("fail to parse number %s", splitArgs[1].Text) } diff --git a/cmd/brick/exec/getstateAccount.go b/cmd/brick/exec/getstateAccount.go index 23d01761a..e6376a8b2 100644 --- a/cmd/brick/exec/getstateAccount.go +++ b/cmd/brick/exec/getstateAccount.go @@ -49,7 +49,11 @@ func (c *getStateAccount) parse(args string) (string, string, error) { expectedResult := "" if len(splitArgs) == 2 { - expectedResult = splitArgs[1].Text + expectedResult = context.ParseDecimalAmount(splitArgs[1].Text, 18) + _, success := new(big.Int).SetString(expectedResult, 10) + if expectedResult == "error" || success == false { + return "", "", fmt.Errorf("fail to parse number: %s", splitArgs[1].Text) + } } else if len(splitArgs) > 2 { return "", "", fmt.Errorf("too many arguments. usage: %s", c.Usage()) } diff --git a/cmd/brick/exec/injectAccount.go b/cmd/brick/exec/injectAccount.go index 4a3c09cb2..5de3909b3 100644 --- a/cmd/brick/exec/injectAccount.go +++ b/cmd/brick/exec/injectAccount.go @@ -49,7 +49,8 @@ func (c *injectAccount) parse(args string) (string, *big.Int, error) { return "", nil, fmt.Errorf("need 2 arguments. usage: %s", c.Usage()) } - amount, success := new(big.Int).SetString(splitArgs[1].Text, 10) + amountStr := context.ParseDecimalAmount(splitArgs[1].Text, 18) + amount, success := new(big.Int).SetString(amountStr, 10) if success == false { return "", nil, fmt.Errorf("fail to parse number %s", splitArgs[1].Text) } diff --git a/cmd/brick/exec/sendCoin.go b/cmd/brick/exec/sendCoin.go index 7f001cbd8..cbfd5f0ae 100644 --- a/cmd/brick/exec/sendCoin.go +++ b/cmd/brick/exec/sendCoin.go @@ -51,9 +51,10 @@ func (c *sendCoin) parse(args string) (string, string, *big.Int, error) { return "", "", nil, fmt.Errorf("need 3 arguments. usage: %s", c.Usage()) } - amount, success := new(big.Int).SetString(splitArgs[2].Text, 10) + amountStr := context.ParseDecimalAmount(splitArgs[2].Text, 18) + amount, success := new(big.Int).SetString(amountStr, 10) if success == false { - return "", "", nil, fmt.Errorf("fail to parse number %s", splitArgs[1].Text) + return "", "", nil, fmt.Errorf("fail to parse number %s", splitArgs[2].Text) } return splitArgs[0].Text, From 67322afe651024b7811d14c978195eb9ecfdd6d5 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 24 Jun 2022 00:25:01 -0300 Subject: [PATCH 006/182] [brick] update multicall command --- cmd/brick/context/symbol.go | 2 ++ cmd/brick/exec/multicall.go | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/brick/context/symbol.go b/cmd/brick/context/symbol.go index a3b9b13d3..22e59f28d 100644 --- a/cmd/brick/context/symbol.go +++ b/cmd/brick/context/symbol.go @@ -7,6 +7,7 @@ var ( AccountSymbol = "" AmountSymbol = "" ContractArgsSymbol = "" + MulticallSymbol = "" ExpectedSymbol = "" ExpectedErrSymbol = "" FunctionSymbol = "" @@ -21,6 +22,7 @@ func init() { Symbols[ContractSymbol] = "contract address" Symbols[AccountSymbol] = "account address" Symbols[ContractArgsSymbol] = "an array of argments to call a contract" + Symbols[MulticallSymbol] = "a list of commands in JSON" Symbols[AmountSymbol] = "amount of aergo to send" Symbols[ExpectedSymbol] = "expected result" Symbols[ExpectedErrSymbol] = "expected error" diff --git a/cmd/brick/exec/multicall.go b/cmd/brick/exec/multicall.go index 3825ec79e..d3d1a00f6 100644 --- a/cmd/brick/exec/multicall.go +++ b/cmd/brick/exec/multicall.go @@ -22,12 +22,12 @@ func (c *multicall) Command() string { func (c *multicall) Syntax() string { return fmt.Sprintf("%s %s %s %s", context.AccountSymbol, - context.ContractArgsSymbol, + context.MulticallSymbol, context.ExpectedErrSymbol, context.ExpectedSymbol) } func (c *multicall) Usage() string { - return fmt.Sprintf("multicall `[call_json_str]` `[expected_error_str]` `[expected_result_str]`") + return fmt.Sprintf("multicall `[commands_json_str]` `[expected_error_str]` `[expected_result_str]`") } func (c *multicall) Describe() string { From 08da940d99e8a520b2ba08cef2440da7af1cb2a4 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 25 Jun 2022 18:03:29 -0300 Subject: [PATCH 007/182] [contract] update composable transactions --- contract/vm_multicall.go | 440 +++++++++++++++++++++----------------- contract/vm_multicall.lua | 68 ++++-- 2 files changed, 303 insertions(+), 205 deletions(-) diff --git a/contract/vm_multicall.go b/contract/vm_multicall.go index f353a1df3..0c96e4973 100644 --- a/contract/vm_multicall.go +++ b/contract/vm_multicall.go @@ -1,7 +1,7 @@ package contract var multicall_payload = []byte { - 0xd4,0x0c,0x00,0x00,0x1b,0x4c,0x4a,0x02,0x0a,0x25,0x02,0x00,0x03,0x00,0x02, + 0x51,0x10,0x00,0x00,0x1b,0x4c,0x4a,0x02,0x0a,0x25,0x02,0x00,0x03,0x00,0x02, 0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00, 0x00,0x00,0x09,0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63,0x74, 0x37,0x02,0x01,0x04,0x00,0x03,0x00,0x07,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01, @@ -22,195 +22,251 @@ var multicall_payload = []byte { 0x6f,0x6e,0x74,0x72,0x61,0x63,0x74,0x29,0x00,0x02,0x06,0x00,0x02,0x00,0x05,0x36, 0x02,0x00,0x00,0x39,0x02,0x01,0x02,0x12,0x04,0x00,0x00,0x12,0x05,0x01,0x00,0x44, 0x02,0x03,0x00,0x09,0x73,0x65,0x6e,0x64,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63, - 0x74,0x18,0x00,0x02,0x03,0x00,0x01,0x00,0x03,0x36,0x02,0x00,0x00,0x3c,0x01,0x00, - 0x02,0x4b,0x00,0x01,0x00,0x09,0x76,0x61,0x72,0x73,0x2c,0x00,0x01,0x03,0x00,0x02, - 0x00,0x05,0x36,0x01,0x00,0x00,0x36,0x02,0x00,0x00,0x39,0x02,0x01,0x02,0x3c,0x02, - 0x00,0x01,0x4b,0x00,0x01,0x00,0x10,0x6c,0x61,0x73,0x74,0x5f,0x72,0x65,0x73,0x75, - 0x6c,0x74,0x09,0x76,0x61,0x72,0x73,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x38, - 0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x0f,0x00,0x03,0x03,0x00,0x00,0x00,0x02,0x3c, - 0x02,0x01,0x00,0x4b,0x00,0x01,0x00,0x28,0x02,0x00,0x03,0x00,0x02,0x00,0x05,0x36, - 0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x41,0x00,0x00,0x01,0x4b, - 0x00,0x01,0x00,0x0b,0x69,0x6e,0x73,0x65,0x72,0x74,0x0a,0x74,0x61,0x62,0x6c,0x65, - 0x28,0x02,0x00,0x03,0x00,0x02,0x00,0x05,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00, - 0x47,0x02,0x00,0x00,0x41,0x00,0x00,0x01,0x4b,0x00,0x01,0x00,0x0b,0x72,0x65,0x6d, - 0x6f,0x76,0x65,0x0a,0x74,0x61,0x62,0x6c,0x65,0x0f,0x00,0x02,0x03,0x00,0x00,0x00, - 0x02,0x20,0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00, - 0x02,0x21,0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00, - 0x02,0x22,0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00, - 0x02,0x23,0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00, - 0x02,0x25,0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00, - 0x02,0x24,0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x23,0x00,0x01,0x04,0x00,0x02,0x00, - 0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03,0x00,0x00,0x44,0x01,0x02, - 0x00,0x09,0x73,0x71,0x72,0x74,0x0b,0x62,0x69,0x67,0x6e,0x75,0x6d,0x25,0x02,0x00, - 0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00, - 0x00,0x43,0x00,0x00,0x00,0x0b,0x66,0x6f,0x72,0x6d,0x61,0x74,0x0b,0x73,0x74,0x72, - 0x69,0x6e,0x67,0x22,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00,0x00,0x39, - 0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x08,0x73,0x75,0x62,0x0b, - 0x73,0x74,0x72,0x69,0x6e,0x67,0x24,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00, - 0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x0a,0x6d, - 0x61,0x74,0x63,0x68,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x23,0x02,0x00,0x03,0x00, - 0x02,0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43, - 0x00,0x00,0x00,0x09,0x67,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x25, - 0x00,0x01,0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12, - 0x03,0x00,0x00,0x44,0x01,0x02,0x00,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x0b,0x62, - 0x69,0x67,0x6e,0x75,0x6d,0x1c,0x00,0x01,0x04,0x00,0x01,0x00,0x03,0x36,0x01,0x00, - 0x00,0x12,0x03,0x00,0x00,0x44,0x01,0x02,0x00,0x0d,0x74,0x6f,0x6e,0x75,0x6d,0x62, - 0x65,0x72,0x1c,0x00,0x01,0x04,0x00,0x01,0x00,0x03,0x36,0x01,0x00,0x00,0x12,0x03, - 0x00,0x00,0x44,0x01,0x02,0x00,0x0d,0x74,0x6f,0x73,0x74,0x72,0x69,0x6e,0x67,0x23, - 0x00,0x01,0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12, - 0x03,0x00,0x00,0x44,0x01,0x02,0x00,0x0b,0x65,0x6e,0x63,0x6f,0x64,0x65,0x09,0x6a, - 0x73,0x6f,0x6e,0x23,0x00,0x01,0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00,0x39, - 0x01,0x01,0x01,0x12,0x03,0x00,0x00,0x44,0x01,0x02,0x00,0x0b,0x64,0x65,0x63,0x6f, - 0x64,0x65,0x09,0x6a,0x73,0x6f,0x6e,0x70,0x02,0x00,0x08,0x00,0x05,0x01,0x0e,0x36, - 0x00,0x00,0x00,0x36,0x02,0x01,0x00,0x47,0x04,0x00,0x00,0x41,0x02,0x00,0x02,0x27, - 0x03,0x02,0x00,0x36,0x04,0x03,0x00,0x39,0x04,0x04,0x04,0x34,0x06,0x03,0x00,0x47, - 0x07,0x00,0x00,0x3f,0x07,0x00,0x00,0x42,0x04,0x02,0x02,0x26,0x03,0x04,0x03,0x42, - 0x00,0x03,0x01,0x4b,0x00,0x01,0x00,0x0b,0x65,0x6e,0x63,0x6f,0x64,0x65,0x09,0x6a, - 0x73,0x6f,0x6e,0x17,0x61,0x73,0x73,0x65,0x72,0x74,0x69,0x6f,0x6e,0x20,0x66,0x61, - 0x69,0x6c,0x65,0x64,0x3a,0x20,0x09,0x65,0x76,0x61,0x6c,0x0b,0x61,0x73,0x73,0x65, - 0x72,0x74,0x03,0x80,0x80,0xc0,0x99,0x04,0x80,0x08,0x00,0x01,0x17,0x00,0x19,0x01, - 0xd6,0x01,0x2b,0x01,0x02,0x00,0x2b,0x02,0x01,0x00,0x2c,0x03,0x09,0x00,0x29,0x0a, - 0x01,0x00,0x15,0x0b,0x00,0x00,0x03,0x0a,0x0b,0x00,0x58,0x0b,0xce,0x80,0x55,0x0b, - 0xcd,0x80,0x38,0x0b,0x0a,0x00,0x34,0x0c,0x00,0x00,0x36,0x0d,0x00,0x00,0x12,0x0f, - 0x0b,0x00,0x42,0x0d,0x02,0x04,0x58,0x10,0x01,0x80,0x3c,0x11,0x10,0x0c,0x45,0x10, - 0x03,0x03,0x52,0x10,0xfd,0x7f,0x36,0x0d,0x00,0x00,0x12,0x0f,0x0c,0x00,0x42,0x0d, - 0x02,0x04,0x58,0x10,0x29,0x80,0x29,0x12,0x01,0x00,0x01,0x12,0x10,0x00,0x58,0x12, - 0x26,0x80,0x36,0x12,0x01,0x00,0x12,0x14,0x11,0x00,0x42,0x12,0x02,0x02,0x07,0x12, - 0x02,0x00,0x58,0x12,0x21,0x80,0x15,0x12,0x11,0x00,0x29,0x13,0x03,0x00,0x03,0x13, - 0x12,0x00,0x58,0x12,0x1d,0x80,0x36,0x12,0x02,0x00,0x39,0x12,0x03,0x12,0x12,0x14, - 0x11,0x00,0x29,0x15,0x01,0x00,0x29,0x16,0x01,0x00,0x42,0x12,0x04,0x02,0x07,0x12, - 0x04,0x00,0x58,0x12,0x15,0x80,0x36,0x12,0x02,0x00,0x39,0x12,0x03,0x12,0x12,0x14, - 0x11,0x00,0x29,0x15,0xff,0xff,0x29,0x16,0xff,0xff,0x42,0x12,0x04,0x02,0x07,0x12, - 0x04,0x00,0x58,0x12,0x0d,0x80,0x36,0x12,0x02,0x00,0x39,0x12,0x03,0x12,0x12,0x14, - 0x11,0x00,0x29,0x15,0x02,0x00,0x29,0x16,0xfe,0xff,0x42,0x12,0x04,0x02,0x36,0x13, - 0x05,0x00,0x38,0x13,0x12,0x13,0x0a,0x13,0x00,0x00,0x58,0x13,0x03,0x80,0x36,0x13, - 0x05,0x00,0x38,0x13,0x12,0x13,0x3c,0x13,0x10,0x0c,0x45,0x10,0x03,0x03,0x52,0x10, - 0xd5,0x7f,0x36,0x0d,0x06,0x00,0x39,0x0d,0x07,0x0d,0x12,0x0f,0x0c,0x00,0x29,0x10, - 0x01,0x00,0x42,0x0d,0x03,0x02,0x36,0x0e,0x08,0x00,0x38,0x0e,0x0d,0x0e,0x0f,0x00, - 0x0e,0x00,0x58,0x0f,0x0e,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x0c,0x80,0x12,0x0f, - 0x0e,0x00,0x36,0x11,0x09,0x00,0x12,0x13,0x0c,0x00,0x42,0x11,0x02,0x00,0x41,0x0f, - 0x00,0x02,0x36,0x10,0x0a,0x00,0x38,0x10,0x0d,0x10,0x0e,0x00,0x10,0x00,0x58,0x10, - 0x7f,0x80,0x36,0x10,0x05,0x00,0x3d,0x0f,0x0b,0x10,0x58,0x0f,0x7c,0x80,0x07,0x0d, - 0x0c,0x00,0x58,0x0f,0x08,0x80,0x36,0x0f,0x0d,0x00,0x36,0x11,0x09,0x00,0x12,0x13, - 0x0c,0x00,0x42,0x11,0x02,0x00,0x41,0x0f,0x00,0x02,0x12,0x01,0x0f,0x00,0x12,0x02, - 0x01,0x00,0x58,0x0f,0x72,0x80,0x07,0x0d,0x0e,0x00,0x58,0x0f,0x0e,0x80,0x0f,0x00, - 0x01,0x00,0x58,0x0f,0x02,0x80,0x2b,0x01,0x01,0x00,0x58,0x0f,0x6c,0x80,0x0e,0x00, - 0x02,0x00,0x58,0x0f,0x6a,0x80,0x36,0x0f,0x0d,0x00,0x36,0x11,0x09,0x00,0x12,0x13, - 0x0c,0x00,0x42,0x11,0x02,0x00,0x41,0x0f,0x00,0x02,0x12,0x01,0x0f,0x00,0x12,0x02, - 0x01,0x00,0x58,0x0f,0x62,0x80,0x07,0x0d,0x0f,0x00,0x58,0x0f,0x08,0x80,0x0e,0x00, - 0x01,0x00,0x58,0x0f,0x02,0x80,0x13,0x01,0x02,0x00,0x58,0x0f,0x5c,0x80,0x2b,0x01, - 0x01,0x00,0x58,0x0f,0x01,0x80,0x2b,0x01,0x02,0x00,0x58,0x0f,0x58,0x80,0x07,0x0d, - 0x10,0x00,0x58,0x0f,0x02,0x80,0x2b,0x01,0x02,0x00,0x58,0x0f,0x54,0x80,0x07,0x0d, - 0x11,0x00,0x58,0x0f,0x0b,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x09,0x80,0x12,0x03, - 0x0a,0x00,0x27,0x05,0x12,0x00,0x3a,0x04,0x01,0x0c,0x3a,0x06,0x02,0x0c,0x29,0x07, - 0x01,0x00,0x36,0x0f,0x05,0x00,0x38,0x10,0x07,0x06,0x3c,0x10,0x04,0x0f,0x58,0x0f, - 0x47,0x80,0x07,0x0d,0x13,0x00,0x58,0x0f,0x0e,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f, - 0x0c,0x80,0x12,0x03,0x0a,0x00,0x27,0x05,0x14,0x00,0x3a,0x04,0x01,0x0c,0x3a,0x08, - 0x03,0x0c,0x3a,0x0f,0x04,0x0c,0x0c,0x09,0x0f,0x00,0x58,0x10,0x01,0x80,0x29,0x09, - 0x01,0x00,0x36,0x0f,0x05,0x00,0x3a,0x10,0x02,0x0c,0x3c,0x10,0x04,0x0f,0x58,0x0f, - 0x37,0x80,0x07,0x0d,0x15,0x00,0x58,0x0f,0x25,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f, - 0x23,0x80,0x07,0x05,0x12,0x00,0x58,0x0f,0x09,0x80,0x16,0x07,0x00,0x07,0x15,0x0f, - 0x06,0x00,0x03,0x07,0x0f,0x00,0x58,0x0f,0x2d,0x80,0x36,0x0f,0x05,0x00,0x38,0x10, - 0x07,0x06,0x3c,0x10,0x04,0x0f,0x12,0x0a,0x03,0x00,0x58,0x0f,0x28,0x80,0x07,0x05, - 0x14,0x00,0x58,0x0f,0x26,0x80,0x36,0x0f,0x05,0x00,0x36,0x10,0x05,0x00,0x38,0x10, - 0x04,0x10,0x20,0x10,0x09,0x10,0x3c,0x10,0x04,0x0f,0x29,0x0f,0x00,0x00,0x01,0x0f, - 0x09,0x00,0x58,0x0f,0x04,0x80,0x36,0x0f,0x05,0x00,0x38,0x0f,0x04,0x0f,0x00,0x08, - 0x0f,0x00,0x58,0x0f,0x1a,0x80,0x29,0x0f,0x00,0x00,0x01,0x09,0x0f,0x00,0x58,0x0f, - 0x05,0x80,0x36,0x0f,0x05,0x00,0x38,0x0f,0x04,0x0f,0x01,0x0f,0x08,0x00,0x58,0x0f, - 0x01,0x80,0x58,0x0f,0x12,0x80,0x12,0x0a,0x03,0x00,0x58,0x0f,0x10,0x80,0x07,0x0d, - 0x16,0x00,0x58,0x0f,0x06,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x04,0x80,0x36,0x0f, - 0x09,0x00,0x12,0x11,0x0c,0x00,0x44,0x0f,0x02,0x00,0x58,0x0f,0x08,0x80,0x0f,0x00, - 0x01,0x00,0x58,0x0f,0x06,0x80,0x36,0x0f,0x17,0x00,0x2b,0x11,0x01,0x00,0x27,0x12, - 0x18,0x00,0x12,0x13,0x0d,0x00,0x26,0x12,0x13,0x12,0x42,0x0f,0x03,0x01,0x16,0x0a, - 0x00,0x0a,0x58,0x0b,0x2f,0x7f,0x4b,0x00,0x01,0x00,0x18,0x63,0x6f,0x6d,0x6d,0x61, - 0x6e,0x64,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x3a,0x20,0x0b,0x61, - 0x73,0x73,0x65,0x72,0x74,0x0b,0x72,0x65,0x74,0x75,0x72,0x6e,0x09,0x6c,0x6f,0x6f, - 0x70,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x08,0x66,0x6f,0x72,0x09,0x65,0x61,0x63, - 0x68,0x0c,0x66,0x6f,0x72,0x65,0x61,0x63,0x68,0x08,0x65,0x6e,0x64,0x09,0x65,0x6c, - 0x73,0x65,0x09,0x65,0x6c,0x69,0x66,0x09,0x65,0x76,0x61,0x6c,0x07,0x69,0x66,0x10, - 0x6c,0x61,0x73,0x74,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x09,0x73,0x6b,0x69,0x70, - 0x0b,0x75,0x6e,0x70,0x61,0x63,0x6b,0x0b,0x61,0x63,0x74,0x69,0x6f,0x6e,0x0b,0x72, - 0x65,0x6d,0x6f,0x76,0x65,0x0a,0x74,0x61,0x62,0x6c,0x65,0x09,0x76,0x61,0x72,0x73, - 0x06,0x25,0x08,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x09,0x74,0x79, - 0x70,0x65,0x0b,0x69,0x70,0x61,0x69,0x72,0x73,0x02,0xc7,0x04,0x02,0x00,0x0d,0x00, - 0x0f,0x01,0x7b,0x34,0x00,0x03,0x00,0x47,0x01,0x00,0x00,0x3f,0x01,0x00,0x00,0x3a, - 0x01,0x01,0x00,0x3a,0x02,0x02,0x00,0x3a,0x03,0x03,0x00,0x2b,0x04,0x01,0x00,0x2b, - 0x05,0x01,0x00,0x36,0x06,0x00,0x00,0x39,0x06,0x01,0x06,0x12,0x08,0x02,0x00,0x29, - 0x09,0x01,0x00,0x29,0x0a,0x01,0x00,0x42,0x06,0x04,0x02,0x07,0x06,0x02,0x00,0x58, - 0x06,0x07,0x80,0x2b,0x04,0x02,0x00,0x36,0x06,0x00,0x00,0x39,0x06,0x01,0x06,0x12, - 0x08,0x02,0x00,0x29,0x09,0x02,0x00,0x42,0x06,0x03,0x02,0x12,0x02,0x06,0x00,0x0b, - 0x01,0x00,0x00,0x58,0x06,0x03,0x80,0x06,0x02,0x03,0x00,0x58,0x06,0x01,0x80,0x58, - 0x06,0x3b,0x80,0x07,0x02,0x03,0x00,0x58,0x06,0x06,0x80,0x04,0x01,0x03,0x00,0x58, - 0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58, - 0x06,0x33,0x80,0x07,0x02,0x04,0x00,0x58,0x06,0x06,0x80,0x00,0x03,0x01,0x00,0x58, - 0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58, - 0x06,0x2b,0x80,0x07,0x02,0x05,0x00,0x58,0x06,0x06,0x80,0x02,0x03,0x01,0x00,0x58, - 0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58, - 0x06,0x23,0x80,0x07,0x02,0x06,0x00,0x58,0x06,0x06,0x80,0x00,0x01,0x03,0x00,0x58, - 0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58, - 0x06,0x1b,0x80,0x07,0x02,0x07,0x00,0x58,0x06,0x06,0x80,0x02,0x01,0x03,0x00,0x58, - 0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58, - 0x06,0x13,0x80,0x07,0x02,0x08,0x00,0x58,0x06,0x0b,0x80,0x36,0x06,0x00,0x00,0x39, - 0x06,0x08,0x06,0x12,0x08,0x01,0x00,0x12,0x09,0x03,0x00,0x42,0x06,0x03,0x02,0x0b, - 0x06,0x00,0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b, - 0x05,0x02,0x00,0x58,0x06,0x06,0x80,0x36,0x06,0x09,0x00,0x2b,0x08,0x01,0x00,0x27, - 0x09,0x0a,0x00,0x12,0x0a,0x02,0x00,0x26,0x09,0x0a,0x09,0x42,0x06,0x03,0x01,0x0f, - 0x00,0x04,0x00,0x58,0x06,0x01,0x80,0x13,0x05,0x05,0x00,0x15,0x06,0x00,0x00,0x29, - 0x07,0x03,0x00,0x01,0x07,0x06,0x00,0x58,0x06,0x1c,0x80,0x3a,0x02,0x04,0x00,0x36, - 0x06,0x0b,0x00,0x36,0x08,0x0c,0x00,0x12,0x0a,0x00,0x00,0x29,0x0b,0x05,0x00,0x15, - 0x0c,0x00,0x00,0x42,0x08,0x04,0x00,0x41,0x06,0x00,0x02,0x07,0x02,0x0d,0x00,0x58, - 0x07,0x05,0x80,0x0d,0x07,0x05,0x00,0x58,0x07,0x01,0x80,0x12,0x07,0x06,0x00,0x4c, - 0x07,0x02,0x00,0x58,0x07,0x0d,0x80,0x07,0x02,0x0e,0x00,0x58,0x07,0x05,0x80,0x0c, - 0x07,0x05,0x00,0x58,0x07,0x01,0x80,0x12,0x07,0x06,0x00,0x4c,0x07,0x02,0x00,0x58, - 0x07,0x06,0x80,0x36,0x07,0x09,0x00,0x2b,0x09,0x01,0x00,0x27,0x0a,0x0a,0x00,0x12, - 0x0b,0x02,0x00,0x26,0x0a,0x0b,0x0a,0x42,0x07,0x03,0x01,0x4c,0x05,0x02,0x00,0x07, - 0x6f,0x72,0x08,0x61,0x6e,0x64,0x0b,0x75,0x6e,0x70,0x61,0x63,0x6b,0x09,0x65,0x76, - 0x61,0x6c,0x19,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x20,0x6e,0x6f,0x74,0x20, - 0x6b,0x6e,0x6f,0x77,0x6e,0x3a,0x20,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x0a,0x6d, - 0x61,0x74,0x63,0x68,0x07,0x3c,0x3d,0x06,0x3c,0x07,0x3e,0x3d,0x06,0x3e,0x06,0x3d, - 0x06,0x21,0x08,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x03,0x80,0x80, - 0xc0,0x99,0x04,0xd3,0x04,0x03,0x00,0x03,0x00,0x45,0x00,0x49,0x34,0x00,0x00,0x00, - 0x37,0x00,0x00,0x00,0x35,0x00,0x01,0x00,0x37,0x00,0x02,0x00,0x35,0x00,0x04,0x00, - 0x33,0x01,0x03,0x00,0x3d,0x01,0x05,0x00,0x33,0x01,0x06,0x00,0x3d,0x01,0x07,0x00, - 0x33,0x01,0x08,0x00,0x3d,0x01,0x09,0x00,0x33,0x01,0x0a,0x00,0x3d,0x01,0x0b,0x00, - 0x33,0x01,0x0c,0x00,0x3d,0x01,0x0d,0x00,0x33,0x01,0x0e,0x00,0x3d,0x01,0x0f,0x00, - 0x33,0x01,0x10,0x00,0x3d,0x01,0x11,0x00,0x33,0x01,0x12,0x00,0x3d,0x01,0x13,0x00, - 0x33,0x01,0x14,0x00,0x3d,0x01,0x15,0x00,0x33,0x01,0x16,0x00,0x3d,0x01,0x17,0x00, - 0x33,0x01,0x18,0x00,0x3d,0x01,0x19,0x00,0x33,0x01,0x1a,0x00,0x3d,0x01,0x1b,0x00, - 0x33,0x01,0x1c,0x00,0x3d,0x01,0x1d,0x00,0x33,0x01,0x1e,0x00,0x3d,0x01,0x1f,0x00, - 0x33,0x01,0x20,0x00,0x3d,0x01,0x21,0x00,0x33,0x01,0x22,0x00,0x3d,0x01,0x23,0x00, - 0x33,0x01,0x24,0x00,0x3d,0x01,0x25,0x00,0x33,0x01,0x26,0x00,0x3d,0x01,0x27,0x00, - 0x33,0x01,0x28,0x00,0x3d,0x01,0x29,0x00,0x33,0x01,0x2a,0x00,0x3d,0x01,0x2b,0x00, - 0x33,0x01,0x2c,0x00,0x3d,0x01,0x2d,0x00,0x33,0x01,0x2e,0x00,0x3d,0x01,0x2f,0x00, - 0x33,0x01,0x30,0x00,0x3d,0x01,0x31,0x00,0x33,0x01,0x32,0x00,0x3d,0x01,0x33,0x00, - 0x33,0x01,0x34,0x00,0x3d,0x01,0x35,0x00,0x33,0x01,0x36,0x00,0x3d,0x01,0x37,0x00, - 0x33,0x01,0x38,0x00,0x3d,0x01,0x39,0x00,0x33,0x01,0x3a,0x00,0x3d,0x01,0x3b,0x00, - 0x33,0x01,0x3c,0x00,0x3d,0x01,0x3d,0x00,0x37,0x00,0x3e,0x00,0x33,0x00,0x3f,0x00, - 0x37,0x00,0x40,0x00,0x33,0x00,0x41,0x00,0x37,0x00,0x42,0x00,0x36,0x00,0x43,0x00, - 0x39,0x00,0x44,0x00,0x36,0x02,0x40,0x00,0x42,0x00,0x02,0x01,0x4b,0x00,0x01,0x00, - 0x0d,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x08,0x61,0x62,0x69,0x09,0x65,0x76, - 0x61,0x6c,0x00,0x0c,0x65,0x78,0x65,0x63,0x75,0x74,0x65,0x00,0x0b,0x61,0x63,0x74, - 0x69,0x6f,0x6e,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x00,0x0d,0x66,0x72,0x6f,0x6d, - 0x6a,0x73,0x6f,0x6e,0x00,0x0b,0x74,0x6f,0x6a,0x73,0x6f,0x6e,0x00,0x0d,0x74,0x6f, - 0x73,0x74,0x72,0x69,0x6e,0x67,0x00,0x0d,0x74,0x6f,0x6e,0x75,0x6d,0x62,0x65,0x72, - 0x00,0x0d,0x74,0x6f,0x62,0x69,0x67,0x6e,0x75,0x6d,0x00,0x0c,0x72,0x65,0x70,0x6c, - 0x61,0x63,0x65,0x00,0x09,0x66,0x69,0x6e,0x64,0x00,0x0b,0x73,0x75,0x62,0x73,0x74, - 0x72,0x00,0x0b,0x66,0x6f,0x72,0x6d,0x61,0x74,0x00,0x09,0x73,0x71,0x72,0x74,0x00, - 0x08,0x6d,0x6f,0x64,0x00,0x08,0x70,0x6f,0x77,0x00,0x08,0x64,0x69,0x76,0x00,0x08, - 0x6d,0x75,0x6c,0x00,0x08,0x73,0x75,0x62,0x00,0x08,0x61,0x64,0x64,0x00,0x0b,0x72, - 0x65,0x6d,0x6f,0x76,0x65,0x00,0x0b,0x69,0x6e,0x73,0x65,0x72,0x74,0x00,0x08,0x73, - 0x65,0x74,0x00,0x08,0x67,0x65,0x74,0x00,0x0a,0x73,0x74,0x6f,0x72,0x65,0x00,0x08, - 0x6c,0x65,0x74,0x00,0x09,0x73,0x65,0x6e,0x64,0x00,0x0c,0x62,0x61,0x6c,0x61,0x6e, - 0x63,0x65,0x00,0x0f,0x70,0x63,0x61,0x6c,0x6c,0x2d,0x73,0x65,0x6e,0x64,0x00,0x0a, - 0x70,0x63,0x61,0x6c,0x6c,0x00,0x0e,0x63,0x61,0x6c,0x6c,0x2d,0x73,0x65,0x6e,0x64, - 0x00,0x09,0x63,0x61,0x6c,0x6c,0x01,0x00,0x00,0x00,0x09,0x73,0x6b,0x69,0x70,0x01, - 0x00,0x05,0x0b,0x69,0x6e,0x73,0x65,0x72,0x74,0x02,0x08,0x6c,0x65,0x74,0x02,0x0a, - 0x73,0x74,0x6f,0x72,0x65,0x02,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x02,0x08,0x73, - 0x65,0x74,0x02,0x09,0x76,0x61,0x72,0x73,0x00,0x7b,0x22,0x76,0x65,0x72,0x73,0x69, - 0x6f,0x6e,0x22,0x3a,0x22,0x30,0x2e,0x32,0x22,0x2c,0x22,0x6c,0x61,0x6e,0x67,0x75, - 0x61,0x67,0x65,0x22,0x3a,0x22,0x6c,0x75,0x61,0x22,0x2c,0x22,0x66,0x75,0x6e,0x63, - 0x74,0x69,0x6f,0x6e,0x73,0x22,0x3a,0x5b,0x7b,0x22,0x6e,0x61,0x6d,0x65,0x22,0x3a, - 0x22,0x65,0x78,0x65,0x63,0x75,0x74,0x65,0x22,0x2c,0x22,0x61,0x72,0x67,0x75,0x6d, - 0x65,0x6e,0x74,0x73,0x22,0x3a,0x5b,0x7b,0x22,0x6e,0x61,0x6d,0x65,0x22,0x3a,0x22, - 0x63,0x61,0x6c,0x6c,0x73,0x22,0x7d,0x5d,0x7d,0x5d,0x7d, + 0x74,0x43,0x00,0x03,0x07,0x00,0x02,0x00,0x0a,0x0f,0x00,0x02,0x00,0x58,0x03,0x05, + 0x80,0x36,0x03,0x00,0x00,0x12,0x05,0x01,0x00,0x12,0x06,0x02,0x00,0x42,0x03,0x03, + 0x02,0x12,0x01,0x03,0x00,0x36,0x03,0x01,0x00,0x3c,0x01,0x00,0x03,0x4b,0x00,0x01, + 0x00,0x09,0x76,0x61,0x72,0x73,0x13,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x62, + 0x69,0x67,0x6e,0x75,0x6d,0x2c,0x00,0x01,0x03,0x00,0x02,0x00,0x05,0x36,0x01,0x00, + 0x00,0x36,0x02,0x00,0x00,0x39,0x02,0x01,0x02,0x3c,0x02,0x00,0x01,0x4b,0x00,0x01, + 0x00,0x10,0x6c,0x61,0x73,0x74,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x09,0x76,0x61, + 0x72,0x73,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x38,0x02,0x01,0x00,0x4c,0x02, + 0x02,0x00,0x0f,0x00,0x03,0x03,0x00,0x00,0x00,0x02,0x3c,0x02,0x01,0x00,0x4b,0x00, + 0x01,0x00,0x28,0x02,0x00,0x03,0x00,0x02,0x00,0x05,0x36,0x00,0x00,0x00,0x39,0x00, + 0x01,0x00,0x47,0x02,0x00,0x00,0x41,0x00,0x00,0x01,0x4b,0x00,0x01,0x00,0x0b,0x69, + 0x6e,0x73,0x65,0x72,0x74,0x0a,0x74,0x61,0x62,0x6c,0x65,0x28,0x02,0x00,0x03,0x00, + 0x02,0x00,0x05,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x41, + 0x00,0x00,0x01,0x4b,0x00,0x01,0x00,0x0b,0x72,0x65,0x6d,0x6f,0x76,0x65,0x0a,0x74, + 0x61,0x62,0x6c,0x65,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x20,0x02,0x01,0x00, + 0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x21,0x02,0x01,0x00, + 0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x22,0x02,0x01,0x00, + 0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x23,0x02,0x01,0x00, + 0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x25,0x02,0x01,0x00, + 0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x24,0x02,0x01,0x00, + 0x4c,0x02,0x02,0x00,0x23,0x00,0x01,0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00, + 0x39,0x01,0x01,0x01,0x12,0x03,0x00,0x00,0x44,0x01,0x02,0x00,0x09,0x73,0x71,0x72, + 0x74,0x0b,0x62,0x69,0x67,0x6e,0x75,0x6d,0x25,0x02,0x00,0x03,0x00,0x02,0x00,0x04, + 0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00, + 0x0b,0x66,0x6f,0x72,0x6d,0x61,0x74,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x22,0x02, + 0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02, + 0x00,0x00,0x43,0x00,0x00,0x00,0x08,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e, + 0x67,0x24,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01, + 0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x0a,0x6d,0x61,0x74,0x63,0x68,0x0b, + 0x73,0x74,0x72,0x69,0x6e,0x67,0x23,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00, + 0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x09,0x67, + 0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x25,0x00,0x01,0x04,0x00,0x02, + 0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03,0x00,0x00,0x44,0x01, + 0x02,0x00,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x0b,0x62,0x69,0x67,0x6e,0x75,0x6d, + 0x1c,0x00,0x01,0x04,0x00,0x01,0x00,0x03,0x36,0x01,0x00,0x00,0x12,0x03,0x00,0x00, + 0x44,0x01,0x02,0x00,0x0d,0x74,0x6f,0x6e,0x75,0x6d,0x62,0x65,0x72,0x1c,0x00,0x01, + 0x04,0x00,0x01,0x00,0x03,0x36,0x01,0x00,0x00,0x12,0x03,0x00,0x00,0x44,0x01,0x02, + 0x00,0x0d,0x74,0x6f,0x73,0x74,0x72,0x69,0x6e,0x67,0x23,0x00,0x01,0x04,0x00,0x02, + 0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03,0x00,0x00,0x44,0x01, + 0x02,0x00,0x0b,0x65,0x6e,0x63,0x6f,0x64,0x65,0x09,0x6a,0x73,0x6f,0x6e,0x23,0x00, + 0x01,0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03, + 0x00,0x00,0x44,0x01,0x02,0x00,0x0b,0x64,0x65,0x63,0x6f,0x64,0x65,0x09,0x6a,0x73, + 0x6f,0x6e,0x70,0x02,0x00,0x08,0x00,0x05,0x01,0x0e,0x36,0x00,0x00,0x00,0x36,0x02, + 0x01,0x00,0x47,0x04,0x00,0x00,0x41,0x02,0x00,0x02,0x27,0x03,0x02,0x00,0x36,0x04, + 0x03,0x00,0x39,0x04,0x04,0x04,0x34,0x06,0x03,0x00,0x47,0x07,0x00,0x00,0x3f,0x07, + 0x00,0x00,0x42,0x04,0x02,0x02,0x26,0x03,0x04,0x03,0x42,0x00,0x03,0x01,0x4b,0x00, + 0x01,0x00,0x0b,0x65,0x6e,0x63,0x6f,0x64,0x65,0x09,0x6a,0x73,0x6f,0x6e,0x17,0x61, + 0x73,0x73,0x65,0x72,0x74,0x69,0x6f,0x6e,0x20,0x66,0x61,0x69,0x6c,0x65,0x64,0x3a, + 0x20,0x09,0x65,0x76,0x61,0x6c,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x03,0x80,0x80, + 0xc0,0x99,0x04,0x8e,0x02,0x00,0x01,0x09,0x00,0x08,0x00,0x36,0x36,0x01,0x00,0x00, + 0x12,0x03,0x00,0x00,0x42,0x01,0x02,0x02,0x07,0x01,0x01,0x00,0x58,0x01,0x21,0x80, + 0x15,0x01,0x00,0x00,0x29,0x02,0x03,0x00,0x03,0x02,0x01,0x00,0x58,0x01,0x2c,0x80, + 0x36,0x01,0x01,0x00,0x39,0x01,0x02,0x01,0x12,0x03,0x00,0x00,0x29,0x04,0x01,0x00, + 0x29,0x05,0x01,0x00,0x42,0x01,0x04,0x02,0x07,0x01,0x03,0x00,0x58,0x01,0x24,0x80, + 0x36,0x01,0x01,0x00,0x39,0x01,0x02,0x01,0x12,0x03,0x00,0x00,0x29,0x04,0xff,0xff, + 0x29,0x05,0xff,0xff,0x42,0x01,0x04,0x02,0x07,0x01,0x03,0x00,0x58,0x01,0x1c,0x80, + 0x36,0x01,0x01,0x00,0x39,0x01,0x02,0x01,0x12,0x03,0x00,0x00,0x29,0x04,0x02,0x00, + 0x29,0x05,0xfe,0xff,0x42,0x01,0x04,0x02,0x36,0x02,0x04,0x00,0x38,0x02,0x01,0x02, + 0x0a,0x02,0x00,0x00,0x58,0x02,0x12,0x80,0x36,0x02,0x04,0x00,0x38,0x00,0x01,0x02, + 0x58,0x01,0x0f,0x80,0x36,0x01,0x00,0x00,0x12,0x03,0x00,0x00,0x42,0x01,0x02,0x02, + 0x07,0x01,0x05,0x00,0x58,0x01,0x0a,0x80,0x36,0x01,0x06,0x00,0x12,0x03,0x00,0x00, + 0x42,0x01,0x02,0x04,0x48,0x04,0x04,0x80,0x36,0x06,0x07,0x00,0x12,0x08,0x05,0x00, + 0x42,0x06,0x02,0x02,0x3c,0x06,0x04,0x00,0x46,0x04,0x03,0x03,0x52,0x04,0xfa,0x7f, + 0x4c,0x00,0x02,0x00,0x10,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x61,0x72,0x67, + 0x0a,0x70,0x61,0x69,0x72,0x73,0x0a,0x74,0x61,0x62,0x6c,0x65,0x09,0x76,0x61,0x72, + 0x73,0x06,0x25,0x08,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x09,0x74, + 0x79,0x70,0x65,0xe2,0x06,0x00,0x01,0x15,0x00,0x16,0x01,0xb0,0x01,0x2b,0x01,0x02, + 0x00,0x2b,0x02,0x01,0x00,0x2c,0x03,0x09,0x00,0x29,0x0a,0x01,0x00,0x15,0x0b,0x00, + 0x00,0x03,0x0a,0x0b,0x00,0x58,0x0b,0xa8,0x80,0x55,0x0b,0xa7,0x80,0x38,0x0b,0x0a, + 0x00,0x34,0x0c,0x00,0x00,0x36,0x0d,0x00,0x00,0x12,0x0f,0x0b,0x00,0x42,0x0d,0x02, + 0x04,0x58,0x10,0x08,0x80,0x09,0x10,0x00,0x00,0x58,0x12,0x02,0x80,0x3c,0x11,0x10, + 0x0c,0x58,0x12,0x04,0x80,0x36,0x12,0x01,0x00,0x12,0x14,0x11,0x00,0x42,0x12,0x02, + 0x02,0x3c,0x12,0x10,0x0c,0x45,0x10,0x03,0x03,0x52,0x10,0xf6,0x7f,0x36,0x0d,0x02, + 0x00,0x39,0x0d,0x03,0x0d,0x12,0x0f,0x0c,0x00,0x29,0x10,0x01,0x00,0x42,0x0d,0x03, + 0x02,0x36,0x0e,0x04,0x00,0x38,0x0e,0x0d,0x0e,0x0f,0x00,0x0e,0x00,0x58,0x0f,0x0e, + 0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x0c,0x80,0x12,0x0f,0x0e,0x00,0x36,0x11,0x05, + 0x00,0x12,0x13,0x0c,0x00,0x42,0x11,0x02,0x00,0x41,0x0f,0x00,0x02,0x36,0x10,0x06, + 0x00,0x38,0x10,0x0d,0x10,0x0e,0x00,0x10,0x00,0x58,0x10,0x81,0x80,0x36,0x10,0x07, + 0x00,0x3d,0x0f,0x08,0x10,0x58,0x0f,0x7e,0x80,0x07,0x0d,0x09,0x00,0x58,0x0f,0x08, + 0x80,0x36,0x0f,0x0a,0x00,0x36,0x11,0x05,0x00,0x12,0x13,0x0c,0x00,0x42,0x11,0x02, + 0x00,0x41,0x0f,0x00,0x02,0x12,0x01,0x0f,0x00,0x12,0x02,0x01,0x00,0x58,0x0f,0x74, + 0x80,0x07,0x0d,0x0b,0x00,0x58,0x0f,0x0e,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x02, + 0x80,0x2b,0x01,0x01,0x00,0x58,0x0f,0x6e,0x80,0x0e,0x00,0x02,0x00,0x58,0x0f,0x6c, + 0x80,0x36,0x0f,0x0a,0x00,0x36,0x11,0x05,0x00,0x12,0x13,0x0c,0x00,0x42,0x11,0x02, + 0x00,0x41,0x0f,0x00,0x02,0x12,0x01,0x0f,0x00,0x12,0x02,0x01,0x00,0x58,0x0f,0x64, + 0x80,0x07,0x0d,0x0c,0x00,0x58,0x0f,0x08,0x80,0x0e,0x00,0x01,0x00,0x58,0x0f,0x02, + 0x80,0x13,0x01,0x02,0x00,0x58,0x0f,0x5e,0x80,0x2b,0x01,0x01,0x00,0x58,0x0f,0x01, + 0x80,0x2b,0x01,0x02,0x00,0x58,0x0f,0x5a,0x80,0x07,0x0d,0x0d,0x00,0x58,0x0f,0x02, + 0x80,0x2b,0x01,0x02,0x00,0x58,0x0f,0x56,0x80,0x07,0x0d,0x0e,0x00,0x58,0x0f,0x0b, + 0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x09,0x80,0x12,0x03,0x0a,0x00,0x27,0x05,0x0f, + 0x00,0x3a,0x04,0x01,0x0c,0x3a,0x06,0x02,0x0c,0x29,0x07,0x01,0x00,0x36,0x0f,0x07, + 0x00,0x38,0x10,0x07,0x06,0x3c,0x10,0x04,0x0f,0x58,0x0f,0x49,0x80,0x07,0x0d,0x10, + 0x00,0x58,0x0f,0x0e,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x0c,0x80,0x12,0x03,0x0a, + 0x00,0x27,0x05,0x11,0x00,0x3a,0x04,0x01,0x0c,0x3a,0x08,0x03,0x0c,0x3a,0x0f,0x04, + 0x0c,0x0c,0x09,0x0f,0x00,0x58,0x10,0x01,0x80,0x29,0x09,0x01,0x00,0x36,0x0f,0x07, + 0x00,0x3a,0x10,0x02,0x0c,0x3c,0x10,0x04,0x0f,0x58,0x0f,0x39,0x80,0x07,0x0d,0x12, + 0x00,0x58,0x0f,0x27,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x25,0x80,0x07,0x05,0x0f, + 0x00,0x58,0x0f,0x09,0x80,0x16,0x07,0x00,0x07,0x15,0x0f,0x06,0x00,0x03,0x07,0x0f, + 0x00,0x58,0x0f,0x2f,0x80,0x36,0x0f,0x07,0x00,0x38,0x10,0x07,0x06,0x3c,0x10,0x04, + 0x0f,0x12,0x0a,0x03,0x00,0x58,0x0f,0x2a,0x80,0x07,0x05,0x11,0x00,0x58,0x0f,0x16, + 0x80,0x36,0x0f,0x07,0x00,0x36,0x10,0x07,0x00,0x38,0x10,0x04,0x10,0x20,0x10,0x09, + 0x10,0x3c,0x10,0x04,0x0f,0x29,0x0f,0x00,0x00,0x01,0x0f,0x09,0x00,0x58,0x0f,0x04, + 0x80,0x36,0x0f,0x07,0x00,0x38,0x0f,0x04,0x0f,0x00,0x08,0x0f,0x00,0x58,0x0f,0x1c, + 0x80,0x29,0x0f,0x00,0x00,0x01,0x09,0x0f,0x00,0x58,0x0f,0x05,0x80,0x36,0x0f,0x07, + 0x00,0x38,0x0f,0x04,0x0f,0x01,0x0f,0x08,0x00,0x58,0x0f,0x01,0x80,0x58,0x0f,0x14, + 0x80,0x12,0x0a,0x03,0x00,0x58,0x0f,0x12,0x80,0x29,0x0a,0x00,0x00,0x58,0x0f,0x10, + 0x80,0x07,0x0d,0x13,0x00,0x58,0x0f,0x06,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x04, + 0x80,0x36,0x0f,0x05,0x00,0x12,0x11,0x0c,0x00,0x44,0x0f,0x02,0x00,0x58,0x0f,0x08, + 0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x06,0x80,0x36,0x0f,0x14,0x00,0x2b,0x11,0x01, + 0x00,0x27,0x12,0x15,0x00,0x12,0x13,0x0d,0x00,0x26,0x12,0x13,0x12,0x42,0x0f,0x03, + 0x01,0x16,0x0a,0x00,0x0a,0x58,0x0b,0x55,0x7f,0x4b,0x00,0x01,0x00,0x18,0x63,0x6f, + 0x6d,0x6d,0x61,0x6e,0x64,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x3a, + 0x20,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x0b,0x72,0x65,0x74,0x75,0x72,0x6e,0x09, + 0x6c,0x6f,0x6f,0x70,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x08,0x66,0x6f,0x72,0x09, + 0x65,0x61,0x63,0x68,0x0c,0x66,0x6f,0x72,0x65,0x61,0x63,0x68,0x08,0x65,0x6e,0x64, + 0x09,0x65,0x6c,0x73,0x65,0x09,0x65,0x6c,0x69,0x66,0x09,0x65,0x76,0x61,0x6c,0x07, + 0x69,0x66,0x10,0x6c,0x61,0x73,0x74,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x09,0x76, + 0x61,0x72,0x73,0x09,0x73,0x6b,0x69,0x70,0x0b,0x75,0x6e,0x70,0x61,0x63,0x6b,0x0b, + 0x61,0x63,0x74,0x69,0x6f,0x6e,0x0b,0x72,0x65,0x6d,0x6f,0x76,0x65,0x0a,0x74,0x61, + 0x62,0x6c,0x65,0x10,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x61,0x72,0x67,0x0b, + 0x69,0x70,0x61,0x69,0x72,0x73,0x02,0xc7,0x04,0x02,0x00,0x0d,0x00,0x0f,0x01,0x7b, + 0x34,0x00,0x03,0x00,0x47,0x01,0x00,0x00,0x3f,0x01,0x00,0x00,0x3a,0x01,0x01,0x00, + 0x3a,0x02,0x02,0x00,0x3a,0x03,0x03,0x00,0x2b,0x04,0x01,0x00,0x2b,0x05,0x01,0x00, + 0x36,0x06,0x00,0x00,0x39,0x06,0x01,0x06,0x12,0x08,0x02,0x00,0x29,0x09,0x01,0x00, + 0x29,0x0a,0x01,0x00,0x42,0x06,0x04,0x02,0x07,0x06,0x02,0x00,0x58,0x06,0x07,0x80, + 0x2b,0x04,0x02,0x00,0x36,0x06,0x00,0x00,0x39,0x06,0x01,0x06,0x12,0x08,0x02,0x00, + 0x29,0x09,0x02,0x00,0x42,0x06,0x03,0x02,0x12,0x02,0x06,0x00,0x0b,0x01,0x00,0x00, + 0x58,0x06,0x03,0x80,0x06,0x02,0x03,0x00,0x58,0x06,0x01,0x80,0x58,0x06,0x3b,0x80, + 0x07,0x02,0x03,0x00,0x58,0x06,0x06,0x80,0x04,0x01,0x03,0x00,0x58,0x06,0x02,0x80, + 0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x33,0x80, + 0x07,0x02,0x04,0x00,0x58,0x06,0x06,0x80,0x00,0x03,0x01,0x00,0x58,0x06,0x02,0x80, + 0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x2b,0x80, + 0x07,0x02,0x05,0x00,0x58,0x06,0x06,0x80,0x02,0x03,0x01,0x00,0x58,0x06,0x02,0x80, + 0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x23,0x80, + 0x07,0x02,0x06,0x00,0x58,0x06,0x06,0x80,0x00,0x01,0x03,0x00,0x58,0x06,0x02,0x80, + 0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x1b,0x80, + 0x07,0x02,0x07,0x00,0x58,0x06,0x06,0x80,0x02,0x01,0x03,0x00,0x58,0x06,0x02,0x80, + 0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x13,0x80, + 0x07,0x02,0x08,0x00,0x58,0x06,0x0b,0x80,0x36,0x06,0x00,0x00,0x39,0x06,0x08,0x06, + 0x12,0x08,0x01,0x00,0x12,0x09,0x03,0x00,0x42,0x06,0x03,0x02,0x0b,0x06,0x00,0x00, + 0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00, + 0x58,0x06,0x06,0x80,0x36,0x06,0x09,0x00,0x2b,0x08,0x01,0x00,0x27,0x09,0x0a,0x00, + 0x12,0x0a,0x02,0x00,0x26,0x09,0x0a,0x09,0x42,0x06,0x03,0x01,0x0f,0x00,0x04,0x00, + 0x58,0x06,0x01,0x80,0x13,0x05,0x05,0x00,0x15,0x06,0x00,0x00,0x29,0x07,0x03,0x00, + 0x01,0x07,0x06,0x00,0x58,0x06,0x1c,0x80,0x3a,0x02,0x04,0x00,0x36,0x06,0x0b,0x00, + 0x36,0x08,0x0c,0x00,0x12,0x0a,0x00,0x00,0x29,0x0b,0x05,0x00,0x15,0x0c,0x00,0x00, + 0x42,0x08,0x04,0x00,0x41,0x06,0x00,0x02,0x07,0x02,0x0d,0x00,0x58,0x07,0x05,0x80, + 0x0d,0x07,0x05,0x00,0x58,0x07,0x01,0x80,0x12,0x07,0x06,0x00,0x4c,0x07,0x02,0x00, + 0x58,0x07,0x0d,0x80,0x07,0x02,0x0e,0x00,0x58,0x07,0x05,0x80,0x0c,0x07,0x05,0x00, + 0x58,0x07,0x01,0x80,0x12,0x07,0x06,0x00,0x4c,0x07,0x02,0x00,0x58,0x07,0x06,0x80, + 0x36,0x07,0x09,0x00,0x2b,0x09,0x01,0x00,0x27,0x0a,0x0a,0x00,0x12,0x0b,0x02,0x00, + 0x26,0x0a,0x0b,0x0a,0x42,0x07,0x03,0x01,0x4c,0x05,0x02,0x00,0x07,0x6f,0x72,0x08, + 0x61,0x6e,0x64,0x0b,0x75,0x6e,0x70,0x61,0x63,0x6b,0x09,0x65,0x76,0x61,0x6c,0x19, + 0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x20,0x6e,0x6f,0x74,0x20,0x6b,0x6e,0x6f, + 0x77,0x6e,0x3a,0x20,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x0a,0x6d,0x61,0x74,0x63, + 0x68,0x07,0x3c,0x3d,0x06,0x3c,0x07,0x3e,0x3d,0x06,0x3e,0x06,0x3d,0x06,0x21,0x08, + 0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x03,0x80,0x80,0xc0,0x99,0x04, + 0xab,0x05,0x00,0x02,0x0e,0x00,0x18,0x02,0x73,0x36,0x02,0x00,0x00,0x12,0x04,0x00, + 0x00,0x42,0x02,0x02,0x02,0x06,0x02,0x01,0x00,0x58,0x02,0x04,0x80,0x36,0x02,0x02, + 0x00,0x12,0x04,0x00,0x00,0x42,0x02,0x02,0x02,0x12,0x00,0x02,0x00,0x36,0x02,0x03, + 0x00,0x36,0x04,0x01,0x00,0x39,0x04,0x04,0x04,0x12,0x06,0x00,0x00,0x27,0x07,0x05, + 0x00,0x42,0x04,0x03,0x02,0x0a,0x04,0x00,0x00,0x58,0x04,0x02,0x80,0x2b,0x04,0x01, + 0x00,0x58,0x05,0x01,0x80,0x2b,0x04,0x02,0x00,0x27,0x05,0x06,0x00,0x42,0x02,0x03, + 0x01,0x36,0x02,0x01,0x00,0x39,0x02,0x07,0x02,0x12,0x04,0x00,0x00,0x27,0x05,0x08, + 0x00,0x27,0x06,0x09,0x00,0x42,0x02,0x04,0x03,0x36,0x04,0x03,0x00,0x29,0x06,0x01, + 0x00,0x02,0x03,0x06,0x00,0x58,0x06,0x02,0x80,0x2b,0x06,0x01,0x00,0x58,0x07,0x01, + 0x80,0x2b,0x06,0x02,0x00,0x27,0x07,0x0a,0x00,0x42,0x04,0x03,0x01,0x09,0x03,0x00, + 0x00,0x58,0x04,0x48,0x80,0x2b,0x04,0x00,0x00,0x12,0x07,0x01,0x00,0x39,0x05,0x0b, + 0x01,0x42,0x05,0x02,0x02,0x07,0x05,0x0c,0x00,0x58,0x05,0x02,0x80,0x29,0x04,0x12, + 0x00,0x58,0x05,0x06,0x80,0x36,0x05,0x0d,0x00,0x39,0x05,0x0e,0x05,0x12,0x07,0x01, + 0x00,0x27,0x08,0x0f,0x00,0x42,0x05,0x03,0x02,0x12,0x04,0x05,0x00,0x36,0x05,0x03, + 0x00,0x29,0x07,0x00,0x00,0x03,0x07,0x04,0x00,0x58,0x07,0x03,0x80,0x29,0x07,0x12, + 0x00,0x02,0x04,0x07,0x00,0x58,0x07,0x02,0x80,0x2b,0x07,0x01,0x00,0x58,0x08,0x01, + 0x80,0x2b,0x07,0x02,0x00,0x27,0x08,0x10,0x00,0x42,0x05,0x03,0x01,0x36,0x05,0x01, + 0x00,0x39,0x05,0x04,0x05,0x27,0x07,0x11,0x00,0x12,0x08,0x00,0x00,0x27,0x09,0x11, + 0x00,0x26,0x07,0x09,0x07,0x27,0x08,0x12,0x00,0x42,0x05,0x03,0x03,0x15,0x07,0x06, + 0x00,0x21,0x07,0x07,0x04,0x29,0x08,0x00,0x00,0x01,0x08,0x07,0x00,0x58,0x08,0x08, + 0x80,0x12,0x08,0x06,0x00,0x36,0x09,0x01,0x00,0x39,0x09,0x13,0x09,0x27,0x0b,0x11, + 0x00,0x12,0x0c,0x07,0x00,0x42,0x09,0x03,0x02,0x26,0x06,0x09,0x08,0x58,0x08,0x0a, + 0x80,0x29,0x08,0x00,0x00,0x01,0x07,0x08,0x00,0x58,0x08,0x07,0x80,0x36,0x08,0x01, + 0x00,0x39,0x08,0x14,0x08,0x12,0x0a,0x06,0x00,0x29,0x0b,0x01,0x00,0x12,0x0c,0x04, + 0x00,0x42,0x08,0x04,0x02,0x12,0x06,0x08,0x00,0x12,0x08,0x05,0x00,0x12,0x09,0x06, + 0x00,0x26,0x00,0x09,0x08,0x36,0x08,0x01,0x00,0x39,0x08,0x07,0x08,0x12,0x0a,0x00, + 0x00,0x27,0x0b,0x15,0x00,0x27,0x0c,0x09,0x00,0x29,0x0d,0x01,0x00,0x42,0x08,0x05, + 0x02,0x12,0x00,0x08,0x00,0x15,0x08,0x00,0x00,0x09,0x08,0x01,0x00,0x58,0x08,0x01, + 0x80,0x27,0x00,0x11,0x00,0x36,0x04,0x16,0x00,0x39,0x04,0x17,0x04,0x12,0x06,0x00, + 0x00,0x44,0x04,0x02,0x00,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x0b,0x62,0x69,0x67, + 0x6e,0x75,0x6d,0x07,0x30,0x2a,0x08,0x73,0x75,0x62,0x08,0x72,0x65,0x70,0x11,0x28, + 0x25,0x64,0x2b,0x29,0x25,0x2e,0x28,0x25,0x64,0x2b,0x29,0x06,0x30,0x20,0x74,0x6f, + 0x6b,0x65,0x6e,0x20,0x77,0x69,0x74,0x68,0x20,0x69,0x6e,0x76,0x61,0x6c,0x69,0x64, + 0x20,0x64,0x65,0x63,0x69,0x6d,0x61,0x6c,0x73,0x0d,0x64,0x65,0x63,0x69,0x6d,0x61, + 0x6c,0x73,0x09,0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63,0x74, + 0x0a,0x61,0x65,0x72,0x67,0x6f,0x0a,0x6c,0x6f,0x77,0x65,0x72,0x1a,0x74,0x68,0x65, + 0x20,0x61,0x6d,0x6f,0x75,0x6e,0x74,0x20,0x69,0x73,0x20,0x69,0x6e,0x76,0x61,0x6c, + 0x69,0x64,0x05,0x07,0x25,0x2e,0x09,0x67,0x73,0x75,0x62,0x2a,0x74,0x68,0x65,0x20, + 0x61,0x6d,0x6f,0x75,0x6e,0x74,0x20,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x73,0x20, + 0x69,0x6e,0x76,0x61,0x6c,0x69,0x64,0x20,0x63,0x68,0x61,0x72,0x61,0x63,0x74,0x65, + 0x72,0x0c,0x5b,0x5e,0x30,0x2d,0x39,0x2e,0x5d,0x0a,0x6d,0x61,0x74,0x63,0x68,0x0b, + 0x61,0x73,0x73,0x65,0x72,0x74,0x0d,0x74,0x6f,0x73,0x74,0x72,0x69,0x6e,0x67,0x0b, + 0x73,0x74,0x72,0x69,0x6e,0x67,0x09,0x74,0x79,0x70,0x65,0x02,0x00,0x86,0x05,0x03, + 0x00,0x03,0x00,0x49,0x00,0x4d,0x34,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x35,0x00, + 0x01,0x00,0x37,0x00,0x02,0x00,0x35,0x00,0x04,0x00,0x33,0x01,0x03,0x00,0x3d,0x01, + 0x05,0x00,0x33,0x01,0x06,0x00,0x3d,0x01,0x07,0x00,0x33,0x01,0x08,0x00,0x3d,0x01, + 0x09,0x00,0x33,0x01,0x0a,0x00,0x3d,0x01,0x0b,0x00,0x33,0x01,0x0c,0x00,0x3d,0x01, + 0x0d,0x00,0x33,0x01,0x0e,0x00,0x3d,0x01,0x0f,0x00,0x33,0x01,0x10,0x00,0x3d,0x01, + 0x11,0x00,0x33,0x01,0x12,0x00,0x3d,0x01,0x13,0x00,0x33,0x01,0x14,0x00,0x3d,0x01, + 0x15,0x00,0x33,0x01,0x16,0x00,0x3d,0x01,0x17,0x00,0x33,0x01,0x18,0x00,0x3d,0x01, + 0x19,0x00,0x33,0x01,0x1a,0x00,0x3d,0x01,0x1b,0x00,0x33,0x01,0x1c,0x00,0x3d,0x01, + 0x1d,0x00,0x33,0x01,0x1e,0x00,0x3d,0x01,0x1f,0x00,0x33,0x01,0x20,0x00,0x3d,0x01, + 0x21,0x00,0x33,0x01,0x22,0x00,0x3d,0x01,0x23,0x00,0x33,0x01,0x24,0x00,0x3d,0x01, + 0x25,0x00,0x33,0x01,0x26,0x00,0x3d,0x01,0x27,0x00,0x33,0x01,0x28,0x00,0x3d,0x01, + 0x29,0x00,0x33,0x01,0x2a,0x00,0x3d,0x01,0x2b,0x00,0x33,0x01,0x2c,0x00,0x3d,0x01, + 0x2d,0x00,0x33,0x01,0x2e,0x00,0x3d,0x01,0x2f,0x00,0x33,0x01,0x30,0x00,0x3d,0x01, + 0x31,0x00,0x33,0x01,0x32,0x00,0x3d,0x01,0x33,0x00,0x33,0x01,0x34,0x00,0x3d,0x01, + 0x35,0x00,0x33,0x01,0x36,0x00,0x3d,0x01,0x37,0x00,0x33,0x01,0x38,0x00,0x3d,0x01, + 0x39,0x00,0x33,0x01,0x3a,0x00,0x3d,0x01,0x3b,0x00,0x33,0x01,0x3c,0x00,0x3d,0x01, + 0x3d,0x00,0x37,0x00,0x3e,0x00,0x33,0x00,0x3f,0x00,0x37,0x00,0x40,0x00,0x33,0x00, + 0x41,0x00,0x37,0x00,0x42,0x00,0x33,0x00,0x43,0x00,0x37,0x00,0x44,0x00,0x33,0x00, + 0x45,0x00,0x37,0x00,0x46,0x00,0x36,0x00,0x47,0x00,0x39,0x00,0x48,0x00,0x36,0x02, + 0x42,0x00,0x42,0x00,0x02,0x01,0x4b,0x00,0x01,0x00,0x0d,0x72,0x65,0x67,0x69,0x73, + 0x74,0x65,0x72,0x08,0x61,0x62,0x69,0x13,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f, + 0x62,0x69,0x67,0x6e,0x75,0x6d,0x00,0x09,0x65,0x76,0x61,0x6c,0x00,0x0c,0x65,0x78, + 0x65,0x63,0x75,0x74,0x65,0x00,0x10,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x61, + 0x72,0x67,0x00,0x0b,0x61,0x63,0x74,0x69,0x6f,0x6e,0x0b,0x61,0x73,0x73,0x65,0x72, + 0x74,0x00,0x0d,0x66,0x72,0x6f,0x6d,0x6a,0x73,0x6f,0x6e,0x00,0x0b,0x74,0x6f,0x6a, + 0x73,0x6f,0x6e,0x00,0x0d,0x74,0x6f,0x73,0x74,0x72,0x69,0x6e,0x67,0x00,0x0d,0x74, + 0x6f,0x6e,0x75,0x6d,0x62,0x65,0x72,0x00,0x0d,0x74,0x6f,0x62,0x69,0x67,0x6e,0x75, + 0x6d,0x00,0x0c,0x72,0x65,0x70,0x6c,0x61,0x63,0x65,0x00,0x09,0x66,0x69,0x6e,0x64, + 0x00,0x0b,0x73,0x75,0x62,0x73,0x74,0x72,0x00,0x0b,0x66,0x6f,0x72,0x6d,0x61,0x74, + 0x00,0x09,0x73,0x71,0x72,0x74,0x00,0x08,0x6d,0x6f,0x64,0x00,0x08,0x70,0x6f,0x77, + 0x00,0x08,0x64,0x69,0x76,0x00,0x08,0x6d,0x75,0x6c,0x00,0x08,0x73,0x75,0x62,0x00, + 0x08,0x61,0x64,0x64,0x00,0x0b,0x72,0x65,0x6d,0x6f,0x76,0x65,0x00,0x0b,0x69,0x6e, + 0x73,0x65,0x72,0x74,0x00,0x08,0x73,0x65,0x74,0x00,0x08,0x67,0x65,0x74,0x00,0x0a, + 0x73,0x74,0x6f,0x72,0x65,0x00,0x08,0x6c,0x65,0x74,0x00,0x09,0x73,0x65,0x6e,0x64, + 0x00,0x0c,0x62,0x61,0x6c,0x61,0x6e,0x63,0x65,0x00,0x0f,0x70,0x63,0x61,0x6c,0x6c, + 0x2d,0x73,0x65,0x6e,0x64,0x00,0x0a,0x70,0x63,0x61,0x6c,0x6c,0x00,0x0e,0x63,0x61, + 0x6c,0x6c,0x2d,0x73,0x65,0x6e,0x64,0x00,0x09,0x63,0x61,0x6c,0x6c,0x01,0x00,0x00, + 0x00,0x09,0x73,0x6b,0x69,0x70,0x01,0x00,0x06,0x0b,0x69,0x6e,0x73,0x65,0x72,0x74, + 0x02,0x08,0x6c,0x65,0x74,0x02,0x0a,0x73,0x74,0x6f,0x72,0x65,0x02,0x09,0x73,0x65, + 0x6e,0x64,0x02,0x08,0x73,0x65,0x74,0x02,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x02, + 0x09,0x76,0x61,0x72,0x73,0x00,0x7b,0x22,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x22, + 0x3a,0x22,0x30,0x2e,0x32,0x22,0x2c,0x22,0x6c,0x61,0x6e,0x67,0x75,0x61,0x67,0x65, + 0x22,0x3a,0x22,0x6c,0x75,0x61,0x22,0x2c,0x22,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f, + 0x6e,0x73,0x22,0x3a,0x5b,0x7b,0x22,0x6e,0x61,0x6d,0x65,0x22,0x3a,0x22,0x65,0x78, + 0x65,0x63,0x75,0x74,0x65,0x22,0x2c,0x22,0x61,0x72,0x67,0x75,0x6d,0x65,0x6e,0x74, + 0x73,0x22,0x3a,0x5b,0x7b,0x22,0x6e,0x61,0x6d,0x65,0x22,0x3a,0x22,0x63,0x61,0x6c, + 0x6c,0x73,0x22,0x7d,0x5d,0x7d,0x5d,0x7d, } diff --git a/contract/vm_multicall.lua b/contract/vm_multicall.lua index e0ec420f2..6997917ef 100644 --- a/contract/vm_multicall.lua +++ b/contract/vm_multicall.lua @@ -4,7 +4,7 @@ vars = {} -skip = {store=true,let=true,set=true,insert=true,assert=true} +skip = {store=true,let=true,set=true,insert=true,assert=true,send=true} action = { @@ -19,14 +19,14 @@ action = { send = function (address,amount) return contract.send(address, amount) end, -- variables - let = function (x,y) vars[x] = y end, + let = function (x,y,z) if z then y = convert_bignum(y,z) end vars[x] = y end, store = function (n) vars[n] = vars['last_result'] end, -- tables get = function (o,k) return o[k] end, set = function (o,k,v) o[k] = v end, insert = function (...) table.insert(...) end, -- inserts at the end if no pos informed - remove = function (...) table.remove(...) end, + remove = function (...) table.remove(...) end, -- returns the removed item -- math add = function (x,y) return x+y end, @@ -55,6 +55,20 @@ action = { } +function process_arg(arg) + if type(arg) == 'string' then + if #arg >= 3 and string.sub(arg, 1, 1) == '%' and string.sub(arg, -1, -1) == '%' then + local varname = string.sub(arg, 2, -2) + if vars[varname] ~= nil then + arg = vars[varname] + end + end + elseif type(arg) == 'table' then + for k,v in pairs(arg) do arg[k] = process_arg(v) end + end + return arg +end + function execute(calls) local if_on = true @@ -69,16 +83,13 @@ function execute(calls) while cmdpos <= #calls do local call = calls[cmdpos] local args = {} -- use a copy of the list because of loops - for i,v in ipairs(call) do args[i] = v end - - -- process variables - for i,item in ipairs(args) do - if i > 1 and type(item) == 'string' and #item >= 3 and - string.sub(item, 1, 1) == '%' and string.sub(item, -1, -1) == '%' then - local varname = string.sub(item, 2, -2) - if vars[varname] ~= nil then - args[i] = vars[varname] - end + + -- copy values and process variables + for i,arg in ipairs(call) do + if i == 1 then + args[i] = arg + else + args[i] = process_arg(arg) end end @@ -136,6 +147,8 @@ function execute(calls) else cmdpos = for_cmdpos end + else + cmdpos = 0 end -- return @@ -193,4 +206,33 @@ function eval(...) return matches end +function convert_bignum(x, token) + if type(x) ~= 'string' then + x = tostring(x) + end + assert(string.match(x, '[^0-9.]') == nil, "the amount contains invalid character") + local _, count = string.gsub(x, "%.", "") + assert(count <= 1, "the amount is invalid") + if count == 1 then + local num_decimals + if token:lower() == 'aergo' then + num_decimals = 18 + else + num_decimals = contract.call(token, "decimals") + end + assert(num_decimals >= 0 and num_decimals <= 18, "token with invalid decimals") + local p1, p2 = string.match('0' .. x .. '0', '(%d+)%.(%d+)') + local to_add = num_decimals - #p2 + if to_add > 0 then + p2 = p2 .. string.rep('0', to_add) + elseif to_add < 0 then + p2 = string.sub(p2, 1, num_decimals) + end + x = p1 .. p2 + x = string.gsub(x, '0*', '', 1) -- remove leading zeros + if #x == 0 then x = '0' end + end + return bignum.number(x) +end + abi.register(execute) From e973975c2435cc93f289bb9d5138b1e7939036be Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 26 Jul 2022 22:26:25 -0300 Subject: [PATCH 008/182] [contract] add functions to composable transactions --- contract/vm_multicall.go | 539 ++++++++++++++++++++------------------ contract/vm_multicall.lua | 54 +++- 2 files changed, 330 insertions(+), 263 deletions(-) diff --git a/contract/vm_multicall.go b/contract/vm_multicall.go index 0c96e4973..fe9864826 100644 --- a/contract/vm_multicall.go +++ b/contract/vm_multicall.go @@ -1,7 +1,7 @@ package contract var multicall_payload = []byte { - 0x51,0x10,0x00,0x00,0x1b,0x4c,0x4a,0x02,0x0a,0x25,0x02,0x00,0x03,0x00,0x02, + 0x62,0x12,0x00,0x00,0x1b,0x4c,0x4a,0x02,0x0a,0x25,0x02,0x00,0x03,0x00,0x02, 0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00, 0x00,0x00,0x09,0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63,0x74, 0x37,0x02,0x01,0x04,0x00,0x03,0x00,0x07,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01, @@ -16,257 +16,290 @@ var multicall_payload = []byte { 0x02,0x04,0x39,0x04,0x03,0x04,0x12,0x06,0x00,0x00,0x42,0x04,0x02,0x02,0x47,0x05, 0x01,0x00,0x41,0x02,0x01,0x00,0x3f,0x02,0x00,0x00,0x4c,0x01,0x02,0x00,0x0a,0x76, 0x61,0x6c,0x75,0x65,0x09,0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61, - 0x63,0x74,0x0a,0x70,0x63,0x61,0x6c,0x6c,0x03,0x80,0x80,0xc0,0x99,0x04,0x28,0x00, - 0x01,0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03, - 0x00,0x00,0x44,0x01,0x02,0x00,0x0c,0x62,0x61,0x6c,0x61,0x6e,0x63,0x65,0x0d,0x63, - 0x6f,0x6e,0x74,0x72,0x61,0x63,0x74,0x29,0x00,0x02,0x06,0x00,0x02,0x00,0x05,0x36, - 0x02,0x00,0x00,0x39,0x02,0x01,0x02,0x12,0x04,0x00,0x00,0x12,0x05,0x01,0x00,0x44, - 0x02,0x03,0x00,0x09,0x73,0x65,0x6e,0x64,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63, - 0x74,0x43,0x00,0x03,0x07,0x00,0x02,0x00,0x0a,0x0f,0x00,0x02,0x00,0x58,0x03,0x05, - 0x80,0x36,0x03,0x00,0x00,0x12,0x05,0x01,0x00,0x12,0x06,0x02,0x00,0x42,0x03,0x03, - 0x02,0x12,0x01,0x03,0x00,0x36,0x03,0x01,0x00,0x3c,0x01,0x00,0x03,0x4b,0x00,0x01, - 0x00,0x09,0x76,0x61,0x72,0x73,0x13,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x62, - 0x69,0x67,0x6e,0x75,0x6d,0x2c,0x00,0x01,0x03,0x00,0x02,0x00,0x05,0x36,0x01,0x00, - 0x00,0x36,0x02,0x00,0x00,0x39,0x02,0x01,0x02,0x3c,0x02,0x00,0x01,0x4b,0x00,0x01, - 0x00,0x10,0x6c,0x61,0x73,0x74,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x09,0x76,0x61, - 0x72,0x73,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x38,0x02,0x01,0x00,0x4c,0x02, - 0x02,0x00,0x0f,0x00,0x03,0x03,0x00,0x00,0x00,0x02,0x3c,0x02,0x01,0x00,0x4b,0x00, - 0x01,0x00,0x28,0x02,0x00,0x03,0x00,0x02,0x00,0x05,0x36,0x00,0x00,0x00,0x39,0x00, - 0x01,0x00,0x47,0x02,0x00,0x00,0x41,0x00,0x00,0x01,0x4b,0x00,0x01,0x00,0x0b,0x69, - 0x6e,0x73,0x65,0x72,0x74,0x0a,0x74,0x61,0x62,0x6c,0x65,0x28,0x02,0x00,0x03,0x00, - 0x02,0x00,0x05,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x41, - 0x00,0x00,0x01,0x4b,0x00,0x01,0x00,0x0b,0x72,0x65,0x6d,0x6f,0x76,0x65,0x0a,0x74, - 0x61,0x62,0x6c,0x65,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x20,0x02,0x01,0x00, - 0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x21,0x02,0x01,0x00, - 0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x22,0x02,0x01,0x00, - 0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x23,0x02,0x01,0x00, - 0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x25,0x02,0x01,0x00, - 0x4c,0x02,0x02,0x00,0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x24,0x02,0x01,0x00, - 0x4c,0x02,0x02,0x00,0x23,0x00,0x01,0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00, - 0x39,0x01,0x01,0x01,0x12,0x03,0x00,0x00,0x44,0x01,0x02,0x00,0x09,0x73,0x71,0x72, - 0x74,0x0b,0x62,0x69,0x67,0x6e,0x75,0x6d,0x25,0x02,0x00,0x03,0x00,0x02,0x00,0x04, - 0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00, - 0x0b,0x66,0x6f,0x72,0x6d,0x61,0x74,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x22,0x02, - 0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02, - 0x00,0x00,0x43,0x00,0x00,0x00,0x08,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e, - 0x67,0x24,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01, - 0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x0a,0x6d,0x61,0x74,0x63,0x68,0x0b, - 0x73,0x74,0x72,0x69,0x6e,0x67,0x23,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00, - 0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x09,0x67, - 0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x25,0x00,0x01,0x04,0x00,0x02, - 0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03,0x00,0x00,0x44,0x01, + 0x63,0x74,0x0a,0x70,0x63,0x61,0x6c,0x6c,0x03,0x80,0x80,0xc0,0x99,0x04,0x42,0x00, + 0x01,0x06,0x00,0x04,0x00,0x07,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x36,0x03, + 0x02,0x00,0x39,0x03,0x03,0x03,0x12,0x05,0x00,0x00,0x42,0x03,0x02,0x00,0x43,0x01, + 0x00,0x00,0x0c,0x62,0x61,0x6c,0x61,0x6e,0x63,0x65,0x0d,0x63,0x6f,0x6e,0x74,0x72, + 0x61,0x63,0x74,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x0b,0x62,0x69,0x67,0x6e,0x75, + 0x6d,0x29,0x00,0x02,0x06,0x00,0x02,0x00,0x05,0x36,0x02,0x00,0x00,0x39,0x02,0x01, + 0x02,0x12,0x04,0x00,0x00,0x12,0x05,0x01,0x00,0x44,0x02,0x03,0x00,0x09,0x73,0x65, + 0x6e,0x64,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63,0x74,0x43,0x00,0x03,0x07,0x00, + 0x02,0x00,0x0a,0x0f,0x00,0x02,0x00,0x58,0x03,0x05,0x80,0x36,0x03,0x00,0x00,0x12, + 0x05,0x01,0x00,0x12,0x06,0x02,0x00,0x42,0x03,0x03,0x02,0x12,0x01,0x03,0x00,0x36, + 0x03,0x01,0x00,0x3c,0x01,0x00,0x03,0x4b,0x00,0x01,0x00,0x09,0x76,0x61,0x72,0x73, + 0x13,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x62,0x69,0x67,0x6e,0x75,0x6d,0x2c, + 0x00,0x01,0x03,0x00,0x02,0x00,0x05,0x36,0x01,0x00,0x00,0x36,0x02,0x00,0x00,0x39, + 0x02,0x01,0x02,0x3c,0x02,0x00,0x01,0x4b,0x00,0x01,0x00,0x10,0x6c,0x61,0x73,0x74, + 0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x09,0x76,0x61,0x72,0x73,0x0f,0x00,0x02,0x03, + 0x00,0x00,0x00,0x02,0x38,0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x0f,0x00,0x03,0x03, + 0x00,0x00,0x00,0x02,0x3c,0x02,0x01,0x00,0x4b,0x00,0x01,0x00,0x28,0x02,0x00,0x03, + 0x00,0x02,0x00,0x05,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00, + 0x41,0x00,0x00,0x01,0x4b,0x00,0x01,0x00,0x0b,0x69,0x6e,0x73,0x65,0x72,0x74,0x0a, + 0x74,0x61,0x62,0x6c,0x65,0x24,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00, + 0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x0b,0x72,0x65, + 0x6d,0x6f,0x76,0x65,0x0a,0x74,0x61,0x62,0x6c,0x65,0x0f,0x00,0x01,0x02,0x00,0x00, + 0x00,0x02,0x15,0x01,0x00,0x00,0x4c,0x01,0x02,0x00,0x55,0x00,0x01,0x09,0x00,0x03, + 0x01,0x0f,0x34,0x01,0x00,0x00,0x36,0x02,0x00,0x00,0x12,0x04,0x00,0x00,0x42,0x02, + 0x02,0x04,0x48,0x05,0x03,0x80,0x15,0x07,0x01,0x00,0x16,0x07,0x00,0x07,0x3c,0x05, + 0x07,0x01,0x46,0x05,0x03,0x03,0x52,0x05,0xfb,0x7f,0x36,0x02,0x01,0x00,0x39,0x02, + 0x02,0x02,0x12,0x04,0x01,0x00,0x42,0x02,0x02,0x01,0x4c,0x01,0x02,0x00,0x09,0x73, + 0x6f,0x72,0x74,0x0a,0x74,0x61,0x62,0x6c,0x65,0x0a,0x70,0x61,0x69,0x72,0x73,0x02, + 0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x20,0x02,0x01,0x00,0x4c,0x02,0x02,0x00, + 0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x21,0x02,0x01,0x00,0x4c,0x02,0x02,0x00, + 0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x22,0x02,0x01,0x00,0x4c,0x02,0x02,0x00, + 0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x23,0x02,0x01,0x00,0x4c,0x02,0x02,0x00, + 0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x25,0x02,0x01,0x00,0x4c,0x02,0x02,0x00, + 0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x24,0x02,0x01,0x00,0x4c,0x02,0x02,0x00, + 0x23,0x00,0x01,0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01, + 0x12,0x03,0x00,0x00,0x44,0x01,0x02,0x00,0x09,0x73,0x71,0x72,0x74,0x0b,0x62,0x69, + 0x67,0x6e,0x75,0x6d,0x32,0x02,0x00,0x04,0x00,0x02,0x01,0x06,0x36,0x00,0x00,0x00, + 0x39,0x00,0x01,0x00,0x34,0x02,0x03,0x00,0x47,0x03,0x00,0x00,0x3f,0x03,0x00,0x00, + 0x44,0x00,0x02,0x00,0x0b,0x63,0x6f,0x6e,0x63,0x61,0x74,0x0a,0x74,0x61,0x62,0x6c, + 0x65,0x03,0x80,0x80,0xc0,0x99,0x04,0x25,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36, + 0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x0b, + 0x66,0x6f,0x72,0x6d,0x61,0x74,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x22,0x02,0x00, + 0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00, + 0x00,0x43,0x00,0x00,0x00,0x08,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67, + 0x24,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00, + 0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x0a,0x6d,0x61,0x74,0x63,0x68,0x0b,0x73, + 0x74,0x72,0x69,0x6e,0x67,0x23,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00, + 0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x09,0x67,0x73, + 0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x25,0x00,0x01,0x04,0x00,0x02,0x00, + 0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03,0x00,0x00,0x44,0x01,0x02, + 0x00,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x0b,0x62,0x69,0x67,0x6e,0x75,0x6d,0x1c, + 0x00,0x01,0x04,0x00,0x01,0x00,0x03,0x36,0x01,0x00,0x00,0x12,0x03,0x00,0x00,0x44, + 0x01,0x02,0x00,0x0d,0x74,0x6f,0x6e,0x75,0x6d,0x62,0x65,0x72,0x1c,0x00,0x01,0x04, + 0x00,0x01,0x00,0x03,0x36,0x01,0x00,0x00,0x12,0x03,0x00,0x00,0x44,0x01,0x02,0x00, + 0x0d,0x74,0x6f,0x73,0x74,0x72,0x69,0x6e,0x67,0x23,0x00,0x01,0x04,0x00,0x02,0x00, + 0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03,0x00,0x00,0x44,0x01,0x02, + 0x00,0x0b,0x65,0x6e,0x63,0x6f,0x64,0x65,0x09,0x6a,0x73,0x6f,0x6e,0x23,0x00,0x01, + 0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03,0x00, + 0x00,0x44,0x01,0x02,0x00,0x0b,0x64,0x65,0x63,0x6f,0x64,0x65,0x09,0x6a,0x73,0x6f, + 0x6e,0x70,0x02,0x00,0x08,0x00,0x05,0x01,0x0e,0x36,0x00,0x00,0x00,0x36,0x02,0x01, + 0x00,0x47,0x04,0x00,0x00,0x41,0x02,0x00,0x02,0x27,0x03,0x02,0x00,0x36,0x04,0x03, + 0x00,0x39,0x04,0x04,0x04,0x34,0x06,0x03,0x00,0x47,0x07,0x00,0x00,0x3f,0x07,0x00, + 0x00,0x42,0x04,0x02,0x02,0x26,0x03,0x04,0x03,0x42,0x00,0x03,0x01,0x4b,0x00,0x01, + 0x00,0x0b,0x65,0x6e,0x63,0x6f,0x64,0x65,0x09,0x6a,0x73,0x6f,0x6e,0x17,0x61,0x73, + 0x73,0x65,0x72,0x74,0x69,0x6f,0x6e,0x20,0x66,0x61,0x69,0x6c,0x65,0x64,0x3a,0x20, + 0x09,0x65,0x76,0x61,0x6c,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x03,0x80,0x80,0xc0, + 0x99,0x04,0x8e,0x02,0x00,0x01,0x09,0x00,0x08,0x00,0x36,0x36,0x01,0x00,0x00,0x12, + 0x03,0x00,0x00,0x42,0x01,0x02,0x02,0x07,0x01,0x01,0x00,0x58,0x01,0x21,0x80,0x15, + 0x01,0x00,0x00,0x29,0x02,0x03,0x00,0x03,0x02,0x01,0x00,0x58,0x01,0x2c,0x80,0x36, + 0x01,0x01,0x00,0x39,0x01,0x02,0x01,0x12,0x03,0x00,0x00,0x29,0x04,0x01,0x00,0x29, + 0x05,0x01,0x00,0x42,0x01,0x04,0x02,0x07,0x01,0x03,0x00,0x58,0x01,0x24,0x80,0x36, + 0x01,0x01,0x00,0x39,0x01,0x02,0x01,0x12,0x03,0x00,0x00,0x29,0x04,0xff,0xff,0x29, + 0x05,0xff,0xff,0x42,0x01,0x04,0x02,0x07,0x01,0x03,0x00,0x58,0x01,0x1c,0x80,0x36, + 0x01,0x01,0x00,0x39,0x01,0x02,0x01,0x12,0x03,0x00,0x00,0x29,0x04,0x02,0x00,0x29, + 0x05,0xfe,0xff,0x42,0x01,0x04,0x02,0x36,0x02,0x04,0x00,0x38,0x02,0x01,0x02,0x0a, + 0x02,0x00,0x00,0x58,0x02,0x12,0x80,0x36,0x02,0x04,0x00,0x38,0x00,0x01,0x02,0x58, + 0x01,0x0f,0x80,0x36,0x01,0x00,0x00,0x12,0x03,0x00,0x00,0x42,0x01,0x02,0x02,0x07, + 0x01,0x05,0x00,0x58,0x01,0x0a,0x80,0x36,0x01,0x06,0x00,0x12,0x03,0x00,0x00,0x42, + 0x01,0x02,0x04,0x48,0x04,0x04,0x80,0x36,0x06,0x07,0x00,0x12,0x08,0x05,0x00,0x42, + 0x06,0x02,0x02,0x3c,0x06,0x04,0x00,0x46,0x04,0x03,0x03,0x52,0x04,0xfa,0x7f,0x4c, + 0x00,0x02,0x00,0x10,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x61,0x72,0x67,0x0a, + 0x70,0x61,0x69,0x72,0x73,0x0a,0x74,0x61,0x62,0x6c,0x65,0x09,0x76,0x61,0x72,0x73, + 0x06,0x25,0x08,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x09,0x74,0x79, + 0x70,0x65,0x90,0x09,0x00,0x01,0x18,0x00,0x1a,0x01,0xf5,0x01,0x2b,0x01,0x02,0x00, + 0x2b,0x02,0x01,0x00,0x2c,0x03,0x0b,0x00,0x2b,0x0c,0x01,0x00,0x29,0x0d,0x01,0x00, + 0x15,0x0e,0x00,0x00,0x03,0x0d,0x0e,0x00,0x58,0x0e,0xec,0x80,0x55,0x0e,0xeb,0x80, + 0x38,0x0e,0x0d,0x00,0x34,0x0f,0x00,0x00,0x36,0x10,0x00,0x00,0x12,0x12,0x0e,0x00, + 0x42,0x10,0x02,0x04,0x58,0x13,0x08,0x80,0x09,0x13,0x00,0x00,0x58,0x15,0x02,0x80, + 0x3c,0x14,0x13,0x0f,0x58,0x15,0x04,0x80,0x36,0x15,0x01,0x00,0x12,0x17,0x14,0x00, + 0x42,0x15,0x02,0x02,0x3c,0x15,0x13,0x0f,0x45,0x13,0x03,0x03,0x52,0x13,0xf6,0x7f, + 0x36,0x10,0x02,0x00,0x39,0x10,0x03,0x10,0x12,0x12,0x0f,0x00,0x29,0x13,0x01,0x00, + 0x42,0x10,0x03,0x02,0x36,0x11,0x04,0x00,0x38,0x11,0x10,0x11,0x0f,0x00,0x11,0x00, + 0x58,0x12,0x0e,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x0c,0x80,0x12,0x12,0x11,0x00, + 0x36,0x14,0x05,0x00,0x12,0x16,0x0f,0x00,0x42,0x14,0x02,0x00,0x41,0x12,0x00,0x02, + 0x36,0x13,0x06,0x00,0x38,0x13,0x10,0x13,0x0e,0x00,0x13,0x00,0x58,0x13,0xa7,0x80, + 0x36,0x13,0x07,0x00,0x3d,0x12,0x08,0x13,0x58,0x12,0xa4,0x80,0x07,0x10,0x09,0x00, + 0x58,0x12,0x08,0x80,0x36,0x12,0x0a,0x00,0x36,0x14,0x05,0x00,0x12,0x16,0x0f,0x00, + 0x42,0x14,0x02,0x00,0x41,0x12,0x00,0x02,0x12,0x01,0x12,0x00,0x12,0x02,0x01,0x00, + 0x58,0x12,0x9a,0x80,0x07,0x10,0x0b,0x00,0x58,0x12,0x0e,0x80,0x0f,0x00,0x01,0x00, + 0x58,0x12,0x02,0x80,0x2b,0x01,0x01,0x00,0x58,0x12,0x94,0x80,0x0e,0x00,0x02,0x00, + 0x58,0x12,0x92,0x80,0x36,0x12,0x0a,0x00,0x36,0x14,0x05,0x00,0x12,0x16,0x0f,0x00, + 0x42,0x14,0x02,0x00,0x41,0x12,0x00,0x02,0x12,0x01,0x12,0x00,0x12,0x02,0x01,0x00, + 0x58,0x12,0x8a,0x80,0x07,0x10,0x0c,0x00,0x58,0x12,0x08,0x80,0x0e,0x00,0x01,0x00, + 0x58,0x12,0x02,0x80,0x13,0x01,0x02,0x00,0x58,0x12,0x84,0x80,0x2b,0x01,0x01,0x00, + 0x58,0x12,0x01,0x80,0x2b,0x01,0x02,0x00,0x58,0x12,0x80,0x80,0x07,0x10,0x0d,0x00, + 0x58,0x12,0x02,0x80,0x2b,0x01,0x02,0x00,0x58,0x12,0x7c,0x80,0x07,0x10,0x0e,0x00, + 0x58,0x12,0x06,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x04,0x80,0x27,0x05,0x0f,0x00, + 0x34,0x07,0x00,0x00,0x3a,0x08,0x02,0x0f,0x58,0x12,0x74,0x80,0x07,0x10,0x10,0x00, + 0x58,0x12,0x0e,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x0c,0x80,0x3a,0x05,0x02,0x0f, + 0x3a,0x07,0x03,0x0f,0x36,0x12,0x04,0x00,0x39,0x12,0x11,0x12,0x12,0x14,0x07,0x00, + 0x42,0x12,0x02,0x02,0x12,0x08,0x12,0x00,0x36,0x12,0x07,0x00,0x3a,0x13,0x01,0x08, + 0x38,0x13,0x13,0x07,0x3c,0x13,0x05,0x12,0x58,0x12,0x64,0x80,0x07,0x10,0x12,0x00, + 0x58,0x12,0x1f,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x1d,0x80,0x12,0x03,0x0d,0x00, + 0x27,0x06,0x13,0x00,0x3a,0x04,0x01,0x0f,0x3a,0x0a,0x03,0x0f,0x3a,0x12,0x04,0x0f, + 0x0c,0x0b,0x12,0x00,0x58,0x13,0x01,0x80,0x29,0x0b,0x01,0x00,0x36,0x12,0x07,0x00, + 0x3a,0x13,0x02,0x0f,0x3c,0x13,0x04,0x12,0x29,0x12,0x00,0x00,0x01,0x12,0x0b,0x00, + 0x58,0x12,0x04,0x80,0x36,0x12,0x07,0x00,0x38,0x12,0x04,0x12,0x00,0x0a,0x12,0x00, + 0x58,0x12,0x09,0x80,0x29,0x12,0x00,0x00,0x01,0x0b,0x12,0x00,0x58,0x12,0x04,0x80, + 0x36,0x12,0x07,0x00,0x38,0x12,0x04,0x12,0x00,0x12,0x0a,0x00,0x58,0x12,0x02,0x80, + 0x2b,0x0c,0x01,0x00,0x58,0x12,0x01,0x80,0x2b,0x0c,0x02,0x00,0x58,0x12,0x43,0x80, + 0x07,0x10,0x14,0x00,0x58,0x12,0x04,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x02,0x80, + 0x2b,0x0c,0x02,0x00,0x58,0x12,0x3d,0x80,0x07,0x10,0x15,0x00,0x58,0x12,0x2b,0x80, + 0x0f,0x00,0x01,0x00,0x58,0x12,0x29,0x80,0x07,0x06,0x16,0x00,0x58,0x12,0x0d,0x80, + 0x16,0x09,0x00,0x09,0x15,0x12,0x08,0x00,0x03,0x09,0x12,0x00,0x58,0x12,0x33,0x80, + 0x36,0x12,0x07,0x00,0x38,0x13,0x09,0x08,0x3c,0x13,0x04,0x12,0x36,0x12,0x07,0x00, + 0x38,0x13,0x09,0x08,0x38,0x13,0x13,0x07,0x3c,0x13,0x05,0x12,0x12,0x0d,0x03,0x00, + 0x58,0x12,0x2a,0x80,0x07,0x06,0x13,0x00,0x58,0x12,0x16,0x80,0x36,0x12,0x07,0x00, + 0x36,0x13,0x07,0x00,0x38,0x13,0x04,0x13,0x20,0x13,0x0b,0x13,0x3c,0x13,0x04,0x12, + 0x29,0x12,0x00,0x00,0x01,0x12,0x0b,0x00,0x58,0x12,0x04,0x80,0x36,0x12,0x07,0x00, + 0x38,0x12,0x04,0x12,0x00,0x0a,0x12,0x00,0x58,0x12,0x1c,0x80,0x29,0x12,0x00,0x00, + 0x01,0x0b,0x12,0x00,0x58,0x12,0x05,0x80,0x36,0x12,0x07,0x00,0x38,0x12,0x04,0x12, + 0x01,0x12,0x0a,0x00,0x58,0x12,0x01,0x80,0x58,0x12,0x14,0x80,0x12,0x0d,0x03,0x00, + 0x58,0x12,0x12,0x80,0x29,0x0d,0x00,0x00,0x58,0x12,0x10,0x80,0x07,0x10,0x17,0x00, + 0x58,0x12,0x06,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x04,0x80,0x36,0x12,0x05,0x00, + 0x12,0x14,0x0f,0x00,0x44,0x12,0x02,0x00,0x58,0x12,0x08,0x80,0x0f,0x00,0x01,0x00, + 0x58,0x12,0x06,0x80,0x36,0x12,0x18,0x00,0x2b,0x14,0x01,0x00,0x27,0x15,0x19,0x00, + 0x12,0x16,0x10,0x00,0x26,0x15,0x16,0x15,0x42,0x12,0x03,0x01,0x0f,0x00,0x01,0x00, + 0x58,0x12,0x11,0x80,0x06,0x10,0x0e,0x00,0x58,0x12,0x02,0x80,0x07,0x10,0x10,0x00, + 0x58,0x12,0x0d,0x80,0x12,0x03,0x0d,0x00,0x27,0x06,0x16,0x00,0x3a,0x04,0x01,0x0f, + 0x29,0x09,0x01,0x00,0x36,0x12,0x07,0x00,0x3a,0x13,0x01,0x08,0x3c,0x13,0x04,0x12, + 0x3a,0x12,0x01,0x08,0x0a,0x12,0x00,0x00,0x58,0x12,0x02,0x80,0x2b,0x0c,0x01,0x00, + 0x58,0x12,0x01,0x80,0x2b,0x0c,0x02,0x00,0x0f,0x00,0x0c,0x00,0x58,0x12,0x09,0x80, + 0x55,0x12,0x07,0x80,0x16,0x0d,0x00,0x0d,0x38,0x0e,0x0d,0x00,0x0a,0x0e,0x00,0x00, + 0x58,0x12,0x03,0x80,0x3a,0x12,0x01,0x0e,0x07,0x12,0x15,0x00,0x58,0x12,0xf8,0x7f, + 0x2b,0x0c,0x01,0x00,0x16,0x0d,0x00,0x0d,0x58,0x0e,0x11,0x7f,0x4b,0x00,0x01,0x00, + 0x18,0x63,0x6f,0x6d,0x6d,0x61,0x6e,0x64,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75, + 0x6e,0x64,0x3a,0x20,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x0b,0x72,0x65,0x74,0x75, + 0x72,0x6e,0x09,0x65,0x61,0x63,0x68,0x09,0x6c,0x6f,0x6f,0x70,0x0a,0x62,0x72,0x65, + 0x61,0x6b,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x08,0x66,0x6f,0x72,0x0d,0x67,0x65, + 0x74,0x5f,0x6b,0x65,0x79,0x73,0x0c,0x66,0x6f,0x72,0x70,0x61,0x69,0x72,0x07,0x5f, + 0x5f,0x0c,0x66,0x6f,0x72,0x65,0x61,0x63,0x68,0x08,0x65,0x6e,0x64,0x09,0x65,0x6c, + 0x73,0x65,0x09,0x65,0x6c,0x69,0x66,0x09,0x65,0x76,0x61,0x6c,0x07,0x69,0x66,0x10, + 0x6c,0x61,0x73,0x74,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x09,0x76,0x61,0x72,0x73, + 0x09,0x73,0x6b,0x69,0x70,0x0b,0x75,0x6e,0x70,0x61,0x63,0x6b,0x0b,0x61,0x63,0x74, + 0x69,0x6f,0x6e,0x0b,0x72,0x65,0x6d,0x6f,0x76,0x65,0x0a,0x74,0x61,0x62,0x6c,0x65, + 0x10,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x61,0x72,0x67,0x0b,0x69,0x70,0x61, + 0x69,0x72,0x73,0x02,0xc7,0x04,0x02,0x00,0x0d,0x00,0x0f,0x01,0x7b,0x34,0x00,0x03, + 0x00,0x47,0x01,0x00,0x00,0x3f,0x01,0x00,0x00,0x3a,0x01,0x01,0x00,0x3a,0x02,0x02, + 0x00,0x3a,0x03,0x03,0x00,0x2b,0x04,0x01,0x00,0x2b,0x05,0x01,0x00,0x36,0x06,0x00, + 0x00,0x39,0x06,0x01,0x06,0x12,0x08,0x02,0x00,0x29,0x09,0x01,0x00,0x29,0x0a,0x01, + 0x00,0x42,0x06,0x04,0x02,0x07,0x06,0x02,0x00,0x58,0x06,0x07,0x80,0x2b,0x04,0x02, + 0x00,0x36,0x06,0x00,0x00,0x39,0x06,0x01,0x06,0x12,0x08,0x02,0x00,0x29,0x09,0x02, + 0x00,0x42,0x06,0x03,0x02,0x12,0x02,0x06,0x00,0x0b,0x01,0x00,0x00,0x58,0x06,0x03, + 0x80,0x06,0x02,0x03,0x00,0x58,0x06,0x01,0x80,0x58,0x06,0x3b,0x80,0x07,0x02,0x03, + 0x00,0x58,0x06,0x06,0x80,0x04,0x01,0x03,0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01, + 0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x33,0x80,0x07,0x02,0x04, + 0x00,0x58,0x06,0x06,0x80,0x00,0x03,0x01,0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01, + 0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x2b,0x80,0x07,0x02,0x05, + 0x00,0x58,0x06,0x06,0x80,0x02,0x03,0x01,0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01, + 0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x23,0x80,0x07,0x02,0x06, + 0x00,0x58,0x06,0x06,0x80,0x00,0x01,0x03,0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01, + 0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x1b,0x80,0x07,0x02,0x07, + 0x00,0x58,0x06,0x06,0x80,0x02,0x01,0x03,0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01, + 0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x13,0x80,0x07,0x02,0x08, + 0x00,0x58,0x06,0x0b,0x80,0x36,0x06,0x00,0x00,0x39,0x06,0x08,0x06,0x12,0x08,0x01, + 0x00,0x12,0x09,0x03,0x00,0x42,0x06,0x03,0x02,0x0b,0x06,0x00,0x00,0x58,0x06,0x02, + 0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x06, + 0x80,0x36,0x06,0x09,0x00,0x2b,0x08,0x01,0x00,0x27,0x09,0x0a,0x00,0x12,0x0a,0x02, + 0x00,0x26,0x09,0x0a,0x09,0x42,0x06,0x03,0x01,0x0f,0x00,0x04,0x00,0x58,0x06,0x01, + 0x80,0x13,0x05,0x05,0x00,0x15,0x06,0x00,0x00,0x29,0x07,0x03,0x00,0x01,0x07,0x06, + 0x00,0x58,0x06,0x1c,0x80,0x3a,0x02,0x04,0x00,0x36,0x06,0x0b,0x00,0x36,0x08,0x0c, + 0x00,0x12,0x0a,0x00,0x00,0x29,0x0b,0x05,0x00,0x15,0x0c,0x00,0x00,0x42,0x08,0x04, + 0x00,0x41,0x06,0x00,0x02,0x07,0x02,0x0d,0x00,0x58,0x07,0x05,0x80,0x0d,0x07,0x05, + 0x00,0x58,0x07,0x01,0x80,0x12,0x07,0x06,0x00,0x4c,0x07,0x02,0x00,0x58,0x07,0x0d, + 0x80,0x07,0x02,0x0e,0x00,0x58,0x07,0x05,0x80,0x0c,0x07,0x05,0x00,0x58,0x07,0x01, + 0x80,0x12,0x07,0x06,0x00,0x4c,0x07,0x02,0x00,0x58,0x07,0x06,0x80,0x36,0x07,0x09, + 0x00,0x2b,0x09,0x01,0x00,0x27,0x0a,0x0a,0x00,0x12,0x0b,0x02,0x00,0x26,0x0a,0x0b, + 0x0a,0x42,0x07,0x03,0x01,0x4c,0x05,0x02,0x00,0x07,0x6f,0x72,0x08,0x61,0x6e,0x64, + 0x0b,0x75,0x6e,0x70,0x61,0x63,0x6b,0x09,0x65,0x76,0x61,0x6c,0x19,0x6f,0x70,0x65, + 0x72,0x61,0x74,0x6f,0x72,0x20,0x6e,0x6f,0x74,0x20,0x6b,0x6e,0x6f,0x77,0x6e,0x3a, + 0x20,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x0a,0x6d,0x61,0x74,0x63,0x68,0x07,0x3c, + 0x3d,0x06,0x3c,0x07,0x3e,0x3d,0x06,0x3e,0x06,0x3d,0x06,0x21,0x08,0x73,0x75,0x62, + 0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x03,0x80,0x80,0xc0,0x99,0x04,0xab,0x05,0x00, + 0x02,0x0e,0x00,0x18,0x02,0x73,0x36,0x02,0x00,0x00,0x12,0x04,0x00,0x00,0x42,0x02, + 0x02,0x02,0x06,0x02,0x01,0x00,0x58,0x02,0x04,0x80,0x36,0x02,0x02,0x00,0x12,0x04, + 0x00,0x00,0x42,0x02,0x02,0x02,0x12,0x00,0x02,0x00,0x36,0x02,0x03,0x00,0x36,0x04, + 0x01,0x00,0x39,0x04,0x04,0x04,0x12,0x06,0x00,0x00,0x27,0x07,0x05,0x00,0x42,0x04, + 0x03,0x02,0x0a,0x04,0x00,0x00,0x58,0x04,0x02,0x80,0x2b,0x04,0x01,0x00,0x58,0x05, + 0x01,0x80,0x2b,0x04,0x02,0x00,0x27,0x05,0x06,0x00,0x42,0x02,0x03,0x01,0x36,0x02, + 0x01,0x00,0x39,0x02,0x07,0x02,0x12,0x04,0x00,0x00,0x27,0x05,0x08,0x00,0x27,0x06, + 0x09,0x00,0x42,0x02,0x04,0x03,0x36,0x04,0x03,0x00,0x29,0x06,0x01,0x00,0x02,0x03, + 0x06,0x00,0x58,0x06,0x02,0x80,0x2b,0x06,0x01,0x00,0x58,0x07,0x01,0x80,0x2b,0x06, + 0x02,0x00,0x27,0x07,0x0a,0x00,0x42,0x04,0x03,0x01,0x09,0x03,0x00,0x00,0x58,0x04, + 0x48,0x80,0x2b,0x04,0x00,0x00,0x12,0x07,0x01,0x00,0x39,0x05,0x0b,0x01,0x42,0x05, + 0x02,0x02,0x07,0x05,0x0c,0x00,0x58,0x05,0x02,0x80,0x29,0x04,0x12,0x00,0x58,0x05, + 0x06,0x80,0x36,0x05,0x0d,0x00,0x39,0x05,0x0e,0x05,0x12,0x07,0x01,0x00,0x27,0x08, + 0x0f,0x00,0x42,0x05,0x03,0x02,0x12,0x04,0x05,0x00,0x36,0x05,0x03,0x00,0x29,0x07, + 0x00,0x00,0x03,0x07,0x04,0x00,0x58,0x07,0x03,0x80,0x29,0x07,0x12,0x00,0x02,0x04, + 0x07,0x00,0x58,0x07,0x02,0x80,0x2b,0x07,0x01,0x00,0x58,0x08,0x01,0x80,0x2b,0x07, + 0x02,0x00,0x27,0x08,0x10,0x00,0x42,0x05,0x03,0x01,0x36,0x05,0x01,0x00,0x39,0x05, + 0x04,0x05,0x27,0x07,0x11,0x00,0x12,0x08,0x00,0x00,0x27,0x09,0x11,0x00,0x26,0x07, + 0x09,0x07,0x27,0x08,0x12,0x00,0x42,0x05,0x03,0x03,0x15,0x07,0x06,0x00,0x21,0x07, + 0x07,0x04,0x29,0x08,0x00,0x00,0x01,0x08,0x07,0x00,0x58,0x08,0x08,0x80,0x12,0x08, + 0x06,0x00,0x36,0x09,0x01,0x00,0x39,0x09,0x13,0x09,0x27,0x0b,0x11,0x00,0x12,0x0c, + 0x07,0x00,0x42,0x09,0x03,0x02,0x26,0x06,0x09,0x08,0x58,0x08,0x0a,0x80,0x29,0x08, + 0x00,0x00,0x01,0x07,0x08,0x00,0x58,0x08,0x07,0x80,0x36,0x08,0x01,0x00,0x39,0x08, + 0x14,0x08,0x12,0x0a,0x06,0x00,0x29,0x0b,0x01,0x00,0x12,0x0c,0x04,0x00,0x42,0x08, + 0x04,0x02,0x12,0x06,0x08,0x00,0x12,0x08,0x05,0x00,0x12,0x09,0x06,0x00,0x26,0x00, + 0x09,0x08,0x36,0x08,0x01,0x00,0x39,0x08,0x07,0x08,0x12,0x0a,0x00,0x00,0x27,0x0b, + 0x15,0x00,0x27,0x0c,0x09,0x00,0x29,0x0d,0x01,0x00,0x42,0x08,0x05,0x02,0x12,0x00, + 0x08,0x00,0x15,0x08,0x00,0x00,0x09,0x08,0x01,0x00,0x58,0x08,0x01,0x80,0x27,0x00, + 0x11,0x00,0x36,0x04,0x16,0x00,0x39,0x04,0x17,0x04,0x12,0x06,0x00,0x00,0x44,0x04, 0x02,0x00,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x0b,0x62,0x69,0x67,0x6e,0x75,0x6d, - 0x1c,0x00,0x01,0x04,0x00,0x01,0x00,0x03,0x36,0x01,0x00,0x00,0x12,0x03,0x00,0x00, - 0x44,0x01,0x02,0x00,0x0d,0x74,0x6f,0x6e,0x75,0x6d,0x62,0x65,0x72,0x1c,0x00,0x01, - 0x04,0x00,0x01,0x00,0x03,0x36,0x01,0x00,0x00,0x12,0x03,0x00,0x00,0x44,0x01,0x02, - 0x00,0x0d,0x74,0x6f,0x73,0x74,0x72,0x69,0x6e,0x67,0x23,0x00,0x01,0x04,0x00,0x02, - 0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03,0x00,0x00,0x44,0x01, - 0x02,0x00,0x0b,0x65,0x6e,0x63,0x6f,0x64,0x65,0x09,0x6a,0x73,0x6f,0x6e,0x23,0x00, - 0x01,0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03, - 0x00,0x00,0x44,0x01,0x02,0x00,0x0b,0x64,0x65,0x63,0x6f,0x64,0x65,0x09,0x6a,0x73, - 0x6f,0x6e,0x70,0x02,0x00,0x08,0x00,0x05,0x01,0x0e,0x36,0x00,0x00,0x00,0x36,0x02, - 0x01,0x00,0x47,0x04,0x00,0x00,0x41,0x02,0x00,0x02,0x27,0x03,0x02,0x00,0x36,0x04, - 0x03,0x00,0x39,0x04,0x04,0x04,0x34,0x06,0x03,0x00,0x47,0x07,0x00,0x00,0x3f,0x07, - 0x00,0x00,0x42,0x04,0x02,0x02,0x26,0x03,0x04,0x03,0x42,0x00,0x03,0x01,0x4b,0x00, - 0x01,0x00,0x0b,0x65,0x6e,0x63,0x6f,0x64,0x65,0x09,0x6a,0x73,0x6f,0x6e,0x17,0x61, - 0x73,0x73,0x65,0x72,0x74,0x69,0x6f,0x6e,0x20,0x66,0x61,0x69,0x6c,0x65,0x64,0x3a, - 0x20,0x09,0x65,0x76,0x61,0x6c,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x03,0x80,0x80, - 0xc0,0x99,0x04,0x8e,0x02,0x00,0x01,0x09,0x00,0x08,0x00,0x36,0x36,0x01,0x00,0x00, - 0x12,0x03,0x00,0x00,0x42,0x01,0x02,0x02,0x07,0x01,0x01,0x00,0x58,0x01,0x21,0x80, - 0x15,0x01,0x00,0x00,0x29,0x02,0x03,0x00,0x03,0x02,0x01,0x00,0x58,0x01,0x2c,0x80, - 0x36,0x01,0x01,0x00,0x39,0x01,0x02,0x01,0x12,0x03,0x00,0x00,0x29,0x04,0x01,0x00, - 0x29,0x05,0x01,0x00,0x42,0x01,0x04,0x02,0x07,0x01,0x03,0x00,0x58,0x01,0x24,0x80, - 0x36,0x01,0x01,0x00,0x39,0x01,0x02,0x01,0x12,0x03,0x00,0x00,0x29,0x04,0xff,0xff, - 0x29,0x05,0xff,0xff,0x42,0x01,0x04,0x02,0x07,0x01,0x03,0x00,0x58,0x01,0x1c,0x80, - 0x36,0x01,0x01,0x00,0x39,0x01,0x02,0x01,0x12,0x03,0x00,0x00,0x29,0x04,0x02,0x00, - 0x29,0x05,0xfe,0xff,0x42,0x01,0x04,0x02,0x36,0x02,0x04,0x00,0x38,0x02,0x01,0x02, - 0x0a,0x02,0x00,0x00,0x58,0x02,0x12,0x80,0x36,0x02,0x04,0x00,0x38,0x00,0x01,0x02, - 0x58,0x01,0x0f,0x80,0x36,0x01,0x00,0x00,0x12,0x03,0x00,0x00,0x42,0x01,0x02,0x02, - 0x07,0x01,0x05,0x00,0x58,0x01,0x0a,0x80,0x36,0x01,0x06,0x00,0x12,0x03,0x00,0x00, - 0x42,0x01,0x02,0x04,0x48,0x04,0x04,0x80,0x36,0x06,0x07,0x00,0x12,0x08,0x05,0x00, - 0x42,0x06,0x02,0x02,0x3c,0x06,0x04,0x00,0x46,0x04,0x03,0x03,0x52,0x04,0xfa,0x7f, - 0x4c,0x00,0x02,0x00,0x10,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x61,0x72,0x67, - 0x0a,0x70,0x61,0x69,0x72,0x73,0x0a,0x74,0x61,0x62,0x6c,0x65,0x09,0x76,0x61,0x72, - 0x73,0x06,0x25,0x08,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x09,0x74, - 0x79,0x70,0x65,0xe2,0x06,0x00,0x01,0x15,0x00,0x16,0x01,0xb0,0x01,0x2b,0x01,0x02, - 0x00,0x2b,0x02,0x01,0x00,0x2c,0x03,0x09,0x00,0x29,0x0a,0x01,0x00,0x15,0x0b,0x00, - 0x00,0x03,0x0a,0x0b,0x00,0x58,0x0b,0xa8,0x80,0x55,0x0b,0xa7,0x80,0x38,0x0b,0x0a, - 0x00,0x34,0x0c,0x00,0x00,0x36,0x0d,0x00,0x00,0x12,0x0f,0x0b,0x00,0x42,0x0d,0x02, - 0x04,0x58,0x10,0x08,0x80,0x09,0x10,0x00,0x00,0x58,0x12,0x02,0x80,0x3c,0x11,0x10, - 0x0c,0x58,0x12,0x04,0x80,0x36,0x12,0x01,0x00,0x12,0x14,0x11,0x00,0x42,0x12,0x02, - 0x02,0x3c,0x12,0x10,0x0c,0x45,0x10,0x03,0x03,0x52,0x10,0xf6,0x7f,0x36,0x0d,0x02, - 0x00,0x39,0x0d,0x03,0x0d,0x12,0x0f,0x0c,0x00,0x29,0x10,0x01,0x00,0x42,0x0d,0x03, - 0x02,0x36,0x0e,0x04,0x00,0x38,0x0e,0x0d,0x0e,0x0f,0x00,0x0e,0x00,0x58,0x0f,0x0e, - 0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x0c,0x80,0x12,0x0f,0x0e,0x00,0x36,0x11,0x05, - 0x00,0x12,0x13,0x0c,0x00,0x42,0x11,0x02,0x00,0x41,0x0f,0x00,0x02,0x36,0x10,0x06, - 0x00,0x38,0x10,0x0d,0x10,0x0e,0x00,0x10,0x00,0x58,0x10,0x81,0x80,0x36,0x10,0x07, - 0x00,0x3d,0x0f,0x08,0x10,0x58,0x0f,0x7e,0x80,0x07,0x0d,0x09,0x00,0x58,0x0f,0x08, - 0x80,0x36,0x0f,0x0a,0x00,0x36,0x11,0x05,0x00,0x12,0x13,0x0c,0x00,0x42,0x11,0x02, - 0x00,0x41,0x0f,0x00,0x02,0x12,0x01,0x0f,0x00,0x12,0x02,0x01,0x00,0x58,0x0f,0x74, - 0x80,0x07,0x0d,0x0b,0x00,0x58,0x0f,0x0e,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x02, - 0x80,0x2b,0x01,0x01,0x00,0x58,0x0f,0x6e,0x80,0x0e,0x00,0x02,0x00,0x58,0x0f,0x6c, - 0x80,0x36,0x0f,0x0a,0x00,0x36,0x11,0x05,0x00,0x12,0x13,0x0c,0x00,0x42,0x11,0x02, - 0x00,0x41,0x0f,0x00,0x02,0x12,0x01,0x0f,0x00,0x12,0x02,0x01,0x00,0x58,0x0f,0x64, - 0x80,0x07,0x0d,0x0c,0x00,0x58,0x0f,0x08,0x80,0x0e,0x00,0x01,0x00,0x58,0x0f,0x02, - 0x80,0x13,0x01,0x02,0x00,0x58,0x0f,0x5e,0x80,0x2b,0x01,0x01,0x00,0x58,0x0f,0x01, - 0x80,0x2b,0x01,0x02,0x00,0x58,0x0f,0x5a,0x80,0x07,0x0d,0x0d,0x00,0x58,0x0f,0x02, - 0x80,0x2b,0x01,0x02,0x00,0x58,0x0f,0x56,0x80,0x07,0x0d,0x0e,0x00,0x58,0x0f,0x0b, - 0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x09,0x80,0x12,0x03,0x0a,0x00,0x27,0x05,0x0f, - 0x00,0x3a,0x04,0x01,0x0c,0x3a,0x06,0x02,0x0c,0x29,0x07,0x01,0x00,0x36,0x0f,0x07, - 0x00,0x38,0x10,0x07,0x06,0x3c,0x10,0x04,0x0f,0x58,0x0f,0x49,0x80,0x07,0x0d,0x10, - 0x00,0x58,0x0f,0x0e,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x0c,0x80,0x12,0x03,0x0a, - 0x00,0x27,0x05,0x11,0x00,0x3a,0x04,0x01,0x0c,0x3a,0x08,0x03,0x0c,0x3a,0x0f,0x04, - 0x0c,0x0c,0x09,0x0f,0x00,0x58,0x10,0x01,0x80,0x29,0x09,0x01,0x00,0x36,0x0f,0x07, - 0x00,0x3a,0x10,0x02,0x0c,0x3c,0x10,0x04,0x0f,0x58,0x0f,0x39,0x80,0x07,0x0d,0x12, - 0x00,0x58,0x0f,0x27,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x25,0x80,0x07,0x05,0x0f, - 0x00,0x58,0x0f,0x09,0x80,0x16,0x07,0x00,0x07,0x15,0x0f,0x06,0x00,0x03,0x07,0x0f, - 0x00,0x58,0x0f,0x2f,0x80,0x36,0x0f,0x07,0x00,0x38,0x10,0x07,0x06,0x3c,0x10,0x04, - 0x0f,0x12,0x0a,0x03,0x00,0x58,0x0f,0x2a,0x80,0x07,0x05,0x11,0x00,0x58,0x0f,0x16, - 0x80,0x36,0x0f,0x07,0x00,0x36,0x10,0x07,0x00,0x38,0x10,0x04,0x10,0x20,0x10,0x09, - 0x10,0x3c,0x10,0x04,0x0f,0x29,0x0f,0x00,0x00,0x01,0x0f,0x09,0x00,0x58,0x0f,0x04, - 0x80,0x36,0x0f,0x07,0x00,0x38,0x0f,0x04,0x0f,0x00,0x08,0x0f,0x00,0x58,0x0f,0x1c, - 0x80,0x29,0x0f,0x00,0x00,0x01,0x09,0x0f,0x00,0x58,0x0f,0x05,0x80,0x36,0x0f,0x07, - 0x00,0x38,0x0f,0x04,0x0f,0x01,0x0f,0x08,0x00,0x58,0x0f,0x01,0x80,0x58,0x0f,0x14, - 0x80,0x12,0x0a,0x03,0x00,0x58,0x0f,0x12,0x80,0x29,0x0a,0x00,0x00,0x58,0x0f,0x10, - 0x80,0x07,0x0d,0x13,0x00,0x58,0x0f,0x06,0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x04, - 0x80,0x36,0x0f,0x05,0x00,0x12,0x11,0x0c,0x00,0x44,0x0f,0x02,0x00,0x58,0x0f,0x08, - 0x80,0x0f,0x00,0x01,0x00,0x58,0x0f,0x06,0x80,0x36,0x0f,0x14,0x00,0x2b,0x11,0x01, - 0x00,0x27,0x12,0x15,0x00,0x12,0x13,0x0d,0x00,0x26,0x12,0x13,0x12,0x42,0x0f,0x03, - 0x01,0x16,0x0a,0x00,0x0a,0x58,0x0b,0x55,0x7f,0x4b,0x00,0x01,0x00,0x18,0x63,0x6f, - 0x6d,0x6d,0x61,0x6e,0x64,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x3a, - 0x20,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x0b,0x72,0x65,0x74,0x75,0x72,0x6e,0x09, - 0x6c,0x6f,0x6f,0x70,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x08,0x66,0x6f,0x72,0x09, - 0x65,0x61,0x63,0x68,0x0c,0x66,0x6f,0x72,0x65,0x61,0x63,0x68,0x08,0x65,0x6e,0x64, - 0x09,0x65,0x6c,0x73,0x65,0x09,0x65,0x6c,0x69,0x66,0x09,0x65,0x76,0x61,0x6c,0x07, - 0x69,0x66,0x10,0x6c,0x61,0x73,0x74,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x09,0x76, - 0x61,0x72,0x73,0x09,0x73,0x6b,0x69,0x70,0x0b,0x75,0x6e,0x70,0x61,0x63,0x6b,0x0b, - 0x61,0x63,0x74,0x69,0x6f,0x6e,0x0b,0x72,0x65,0x6d,0x6f,0x76,0x65,0x0a,0x74,0x61, - 0x62,0x6c,0x65,0x10,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x61,0x72,0x67,0x0b, - 0x69,0x70,0x61,0x69,0x72,0x73,0x02,0xc7,0x04,0x02,0x00,0x0d,0x00,0x0f,0x01,0x7b, - 0x34,0x00,0x03,0x00,0x47,0x01,0x00,0x00,0x3f,0x01,0x00,0x00,0x3a,0x01,0x01,0x00, - 0x3a,0x02,0x02,0x00,0x3a,0x03,0x03,0x00,0x2b,0x04,0x01,0x00,0x2b,0x05,0x01,0x00, - 0x36,0x06,0x00,0x00,0x39,0x06,0x01,0x06,0x12,0x08,0x02,0x00,0x29,0x09,0x01,0x00, - 0x29,0x0a,0x01,0x00,0x42,0x06,0x04,0x02,0x07,0x06,0x02,0x00,0x58,0x06,0x07,0x80, - 0x2b,0x04,0x02,0x00,0x36,0x06,0x00,0x00,0x39,0x06,0x01,0x06,0x12,0x08,0x02,0x00, - 0x29,0x09,0x02,0x00,0x42,0x06,0x03,0x02,0x12,0x02,0x06,0x00,0x0b,0x01,0x00,0x00, - 0x58,0x06,0x03,0x80,0x06,0x02,0x03,0x00,0x58,0x06,0x01,0x80,0x58,0x06,0x3b,0x80, - 0x07,0x02,0x03,0x00,0x58,0x06,0x06,0x80,0x04,0x01,0x03,0x00,0x58,0x06,0x02,0x80, - 0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x33,0x80, - 0x07,0x02,0x04,0x00,0x58,0x06,0x06,0x80,0x00,0x03,0x01,0x00,0x58,0x06,0x02,0x80, - 0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x2b,0x80, - 0x07,0x02,0x05,0x00,0x58,0x06,0x06,0x80,0x02,0x03,0x01,0x00,0x58,0x06,0x02,0x80, - 0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x23,0x80, - 0x07,0x02,0x06,0x00,0x58,0x06,0x06,0x80,0x00,0x01,0x03,0x00,0x58,0x06,0x02,0x80, - 0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x1b,0x80, - 0x07,0x02,0x07,0x00,0x58,0x06,0x06,0x80,0x02,0x01,0x03,0x00,0x58,0x06,0x02,0x80, - 0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x13,0x80, - 0x07,0x02,0x08,0x00,0x58,0x06,0x0b,0x80,0x36,0x06,0x00,0x00,0x39,0x06,0x08,0x06, - 0x12,0x08,0x01,0x00,0x12,0x09,0x03,0x00,0x42,0x06,0x03,0x02,0x0b,0x06,0x00,0x00, - 0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00, - 0x58,0x06,0x06,0x80,0x36,0x06,0x09,0x00,0x2b,0x08,0x01,0x00,0x27,0x09,0x0a,0x00, - 0x12,0x0a,0x02,0x00,0x26,0x09,0x0a,0x09,0x42,0x06,0x03,0x01,0x0f,0x00,0x04,0x00, - 0x58,0x06,0x01,0x80,0x13,0x05,0x05,0x00,0x15,0x06,0x00,0x00,0x29,0x07,0x03,0x00, - 0x01,0x07,0x06,0x00,0x58,0x06,0x1c,0x80,0x3a,0x02,0x04,0x00,0x36,0x06,0x0b,0x00, - 0x36,0x08,0x0c,0x00,0x12,0x0a,0x00,0x00,0x29,0x0b,0x05,0x00,0x15,0x0c,0x00,0x00, - 0x42,0x08,0x04,0x00,0x41,0x06,0x00,0x02,0x07,0x02,0x0d,0x00,0x58,0x07,0x05,0x80, - 0x0d,0x07,0x05,0x00,0x58,0x07,0x01,0x80,0x12,0x07,0x06,0x00,0x4c,0x07,0x02,0x00, - 0x58,0x07,0x0d,0x80,0x07,0x02,0x0e,0x00,0x58,0x07,0x05,0x80,0x0c,0x07,0x05,0x00, - 0x58,0x07,0x01,0x80,0x12,0x07,0x06,0x00,0x4c,0x07,0x02,0x00,0x58,0x07,0x06,0x80, - 0x36,0x07,0x09,0x00,0x2b,0x09,0x01,0x00,0x27,0x0a,0x0a,0x00,0x12,0x0b,0x02,0x00, - 0x26,0x0a,0x0b,0x0a,0x42,0x07,0x03,0x01,0x4c,0x05,0x02,0x00,0x07,0x6f,0x72,0x08, - 0x61,0x6e,0x64,0x0b,0x75,0x6e,0x70,0x61,0x63,0x6b,0x09,0x65,0x76,0x61,0x6c,0x19, - 0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x20,0x6e,0x6f,0x74,0x20,0x6b,0x6e,0x6f, - 0x77,0x6e,0x3a,0x20,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x0a,0x6d,0x61,0x74,0x63, - 0x68,0x07,0x3c,0x3d,0x06,0x3c,0x07,0x3e,0x3d,0x06,0x3e,0x06,0x3d,0x06,0x21,0x08, - 0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x03,0x80,0x80,0xc0,0x99,0x04, - 0xab,0x05,0x00,0x02,0x0e,0x00,0x18,0x02,0x73,0x36,0x02,0x00,0x00,0x12,0x04,0x00, - 0x00,0x42,0x02,0x02,0x02,0x06,0x02,0x01,0x00,0x58,0x02,0x04,0x80,0x36,0x02,0x02, - 0x00,0x12,0x04,0x00,0x00,0x42,0x02,0x02,0x02,0x12,0x00,0x02,0x00,0x36,0x02,0x03, - 0x00,0x36,0x04,0x01,0x00,0x39,0x04,0x04,0x04,0x12,0x06,0x00,0x00,0x27,0x07,0x05, - 0x00,0x42,0x04,0x03,0x02,0x0a,0x04,0x00,0x00,0x58,0x04,0x02,0x80,0x2b,0x04,0x01, - 0x00,0x58,0x05,0x01,0x80,0x2b,0x04,0x02,0x00,0x27,0x05,0x06,0x00,0x42,0x02,0x03, - 0x01,0x36,0x02,0x01,0x00,0x39,0x02,0x07,0x02,0x12,0x04,0x00,0x00,0x27,0x05,0x08, - 0x00,0x27,0x06,0x09,0x00,0x42,0x02,0x04,0x03,0x36,0x04,0x03,0x00,0x29,0x06,0x01, - 0x00,0x02,0x03,0x06,0x00,0x58,0x06,0x02,0x80,0x2b,0x06,0x01,0x00,0x58,0x07,0x01, - 0x80,0x2b,0x06,0x02,0x00,0x27,0x07,0x0a,0x00,0x42,0x04,0x03,0x01,0x09,0x03,0x00, - 0x00,0x58,0x04,0x48,0x80,0x2b,0x04,0x00,0x00,0x12,0x07,0x01,0x00,0x39,0x05,0x0b, - 0x01,0x42,0x05,0x02,0x02,0x07,0x05,0x0c,0x00,0x58,0x05,0x02,0x80,0x29,0x04,0x12, - 0x00,0x58,0x05,0x06,0x80,0x36,0x05,0x0d,0x00,0x39,0x05,0x0e,0x05,0x12,0x07,0x01, - 0x00,0x27,0x08,0x0f,0x00,0x42,0x05,0x03,0x02,0x12,0x04,0x05,0x00,0x36,0x05,0x03, - 0x00,0x29,0x07,0x00,0x00,0x03,0x07,0x04,0x00,0x58,0x07,0x03,0x80,0x29,0x07,0x12, - 0x00,0x02,0x04,0x07,0x00,0x58,0x07,0x02,0x80,0x2b,0x07,0x01,0x00,0x58,0x08,0x01, - 0x80,0x2b,0x07,0x02,0x00,0x27,0x08,0x10,0x00,0x42,0x05,0x03,0x01,0x36,0x05,0x01, - 0x00,0x39,0x05,0x04,0x05,0x27,0x07,0x11,0x00,0x12,0x08,0x00,0x00,0x27,0x09,0x11, - 0x00,0x26,0x07,0x09,0x07,0x27,0x08,0x12,0x00,0x42,0x05,0x03,0x03,0x15,0x07,0x06, - 0x00,0x21,0x07,0x07,0x04,0x29,0x08,0x00,0x00,0x01,0x08,0x07,0x00,0x58,0x08,0x08, - 0x80,0x12,0x08,0x06,0x00,0x36,0x09,0x01,0x00,0x39,0x09,0x13,0x09,0x27,0x0b,0x11, - 0x00,0x12,0x0c,0x07,0x00,0x42,0x09,0x03,0x02,0x26,0x06,0x09,0x08,0x58,0x08,0x0a, - 0x80,0x29,0x08,0x00,0x00,0x01,0x07,0x08,0x00,0x58,0x08,0x07,0x80,0x36,0x08,0x01, - 0x00,0x39,0x08,0x14,0x08,0x12,0x0a,0x06,0x00,0x29,0x0b,0x01,0x00,0x12,0x0c,0x04, - 0x00,0x42,0x08,0x04,0x02,0x12,0x06,0x08,0x00,0x12,0x08,0x05,0x00,0x12,0x09,0x06, - 0x00,0x26,0x00,0x09,0x08,0x36,0x08,0x01,0x00,0x39,0x08,0x07,0x08,0x12,0x0a,0x00, - 0x00,0x27,0x0b,0x15,0x00,0x27,0x0c,0x09,0x00,0x29,0x0d,0x01,0x00,0x42,0x08,0x05, - 0x02,0x12,0x00,0x08,0x00,0x15,0x08,0x00,0x00,0x09,0x08,0x01,0x00,0x58,0x08,0x01, - 0x80,0x27,0x00,0x11,0x00,0x36,0x04,0x16,0x00,0x39,0x04,0x17,0x04,0x12,0x06,0x00, - 0x00,0x44,0x04,0x02,0x00,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x0b,0x62,0x69,0x67, - 0x6e,0x75,0x6d,0x07,0x30,0x2a,0x08,0x73,0x75,0x62,0x08,0x72,0x65,0x70,0x11,0x28, - 0x25,0x64,0x2b,0x29,0x25,0x2e,0x28,0x25,0x64,0x2b,0x29,0x06,0x30,0x20,0x74,0x6f, - 0x6b,0x65,0x6e,0x20,0x77,0x69,0x74,0x68,0x20,0x69,0x6e,0x76,0x61,0x6c,0x69,0x64, - 0x20,0x64,0x65,0x63,0x69,0x6d,0x61,0x6c,0x73,0x0d,0x64,0x65,0x63,0x69,0x6d,0x61, - 0x6c,0x73,0x09,0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63,0x74, - 0x0a,0x61,0x65,0x72,0x67,0x6f,0x0a,0x6c,0x6f,0x77,0x65,0x72,0x1a,0x74,0x68,0x65, - 0x20,0x61,0x6d,0x6f,0x75,0x6e,0x74,0x20,0x69,0x73,0x20,0x69,0x6e,0x76,0x61,0x6c, - 0x69,0x64,0x05,0x07,0x25,0x2e,0x09,0x67,0x73,0x75,0x62,0x2a,0x74,0x68,0x65,0x20, - 0x61,0x6d,0x6f,0x75,0x6e,0x74,0x20,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x73,0x20, - 0x69,0x6e,0x76,0x61,0x6c,0x69,0x64,0x20,0x63,0x68,0x61,0x72,0x61,0x63,0x74,0x65, - 0x72,0x0c,0x5b,0x5e,0x30,0x2d,0x39,0x2e,0x5d,0x0a,0x6d,0x61,0x74,0x63,0x68,0x0b, - 0x61,0x73,0x73,0x65,0x72,0x74,0x0d,0x74,0x6f,0x73,0x74,0x72,0x69,0x6e,0x67,0x0b, - 0x73,0x74,0x72,0x69,0x6e,0x67,0x09,0x74,0x79,0x70,0x65,0x02,0x00,0x86,0x05,0x03, - 0x00,0x03,0x00,0x49,0x00,0x4d,0x34,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x35,0x00, - 0x01,0x00,0x37,0x00,0x02,0x00,0x35,0x00,0x04,0x00,0x33,0x01,0x03,0x00,0x3d,0x01, - 0x05,0x00,0x33,0x01,0x06,0x00,0x3d,0x01,0x07,0x00,0x33,0x01,0x08,0x00,0x3d,0x01, - 0x09,0x00,0x33,0x01,0x0a,0x00,0x3d,0x01,0x0b,0x00,0x33,0x01,0x0c,0x00,0x3d,0x01, - 0x0d,0x00,0x33,0x01,0x0e,0x00,0x3d,0x01,0x0f,0x00,0x33,0x01,0x10,0x00,0x3d,0x01, - 0x11,0x00,0x33,0x01,0x12,0x00,0x3d,0x01,0x13,0x00,0x33,0x01,0x14,0x00,0x3d,0x01, - 0x15,0x00,0x33,0x01,0x16,0x00,0x3d,0x01,0x17,0x00,0x33,0x01,0x18,0x00,0x3d,0x01, - 0x19,0x00,0x33,0x01,0x1a,0x00,0x3d,0x01,0x1b,0x00,0x33,0x01,0x1c,0x00,0x3d,0x01, - 0x1d,0x00,0x33,0x01,0x1e,0x00,0x3d,0x01,0x1f,0x00,0x33,0x01,0x20,0x00,0x3d,0x01, - 0x21,0x00,0x33,0x01,0x22,0x00,0x3d,0x01,0x23,0x00,0x33,0x01,0x24,0x00,0x3d,0x01, - 0x25,0x00,0x33,0x01,0x26,0x00,0x3d,0x01,0x27,0x00,0x33,0x01,0x28,0x00,0x3d,0x01, - 0x29,0x00,0x33,0x01,0x2a,0x00,0x3d,0x01,0x2b,0x00,0x33,0x01,0x2c,0x00,0x3d,0x01, - 0x2d,0x00,0x33,0x01,0x2e,0x00,0x3d,0x01,0x2f,0x00,0x33,0x01,0x30,0x00,0x3d,0x01, - 0x31,0x00,0x33,0x01,0x32,0x00,0x3d,0x01,0x33,0x00,0x33,0x01,0x34,0x00,0x3d,0x01, - 0x35,0x00,0x33,0x01,0x36,0x00,0x3d,0x01,0x37,0x00,0x33,0x01,0x38,0x00,0x3d,0x01, - 0x39,0x00,0x33,0x01,0x3a,0x00,0x3d,0x01,0x3b,0x00,0x33,0x01,0x3c,0x00,0x3d,0x01, - 0x3d,0x00,0x37,0x00,0x3e,0x00,0x33,0x00,0x3f,0x00,0x37,0x00,0x40,0x00,0x33,0x00, - 0x41,0x00,0x37,0x00,0x42,0x00,0x33,0x00,0x43,0x00,0x37,0x00,0x44,0x00,0x33,0x00, - 0x45,0x00,0x37,0x00,0x46,0x00,0x36,0x00,0x47,0x00,0x39,0x00,0x48,0x00,0x36,0x02, - 0x42,0x00,0x42,0x00,0x02,0x01,0x4b,0x00,0x01,0x00,0x0d,0x72,0x65,0x67,0x69,0x73, - 0x74,0x65,0x72,0x08,0x61,0x62,0x69,0x13,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f, - 0x62,0x69,0x67,0x6e,0x75,0x6d,0x00,0x09,0x65,0x76,0x61,0x6c,0x00,0x0c,0x65,0x78, - 0x65,0x63,0x75,0x74,0x65,0x00,0x10,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x61, - 0x72,0x67,0x00,0x0b,0x61,0x63,0x74,0x69,0x6f,0x6e,0x0b,0x61,0x73,0x73,0x65,0x72, - 0x74,0x00,0x0d,0x66,0x72,0x6f,0x6d,0x6a,0x73,0x6f,0x6e,0x00,0x0b,0x74,0x6f,0x6a, - 0x73,0x6f,0x6e,0x00,0x0d,0x74,0x6f,0x73,0x74,0x72,0x69,0x6e,0x67,0x00,0x0d,0x74, - 0x6f,0x6e,0x75,0x6d,0x62,0x65,0x72,0x00,0x0d,0x74,0x6f,0x62,0x69,0x67,0x6e,0x75, - 0x6d,0x00,0x0c,0x72,0x65,0x70,0x6c,0x61,0x63,0x65,0x00,0x09,0x66,0x69,0x6e,0x64, - 0x00,0x0b,0x73,0x75,0x62,0x73,0x74,0x72,0x00,0x0b,0x66,0x6f,0x72,0x6d,0x61,0x74, - 0x00,0x09,0x73,0x71,0x72,0x74,0x00,0x08,0x6d,0x6f,0x64,0x00,0x08,0x70,0x6f,0x77, - 0x00,0x08,0x64,0x69,0x76,0x00,0x08,0x6d,0x75,0x6c,0x00,0x08,0x73,0x75,0x62,0x00, - 0x08,0x61,0x64,0x64,0x00,0x0b,0x72,0x65,0x6d,0x6f,0x76,0x65,0x00,0x0b,0x69,0x6e, - 0x73,0x65,0x72,0x74,0x00,0x08,0x73,0x65,0x74,0x00,0x08,0x67,0x65,0x74,0x00,0x0a, - 0x73,0x74,0x6f,0x72,0x65,0x00,0x08,0x6c,0x65,0x74,0x00,0x09,0x73,0x65,0x6e,0x64, - 0x00,0x0c,0x62,0x61,0x6c,0x61,0x6e,0x63,0x65,0x00,0x0f,0x70,0x63,0x61,0x6c,0x6c, - 0x2d,0x73,0x65,0x6e,0x64,0x00,0x0a,0x70,0x63,0x61,0x6c,0x6c,0x00,0x0e,0x63,0x61, - 0x6c,0x6c,0x2d,0x73,0x65,0x6e,0x64,0x00,0x09,0x63,0x61,0x6c,0x6c,0x01,0x00,0x00, - 0x00,0x09,0x73,0x6b,0x69,0x70,0x01,0x00,0x06,0x0b,0x69,0x6e,0x73,0x65,0x72,0x74, - 0x02,0x08,0x6c,0x65,0x74,0x02,0x0a,0x73,0x74,0x6f,0x72,0x65,0x02,0x09,0x73,0x65, - 0x6e,0x64,0x02,0x08,0x73,0x65,0x74,0x02,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x02, - 0x09,0x76,0x61,0x72,0x73,0x00,0x7b,0x22,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x22, - 0x3a,0x22,0x30,0x2e,0x32,0x22,0x2c,0x22,0x6c,0x61,0x6e,0x67,0x75,0x61,0x67,0x65, - 0x22,0x3a,0x22,0x6c,0x75,0x61,0x22,0x2c,0x22,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f, - 0x6e,0x73,0x22,0x3a,0x5b,0x7b,0x22,0x6e,0x61,0x6d,0x65,0x22,0x3a,0x22,0x65,0x78, - 0x65,0x63,0x75,0x74,0x65,0x22,0x2c,0x22,0x61,0x72,0x67,0x75,0x6d,0x65,0x6e,0x74, - 0x73,0x22,0x3a,0x5b,0x7b,0x22,0x6e,0x61,0x6d,0x65,0x22,0x3a,0x22,0x63,0x61,0x6c, - 0x6c,0x73,0x22,0x7d,0x5d,0x7d,0x5d,0x7d, + 0x07,0x30,0x2a,0x08,0x73,0x75,0x62,0x08,0x72,0x65,0x70,0x11,0x28,0x25,0x64,0x2b, + 0x29,0x25,0x2e,0x28,0x25,0x64,0x2b,0x29,0x06,0x30,0x20,0x74,0x6f,0x6b,0x65,0x6e, + 0x20,0x77,0x69,0x74,0x68,0x20,0x69,0x6e,0x76,0x61,0x6c,0x69,0x64,0x20,0x64,0x65, + 0x63,0x69,0x6d,0x61,0x6c,0x73,0x0d,0x64,0x65,0x63,0x69,0x6d,0x61,0x6c,0x73,0x09, + 0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63,0x74,0x0a,0x61,0x65, + 0x72,0x67,0x6f,0x0a,0x6c,0x6f,0x77,0x65,0x72,0x1a,0x74,0x68,0x65,0x20,0x61,0x6d, + 0x6f,0x75,0x6e,0x74,0x20,0x69,0x73,0x20,0x69,0x6e,0x76,0x61,0x6c,0x69,0x64,0x05, + 0x07,0x25,0x2e,0x09,0x67,0x73,0x75,0x62,0x2a,0x74,0x68,0x65,0x20,0x61,0x6d,0x6f, + 0x75,0x6e,0x74,0x20,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x73,0x20,0x69,0x6e,0x76, + 0x61,0x6c,0x69,0x64,0x20,0x63,0x68,0x61,0x72,0x61,0x63,0x74,0x65,0x72,0x0c,0x5b, + 0x5e,0x30,0x2d,0x39,0x2e,0x5d,0x0a,0x6d,0x61,0x74,0x63,0x68,0x0b,0x61,0x73,0x73, + 0x65,0x72,0x74,0x0d,0x74,0x6f,0x73,0x74,0x72,0x69,0x6e,0x67,0x0b,0x73,0x74,0x72, + 0x69,0x6e,0x67,0x09,0x74,0x79,0x70,0x65,0x02,0x00,0xba,0x05,0x03,0x00,0x03,0x00, + 0x4f,0x00,0x53,0x34,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x35,0x00,0x01,0x00,0x37, + 0x00,0x02,0x00,0x35,0x00,0x04,0x00,0x33,0x01,0x03,0x00,0x3d,0x01,0x05,0x00,0x33, + 0x01,0x06,0x00,0x3d,0x01,0x07,0x00,0x33,0x01,0x08,0x00,0x3d,0x01,0x09,0x00,0x33, + 0x01,0x0a,0x00,0x3d,0x01,0x0b,0x00,0x33,0x01,0x0c,0x00,0x3d,0x01,0x0d,0x00,0x33, + 0x01,0x0e,0x00,0x3d,0x01,0x0f,0x00,0x33,0x01,0x10,0x00,0x3d,0x01,0x11,0x00,0x33, + 0x01,0x12,0x00,0x3d,0x01,0x13,0x00,0x33,0x01,0x14,0x00,0x3d,0x01,0x15,0x00,0x33, + 0x01,0x16,0x00,0x3d,0x01,0x17,0x00,0x33,0x01,0x18,0x00,0x3d,0x01,0x19,0x00,0x33, + 0x01,0x1a,0x00,0x3d,0x01,0x1b,0x00,0x33,0x01,0x1c,0x00,0x3d,0x01,0x1d,0x00,0x33, + 0x01,0x1e,0x00,0x3d,0x01,0x1f,0x00,0x33,0x01,0x20,0x00,0x3d,0x01,0x21,0x00,0x33, + 0x01,0x22,0x00,0x3d,0x01,0x23,0x00,0x33,0x01,0x24,0x00,0x3d,0x01,0x25,0x00,0x33, + 0x01,0x26,0x00,0x3d,0x01,0x27,0x00,0x33,0x01,0x28,0x00,0x3d,0x01,0x29,0x00,0x33, + 0x01,0x2a,0x00,0x3d,0x01,0x2b,0x00,0x33,0x01,0x2c,0x00,0x3d,0x01,0x2d,0x00,0x33, + 0x01,0x2e,0x00,0x3d,0x01,0x2f,0x00,0x33,0x01,0x30,0x00,0x3d,0x01,0x31,0x00,0x33, + 0x01,0x32,0x00,0x3d,0x01,0x33,0x00,0x33,0x01,0x34,0x00,0x3d,0x01,0x35,0x00,0x33, + 0x01,0x36,0x00,0x3d,0x01,0x37,0x00,0x33,0x01,0x38,0x00,0x3d,0x01,0x39,0x00,0x33, + 0x01,0x3a,0x00,0x3d,0x01,0x3b,0x00,0x33,0x01,0x3c,0x00,0x3d,0x01,0x3d,0x00,0x33, + 0x01,0x3e,0x00,0x3d,0x01,0x3f,0x00,0x33,0x01,0x40,0x00,0x3d,0x01,0x41,0x00,0x33, + 0x01,0x42,0x00,0x3d,0x01,0x43,0x00,0x37,0x00,0x44,0x00,0x33,0x00,0x45,0x00,0x37, + 0x00,0x46,0x00,0x33,0x00,0x47,0x00,0x37,0x00,0x48,0x00,0x33,0x00,0x49,0x00,0x37, + 0x00,0x4a,0x00,0x33,0x00,0x4b,0x00,0x37,0x00,0x4c,0x00,0x36,0x00,0x4d,0x00,0x39, + 0x00,0x4e,0x00,0x36,0x02,0x48,0x00,0x42,0x00,0x02,0x01,0x4b,0x00,0x01,0x00,0x0d, + 0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x08,0x61,0x62,0x69,0x13,0x63,0x6f,0x6e, + 0x76,0x65,0x72,0x74,0x5f,0x62,0x69,0x67,0x6e,0x75,0x6d,0x00,0x09,0x65,0x76,0x61, + 0x6c,0x00,0x0c,0x65,0x78,0x65,0x63,0x75,0x74,0x65,0x00,0x10,0x70,0x72,0x6f,0x63, + 0x65,0x73,0x73,0x5f,0x61,0x72,0x67,0x00,0x0b,0x61,0x63,0x74,0x69,0x6f,0x6e,0x0b, + 0x61,0x73,0x73,0x65,0x72,0x74,0x00,0x0d,0x66,0x72,0x6f,0x6d,0x6a,0x73,0x6f,0x6e, + 0x00,0x0b,0x74,0x6f,0x6a,0x73,0x6f,0x6e,0x00,0x0d,0x74,0x6f,0x73,0x74,0x72,0x69, + 0x6e,0x67,0x00,0x0d,0x74,0x6f,0x6e,0x75,0x6d,0x62,0x65,0x72,0x00,0x0d,0x74,0x6f, + 0x62,0x69,0x67,0x6e,0x75,0x6d,0x00,0x0c,0x72,0x65,0x70,0x6c,0x61,0x63,0x65,0x00, + 0x09,0x66,0x69,0x6e,0x64,0x00,0x0b,0x73,0x75,0x62,0x73,0x74,0x72,0x00,0x0b,0x66, + 0x6f,0x72,0x6d,0x61,0x74,0x00,0x0b,0x63,0x6f,0x6e,0x63,0x61,0x74,0x00,0x09,0x73, + 0x71,0x72,0x74,0x00,0x08,0x6d,0x6f,0x64,0x00,0x08,0x70,0x6f,0x77,0x00,0x08,0x64, + 0x69,0x76,0x00,0x08,0x6d,0x75,0x6c,0x00,0x08,0x73,0x75,0x62,0x00,0x08,0x61,0x64, + 0x64,0x00,0x0d,0x67,0x65,0x74,0x5f,0x6b,0x65,0x79,0x73,0x00,0x0d,0x67,0x65,0x74, + 0x5f,0x73,0x69,0x7a,0x65,0x00,0x0b,0x72,0x65,0x6d,0x6f,0x76,0x65,0x00,0x0b,0x69, + 0x6e,0x73,0x65,0x72,0x74,0x00,0x08,0x73,0x65,0x74,0x00,0x08,0x67,0x65,0x74,0x00, + 0x0a,0x73,0x74,0x6f,0x72,0x65,0x00,0x08,0x6c,0x65,0x74,0x00,0x09,0x73,0x65,0x6e, + 0x64,0x00,0x0c,0x62,0x61,0x6c,0x61,0x6e,0x63,0x65,0x00,0x0f,0x70,0x63,0x61,0x6c, + 0x6c,0x2d,0x73,0x65,0x6e,0x64,0x00,0x0a,0x70,0x63,0x61,0x6c,0x6c,0x00,0x0e,0x63, + 0x61,0x6c,0x6c,0x2d,0x73,0x65,0x6e,0x64,0x00,0x09,0x63,0x61,0x6c,0x6c,0x01,0x00, + 0x00,0x00,0x09,0x73,0x6b,0x69,0x70,0x01,0x00,0x06,0x0b,0x69,0x6e,0x73,0x65,0x72, + 0x74,0x02,0x08,0x6c,0x65,0x74,0x02,0x0a,0x73,0x74,0x6f,0x72,0x65,0x02,0x09,0x73, + 0x65,0x6e,0x64,0x02,0x08,0x73,0x65,0x74,0x02,0x0b,0x61,0x73,0x73,0x65,0x72,0x74, + 0x02,0x09,0x76,0x61,0x72,0x73,0x00,0x7b,0x22,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e, + 0x22,0x3a,0x22,0x30,0x2e,0x32,0x22,0x2c,0x22,0x6c,0x61,0x6e,0x67,0x75,0x61,0x67, + 0x65,0x22,0x3a,0x22,0x6c,0x75,0x61,0x22,0x2c,0x22,0x66,0x75,0x6e,0x63,0x74,0x69, + 0x6f,0x6e,0x73,0x22,0x3a,0x5b,0x7b,0x22,0x6e,0x61,0x6d,0x65,0x22,0x3a,0x22,0x65, + 0x78,0x65,0x63,0x75,0x74,0x65,0x22,0x2c,0x22,0x61,0x72,0x67,0x75,0x6d,0x65,0x6e, + 0x74,0x73,0x22,0x3a,0x5b,0x7b,0x22,0x6e,0x61,0x6d,0x65,0x22,0x3a,0x22,0x63,0x61, + 0x6c,0x6c,0x73,0x22,0x7d,0x5d,0x7d,0x5d,0x7d } diff --git a/contract/vm_multicall.lua b/contract/vm_multicall.lua index 6997917ef..dc7f25991 100644 --- a/contract/vm_multicall.lua +++ b/contract/vm_multicall.lua @@ -15,7 +15,7 @@ action = { ["pcall-send"] = function (amount,...) return {pcall(contract.call.value(amount),...)} end, -- aergo balance and transfer - balance = function (address) return contract.balance(address) end, + balance = function (address) return bignum.number(contract.balance(address)) end, send = function (address,amount) return contract.send(address, amount) end, -- variables @@ -26,7 +26,16 @@ action = { get = function (o,k) return o[k] end, set = function (o,k,v) o[k] = v end, insert = function (...) table.insert(...) end, -- inserts at the end if no pos informed - remove = function (...) table.remove(...) end, -- returns the removed item + remove = function (...) return table.remove(...) end, -- returns the removed item + get_size = function (x) return #x end, + get_keys = function (obj) + local list = {} + for key,_ in pairs(obj) do + list[#list + 1] = key + end + table.sort(list) -- for a deterministic output + return list + end, -- math add = function (x,y) return x+y end, @@ -38,6 +47,7 @@ action = { sqrt = function (x) return bignum.sqrt(x) end, -- use pow(0.5) for numbers -- strings + concat = function (...) return table.concat({...}) end, format = function (...) return string.format(...) end, -- for concat: ['format','%s%s','%val1%','%val2%'] substr = function (...) return string.sub(...) end, find = function (...) return string.match(...) end, @@ -75,9 +85,10 @@ function execute(calls) local if_done = false local for_cmdpos - local for_var, for_type - local for_list, for_pos + local for_var, for_var2, for_type + local for_obj, for_list, for_pos local for_last, for_increment + local skip_for = false local cmdpos = 1 while cmdpos <= #calls do @@ -118,14 +129,16 @@ function execute(calls) elseif cmd == "end" then if_on = true - -- for foreach loop + -- for foreach forpair break loop elseif cmd == "foreach" and if_on then - for_cmdpos = cmdpos - for_type = "each" - for_var = args[1] + for_var2 = "__" + for_obj = {} for_list = args[2] - for_pos = 1 - vars[for_var] = for_list[for_pos] + elseif cmd == "forpair" and if_on then + for_var2 = args[2] + for_obj = args[3] + for_list = action["get_keys"](for_obj) + vars[for_var2] = for_obj[for_list[1]] elseif cmd == "for" and if_on then for_cmdpos = cmdpos for_type = "number" @@ -133,11 +146,15 @@ function execute(calls) for_last = args[3] for_increment = args[4] or 1 vars[for_var] = args[2] + skip_for = ((for_increment > 0 and vars[for_var] > for_last) or (for_increment < 0 and vars[for_var] < for_last)) + elseif cmd == "break" and if_on then + skip_for = true elseif cmd == "loop" and if_on then if for_type == "each" then for_pos = for_pos + 1 if for_pos <= #for_list then vars[for_var] = for_list[for_pos] + vars[for_var2] = for_obj[for_list[for_pos]] cmdpos = for_cmdpos end elseif for_type == "number" then @@ -158,6 +175,23 @@ function execute(calls) assert(false, "command not found: " .. cmd) end + if if_on and (cmd == "foreach" or cmd == "forpair") then + for_cmdpos = cmdpos + for_type = "each" + for_var = args[1] + for_pos = 1 + vars[for_var] = for_list[1] + skip_for = (for_list[1] == nil) -- if the list is empty or it is a dictionary + end + + if skip_for then + repeat + cmdpos = cmdpos + 1 + call = calls[cmdpos] + until call == nil or call[1] == "loop" + skip_for = false + end + cmdpos = cmdpos + 1 end From 5c1def2e95c05ea9be0ed9be900f86d76bc8c354 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 27 Jul 2022 03:28:41 -0300 Subject: [PATCH 009/182] [contract] add 'break if' to composable transactions --- contract/vm_multicall.go | 366 +++++++++++++++++++------------------- contract/vm_multicall.lua | 6 +- 2 files changed, 190 insertions(+), 182 deletions(-) diff --git a/contract/vm_multicall.go b/contract/vm_multicall.go index fe9864826..5ea72b586 100644 --- a/contract/vm_multicall.go +++ b/contract/vm_multicall.go @@ -1,7 +1,7 @@ package contract var multicall_payload = []byte { - 0x62,0x12,0x00,0x00,0x1b,0x4c,0x4a,0x02,0x0a,0x25,0x02,0x00,0x03,0x00,0x02, + 0x9a,0x12,0x00,0x00,0x1b,0x4c,0x4a,0x02,0x0a,0x25,0x02,0x00,0x03,0x00,0x02, 0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00, 0x00,0x00,0x09,0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63,0x74, 0x37,0x02,0x01,0x04,0x00,0x03,0x00,0x07,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01, @@ -99,9 +99,9 @@ var multicall_payload = []byte { 0x00,0x02,0x00,0x10,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x61,0x72,0x67,0x0a, 0x70,0x61,0x69,0x72,0x73,0x0a,0x74,0x61,0x62,0x6c,0x65,0x09,0x76,0x61,0x72,0x73, 0x06,0x25,0x08,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x09,0x74,0x79, - 0x70,0x65,0x90,0x09,0x00,0x01,0x18,0x00,0x1a,0x01,0xf5,0x01,0x2b,0x01,0x02,0x00, + 0x70,0x65,0xc8,0x09,0x00,0x01,0x18,0x00,0x1a,0x01,0x83,0x02,0x2b,0x01,0x02,0x00, 0x2b,0x02,0x01,0x00,0x2c,0x03,0x0b,0x00,0x2b,0x0c,0x01,0x00,0x29,0x0d,0x01,0x00, - 0x15,0x0e,0x00,0x00,0x03,0x0d,0x0e,0x00,0x58,0x0e,0xec,0x80,0x55,0x0e,0xeb,0x80, + 0x15,0x0e,0x00,0x00,0x03,0x0d,0x0e,0x00,0x58,0x0e,0xfa,0x80,0x55,0x0e,0xf9,0x80, 0x38,0x0e,0x0d,0x00,0x34,0x0f,0x00,0x00,0x36,0x10,0x00,0x00,0x12,0x12,0x0e,0x00, 0x42,0x10,0x02,0x04,0x58,0x13,0x08,0x80,0x09,0x13,0x00,0x00,0x58,0x15,0x02,0x80, 0x3c,0x14,0x13,0x0f,0x58,0x15,0x04,0x80,0x36,0x15,0x01,0x00,0x12,0x17,0x14,0x00, @@ -110,24 +110,24 @@ var multicall_payload = []byte { 0x42,0x10,0x03,0x02,0x36,0x11,0x04,0x00,0x38,0x11,0x10,0x11,0x0f,0x00,0x11,0x00, 0x58,0x12,0x0e,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x0c,0x80,0x12,0x12,0x11,0x00, 0x36,0x14,0x05,0x00,0x12,0x16,0x0f,0x00,0x42,0x14,0x02,0x00,0x41,0x12,0x00,0x02, - 0x36,0x13,0x06,0x00,0x38,0x13,0x10,0x13,0x0e,0x00,0x13,0x00,0x58,0x13,0xa7,0x80, - 0x36,0x13,0x07,0x00,0x3d,0x12,0x08,0x13,0x58,0x12,0xa4,0x80,0x07,0x10,0x09,0x00, + 0x36,0x13,0x06,0x00,0x38,0x13,0x10,0x13,0x0e,0x00,0x13,0x00,0x58,0x13,0xb5,0x80, + 0x36,0x13,0x07,0x00,0x3d,0x12,0x08,0x13,0x58,0x12,0xb2,0x80,0x07,0x10,0x09,0x00, 0x58,0x12,0x08,0x80,0x36,0x12,0x0a,0x00,0x36,0x14,0x05,0x00,0x12,0x16,0x0f,0x00, 0x42,0x14,0x02,0x00,0x41,0x12,0x00,0x02,0x12,0x01,0x12,0x00,0x12,0x02,0x01,0x00, - 0x58,0x12,0x9a,0x80,0x07,0x10,0x0b,0x00,0x58,0x12,0x0e,0x80,0x0f,0x00,0x01,0x00, - 0x58,0x12,0x02,0x80,0x2b,0x01,0x01,0x00,0x58,0x12,0x94,0x80,0x0e,0x00,0x02,0x00, - 0x58,0x12,0x92,0x80,0x36,0x12,0x0a,0x00,0x36,0x14,0x05,0x00,0x12,0x16,0x0f,0x00, + 0x58,0x12,0xa8,0x80,0x07,0x10,0x0b,0x00,0x58,0x12,0x0e,0x80,0x0f,0x00,0x01,0x00, + 0x58,0x12,0x02,0x80,0x2b,0x01,0x01,0x00,0x58,0x12,0xa2,0x80,0x0e,0x00,0x02,0x00, + 0x58,0x12,0xa0,0x80,0x36,0x12,0x0a,0x00,0x36,0x14,0x05,0x00,0x12,0x16,0x0f,0x00, 0x42,0x14,0x02,0x00,0x41,0x12,0x00,0x02,0x12,0x01,0x12,0x00,0x12,0x02,0x01,0x00, - 0x58,0x12,0x8a,0x80,0x07,0x10,0x0c,0x00,0x58,0x12,0x08,0x80,0x0e,0x00,0x01,0x00, - 0x58,0x12,0x02,0x80,0x13,0x01,0x02,0x00,0x58,0x12,0x84,0x80,0x2b,0x01,0x01,0x00, - 0x58,0x12,0x01,0x80,0x2b,0x01,0x02,0x00,0x58,0x12,0x80,0x80,0x07,0x10,0x0d,0x00, - 0x58,0x12,0x02,0x80,0x2b,0x01,0x02,0x00,0x58,0x12,0x7c,0x80,0x07,0x10,0x0e,0x00, + 0x58,0x12,0x98,0x80,0x07,0x10,0x0c,0x00,0x58,0x12,0x08,0x80,0x0e,0x00,0x01,0x00, + 0x58,0x12,0x02,0x80,0x13,0x01,0x02,0x00,0x58,0x12,0x92,0x80,0x2b,0x01,0x01,0x00, + 0x58,0x12,0x01,0x80,0x2b,0x01,0x02,0x00,0x58,0x12,0x8e,0x80,0x07,0x10,0x0d,0x00, + 0x58,0x12,0x02,0x80,0x2b,0x01,0x02,0x00,0x58,0x12,0x8a,0x80,0x07,0x10,0x0e,0x00, 0x58,0x12,0x06,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x04,0x80,0x27,0x05,0x0f,0x00, - 0x34,0x07,0x00,0x00,0x3a,0x08,0x02,0x0f,0x58,0x12,0x74,0x80,0x07,0x10,0x10,0x00, + 0x34,0x07,0x00,0x00,0x3a,0x08,0x02,0x0f,0x58,0x12,0x82,0x80,0x07,0x10,0x10,0x00, 0x58,0x12,0x0e,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x0c,0x80,0x3a,0x05,0x02,0x0f, 0x3a,0x07,0x03,0x0f,0x36,0x12,0x04,0x00,0x39,0x12,0x11,0x12,0x12,0x14,0x07,0x00, 0x42,0x12,0x02,0x02,0x12,0x08,0x12,0x00,0x36,0x12,0x07,0x00,0x3a,0x13,0x01,0x08, - 0x38,0x13,0x13,0x07,0x3c,0x13,0x05,0x12,0x58,0x12,0x64,0x80,0x07,0x10,0x12,0x00, + 0x38,0x13,0x13,0x07,0x3c,0x13,0x05,0x12,0x58,0x12,0x72,0x80,0x07,0x10,0x12,0x00, 0x58,0x12,0x1f,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x1d,0x80,0x12,0x03,0x0d,0x00, 0x27,0x06,0x13,0x00,0x3a,0x04,0x01,0x0f,0x3a,0x0a,0x03,0x0f,0x3a,0x12,0x04,0x0f, 0x0c,0x0b,0x12,0x00,0x58,0x13,0x01,0x80,0x29,0x0b,0x01,0x00,0x36,0x12,0x07,0x00, @@ -135,171 +135,175 @@ var multicall_payload = []byte { 0x58,0x12,0x04,0x80,0x36,0x12,0x07,0x00,0x38,0x12,0x04,0x12,0x00,0x0a,0x12,0x00, 0x58,0x12,0x09,0x80,0x29,0x12,0x00,0x00,0x01,0x0b,0x12,0x00,0x58,0x12,0x04,0x80, 0x36,0x12,0x07,0x00,0x38,0x12,0x04,0x12,0x00,0x12,0x0a,0x00,0x58,0x12,0x02,0x80, - 0x2b,0x0c,0x01,0x00,0x58,0x12,0x01,0x80,0x2b,0x0c,0x02,0x00,0x58,0x12,0x43,0x80, - 0x07,0x10,0x14,0x00,0x58,0x12,0x04,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x02,0x80, - 0x2b,0x0c,0x02,0x00,0x58,0x12,0x3d,0x80,0x07,0x10,0x15,0x00,0x58,0x12,0x2b,0x80, - 0x0f,0x00,0x01,0x00,0x58,0x12,0x29,0x80,0x07,0x06,0x16,0x00,0x58,0x12,0x0d,0x80, - 0x16,0x09,0x00,0x09,0x15,0x12,0x08,0x00,0x03,0x09,0x12,0x00,0x58,0x12,0x33,0x80, - 0x36,0x12,0x07,0x00,0x38,0x13,0x09,0x08,0x3c,0x13,0x04,0x12,0x36,0x12,0x07,0x00, - 0x38,0x13,0x09,0x08,0x38,0x13,0x13,0x07,0x3c,0x13,0x05,0x12,0x12,0x0d,0x03,0x00, - 0x58,0x12,0x2a,0x80,0x07,0x06,0x13,0x00,0x58,0x12,0x16,0x80,0x36,0x12,0x07,0x00, - 0x36,0x13,0x07,0x00,0x38,0x13,0x04,0x13,0x20,0x13,0x0b,0x13,0x3c,0x13,0x04,0x12, - 0x29,0x12,0x00,0x00,0x01,0x12,0x0b,0x00,0x58,0x12,0x04,0x80,0x36,0x12,0x07,0x00, - 0x38,0x12,0x04,0x12,0x00,0x0a,0x12,0x00,0x58,0x12,0x1c,0x80,0x29,0x12,0x00,0x00, - 0x01,0x0b,0x12,0x00,0x58,0x12,0x05,0x80,0x36,0x12,0x07,0x00,0x38,0x12,0x04,0x12, - 0x01,0x12,0x0a,0x00,0x58,0x12,0x01,0x80,0x58,0x12,0x14,0x80,0x12,0x0d,0x03,0x00, - 0x58,0x12,0x12,0x80,0x29,0x0d,0x00,0x00,0x58,0x12,0x10,0x80,0x07,0x10,0x17,0x00, - 0x58,0x12,0x06,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x04,0x80,0x36,0x12,0x05,0x00, - 0x12,0x14,0x0f,0x00,0x44,0x12,0x02,0x00,0x58,0x12,0x08,0x80,0x0f,0x00,0x01,0x00, - 0x58,0x12,0x06,0x80,0x36,0x12,0x18,0x00,0x2b,0x14,0x01,0x00,0x27,0x15,0x19,0x00, - 0x12,0x16,0x10,0x00,0x26,0x15,0x16,0x15,0x42,0x12,0x03,0x01,0x0f,0x00,0x01,0x00, - 0x58,0x12,0x11,0x80,0x06,0x10,0x0e,0x00,0x58,0x12,0x02,0x80,0x07,0x10,0x10,0x00, - 0x58,0x12,0x0d,0x80,0x12,0x03,0x0d,0x00,0x27,0x06,0x16,0x00,0x3a,0x04,0x01,0x0f, - 0x29,0x09,0x01,0x00,0x36,0x12,0x07,0x00,0x3a,0x13,0x01,0x08,0x3c,0x13,0x04,0x12, - 0x3a,0x12,0x01,0x08,0x0a,0x12,0x00,0x00,0x58,0x12,0x02,0x80,0x2b,0x0c,0x01,0x00, - 0x58,0x12,0x01,0x80,0x2b,0x0c,0x02,0x00,0x0f,0x00,0x0c,0x00,0x58,0x12,0x09,0x80, - 0x55,0x12,0x07,0x80,0x16,0x0d,0x00,0x0d,0x38,0x0e,0x0d,0x00,0x0a,0x0e,0x00,0x00, - 0x58,0x12,0x03,0x80,0x3a,0x12,0x01,0x0e,0x07,0x12,0x15,0x00,0x58,0x12,0xf8,0x7f, - 0x2b,0x0c,0x01,0x00,0x16,0x0d,0x00,0x0d,0x58,0x0e,0x11,0x7f,0x4b,0x00,0x01,0x00, - 0x18,0x63,0x6f,0x6d,0x6d,0x61,0x6e,0x64,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75, - 0x6e,0x64,0x3a,0x20,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x0b,0x72,0x65,0x74,0x75, - 0x72,0x6e,0x09,0x65,0x61,0x63,0x68,0x09,0x6c,0x6f,0x6f,0x70,0x0a,0x62,0x72,0x65, - 0x61,0x6b,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x08,0x66,0x6f,0x72,0x0d,0x67,0x65, - 0x74,0x5f,0x6b,0x65,0x79,0x73,0x0c,0x66,0x6f,0x72,0x70,0x61,0x69,0x72,0x07,0x5f, - 0x5f,0x0c,0x66,0x6f,0x72,0x65,0x61,0x63,0x68,0x08,0x65,0x6e,0x64,0x09,0x65,0x6c, - 0x73,0x65,0x09,0x65,0x6c,0x69,0x66,0x09,0x65,0x76,0x61,0x6c,0x07,0x69,0x66,0x10, - 0x6c,0x61,0x73,0x74,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x09,0x76,0x61,0x72,0x73, - 0x09,0x73,0x6b,0x69,0x70,0x0b,0x75,0x6e,0x70,0x61,0x63,0x6b,0x0b,0x61,0x63,0x74, - 0x69,0x6f,0x6e,0x0b,0x72,0x65,0x6d,0x6f,0x76,0x65,0x0a,0x74,0x61,0x62,0x6c,0x65, - 0x10,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x61,0x72,0x67,0x0b,0x69,0x70,0x61, - 0x69,0x72,0x73,0x02,0xc7,0x04,0x02,0x00,0x0d,0x00,0x0f,0x01,0x7b,0x34,0x00,0x03, - 0x00,0x47,0x01,0x00,0x00,0x3f,0x01,0x00,0x00,0x3a,0x01,0x01,0x00,0x3a,0x02,0x02, - 0x00,0x3a,0x03,0x03,0x00,0x2b,0x04,0x01,0x00,0x2b,0x05,0x01,0x00,0x36,0x06,0x00, - 0x00,0x39,0x06,0x01,0x06,0x12,0x08,0x02,0x00,0x29,0x09,0x01,0x00,0x29,0x0a,0x01, - 0x00,0x42,0x06,0x04,0x02,0x07,0x06,0x02,0x00,0x58,0x06,0x07,0x80,0x2b,0x04,0x02, - 0x00,0x36,0x06,0x00,0x00,0x39,0x06,0x01,0x06,0x12,0x08,0x02,0x00,0x29,0x09,0x02, - 0x00,0x42,0x06,0x03,0x02,0x12,0x02,0x06,0x00,0x0b,0x01,0x00,0x00,0x58,0x06,0x03, - 0x80,0x06,0x02,0x03,0x00,0x58,0x06,0x01,0x80,0x58,0x06,0x3b,0x80,0x07,0x02,0x03, - 0x00,0x58,0x06,0x06,0x80,0x04,0x01,0x03,0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01, - 0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x33,0x80,0x07,0x02,0x04, - 0x00,0x58,0x06,0x06,0x80,0x00,0x03,0x01,0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01, - 0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x2b,0x80,0x07,0x02,0x05, - 0x00,0x58,0x06,0x06,0x80,0x02,0x03,0x01,0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01, - 0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x23,0x80,0x07,0x02,0x06, - 0x00,0x58,0x06,0x06,0x80,0x00,0x01,0x03,0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01, - 0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x1b,0x80,0x07,0x02,0x07, - 0x00,0x58,0x06,0x06,0x80,0x02,0x01,0x03,0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01, - 0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x13,0x80,0x07,0x02,0x08, - 0x00,0x58,0x06,0x0b,0x80,0x36,0x06,0x00,0x00,0x39,0x06,0x08,0x06,0x12,0x08,0x01, - 0x00,0x12,0x09,0x03,0x00,0x42,0x06,0x03,0x02,0x0b,0x06,0x00,0x00,0x58,0x06,0x02, - 0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x06, - 0x80,0x36,0x06,0x09,0x00,0x2b,0x08,0x01,0x00,0x27,0x09,0x0a,0x00,0x12,0x0a,0x02, - 0x00,0x26,0x09,0x0a,0x09,0x42,0x06,0x03,0x01,0x0f,0x00,0x04,0x00,0x58,0x06,0x01, - 0x80,0x13,0x05,0x05,0x00,0x15,0x06,0x00,0x00,0x29,0x07,0x03,0x00,0x01,0x07,0x06, - 0x00,0x58,0x06,0x1c,0x80,0x3a,0x02,0x04,0x00,0x36,0x06,0x0b,0x00,0x36,0x08,0x0c, - 0x00,0x12,0x0a,0x00,0x00,0x29,0x0b,0x05,0x00,0x15,0x0c,0x00,0x00,0x42,0x08,0x04, - 0x00,0x41,0x06,0x00,0x02,0x07,0x02,0x0d,0x00,0x58,0x07,0x05,0x80,0x0d,0x07,0x05, - 0x00,0x58,0x07,0x01,0x80,0x12,0x07,0x06,0x00,0x4c,0x07,0x02,0x00,0x58,0x07,0x0d, - 0x80,0x07,0x02,0x0e,0x00,0x58,0x07,0x05,0x80,0x0c,0x07,0x05,0x00,0x58,0x07,0x01, - 0x80,0x12,0x07,0x06,0x00,0x4c,0x07,0x02,0x00,0x58,0x07,0x06,0x80,0x36,0x07,0x09, - 0x00,0x2b,0x09,0x01,0x00,0x27,0x0a,0x0a,0x00,0x12,0x0b,0x02,0x00,0x26,0x0a,0x0b, - 0x0a,0x42,0x07,0x03,0x01,0x4c,0x05,0x02,0x00,0x07,0x6f,0x72,0x08,0x61,0x6e,0x64, - 0x0b,0x75,0x6e,0x70,0x61,0x63,0x6b,0x09,0x65,0x76,0x61,0x6c,0x19,0x6f,0x70,0x65, - 0x72,0x61,0x74,0x6f,0x72,0x20,0x6e,0x6f,0x74,0x20,0x6b,0x6e,0x6f,0x77,0x6e,0x3a, - 0x20,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x0a,0x6d,0x61,0x74,0x63,0x68,0x07,0x3c, - 0x3d,0x06,0x3c,0x07,0x3e,0x3d,0x06,0x3e,0x06,0x3d,0x06,0x21,0x08,0x73,0x75,0x62, - 0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x03,0x80,0x80,0xc0,0x99,0x04,0xab,0x05,0x00, - 0x02,0x0e,0x00,0x18,0x02,0x73,0x36,0x02,0x00,0x00,0x12,0x04,0x00,0x00,0x42,0x02, - 0x02,0x02,0x06,0x02,0x01,0x00,0x58,0x02,0x04,0x80,0x36,0x02,0x02,0x00,0x12,0x04, - 0x00,0x00,0x42,0x02,0x02,0x02,0x12,0x00,0x02,0x00,0x36,0x02,0x03,0x00,0x36,0x04, - 0x01,0x00,0x39,0x04,0x04,0x04,0x12,0x06,0x00,0x00,0x27,0x07,0x05,0x00,0x42,0x04, - 0x03,0x02,0x0a,0x04,0x00,0x00,0x58,0x04,0x02,0x80,0x2b,0x04,0x01,0x00,0x58,0x05, - 0x01,0x80,0x2b,0x04,0x02,0x00,0x27,0x05,0x06,0x00,0x42,0x02,0x03,0x01,0x36,0x02, - 0x01,0x00,0x39,0x02,0x07,0x02,0x12,0x04,0x00,0x00,0x27,0x05,0x08,0x00,0x27,0x06, - 0x09,0x00,0x42,0x02,0x04,0x03,0x36,0x04,0x03,0x00,0x29,0x06,0x01,0x00,0x02,0x03, - 0x06,0x00,0x58,0x06,0x02,0x80,0x2b,0x06,0x01,0x00,0x58,0x07,0x01,0x80,0x2b,0x06, - 0x02,0x00,0x27,0x07,0x0a,0x00,0x42,0x04,0x03,0x01,0x09,0x03,0x00,0x00,0x58,0x04, - 0x48,0x80,0x2b,0x04,0x00,0x00,0x12,0x07,0x01,0x00,0x39,0x05,0x0b,0x01,0x42,0x05, - 0x02,0x02,0x07,0x05,0x0c,0x00,0x58,0x05,0x02,0x80,0x29,0x04,0x12,0x00,0x58,0x05, - 0x06,0x80,0x36,0x05,0x0d,0x00,0x39,0x05,0x0e,0x05,0x12,0x07,0x01,0x00,0x27,0x08, - 0x0f,0x00,0x42,0x05,0x03,0x02,0x12,0x04,0x05,0x00,0x36,0x05,0x03,0x00,0x29,0x07, - 0x00,0x00,0x03,0x07,0x04,0x00,0x58,0x07,0x03,0x80,0x29,0x07,0x12,0x00,0x02,0x04, - 0x07,0x00,0x58,0x07,0x02,0x80,0x2b,0x07,0x01,0x00,0x58,0x08,0x01,0x80,0x2b,0x07, - 0x02,0x00,0x27,0x08,0x10,0x00,0x42,0x05,0x03,0x01,0x36,0x05,0x01,0x00,0x39,0x05, - 0x04,0x05,0x27,0x07,0x11,0x00,0x12,0x08,0x00,0x00,0x27,0x09,0x11,0x00,0x26,0x07, - 0x09,0x07,0x27,0x08,0x12,0x00,0x42,0x05,0x03,0x03,0x15,0x07,0x06,0x00,0x21,0x07, - 0x07,0x04,0x29,0x08,0x00,0x00,0x01,0x08,0x07,0x00,0x58,0x08,0x08,0x80,0x12,0x08, - 0x06,0x00,0x36,0x09,0x01,0x00,0x39,0x09,0x13,0x09,0x27,0x0b,0x11,0x00,0x12,0x0c, - 0x07,0x00,0x42,0x09,0x03,0x02,0x26,0x06,0x09,0x08,0x58,0x08,0x0a,0x80,0x29,0x08, - 0x00,0x00,0x01,0x07,0x08,0x00,0x58,0x08,0x07,0x80,0x36,0x08,0x01,0x00,0x39,0x08, - 0x14,0x08,0x12,0x0a,0x06,0x00,0x29,0x0b,0x01,0x00,0x12,0x0c,0x04,0x00,0x42,0x08, - 0x04,0x02,0x12,0x06,0x08,0x00,0x12,0x08,0x05,0x00,0x12,0x09,0x06,0x00,0x26,0x00, - 0x09,0x08,0x36,0x08,0x01,0x00,0x39,0x08,0x07,0x08,0x12,0x0a,0x00,0x00,0x27,0x0b, - 0x15,0x00,0x27,0x0c,0x09,0x00,0x29,0x0d,0x01,0x00,0x42,0x08,0x05,0x02,0x12,0x00, - 0x08,0x00,0x15,0x08,0x00,0x00,0x09,0x08,0x01,0x00,0x58,0x08,0x01,0x80,0x27,0x00, - 0x11,0x00,0x36,0x04,0x16,0x00,0x39,0x04,0x17,0x04,0x12,0x06,0x00,0x00,0x44,0x04, - 0x02,0x00,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x0b,0x62,0x69,0x67,0x6e,0x75,0x6d, - 0x07,0x30,0x2a,0x08,0x73,0x75,0x62,0x08,0x72,0x65,0x70,0x11,0x28,0x25,0x64,0x2b, - 0x29,0x25,0x2e,0x28,0x25,0x64,0x2b,0x29,0x06,0x30,0x20,0x74,0x6f,0x6b,0x65,0x6e, - 0x20,0x77,0x69,0x74,0x68,0x20,0x69,0x6e,0x76,0x61,0x6c,0x69,0x64,0x20,0x64,0x65, - 0x63,0x69,0x6d,0x61,0x6c,0x73,0x0d,0x64,0x65,0x63,0x69,0x6d,0x61,0x6c,0x73,0x09, - 0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63,0x74,0x0a,0x61,0x65, - 0x72,0x67,0x6f,0x0a,0x6c,0x6f,0x77,0x65,0x72,0x1a,0x74,0x68,0x65,0x20,0x61,0x6d, - 0x6f,0x75,0x6e,0x74,0x20,0x69,0x73,0x20,0x69,0x6e,0x76,0x61,0x6c,0x69,0x64,0x05, - 0x07,0x25,0x2e,0x09,0x67,0x73,0x75,0x62,0x2a,0x74,0x68,0x65,0x20,0x61,0x6d,0x6f, - 0x75,0x6e,0x74,0x20,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x73,0x20,0x69,0x6e,0x76, - 0x61,0x6c,0x69,0x64,0x20,0x63,0x68,0x61,0x72,0x61,0x63,0x74,0x65,0x72,0x0c,0x5b, - 0x5e,0x30,0x2d,0x39,0x2e,0x5d,0x0a,0x6d,0x61,0x74,0x63,0x68,0x0b,0x61,0x73,0x73, - 0x65,0x72,0x74,0x0d,0x74,0x6f,0x73,0x74,0x72,0x69,0x6e,0x67,0x0b,0x73,0x74,0x72, - 0x69,0x6e,0x67,0x09,0x74,0x79,0x70,0x65,0x02,0x00,0xba,0x05,0x03,0x00,0x03,0x00, - 0x4f,0x00,0x53,0x34,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x35,0x00,0x01,0x00,0x37, - 0x00,0x02,0x00,0x35,0x00,0x04,0x00,0x33,0x01,0x03,0x00,0x3d,0x01,0x05,0x00,0x33, - 0x01,0x06,0x00,0x3d,0x01,0x07,0x00,0x33,0x01,0x08,0x00,0x3d,0x01,0x09,0x00,0x33, - 0x01,0x0a,0x00,0x3d,0x01,0x0b,0x00,0x33,0x01,0x0c,0x00,0x3d,0x01,0x0d,0x00,0x33, - 0x01,0x0e,0x00,0x3d,0x01,0x0f,0x00,0x33,0x01,0x10,0x00,0x3d,0x01,0x11,0x00,0x33, - 0x01,0x12,0x00,0x3d,0x01,0x13,0x00,0x33,0x01,0x14,0x00,0x3d,0x01,0x15,0x00,0x33, - 0x01,0x16,0x00,0x3d,0x01,0x17,0x00,0x33,0x01,0x18,0x00,0x3d,0x01,0x19,0x00,0x33, - 0x01,0x1a,0x00,0x3d,0x01,0x1b,0x00,0x33,0x01,0x1c,0x00,0x3d,0x01,0x1d,0x00,0x33, - 0x01,0x1e,0x00,0x3d,0x01,0x1f,0x00,0x33,0x01,0x20,0x00,0x3d,0x01,0x21,0x00,0x33, - 0x01,0x22,0x00,0x3d,0x01,0x23,0x00,0x33,0x01,0x24,0x00,0x3d,0x01,0x25,0x00,0x33, - 0x01,0x26,0x00,0x3d,0x01,0x27,0x00,0x33,0x01,0x28,0x00,0x3d,0x01,0x29,0x00,0x33, - 0x01,0x2a,0x00,0x3d,0x01,0x2b,0x00,0x33,0x01,0x2c,0x00,0x3d,0x01,0x2d,0x00,0x33, - 0x01,0x2e,0x00,0x3d,0x01,0x2f,0x00,0x33,0x01,0x30,0x00,0x3d,0x01,0x31,0x00,0x33, - 0x01,0x32,0x00,0x3d,0x01,0x33,0x00,0x33,0x01,0x34,0x00,0x3d,0x01,0x35,0x00,0x33, - 0x01,0x36,0x00,0x3d,0x01,0x37,0x00,0x33,0x01,0x38,0x00,0x3d,0x01,0x39,0x00,0x33, - 0x01,0x3a,0x00,0x3d,0x01,0x3b,0x00,0x33,0x01,0x3c,0x00,0x3d,0x01,0x3d,0x00,0x33, - 0x01,0x3e,0x00,0x3d,0x01,0x3f,0x00,0x33,0x01,0x40,0x00,0x3d,0x01,0x41,0x00,0x33, - 0x01,0x42,0x00,0x3d,0x01,0x43,0x00,0x37,0x00,0x44,0x00,0x33,0x00,0x45,0x00,0x37, - 0x00,0x46,0x00,0x33,0x00,0x47,0x00,0x37,0x00,0x48,0x00,0x33,0x00,0x49,0x00,0x37, - 0x00,0x4a,0x00,0x33,0x00,0x4b,0x00,0x37,0x00,0x4c,0x00,0x36,0x00,0x4d,0x00,0x39, - 0x00,0x4e,0x00,0x36,0x02,0x48,0x00,0x42,0x00,0x02,0x01,0x4b,0x00,0x01,0x00,0x0d, - 0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x08,0x61,0x62,0x69,0x13,0x63,0x6f,0x6e, - 0x76,0x65,0x72,0x74,0x5f,0x62,0x69,0x67,0x6e,0x75,0x6d,0x00,0x09,0x65,0x76,0x61, - 0x6c,0x00,0x0c,0x65,0x78,0x65,0x63,0x75,0x74,0x65,0x00,0x10,0x70,0x72,0x6f,0x63, - 0x65,0x73,0x73,0x5f,0x61,0x72,0x67,0x00,0x0b,0x61,0x63,0x74,0x69,0x6f,0x6e,0x0b, - 0x61,0x73,0x73,0x65,0x72,0x74,0x00,0x0d,0x66,0x72,0x6f,0x6d,0x6a,0x73,0x6f,0x6e, - 0x00,0x0b,0x74,0x6f,0x6a,0x73,0x6f,0x6e,0x00,0x0d,0x74,0x6f,0x73,0x74,0x72,0x69, - 0x6e,0x67,0x00,0x0d,0x74,0x6f,0x6e,0x75,0x6d,0x62,0x65,0x72,0x00,0x0d,0x74,0x6f, - 0x62,0x69,0x67,0x6e,0x75,0x6d,0x00,0x0c,0x72,0x65,0x70,0x6c,0x61,0x63,0x65,0x00, - 0x09,0x66,0x69,0x6e,0x64,0x00,0x0b,0x73,0x75,0x62,0x73,0x74,0x72,0x00,0x0b,0x66, - 0x6f,0x72,0x6d,0x61,0x74,0x00,0x0b,0x63,0x6f,0x6e,0x63,0x61,0x74,0x00,0x09,0x73, - 0x71,0x72,0x74,0x00,0x08,0x6d,0x6f,0x64,0x00,0x08,0x70,0x6f,0x77,0x00,0x08,0x64, - 0x69,0x76,0x00,0x08,0x6d,0x75,0x6c,0x00,0x08,0x73,0x75,0x62,0x00,0x08,0x61,0x64, - 0x64,0x00,0x0d,0x67,0x65,0x74,0x5f,0x6b,0x65,0x79,0x73,0x00,0x0d,0x67,0x65,0x74, - 0x5f,0x73,0x69,0x7a,0x65,0x00,0x0b,0x72,0x65,0x6d,0x6f,0x76,0x65,0x00,0x0b,0x69, - 0x6e,0x73,0x65,0x72,0x74,0x00,0x08,0x73,0x65,0x74,0x00,0x08,0x67,0x65,0x74,0x00, - 0x0a,0x73,0x74,0x6f,0x72,0x65,0x00,0x08,0x6c,0x65,0x74,0x00,0x09,0x73,0x65,0x6e, - 0x64,0x00,0x0c,0x62,0x61,0x6c,0x61,0x6e,0x63,0x65,0x00,0x0f,0x70,0x63,0x61,0x6c, - 0x6c,0x2d,0x73,0x65,0x6e,0x64,0x00,0x0a,0x70,0x63,0x61,0x6c,0x6c,0x00,0x0e,0x63, - 0x61,0x6c,0x6c,0x2d,0x73,0x65,0x6e,0x64,0x00,0x09,0x63,0x61,0x6c,0x6c,0x01,0x00, - 0x00,0x00,0x09,0x73,0x6b,0x69,0x70,0x01,0x00,0x06,0x0b,0x69,0x6e,0x73,0x65,0x72, - 0x74,0x02,0x08,0x6c,0x65,0x74,0x02,0x0a,0x73,0x74,0x6f,0x72,0x65,0x02,0x09,0x73, - 0x65,0x6e,0x64,0x02,0x08,0x73,0x65,0x74,0x02,0x0b,0x61,0x73,0x73,0x65,0x72,0x74, - 0x02,0x09,0x76,0x61,0x72,0x73,0x00,0x7b,0x22,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e, - 0x22,0x3a,0x22,0x30,0x2e,0x32,0x22,0x2c,0x22,0x6c,0x61,0x6e,0x67,0x75,0x61,0x67, - 0x65,0x22,0x3a,0x22,0x6c,0x75,0x61,0x22,0x2c,0x22,0x66,0x75,0x6e,0x63,0x74,0x69, - 0x6f,0x6e,0x73,0x22,0x3a,0x5b,0x7b,0x22,0x6e,0x61,0x6d,0x65,0x22,0x3a,0x22,0x65, - 0x78,0x65,0x63,0x75,0x74,0x65,0x22,0x2c,0x22,0x61,0x72,0x67,0x75,0x6d,0x65,0x6e, - 0x74,0x73,0x22,0x3a,0x5b,0x7b,0x22,0x6e,0x61,0x6d,0x65,0x22,0x3a,0x22,0x63,0x61, - 0x6c,0x6c,0x73,0x22,0x7d,0x5d,0x7d,0x5d,0x7d + 0x2b,0x0c,0x01,0x00,0x58,0x12,0x01,0x80,0x2b,0x0c,0x02,0x00,0x58,0x12,0x51,0x80, + 0x07,0x10,0x14,0x00,0x58,0x12,0x12,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x10,0x80, + 0x36,0x12,0x02,0x00,0x39,0x12,0x03,0x12,0x12,0x14,0x0f,0x00,0x29,0x15,0x01,0x00, + 0x42,0x12,0x03,0x02,0x07,0x12,0x09,0x00,0x58,0x12,0x07,0x80,0x36,0x12,0x0a,0x00, + 0x36,0x14,0x05,0x00,0x12,0x16,0x0f,0x00,0x42,0x14,0x02,0x00,0x41,0x12,0x00,0x02, + 0x12,0x0c,0x12,0x00,0x58,0x12,0x3f,0x80,0x2b,0x0c,0x02,0x00,0x58,0x12,0x3d,0x80, + 0x07,0x10,0x15,0x00,0x58,0x12,0x2b,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x29,0x80, + 0x07,0x06,0x16,0x00,0x58,0x12,0x0d,0x80,0x16,0x09,0x00,0x09,0x15,0x12,0x08,0x00, + 0x03,0x09,0x12,0x00,0x58,0x12,0x33,0x80,0x36,0x12,0x07,0x00,0x38,0x13,0x09,0x08, + 0x3c,0x13,0x04,0x12,0x36,0x12,0x07,0x00,0x38,0x13,0x09,0x08,0x38,0x13,0x13,0x07, + 0x3c,0x13,0x05,0x12,0x12,0x0d,0x03,0x00,0x58,0x12,0x2a,0x80,0x07,0x06,0x13,0x00, + 0x58,0x12,0x16,0x80,0x36,0x12,0x07,0x00,0x36,0x13,0x07,0x00,0x38,0x13,0x04,0x13, + 0x20,0x13,0x0b,0x13,0x3c,0x13,0x04,0x12,0x29,0x12,0x00,0x00,0x01,0x12,0x0b,0x00, + 0x58,0x12,0x04,0x80,0x36,0x12,0x07,0x00,0x38,0x12,0x04,0x12,0x00,0x0a,0x12,0x00, + 0x58,0x12,0x1c,0x80,0x29,0x12,0x00,0x00,0x01,0x0b,0x12,0x00,0x58,0x12,0x05,0x80, + 0x36,0x12,0x07,0x00,0x38,0x12,0x04,0x12,0x01,0x12,0x0a,0x00,0x58,0x12,0x01,0x80, + 0x58,0x12,0x14,0x80,0x12,0x0d,0x03,0x00,0x58,0x12,0x12,0x80,0x29,0x0d,0x00,0x00, + 0x58,0x12,0x10,0x80,0x07,0x10,0x17,0x00,0x58,0x12,0x06,0x80,0x0f,0x00,0x01,0x00, + 0x58,0x12,0x04,0x80,0x36,0x12,0x05,0x00,0x12,0x14,0x0f,0x00,0x44,0x12,0x02,0x00, + 0x58,0x12,0x08,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x06,0x80,0x36,0x12,0x18,0x00, + 0x2b,0x14,0x01,0x00,0x27,0x15,0x19,0x00,0x12,0x16,0x10,0x00,0x26,0x15,0x16,0x15, + 0x42,0x12,0x03,0x01,0x0f,0x00,0x01,0x00,0x58,0x12,0x11,0x80,0x06,0x10,0x0e,0x00, + 0x58,0x12,0x02,0x80,0x07,0x10,0x10,0x00,0x58,0x12,0x0d,0x80,0x12,0x03,0x0d,0x00, + 0x27,0x06,0x16,0x00,0x3a,0x04,0x01,0x0f,0x29,0x09,0x01,0x00,0x36,0x12,0x07,0x00, + 0x3a,0x13,0x01,0x08,0x3c,0x13,0x04,0x12,0x3a,0x12,0x01,0x08,0x0a,0x12,0x00,0x00, + 0x58,0x12,0x02,0x80,0x2b,0x0c,0x01,0x00,0x58,0x12,0x01,0x80,0x2b,0x0c,0x02,0x00, + 0x0f,0x00,0x0c,0x00,0x58,0x12,0x09,0x80,0x55,0x12,0x07,0x80,0x16,0x0d,0x00,0x0d, + 0x38,0x0e,0x0d,0x00,0x0a,0x0e,0x00,0x00,0x58,0x12,0x03,0x80,0x3a,0x12,0x01,0x0e, + 0x07,0x12,0x15,0x00,0x58,0x12,0xf8,0x7f,0x2b,0x0c,0x01,0x00,0x16,0x0d,0x00,0x0d, + 0x58,0x0e,0x03,0x7f,0x4b,0x00,0x01,0x00,0x18,0x63,0x6f,0x6d,0x6d,0x61,0x6e,0x64, + 0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x3a,0x20,0x0b,0x61,0x73,0x73, + 0x65,0x72,0x74,0x0b,0x72,0x65,0x74,0x75,0x72,0x6e,0x09,0x65,0x61,0x63,0x68,0x09, + 0x6c,0x6f,0x6f,0x70,0x0a,0x62,0x72,0x65,0x61,0x6b,0x0b,0x6e,0x75,0x6d,0x62,0x65, + 0x72,0x08,0x66,0x6f,0x72,0x0d,0x67,0x65,0x74,0x5f,0x6b,0x65,0x79,0x73,0x0c,0x66, + 0x6f,0x72,0x70,0x61,0x69,0x72,0x07,0x5f,0x5f,0x0c,0x66,0x6f,0x72,0x65,0x61,0x63, + 0x68,0x08,0x65,0x6e,0x64,0x09,0x65,0x6c,0x73,0x65,0x09,0x65,0x6c,0x69,0x66,0x09, + 0x65,0x76,0x61,0x6c,0x07,0x69,0x66,0x10,0x6c,0x61,0x73,0x74,0x5f,0x72,0x65,0x73, + 0x75,0x6c,0x74,0x09,0x76,0x61,0x72,0x73,0x09,0x73,0x6b,0x69,0x70,0x0b,0x75,0x6e, + 0x70,0x61,0x63,0x6b,0x0b,0x61,0x63,0x74,0x69,0x6f,0x6e,0x0b,0x72,0x65,0x6d,0x6f, + 0x76,0x65,0x0a,0x74,0x61,0x62,0x6c,0x65,0x10,0x70,0x72,0x6f,0x63,0x65,0x73,0x73, + 0x5f,0x61,0x72,0x67,0x0b,0x69,0x70,0x61,0x69,0x72,0x73,0x02,0xc7,0x04,0x02,0x00, + 0x0d,0x00,0x0f,0x01,0x7b,0x34,0x00,0x03,0x00,0x47,0x01,0x00,0x00,0x3f,0x01,0x00, + 0x00,0x3a,0x01,0x01,0x00,0x3a,0x02,0x02,0x00,0x3a,0x03,0x03,0x00,0x2b,0x04,0x01, + 0x00,0x2b,0x05,0x01,0x00,0x36,0x06,0x00,0x00,0x39,0x06,0x01,0x06,0x12,0x08,0x02, + 0x00,0x29,0x09,0x01,0x00,0x29,0x0a,0x01,0x00,0x42,0x06,0x04,0x02,0x07,0x06,0x02, + 0x00,0x58,0x06,0x07,0x80,0x2b,0x04,0x02,0x00,0x36,0x06,0x00,0x00,0x39,0x06,0x01, + 0x06,0x12,0x08,0x02,0x00,0x29,0x09,0x02,0x00,0x42,0x06,0x03,0x02,0x12,0x02,0x06, + 0x00,0x0b,0x01,0x00,0x00,0x58,0x06,0x03,0x80,0x06,0x02,0x03,0x00,0x58,0x06,0x01, + 0x80,0x58,0x06,0x3b,0x80,0x07,0x02,0x03,0x00,0x58,0x06,0x06,0x80,0x04,0x01,0x03, + 0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02, + 0x00,0x58,0x06,0x33,0x80,0x07,0x02,0x04,0x00,0x58,0x06,0x06,0x80,0x00,0x03,0x01, + 0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02, + 0x00,0x58,0x06,0x2b,0x80,0x07,0x02,0x05,0x00,0x58,0x06,0x06,0x80,0x02,0x03,0x01, + 0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02, + 0x00,0x58,0x06,0x23,0x80,0x07,0x02,0x06,0x00,0x58,0x06,0x06,0x80,0x00,0x01,0x03, + 0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02, + 0x00,0x58,0x06,0x1b,0x80,0x07,0x02,0x07,0x00,0x58,0x06,0x06,0x80,0x02,0x01,0x03, + 0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02, + 0x00,0x58,0x06,0x13,0x80,0x07,0x02,0x08,0x00,0x58,0x06,0x0b,0x80,0x36,0x06,0x00, + 0x00,0x39,0x06,0x08,0x06,0x12,0x08,0x01,0x00,0x12,0x09,0x03,0x00,0x42,0x06,0x03, + 0x02,0x0b,0x06,0x00,0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01, + 0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x06,0x80,0x36,0x06,0x09,0x00,0x2b,0x08,0x01, + 0x00,0x27,0x09,0x0a,0x00,0x12,0x0a,0x02,0x00,0x26,0x09,0x0a,0x09,0x42,0x06,0x03, + 0x01,0x0f,0x00,0x04,0x00,0x58,0x06,0x01,0x80,0x13,0x05,0x05,0x00,0x15,0x06,0x00, + 0x00,0x29,0x07,0x03,0x00,0x01,0x07,0x06,0x00,0x58,0x06,0x1c,0x80,0x3a,0x02,0x04, + 0x00,0x36,0x06,0x0b,0x00,0x36,0x08,0x0c,0x00,0x12,0x0a,0x00,0x00,0x29,0x0b,0x05, + 0x00,0x15,0x0c,0x00,0x00,0x42,0x08,0x04,0x00,0x41,0x06,0x00,0x02,0x07,0x02,0x0d, + 0x00,0x58,0x07,0x05,0x80,0x0d,0x07,0x05,0x00,0x58,0x07,0x01,0x80,0x12,0x07,0x06, + 0x00,0x4c,0x07,0x02,0x00,0x58,0x07,0x0d,0x80,0x07,0x02,0x0e,0x00,0x58,0x07,0x05, + 0x80,0x0c,0x07,0x05,0x00,0x58,0x07,0x01,0x80,0x12,0x07,0x06,0x00,0x4c,0x07,0x02, + 0x00,0x58,0x07,0x06,0x80,0x36,0x07,0x09,0x00,0x2b,0x09,0x01,0x00,0x27,0x0a,0x0a, + 0x00,0x12,0x0b,0x02,0x00,0x26,0x0a,0x0b,0x0a,0x42,0x07,0x03,0x01,0x4c,0x05,0x02, + 0x00,0x07,0x6f,0x72,0x08,0x61,0x6e,0x64,0x0b,0x75,0x6e,0x70,0x61,0x63,0x6b,0x09, + 0x65,0x76,0x61,0x6c,0x19,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x20,0x6e,0x6f, + 0x74,0x20,0x6b,0x6e,0x6f,0x77,0x6e,0x3a,0x20,0x0b,0x61,0x73,0x73,0x65,0x72,0x74, + 0x0a,0x6d,0x61,0x74,0x63,0x68,0x07,0x3c,0x3d,0x06,0x3c,0x07,0x3e,0x3d,0x06,0x3e, + 0x06,0x3d,0x06,0x21,0x08,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x03, + 0x80,0x80,0xc0,0x99,0x04,0xab,0x05,0x00,0x02,0x0e,0x00,0x18,0x02,0x73,0x36,0x02, + 0x00,0x00,0x12,0x04,0x00,0x00,0x42,0x02,0x02,0x02,0x06,0x02,0x01,0x00,0x58,0x02, + 0x04,0x80,0x36,0x02,0x02,0x00,0x12,0x04,0x00,0x00,0x42,0x02,0x02,0x02,0x12,0x00, + 0x02,0x00,0x36,0x02,0x03,0x00,0x36,0x04,0x01,0x00,0x39,0x04,0x04,0x04,0x12,0x06, + 0x00,0x00,0x27,0x07,0x05,0x00,0x42,0x04,0x03,0x02,0x0a,0x04,0x00,0x00,0x58,0x04, + 0x02,0x80,0x2b,0x04,0x01,0x00,0x58,0x05,0x01,0x80,0x2b,0x04,0x02,0x00,0x27,0x05, + 0x06,0x00,0x42,0x02,0x03,0x01,0x36,0x02,0x01,0x00,0x39,0x02,0x07,0x02,0x12,0x04, + 0x00,0x00,0x27,0x05,0x08,0x00,0x27,0x06,0x09,0x00,0x42,0x02,0x04,0x03,0x36,0x04, + 0x03,0x00,0x29,0x06,0x01,0x00,0x02,0x03,0x06,0x00,0x58,0x06,0x02,0x80,0x2b,0x06, + 0x01,0x00,0x58,0x07,0x01,0x80,0x2b,0x06,0x02,0x00,0x27,0x07,0x0a,0x00,0x42,0x04, + 0x03,0x01,0x09,0x03,0x00,0x00,0x58,0x04,0x48,0x80,0x2b,0x04,0x00,0x00,0x12,0x07, + 0x01,0x00,0x39,0x05,0x0b,0x01,0x42,0x05,0x02,0x02,0x07,0x05,0x0c,0x00,0x58,0x05, + 0x02,0x80,0x29,0x04,0x12,0x00,0x58,0x05,0x06,0x80,0x36,0x05,0x0d,0x00,0x39,0x05, + 0x0e,0x05,0x12,0x07,0x01,0x00,0x27,0x08,0x0f,0x00,0x42,0x05,0x03,0x02,0x12,0x04, + 0x05,0x00,0x36,0x05,0x03,0x00,0x29,0x07,0x00,0x00,0x03,0x07,0x04,0x00,0x58,0x07, + 0x03,0x80,0x29,0x07,0x12,0x00,0x02,0x04,0x07,0x00,0x58,0x07,0x02,0x80,0x2b,0x07, + 0x01,0x00,0x58,0x08,0x01,0x80,0x2b,0x07,0x02,0x00,0x27,0x08,0x10,0x00,0x42,0x05, + 0x03,0x01,0x36,0x05,0x01,0x00,0x39,0x05,0x04,0x05,0x27,0x07,0x11,0x00,0x12,0x08, + 0x00,0x00,0x27,0x09,0x11,0x00,0x26,0x07,0x09,0x07,0x27,0x08,0x12,0x00,0x42,0x05, + 0x03,0x03,0x15,0x07,0x06,0x00,0x21,0x07,0x07,0x04,0x29,0x08,0x00,0x00,0x01,0x08, + 0x07,0x00,0x58,0x08,0x08,0x80,0x12,0x08,0x06,0x00,0x36,0x09,0x01,0x00,0x39,0x09, + 0x13,0x09,0x27,0x0b,0x11,0x00,0x12,0x0c,0x07,0x00,0x42,0x09,0x03,0x02,0x26,0x06, + 0x09,0x08,0x58,0x08,0x0a,0x80,0x29,0x08,0x00,0x00,0x01,0x07,0x08,0x00,0x58,0x08, + 0x07,0x80,0x36,0x08,0x01,0x00,0x39,0x08,0x14,0x08,0x12,0x0a,0x06,0x00,0x29,0x0b, + 0x01,0x00,0x12,0x0c,0x04,0x00,0x42,0x08,0x04,0x02,0x12,0x06,0x08,0x00,0x12,0x08, + 0x05,0x00,0x12,0x09,0x06,0x00,0x26,0x00,0x09,0x08,0x36,0x08,0x01,0x00,0x39,0x08, + 0x07,0x08,0x12,0x0a,0x00,0x00,0x27,0x0b,0x15,0x00,0x27,0x0c,0x09,0x00,0x29,0x0d, + 0x01,0x00,0x42,0x08,0x05,0x02,0x12,0x00,0x08,0x00,0x15,0x08,0x00,0x00,0x09,0x08, + 0x01,0x00,0x58,0x08,0x01,0x80,0x27,0x00,0x11,0x00,0x36,0x04,0x16,0x00,0x39,0x04, + 0x17,0x04,0x12,0x06,0x00,0x00,0x44,0x04,0x02,0x00,0x0b,0x6e,0x75,0x6d,0x62,0x65, + 0x72,0x0b,0x62,0x69,0x67,0x6e,0x75,0x6d,0x07,0x30,0x2a,0x08,0x73,0x75,0x62,0x08, + 0x72,0x65,0x70,0x11,0x28,0x25,0x64,0x2b,0x29,0x25,0x2e,0x28,0x25,0x64,0x2b,0x29, + 0x06,0x30,0x20,0x74,0x6f,0x6b,0x65,0x6e,0x20,0x77,0x69,0x74,0x68,0x20,0x69,0x6e, + 0x76,0x61,0x6c,0x69,0x64,0x20,0x64,0x65,0x63,0x69,0x6d,0x61,0x6c,0x73,0x0d,0x64, + 0x65,0x63,0x69,0x6d,0x61,0x6c,0x73,0x09,0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e, + 0x74,0x72,0x61,0x63,0x74,0x0a,0x61,0x65,0x72,0x67,0x6f,0x0a,0x6c,0x6f,0x77,0x65, + 0x72,0x1a,0x74,0x68,0x65,0x20,0x61,0x6d,0x6f,0x75,0x6e,0x74,0x20,0x69,0x73,0x20, + 0x69,0x6e,0x76,0x61,0x6c,0x69,0x64,0x05,0x07,0x25,0x2e,0x09,0x67,0x73,0x75,0x62, + 0x2a,0x74,0x68,0x65,0x20,0x61,0x6d,0x6f,0x75,0x6e,0x74,0x20,0x63,0x6f,0x6e,0x74, + 0x61,0x69,0x6e,0x73,0x20,0x69,0x6e,0x76,0x61,0x6c,0x69,0x64,0x20,0x63,0x68,0x61, + 0x72,0x61,0x63,0x74,0x65,0x72,0x0c,0x5b,0x5e,0x30,0x2d,0x39,0x2e,0x5d,0x0a,0x6d, + 0x61,0x74,0x63,0x68,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x0d,0x74,0x6f,0x73,0x74, + 0x72,0x69,0x6e,0x67,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x09,0x74,0x79,0x70,0x65, + 0x02,0x00,0xba,0x05,0x03,0x00,0x03,0x00,0x4f,0x00,0x53,0x34,0x00,0x00,0x00,0x37, + 0x00,0x00,0x00,0x35,0x00,0x01,0x00,0x37,0x00,0x02,0x00,0x35,0x00,0x04,0x00,0x33, + 0x01,0x03,0x00,0x3d,0x01,0x05,0x00,0x33,0x01,0x06,0x00,0x3d,0x01,0x07,0x00,0x33, + 0x01,0x08,0x00,0x3d,0x01,0x09,0x00,0x33,0x01,0x0a,0x00,0x3d,0x01,0x0b,0x00,0x33, + 0x01,0x0c,0x00,0x3d,0x01,0x0d,0x00,0x33,0x01,0x0e,0x00,0x3d,0x01,0x0f,0x00,0x33, + 0x01,0x10,0x00,0x3d,0x01,0x11,0x00,0x33,0x01,0x12,0x00,0x3d,0x01,0x13,0x00,0x33, + 0x01,0x14,0x00,0x3d,0x01,0x15,0x00,0x33,0x01,0x16,0x00,0x3d,0x01,0x17,0x00,0x33, + 0x01,0x18,0x00,0x3d,0x01,0x19,0x00,0x33,0x01,0x1a,0x00,0x3d,0x01,0x1b,0x00,0x33, + 0x01,0x1c,0x00,0x3d,0x01,0x1d,0x00,0x33,0x01,0x1e,0x00,0x3d,0x01,0x1f,0x00,0x33, + 0x01,0x20,0x00,0x3d,0x01,0x21,0x00,0x33,0x01,0x22,0x00,0x3d,0x01,0x23,0x00,0x33, + 0x01,0x24,0x00,0x3d,0x01,0x25,0x00,0x33,0x01,0x26,0x00,0x3d,0x01,0x27,0x00,0x33, + 0x01,0x28,0x00,0x3d,0x01,0x29,0x00,0x33,0x01,0x2a,0x00,0x3d,0x01,0x2b,0x00,0x33, + 0x01,0x2c,0x00,0x3d,0x01,0x2d,0x00,0x33,0x01,0x2e,0x00,0x3d,0x01,0x2f,0x00,0x33, + 0x01,0x30,0x00,0x3d,0x01,0x31,0x00,0x33,0x01,0x32,0x00,0x3d,0x01,0x33,0x00,0x33, + 0x01,0x34,0x00,0x3d,0x01,0x35,0x00,0x33,0x01,0x36,0x00,0x3d,0x01,0x37,0x00,0x33, + 0x01,0x38,0x00,0x3d,0x01,0x39,0x00,0x33,0x01,0x3a,0x00,0x3d,0x01,0x3b,0x00,0x33, + 0x01,0x3c,0x00,0x3d,0x01,0x3d,0x00,0x33,0x01,0x3e,0x00,0x3d,0x01,0x3f,0x00,0x33, + 0x01,0x40,0x00,0x3d,0x01,0x41,0x00,0x33,0x01,0x42,0x00,0x3d,0x01,0x43,0x00,0x37, + 0x00,0x44,0x00,0x33,0x00,0x45,0x00,0x37,0x00,0x46,0x00,0x33,0x00,0x47,0x00,0x37, + 0x00,0x48,0x00,0x33,0x00,0x49,0x00,0x37,0x00,0x4a,0x00,0x33,0x00,0x4b,0x00,0x37, + 0x00,0x4c,0x00,0x36,0x00,0x4d,0x00,0x39,0x00,0x4e,0x00,0x36,0x02,0x48,0x00,0x42, + 0x00,0x02,0x01,0x4b,0x00,0x01,0x00,0x0d,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72, + 0x08,0x61,0x62,0x69,0x13,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x62,0x69,0x67, + 0x6e,0x75,0x6d,0x00,0x09,0x65,0x76,0x61,0x6c,0x00,0x0c,0x65,0x78,0x65,0x63,0x75, + 0x74,0x65,0x00,0x10,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x61,0x72,0x67,0x00, + 0x0b,0x61,0x63,0x74,0x69,0x6f,0x6e,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x00,0x0d, + 0x66,0x72,0x6f,0x6d,0x6a,0x73,0x6f,0x6e,0x00,0x0b,0x74,0x6f,0x6a,0x73,0x6f,0x6e, + 0x00,0x0d,0x74,0x6f,0x73,0x74,0x72,0x69,0x6e,0x67,0x00,0x0d,0x74,0x6f,0x6e,0x75, + 0x6d,0x62,0x65,0x72,0x00,0x0d,0x74,0x6f,0x62,0x69,0x67,0x6e,0x75,0x6d,0x00,0x0c, + 0x72,0x65,0x70,0x6c,0x61,0x63,0x65,0x00,0x09,0x66,0x69,0x6e,0x64,0x00,0x0b,0x73, + 0x75,0x62,0x73,0x74,0x72,0x00,0x0b,0x66,0x6f,0x72,0x6d,0x61,0x74,0x00,0x0b,0x63, + 0x6f,0x6e,0x63,0x61,0x74,0x00,0x09,0x73,0x71,0x72,0x74,0x00,0x08,0x6d,0x6f,0x64, + 0x00,0x08,0x70,0x6f,0x77,0x00,0x08,0x64,0x69,0x76,0x00,0x08,0x6d,0x75,0x6c,0x00, + 0x08,0x73,0x75,0x62,0x00,0x08,0x61,0x64,0x64,0x00,0x0d,0x67,0x65,0x74,0x5f,0x6b, + 0x65,0x79,0x73,0x00,0x0d,0x67,0x65,0x74,0x5f,0x73,0x69,0x7a,0x65,0x00,0x0b,0x72, + 0x65,0x6d,0x6f,0x76,0x65,0x00,0x0b,0x69,0x6e,0x73,0x65,0x72,0x74,0x00,0x08,0x73, + 0x65,0x74,0x00,0x08,0x67,0x65,0x74,0x00,0x0a,0x73,0x74,0x6f,0x72,0x65,0x00,0x08, + 0x6c,0x65,0x74,0x00,0x09,0x73,0x65,0x6e,0x64,0x00,0x0c,0x62,0x61,0x6c,0x61,0x6e, + 0x63,0x65,0x00,0x0f,0x70,0x63,0x61,0x6c,0x6c,0x2d,0x73,0x65,0x6e,0x64,0x00,0x0a, + 0x70,0x63,0x61,0x6c,0x6c,0x00,0x0e,0x63,0x61,0x6c,0x6c,0x2d,0x73,0x65,0x6e,0x64, + 0x00,0x09,0x63,0x61,0x6c,0x6c,0x01,0x00,0x00,0x00,0x09,0x73,0x6b,0x69,0x70,0x01, + 0x00,0x06,0x0b,0x69,0x6e,0x73,0x65,0x72,0x74,0x02,0x08,0x6c,0x65,0x74,0x02,0x0a, + 0x73,0x74,0x6f,0x72,0x65,0x02,0x09,0x73,0x65,0x6e,0x64,0x02,0x08,0x73,0x65,0x74, + 0x02,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x02,0x09,0x76,0x61,0x72,0x73,0x00,0x7b, + 0x22,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x22,0x3a,0x22,0x30,0x2e,0x32,0x22,0x2c, + 0x22,0x6c,0x61,0x6e,0x67,0x75,0x61,0x67,0x65,0x22,0x3a,0x22,0x6c,0x75,0x61,0x22, + 0x2c,0x22,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x73,0x22,0x3a,0x5b,0x7b,0x22, + 0x6e,0x61,0x6d,0x65,0x22,0x3a,0x22,0x65,0x78,0x65,0x63,0x75,0x74,0x65,0x22,0x2c, + 0x22,0x61,0x72,0x67,0x75,0x6d,0x65,0x6e,0x74,0x73,0x22,0x3a,0x5b,0x7b,0x22,0x6e, + 0x61,0x6d,0x65,0x22,0x3a,0x22,0x63,0x61,0x6c,0x6c,0x73,0x22,0x7d,0x5d,0x7d,0x5d, + 0x7d } diff --git a/contract/vm_multicall.lua b/contract/vm_multicall.lua index dc7f25991..c283711b4 100644 --- a/contract/vm_multicall.lua +++ b/contract/vm_multicall.lua @@ -148,7 +148,11 @@ function execute(calls) vars[for_var] = args[2] skip_for = ((for_increment > 0 and vars[for_var] > for_last) or (for_increment < 0 and vars[for_var] < for_last)) elseif cmd == "break" and if_on then - skip_for = true + if table.remove(args, 1) == "if" then + skip_for = eval(unpack(args)) + else + skip_for = true + end elseif cmd == "loop" and if_on then if for_type == "each" then for_pos = for_pos + 1 From 1f12e79a829020a75e876418014863ab26c566f1 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sun, 7 Aug 2022 15:58:14 -0300 Subject: [PATCH 010/182] [contract] new test cases for composable transactions --- contract/vm_multicall.go | 2 +- contract/vm_test.go | 345 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 327 insertions(+), 20 deletions(-) diff --git a/contract/vm_multicall.go b/contract/vm_multicall.go index 5ea72b586..378565256 100644 --- a/contract/vm_multicall.go +++ b/contract/vm_multicall.go @@ -305,5 +305,5 @@ var multicall_payload = []byte { 0x6e,0x61,0x6d,0x65,0x22,0x3a,0x22,0x65,0x78,0x65,0x63,0x75,0x74,0x65,0x22,0x2c, 0x22,0x61,0x72,0x67,0x75,0x6d,0x65,0x6e,0x74,0x73,0x22,0x3a,0x5b,0x7b,0x22,0x6e, 0x61,0x6d,0x65,0x22,0x3a,0x22,0x63,0x61,0x6c,0x6c,0x73,0x22,0x7d,0x5d,0x7d,0x5d, - 0x7d + 0x7d, } diff --git a/contract/vm_test.go b/contract/vm_test.go index 1a8a949dd..36c5986ad 100644 --- a/contract/vm_test.go +++ b/contract/vm_test.go @@ -6261,6 +6261,11 @@ function set(key, value) dict[key] = value end +function inc(key) + dict[key] = (dict[key] or 0) + 1 + contract.event("new_value", dict[key]) +end + function add(value) local key = (last:get() or 0) + 1 dict[tostring(key)] = value @@ -6271,8 +6276,13 @@ function get(key) return dict[key] end -abi.register(add, set, set_name) -abi.register_view(get_dict, get_list, get_table, works, fails, get, get_name, hello) +function sort(list) + table.sort(list) + return list +end + +abi.register(add, set, inc, set_name) +abi.register_view(get_dict, get_list, get_table, works, fails, get, get_name, sort, hello) function call(...) return contract.call(...) @@ -6341,8 +6351,8 @@ abi.payable(recv_aergo) ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_list"], ["store","array"], ["remove","%array%",3], - ["return","%array%"] - ]`, ``, `["first","second",123,12.5,true]`) + ["return","%array%","%last_result%"] + ]`, ``, `[["first","second",123,12.5,true],"third"]`) // create new dict or array using fromjson @@ -6386,6 +6396,39 @@ abi.payable(recv_aergo) ]`, ``, `["one",22,3.3,true,false]`) + // get_size + + multicall(t, bc, "ac1", `[ + ["let","str","this is a string"], + ["get_size","%str%"], + ["return","%last_result%"] + ]`, ``, `16`) + + multicall(t, bc, "ac1", `[ + ["let","list",["one",1,"two",2,2.5,true,false]], + ["get_size","%list%"], + ["return","%last_result%"] + ]`, ``, `7`) + + multicall(t, bc, "ac1", `[ + ["let","obj",{"one":1,"two":2,"three":3}], + ["get_size","%obj%"], + ["return","%last_result%"] + ]`, ``, `0`) + + + // get_keys + + multicall(t, bc, "ac1", `[ + ["let","obj",{"one":1,"two":2,"three":3}], + ["get_keys","%obj%"], + ["store","keys"], + ["get_size","%keys%"], + ["return","%last_result%","%keys%"] + ]`, ``, `[3,["one","three","two"]]`) + + + // BIGNUM @@ -6841,32 +6884,48 @@ abi.payable(recv_aergo) ]`, ``, `"130000000000000000003"`) - // FOR "BREAK" + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",500,10,-5], + ["add","%last_result%",1], + ["loop"], + ["return","%last_result%"] + ]`, ``, `99`) + multicall(t, bc, "ac1", `[ - ["let","c",0], - ["for","n",1,10], - ["add","%c%",1], - ["store","c"], - ["if","%n%","=",5], - ["let","n",500], - ["end"], + ["tonumber","0"], + ["for","n",5,1,-1], + ["add","%last_result%",1], ["loop"], - ["return","%c%"] + ["return","%last_result%"] ]`, ``, `5`) multicall(t, bc, "ac1", `[ ["tonumber","0"], - ["let","c",0], - ["for","n",1,10], + ["for","n",5,1], + ["add","%last_result%",1], + ["loop"], + ["return","%last_result%"] + ]`, ``, `0`) + + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",1,5], ["add","%last_result%",1], - ["if","%n%","=",5], - ["let","n",500], - ["end"], ["loop"], ["return","%last_result%"] ]`, ``, `5`) + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",1,5,-1], + ["add","%last_result%",1], + ["loop"], + ["return","%last_result%"] + ]`, ``, `0`) + + // FOREACH @@ -6880,6 +6939,36 @@ abi.payable(recv_aergo) ["return","%r%"] ]`, ``, `66`) + multicall(t, bc, "ac1", `[ + ["let","list",[11,22,33]], + ["let","counter",0], + ["foreach","item","%list%"], + ["add","%counter%",1], + ["store","counter"], + ["loop"], + ["return","%counter%"] + ]`, ``, `3`) + + multicall(t, bc, "ac1", `[ + ["let","list",[]], + ["let","counter",0], + ["foreach","item","%list%"], + ["add","%counter%",1], + ["store","counter"], + ["loop"], + ["return","%counter%"] + ]`, ``, `0`) + + multicall(t, bc, "ac1", `[ + ["let","list",["one",1,"two",2,2.5,true,false]], + ["let","counter",0], + ["foreach","item","%list%"], + ["add","%counter%",1], + ["store","counter"], + ["loop"], + ["return","%counter%"] + ]`, ``, `7`) + multicall(t, bc, "ac1", `[ ["let","list",[10,21,32]], ["let","r",0], @@ -6893,6 +6982,209 @@ abi.payable(recv_aergo) ]`, ``, `31`) + multicall(t, bc, "ac1", `[ + ["let","str",""], + ["let","obj",{"one":1,"two":2,"three":3}], + ["get_keys","%obj%"], + ["foreach","key","%last_result%"], + ["concat","%str%","%key%"], + ["store","str"], + ["loop"], + ["return","%str%"] + ]`, ``, `"onethreetwo"`) + + + + // FORPAIR + + multicall(t, bc, "ac1", `[ + ["let","str",""], + ["let","sum",0], + ["let","obj",{"one":1,"two":2,"three":3}], + ["forpair","key","value","%obj%"], + ["concat","%str%","%key%"], + ["store","str"], + ["add","%sum%","%value%"], + ["store","sum"], + ["loop"], + ["return","%str%","%sum%"] + ]`, ``, `["onethreetwo",6]`) + + multicall(t, bc, "ac1", `[ + ["let","str",""], + ["let","sum",0], + ["let","obj",{"one":1.5,"two":2.5,"three":3.5,"four":4.5}], + ["forpair","key","value","%obj%"], + ["concat","%str%","%key%"], + ["store","str"], + ["add","%sum%","%value%"], + ["store","sum"], + ["loop"], + ["return","%str%","%sum%"] + ]`, ``, `["fouronethreetwo",12]`) + + multicall(t, bc, "ac1", `[ + ["let","names",[]], + ["let","values",[]], + ["let","obj",{"one":1.5,"two":2.5,"three":3.5,"four":4.5}], + ["forpair","key","value","%obj%"], + ["insert","%names%","%key%"], + ["insert","%values%","%value%"], + ["loop"], + ["return","%names%","%values%"] + ]`, ``, `[["four","one","three","two"],[4.5,1.5,3.5,2.5]]`) + + multicall(t, bc, "ac1", `[ + ["let","names",[]], + ["let","values",[]], + ["let","obj",{"one":1.5,"two":2.5,"three":3.5,"four":4.5}], + ["forpair","key","value","%obj%"], + ["insert","%names%","%key%"], + ["insert","%values%","%value%"], + ["loop"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","sort","%values%"], + ["store","values"], + ["return","%names%","%values%"] + ]`, ``, `[["four","one","three","two"],[1.5,2.5,3.5,4.5]]`) + + multicall(t, bc, "ac1", `[ + ["let","obj",{}], + ["let","counter",0], + ["forpair","key","value","%obj%"], + ["add","%counter%",1], + ["store","counter"], + ["loop"], + ["return","%counter%"] + ]`, ``, `0`) + + + + // FOR "BREAK" + + multicall(t, bc, "ac1", `[ + ["let","c",0], + ["for","n",1,10], + ["add","%c%",1], + ["store","c"], + ["if","%n%","=",5], + ["let","n",500], + ["end"], + ["loop"], + ["return","%c%"] + ]`, ``, `5`) + + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",500,10,-5], + ["add","%last_result%",1], + ["if","%n%","=",475], + ["let","n",2], + ["end"], + ["loop"], + ["return","%last_result%"] + ]`, ``, `6`) + + multicall(t, bc, "ac1", `[ + ["let","c",0], + ["for","n",1,10], + ["add","%c%",1], + ["store","c"], + ["if","%n%","=",5], + ["break"], + ["end"], + ["loop"], + ["return","%c%"] + ]`, ``, `5`) + + multicall(t, bc, "ac1", `[ + ["let","c",0], + ["for","n",1,10], + ["add","%c%",1], + ["store","c"], + ["break","if","%n%","=",5], + ["loop"], + ["return","%c%"] + ]`, ``, `5`) + + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",500,10,-5], + ["add","%last_result%",1], + ["if","%n%","=",475], + ["break"], + ["end"], + ["loop"], + ["return","%last_result%"] + ]`, ``, `6`) + + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",500,10,-5], + ["add","%last_result%",1], + ["break","if","%n%","=",475], + ["loop"], + ["return","%last_result%"] + ]`, ``, `6`) + + multicall(t, bc, "ac1", `[ + ["for","n",1,5], + ["loop"], + ["return","%n%"] + ]`, ``, `6`) + + multicall(t, bc, "ac1", `[ + ["for","n",1,5], + ["break"], + ["loop"], + ["return","%n%"] + ]`, ``, `1`) + + multicall(t, bc, "ac1", `[ + ["let","names",[]], + ["let","list",["one","two","three","four"]], + ["foreach","item","%list%"], + ["if","%item%","=","three"], + ["break"], + ["end"], + ["insert","%names%","%item%"], + ["loop"], + ["return","%names%"] + ]`, ``, `["one","two"]`) + + multicall(t, bc, "ac1", `[ + ["let","names",[]], + ["let","list",["one","two","three","four"]], + ["foreach","item","%list%"], + ["break","if","%item%","=","three"], + ["insert","%names%","%item%"], + ["loop"], + ["return","%names%"] + ]`, ``, `["one","two"]`) + + multicall(t, bc, "ac1", `[ + ["let","names",[]], + ["let","obj",{"one":true,"two":false,"three":false,"four":true}], + ["forpair","key","value","%obj%"], + ["if","%value%","=",false], + ["break"], + ["end"], + ["insert","%names%","%key%"], + ["loop"], + ["return","%names%"] + ]`, ``, `["four","one"]`) + + multicall(t, bc, "ac1", `[ + ["let","names",[]], + ["let","obj",{"one":true,"two":false,"three":false,"four":true}], + ["forpair","key","value","%obj%"], + ["break","if","%value%","=",false], + ["insert","%names%","%key%"], + ["loop"], + ["return","%names%"] + ]`, ``, `["four","one"]`) + + + // RETURN before the end multicall(t, bc, "ac1", `[ @@ -6915,6 +7207,21 @@ abi.payable(recv_aergo) + // FULL LOOPS + + multicall(t, bc, "ac1", `[ + ["let","c","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA"], + ["call","%c%","inc","n"], + ["call","%c%","get","n"], + ["if","%last_result%",">=",5], + ["return","%last_result%"], + ["end"], + ["loop"] + ]`, ``, `5`) + + + + // CALLS multicall(t, bc, "ac1", `[ @@ -7113,7 +7420,7 @@ abi.payable(recv_aergo) - // aergo balance and send + // aergo BALANCE and SEND multicall(t, bc, "ac5", `[ ["balance"], From a3e3ca488f63c27f06db239fd779144ebccdb930 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Mon, 15 Aug 2022 15:36:39 -0300 Subject: [PATCH 011/182] [contract] fix error messages on multicall code --- contract/vm.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contract/vm.go b/contract/vm.go index 50d90747f..ed1751f36 100644 --- a/contract/vm.go +++ b/contract/vm.go @@ -1386,7 +1386,11 @@ func vmAutoload(L *LState, funcName string) bool { func (ce *executor) vmLoadCode(id []byte) { var chunkId *C.char if HardforkConfig.IsV3Fork(ce.ctx.blockInfo.No) { - chunkId = C.CString("@" + types.EncodeAddress(id)) + if ce.ctx.isMultiCall { + chunkId = C.CString("@multicall") + } else { + chunkId = C.CString("@" + types.EncodeAddress(id)) + } } else { chunkId = C.CString(hex.EncodeToString(id)) } From cb4344a58c1a70e5e1d1e8cf3df6eb4f65cc2de6 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 16 Aug 2022 02:59:29 -0300 Subject: [PATCH 012/182] [chain] fix recipient handling for multicall --- chain/chainhandle.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/chain/chainhandle.go b/chain/chainhandle.go index 47010d0ee..fd64b145d 100644 --- a/chain/chainhandle.go +++ b/chain/chainhandle.go @@ -921,9 +921,7 @@ func executeTx( isMultiCall := (txBody.Type == types.TxType_MULTICALL) - if isMultiCall { - recipient = account - } else { + if !isMultiCall { if recipient, err = name.Resolve(bs, txBody.Recipient, isQuirkTx); err != nil { return err } @@ -932,7 +930,7 @@ func executeTx( var receiver *state.V status := "SUCCESS" if isMultiCall { - receiver = sender + // no receiver } else if len(recipient) > 0 { receiver, err = bs.GetAccountStateV(recipient) if receiver != nil && txBody.Type == types.TxType_REDEPLOY { From 9ed69370c09e7e856e7e339c5632857f5ff35e7b Mon Sep 17 00:00:00 2001 From: Sung-Jae Woo Date: Thu, 6 Oct 2022 15:58:57 +0900 Subject: [PATCH 013/182] [contract] pcall: drop events upon error From the chain version 3, when pcall returns with error, events generated by it are dropped. To implement this behaviour, pcall is overriden by a custom C function. --- contract/vm.c | 62 +++++++++++++++++++++++++++++++++++------ contract/vm_callback.go | 36 ++++++++++++++---------- contract/vm_test.go | 2 +- 3 files changed, 75 insertions(+), 25 deletions(-) diff --git a/contract/vm.c b/contract/vm.c index f3002719d..13cfe52dd 100644 --- a/contract/vm.c +++ b/contract/vm.c @@ -22,6 +22,14 @@ extern void (*lj_internal_view_end)(lua_State *); void vm_internal_view_start(lua_State *L); void vm_internal_view_end(lua_State *L); +int getLuaExecContext(lua_State *L) +{ + int service = luaL_service(L); + if (service < 0) + luaL_error(L, "not permitted state referencing at global scope"); + return service; +} + static void preloadModules(lua_State *L) { int status; @@ -56,6 +64,39 @@ static void preloadModules(lua_State *L) #endif } +static int pcall(lua_State *L) +{ + /* Override pcall to drop events upon error */ + int service = getLuaExecContext(L); + int status, from; + + from = luaGetEventCount(L, service); + + luaL_checkany(L, 1); + status = lua_pcall(L, lua_gettop(L) - 1, -1, 0); + lua_pushboolean(L, status == 0); + lua_insert(L, 1); + + if (status != 0) + { + luaDropEvent(L, service, from); + } + + return lua_gettop(L); +} + +static const struct luaL_Reg _basefuncs[] = { + {"pcall", pcall}, + {NULL, NULL}}; + +static void override_basefuncs(lua_State *L) +{ + // Override Lua builtins functions. + lua_getglobal(L, "_G"); + luaL_register(L, NULL, _basefuncs); + lua_pop(L, 1); +} + static int loadLibs(lua_State *L) { luaL_openlibs(L); @@ -63,6 +104,13 @@ static int loadLibs(lua_State *L) return 0; } +static int loadLibsV3(lua_State *L) +{ + loadLibs(L); + override_basefuncs(L); + return 0; +} + lua_State *vm_newstate(uint8_t use_lock) { lua_State *L = NULL; @@ -73,7 +121,11 @@ lua_State *vm_newstate(uint8_t use_lock) int status; if (L == NULL) return NULL; - status = lua_cpcall(L, loadLibs, NULL); + if (use_lock) + // Overide pcall to drop events upon error. + status = lua_cpcall(L, loadLibsV3, NULL); + else + status = lua_cpcall(L, loadLibs, NULL); if (status != 0) return NULL; return L; @@ -94,14 +146,6 @@ void initViewFunction() lj_internal_view_end = vm_internal_view_end; } -int getLuaExecContext(lua_State *L) -{ - int service = luaL_service(L); - if (service < 0) - luaL_error(L, "not permitted state referencing at global scope"); - return service; -} - bool vm_is_hardfork(lua_State *L, int version) { int v = luaL_hardforkversion(L); diff --git a/contract/vm_callback.go b/contract/vm_callback.go index 219ad59ee..c9bfa6e76 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -1228,6 +1228,27 @@ func luaEvent(L *LState, service C.int, eventName *C.char, args *C.char) *C.char return nil } +//export luaGetEventCount +func luaGetEventCount(L *LState, service C.int) C.int { + eventCount := contexts[service].eventCount + if ctrLgr.IsDebugEnabled() { + ctrLgr.Debug().Int32("eventCount", eventCount).Msg("get event count") + } + return C.int(eventCount) +} + +//export luaDropEvent +func luaDropEvent(L *LState, service C.int, from C.int) { + // Drop all the events after the given index. + ctx := contexts[service] + if ctrLgr.IsDebugEnabled() { + ctrLgr.Debug().Int32("from", int32(from)).Int("len", len(ctx.events)).Msg("drop events") + } + if from >= 0 { + ctx.events = ctx.events[:from] + } +} + //export luaIsContract func luaIsContract(L *LState, service C.int, contractId *C.char) (C.int, *C.char) { ctx := contexts[service] @@ -1388,21 +1409,6 @@ func luaCheckTimeout(service C.int) C.int { default: return 0 } - - // Temporarily disable timeout check to prevent contract timeout raised from chain service - // if service < BlockFactory { - // service = service + MaxVmService - // } - // if service != BlockFactory { - // return 0 - // } - // select { - // case <-bpTimeout: - // return 1 - // default: - // return 0 - // } - //return 0 } //export luaIsFeeDelegation diff --git a/contract/vm_test.go b/contract/vm_test.go index ec52ad3b9..ebc146ed7 100644 --- a/contract/vm_test.go +++ b/contract/vm_test.go @@ -5845,7 +5845,7 @@ func TestBF(t *testing.T) { OldV3 := HardforkConfig.V3 HardforkConfig.V3 = types.BlockNo(0) - feeTest(47513803) + feeTest(47513659) HardforkConfig.V3 = OldV3 } From b9d15025d0dca6784789f9ea31104278f7122ed9 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 18 Jan 2023 19:45:19 -0300 Subject: [PATCH 014/182] [contract] contract.pcall: drop events on error --- contract/contract_module.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contract/contract_module.c b/contract/contract_module.c index cbea9e919..3b5a4d89d 100644 --- a/contract/contract_module.c +++ b/contract/contract_module.c @@ -290,6 +290,7 @@ static int modulePcall(lua_State *L) { int argc = lua_gettop(L) - 1; int service = getLuaExecContext(L); + int num_events = luaGetEventCount(L, service); struct luaSetRecoveryPoint_return start_seq; int ret; @@ -307,6 +308,7 @@ static int modulePcall(lua_State *L) } lua_pushboolean(L, false); lua_insert(L, 1); + luaDropEvent(L, service, num_events); if (start_seq.r0 > 0) { char *errStr = luaClearRecovery(L, service, start_seq.r0, true); if (errStr != NULL) { @@ -321,6 +323,7 @@ static int modulePcall(lua_State *L) if (start_seq.r0 == 1) { char *errStr = luaClearRecovery(L, service, start_seq.r0, false); if (errStr != NULL) { + luaDropEvent(L, service, num_events); strPushAndRelease(L, errStr); luaL_throwerror(L); } From 88b880e40967e026680a2417c3716b9fe1a2f63f Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 18 Jan 2023 19:49:06 -0300 Subject: [PATCH 015/182] [contract] update eventCount when dropping events --- contract/vm_callback.go | 1 + 1 file changed, 1 insertion(+) diff --git a/contract/vm_callback.go b/contract/vm_callback.go index c9bfa6e76..1c2e14fa3 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -1246,6 +1246,7 @@ func luaDropEvent(L *LState, service C.int, from C.int) { } if from >= 0 { ctx.events = ctx.events[:from] + ctx.eventCount = len(ctx.events) } } From e8a7232c5eb137c5152cec8afb0da705380deba8 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 31 Jan 2023 00:02:58 -0300 Subject: [PATCH 016/182] [contract] fix: check for V3 when dropping events --- contract/contract_module.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/contract/contract_module.c b/contract/contract_module.c index 3b5a4d89d..a382f7b94 100644 --- a/contract/contract_module.c +++ b/contract/contract_module.c @@ -308,7 +308,9 @@ static int modulePcall(lua_State *L) } lua_pushboolean(L, false); lua_insert(L, 1); - luaDropEvent(L, service, num_events); + if (vm_is_hardfork(L, 3)) { + luaDropEvent(L, service, num_events); + } if (start_seq.r0 > 0) { char *errStr = luaClearRecovery(L, service, start_seq.r0, true); if (errStr != NULL) { @@ -323,7 +325,9 @@ static int modulePcall(lua_State *L) if (start_seq.r0 == 1) { char *errStr = luaClearRecovery(L, service, start_seq.r0, false); if (errStr != NULL) { - luaDropEvent(L, service, num_events); + if (vm_is_hardfork(L, 3)) { + luaDropEvent(L, service, num_events); + } strPushAndRelease(L, errStr); luaL_throwerror(L); } From d1ba2f8df0d0974979c5d5eec9eb9d94247e7858 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Mon, 13 Feb 2023 00:47:56 -0300 Subject: [PATCH 017/182] [contract] fix: convert int to int32 --- contract/vm_callback.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contract/vm_callback.go b/contract/vm_callback.go index 1c2e14fa3..0eba989af 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -1246,7 +1246,7 @@ func luaDropEvent(L *LState, service C.int, from C.int) { } if from >= 0 { ctx.events = ctx.events[:from] - ctx.eventCount = len(ctx.events) + ctx.eventCount = int32(len(ctx.events)) } } From 96eadecb71f8ffc48381bfb687e791c9bf5a6207 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 16 Feb 2023 00:25:11 -0300 Subject: [PATCH 018/182] [contract] fix: support for hex and binary bignum hex (0x) and binary (0b) formats are kept --- contract/lgmp.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/contract/lgmp.c b/contract/lgmp.c index d205b5b0f..ed35afee5 100644 --- a/contract/lgmp.c +++ b/contract/lgmp.c @@ -67,7 +67,12 @@ const char *lua_set_bignum(lua_State *L, char *s) return mp_num_memory_error; } if (vm_is_hardfork(L, 3)) { - while (s && s[0]=='0' && s[1]!=0) s++; + // remove support for octal format and + // keep support for hex (0x) and binary (0b) formats + if (s && s[0]=='0' && s[1]!=0 && s[1]!='x' && s[1]!='b') { + // convert "0123" -> "123" + while (s && s[0]=='0' && s[1]!=0) s++; + } } if (mpz_init_set_str(x->mpptr, s, 0) != 0) { mp_num_free(x); @@ -124,7 +129,12 @@ static mp_num Bget(lua_State *L, int i) if (x == NULL) luaL_error(L, mp_num_memory_error); if (vm_is_hardfork(L, 3)) { - while (s && s[0]=='0' && s[1]!=0) s++; + // remove support for octal format and + // keep support for hex (0x) and binary (0b) formats + if (s && s[0]=='0' && s[1]!=0 && s[1]!='x' && s[1]!='b') { + // convert "0123" -> "123" + while (s && s[0]=='0' && s[1]!=0) s++; + } } if (mpz_init_set_str(x->mpptr, s, 0) != 0) { mp_num_free(x); From 3c468d76c19ceebf84aab3f4bd69c1925d64f0d9 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 3 Mar 2023 04:14:38 -0300 Subject: [PATCH 019/182] [contract] check for V4 when dropping events --- contract/contract_module.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contract/contract_module.c b/contract/contract_module.c index a382f7b94..e6a513a9f 100644 --- a/contract/contract_module.c +++ b/contract/contract_module.c @@ -308,7 +308,7 @@ static int modulePcall(lua_State *L) } lua_pushboolean(L, false); lua_insert(L, 1); - if (vm_is_hardfork(L, 3)) { + if (vm_is_hardfork(L, 4)) { luaDropEvent(L, service, num_events); } if (start_seq.r0 > 0) { @@ -325,7 +325,7 @@ static int modulePcall(lua_State *L) if (start_seq.r0 == 1) { char *errStr = luaClearRecovery(L, service, start_seq.r0, false); if (errStr != NULL) { - if (vm_is_hardfork(L, 3)) { + if (vm_is_hardfork(L, 4)) { luaDropEvent(L, service, num_events); } strPushAndRelease(L, errStr); From 395617461e6849fe9de971e68c38cce03cd7c699 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 3 Mar 2023 04:23:39 -0300 Subject: [PATCH 020/182] [contract] V4: support for hex and binary formats --- contract/lgmp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/contract/lgmp.c b/contract/lgmp.c index ed35afee5..e08a9397d 100644 --- a/contract/lgmp.c +++ b/contract/lgmp.c @@ -66,13 +66,16 @@ const char *lua_set_bignum(lua_State *L, char *s) if (x == NULL) { return mp_num_memory_error; } - if (vm_is_hardfork(L, 3)) { + if (vm_is_hardfork(L, 4)) { // remove support for octal format and // keep support for hex (0x) and binary (0b) formats if (s && s[0]=='0' && s[1]!=0 && s[1]!='x' && s[1]!='b') { // convert "0123" -> "123" while (s && s[0]=='0' && s[1]!=0) s++; } + } else if (vm_is_hardfork(L, 3)) { + // previous code remove support for octal, hex and binary formats + while (s && s[0]=='0' && s[1]!=0) s++; } if (mpz_init_set_str(x->mpptr, s, 0) != 0) { mp_num_free(x); @@ -128,13 +131,16 @@ static mp_num Bget(lua_State *L, int i) x = bn_alloc(BN_Integer); if (x == NULL) luaL_error(L, mp_num_memory_error); - if (vm_is_hardfork(L, 3)) { + if (vm_is_hardfork(L, 4)) { // remove support for octal format and // keep support for hex (0x) and binary (0b) formats if (s && s[0]=='0' && s[1]!=0 && s[1]!='x' && s[1]!='b') { // convert "0123" -> "123" while (s && s[0]=='0' && s[1]!=0) s++; } + } else if (vm_is_hardfork(L, 3)) { + // previous code remove support for octal, hex and binary formats + while (s && s[0]=='0' && s[1]!=0) s++; } if (mpz_init_set_str(x->mpptr, s, 0) != 0) { mp_num_free(x); From 9237ef10d5918015f7b5cf58232202db2d45c17d Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 2 May 2023 19:31:33 -0300 Subject: [PATCH 021/182] [contract] add system.resolve() --- contract/system_module.c | 24 ++++++++++++++++++++++++ contract/vm_callback.go | 13 +++++++++++++ 2 files changed, 37 insertions(+) diff --git a/contract/system_module.c b/contract/system_module.c index 895c986b0..8a34919f9 100644 --- a/contract/system_module.c +++ b/contract/system_module.c @@ -458,6 +458,29 @@ static int is_contract(lua_State *L) return 1; } +static int resolve(lua_State *L) +{ + char *name, *ret; + int service = getLuaExecContext(L); + + lua_gasuse(L, 100); + + name = (char *)luaL_checkstring(L, 1); + ret = luaResolve(L, service, name); + + if (ret == NULL) { + lua_pushnil(L); + } else { + strPushAndRelease(L, ret); + // if the returned string starts with `[`, it's an error + if (ret[0] == '[') { + luaL_throwerror(L); + } + } + + return 1; +} + static int is_fee_delegation(lua_State *L) { int service = getLuaExecContext(L); @@ -493,6 +516,7 @@ static const luaL_Reg sys_lib[] = { {"time", os_time}, {"difftime", os_difftime}, {"random", lua_random}, + {"resolve", resolve}, {"isContract", is_contract}, {"isFeeDelegation", is_fee_delegation}, {NULL, NULL} diff --git a/contract/vm_callback.go b/contract/vm_callback.go index 219ad59ee..ef914a26b 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -1247,6 +1247,19 @@ func luaIsContract(L *LState, service C.int, contractId *C.char) (C.int, *C.char return C.int(len(cs.curState.GetCodeHash())), nil } +//export luaResolve +func luaResolve(L *LState, service C.int, name *C.char) *C.char { + ctx := contexts[service] + if ctx == nil { + return C.CString("[Contract.LuaResolve] contract state not found") + } + addr, err := getAddressNameResolved(C.GoString(name), ctx.bs) + if err != nil { + return C.CString("[Contract.LuaResolve] invalid name: " + err.Error()) + } + return C.CString(types.EncodeAddress(addr)) +} + //export luaGovernance func luaGovernance(L *LState, service C.int, gType C.char, arg *C.char) *C.char { ctx := contexts[service] From e45ed4b00e8351d69a6edf84d5c2ed6e58f9bdbe Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 3 May 2023 00:37:36 -0300 Subject: [PATCH 022/182] [contract] system.toAddress() + system.toPubkey() --- contract/system_module.c | 50 ++++++++++++++++++++++++++++++++++++++++ contract/vm_callback.go | 33 ++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/contract/system_module.c b/contract/system_module.c index 895c986b0..1a03b6884 100644 --- a/contract/system_module.c +++ b/contract/system_module.c @@ -436,6 +436,54 @@ static int lua_random(lua_State *L) return 1; } +static int toPubkey(lua_State *L) +{ + char *address, *ret; + + lua_gasuse(L, 100); + + // get the function argument + address = (char *)luaL_checkstring(L, 1); + // convert the address to public key + ret = luaToPubkey(L, address); + + if (ret == NULL) { + lua_pushnil(L); + } else { + strPushAndRelease(L, ret); + // if the returned string starts with `[`, it's an error + if (ret[0] == '[') { + luaL_throwerror(L); + } + } + + return 1; +} + +static int toAddress(lua_State *L) +{ + char *pubkey, *ret; + + lua_gasuse(L, 100); + + // get the function argument + pubkey = (char *)luaL_checkstring(L, 1); + // convert the public key to an address + ret = luaToAddress(L, pubkey); + + if (ret == NULL) { + lua_pushnil(L); + } else { + strPushAndRelease(L, ret); + // if the returned string starts with `[`, it's an error + if (ret[0] == '[') { + luaL_throwerror(L); + } + } + + return 1; +} + static int is_contract(lua_State *L) { char *contract; @@ -493,6 +541,8 @@ static const luaL_Reg sys_lib[] = { {"time", os_time}, {"difftime", os_difftime}, {"random", lua_random}, + {"toPubkey", toPubkey}, + {"toAddress", toAddress}, {"isContract", is_contract}, {"isFeeDelegation", is_fee_delegation}, {NULL, NULL} diff --git a/contract/vm_callback.go b/contract/vm_callback.go index 219ad59ee..703d12b5d 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -1228,6 +1228,39 @@ func luaEvent(L *LState, service C.int, eventName *C.char, args *C.char) *C.char return nil } +//export luaToPubkey +func luaToPubkey(L *LState, address *C.char) *C.char { + // check the length of address + if len(address) != types.EncodedAddressLength { + return C.CString("[Contract.LuaToPubkey] invalid address length") + } + // decode the address in string format to bytes (public key) + pubkey, err := types.DecodeAddress(C.GoString(address)) + if err != nil { + return C.CString("[Contract.LuaToPubkey] invalid address: " + err.Error()) + } + // return the public key in hex format + return C.CString("0x" + hex.EncodeToString(pubkey)) +} + +//export luaToAddress +func luaToAddress(L *LState, pubkey *C.char) *C.char { + // decode the pubkey in hex format to bytes + pubkeyBytes, err := decodeHex(C.GoString(pubkey)) + if err != nil { + return C.CString("[Contract.LuaToAddress] invalid public key") + } + // check the length of pubkey + if len(pubkeyBytes) != types.AddressLength { + return C.CString("[Contract.LuaToAddress] invalid public key length") + // or convert the pubkey to compact format - SerializeCompressed() + } + // encode the pubkey in bytes to an address in string format + address := types.EncodeAddress(pubkeyBytes) + // return the address + return C.CString(address) +} + //export luaIsContract func luaIsContract(L *LState, service C.int, contractId *C.char) (C.int, *C.char) { ctx := contexts[service] From 1327d4da33394b21ab4e3f4c43daee40be781e6a Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 3 May 2023 00:44:38 -0300 Subject: [PATCH 023/182] [contract] simplify error message --- contract/vm_callback.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contract/vm_callback.go b/contract/vm_callback.go index 703d12b5d..600e63cfd 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -1237,7 +1237,7 @@ func luaToPubkey(L *LState, address *C.char) *C.char { // decode the address in string format to bytes (public key) pubkey, err := types.DecodeAddress(C.GoString(address)) if err != nil { - return C.CString("[Contract.LuaToPubkey] invalid address: " + err.Error()) + return C.CString("[Contract.LuaToPubkey] invalid address") } // return the public key in hex format return C.CString("0x" + hex.EncodeToString(pubkey)) From c136e02a22f242510eaf66d2b390d0d4f2b30eb0 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 3 May 2023 21:39:11 -0300 Subject: [PATCH 024/182] [contract] create the name_service module --- contract/name_module.c | 46 ++++++++++++++++++++++++++++++++++++++++ contract/name_module.h | 8 +++++++ contract/system_module.c | 24 --------------------- contract/vm.c | 2 ++ 4 files changed, 56 insertions(+), 24 deletions(-) create mode 100644 contract/name_module.c create mode 100644 contract/name_module.h diff --git a/contract/name_module.c b/contract/name_module.c new file mode 100644 index 000000000..fccb8333b --- /dev/null +++ b/contract/name_module.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include "vm.h" +#include "util.h" +#include "_cgo_export.h" + +//#define STATE_DB_KEY_PREFIX "_" + +extern int getLuaExecContext(lua_State *L); + +static int resolve(lua_State *L) +{ + char *name, *ret; + int service = getLuaExecContext(L); + + lua_gasuse(L, 100); + + name = (char *)luaL_checkstring(L, 1); + ret = luaResolve(L, service, name); + + if (ret == NULL) { + lua_pushnil(L); + } else { + strPushAndRelease(L, ret); + // if the returned string starts with `[`, it's an error + if (ret[0] == '[') { + luaL_throwerror(L); + } + } + + return 1; +} + +static const luaL_Reg sys_lib[] = { + {"resolve", resolve}, + {NULL, NULL} +}; + +int luaopen_name(lua_State *L) +{ + luaL_register(L, "name_service", sys_lib); + lua_pop(L, 1); + return 1; +} diff --git a/contract/name_module.h b/contract/name_module.h new file mode 100644 index 000000000..9099f9ceb --- /dev/null +++ b/contract/name_module.h @@ -0,0 +1,8 @@ +#ifndef _NAME_MODULE_H +#define _NAME_MODULE_H + +#include "lua.h" + +extern int luaopen_name(lua_State *L); + +#endif /* _NAME_MODULE_H */ \ No newline at end of file diff --git a/contract/system_module.c b/contract/system_module.c index 8a34919f9..895c986b0 100644 --- a/contract/system_module.c +++ b/contract/system_module.c @@ -458,29 +458,6 @@ static int is_contract(lua_State *L) return 1; } -static int resolve(lua_State *L) -{ - char *name, *ret; - int service = getLuaExecContext(L); - - lua_gasuse(L, 100); - - name = (char *)luaL_checkstring(L, 1); - ret = luaResolve(L, service, name); - - if (ret == NULL) { - lua_pushnil(L); - } else { - strPushAndRelease(L, ret); - // if the returned string starts with `[`, it's an error - if (ret[0] == '[') { - luaL_throwerror(L); - } - } - - return 1; -} - static int is_fee_delegation(lua_State *L) { int service = getLuaExecContext(L); @@ -516,7 +493,6 @@ static const luaL_Reg sys_lib[] = { {"time", os_time}, {"difftime", os_difftime}, {"random", lua_random}, - {"resolve", resolve}, {"isContract", is_contract}, {"isFeeDelegation", is_fee_delegation}, {NULL, NULL} diff --git a/contract/vm.c b/contract/vm.c index f3002719d..1a0b12a40 100644 --- a/contract/vm.c +++ b/contract/vm.c @@ -4,6 +4,7 @@ #include "vm.h" #include "system_module.h" #include "contract_module.h" +#include "name_module.h" #include "db_module.h" #include "state_module.h" #include "crypto_module.h" @@ -29,6 +30,7 @@ static void preloadModules(lua_State *L) luaopen_system(L); luaopen_contract(L); luaopen_state(L); + luaopen_name(L); luaopen_json(L); luaopen_crypto(L); luaopen_gmp(L); From d4e2bce0598a9b51bf7d7b72801db2adaf3f7d1c Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 3 May 2023 21:47:22 -0300 Subject: [PATCH 025/182] [contract] rename struct --- contract/name_module.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/contract/name_module.c b/contract/name_module.c index fccb8333b..646b63be0 100644 --- a/contract/name_module.c +++ b/contract/name_module.c @@ -1,13 +1,9 @@ #include #include -#include -#include #include "vm.h" #include "util.h" #include "_cgo_export.h" -//#define STATE_DB_KEY_PREFIX "_" - extern int getLuaExecContext(lua_State *L); static int resolve(lua_State *L) @@ -33,14 +29,14 @@ static int resolve(lua_State *L) return 1; } -static const luaL_Reg sys_lib[] = { +static const luaL_Reg name_service_lib[] = { {"resolve", resolve}, {NULL, NULL} }; int luaopen_name(lua_State *L) { - luaL_register(L, "name_service", sys_lib); + luaL_register(L, "name_service", name_service_lib); lua_pop(L, 1); return 1; } From 96a4075497657708db285e76dde8033c43ed4b02 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Mon, 8 May 2023 06:47:06 +0000 Subject: [PATCH 026/182] [name_service] fix name_service.resolve() --- contract/name_module.c | 4 +++- contract/vm_callback.go | 14 +++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/contract/name_module.c b/contract/name_module.c index 646b63be0..31580be42 100644 --- a/contract/name_module.c +++ b/contract/name_module.c @@ -19,10 +19,12 @@ static int resolve(lua_State *L) if (ret == NULL) { lua_pushnil(L); } else { - strPushAndRelease(L, ret); // if the returned string starts with `[`, it's an error if (ret[0] == '[') { + strPushAndRelease(L, ret); luaL_throwerror(L); + } else { + strPushAndRelease(L, ret); } } diff --git a/contract/vm_callback.go b/contract/vm_callback.go index ef914a26b..a94fe7ba1 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -1248,14 +1248,22 @@ func luaIsContract(L *LState, service C.int, contractId *C.char) (C.int, *C.char } //export luaResolve -func luaResolve(L *LState, service C.int, name *C.char) *C.char { +func luaResolve(L *LState, service C.int, name_or_address *C.char) *C.char { ctx := contexts[service] if ctx == nil { return C.CString("[Contract.LuaResolve] contract state not found") } - addr, err := getAddressNameResolved(C.GoString(name), ctx.bs) + var addr []byte + var err error + account := C.GoString(name_or_address) + if len(account) == types.EncodedAddressLength { + // also checks if valid address + addr, err = types.DecodeAddress(account) + } else { + addr, err = name.Resolve(ctx.bs, []byte(account), false) + } if err != nil { - return C.CString("[Contract.LuaResolve] invalid name: " + err.Error()) + return C.CString("[Contract.LuaResolve] " + err.Error()) } return C.CString(types.EncodeAddress(addr)) } From cf2c2f40d751f947df43eed441c6c479470db4cc Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Mon, 8 May 2023 07:05:04 +0000 Subject: [PATCH 027/182] add functional tests for name service --- tests/test-name-service.lua | 6 ++ tests/test-name-service.sh | 163 ++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 tests/test-name-service.lua create mode 100755 tests/test-name-service.sh diff --git a/tests/test-name-service.lua b/tests/test-name-service.lua new file mode 100644 index 000000000..fb8046297 --- /dev/null +++ b/tests/test-name-service.lua @@ -0,0 +1,6 @@ + +function resolve(name) + return name_service.resolve(name) +end + +abi.register(resolve) diff --git a/tests/test-name-service.sh b/tests/test-name-service.sh new file mode 100755 index 000000000..f83e6a38c --- /dev/null +++ b/tests/test-name-service.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env bash + +assert_equals() { + local var="$1" + local expected="$2" + + if [[ ! "$var" == "$expected" ]]; then + echo "Assertion failed: $var != $expected" + echo "File: \"$0\", Line: \"$3\"" + exit 1 + fi +} + + + +../bin/aergocli account import --keystore . --if 47zh1byk8MqWkQo5y8dvbrex99ZMdgZqfydar7w2QQgQqc7YrmFsBuMeF1uHWa5TwA1ZwQ7V6 --password bmttest + + +echo "-- deploy contract --" + +../bin/aergoluac --payload test-name-service.lua > test.out + +txhash=$(../bin/aergocli --keystore . \ + contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + --payload `cat test.out` --password bmttest | jq .hash | sed 's/"//g') + +sleep 1 + +sc_id=`../bin/aergocli receipt get $txhash | jq '.contractAddress' | sed 's/"//g'` + + + +echo "-- call contract with an invalid address --" + +txhash=$(../bin/aergocli --keystore . contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + ${sc_id} resolve '["AmgExqUu6J4Za8VjyWMJANxoRaUvwgngGQJgemHgwWvuRSEd3wnX"]' \ + --password bmttest | jq .hash | sed 's/"//g') + +sleep 1 + +../bin/aergocli receipt get $txhash > receipt.json + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') + +assert_equals "$status" "ERROR" +assert_equals "$ret" "[Contract.LuaResolve] Data and checksum don't match" + + +echo "-- call contract with a valid address --" + +txhash=$(../bin/aergocli --keystore . contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + ${sc_id} resolve '["AmgExqUu6J4Za8VjyWMJANxoRaUvwgngGQJgemHgwWvuRSEd3wnE"]' \ + --password bmttest | jq .hash | sed 's/"//g') + +sleep 1 + +../bin/aergocli receipt get $txhash > receipt.json + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') + +assert_equals "$status" "SUCCESS" +assert_equals "$ret" "AmgExqUu6J4Za8VjyWMJANxoRaUvwgngGQJgemHgwWvuRSEd3wnE" + + +echo "-- call contract with invalid name --" + +txhash=$(../bin/aergocli --keystore . contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + ${sc_id} resolve '["long_name-with-invalid.chars"]' \ + --password bmttest | jq .hash | sed 's/"//g') + +sleep 1 + +../bin/aergocli receipt get $txhash > receipt.json + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') + +assert_equals "$status" "SUCCESS" +assert_equals "$ret" "" + + +echo "-- call contract with valid but not set name --" + +txhash=$(../bin/aergocli --keystore . contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + ${sc_id} resolve '["testnametest"]' --password bmttest | jq .hash | sed 's/"//g') + +sleep 1 + +../bin/aergocli receipt get $txhash > receipt.json + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') + +assert_equals "$status" "SUCCESS" +assert_equals "$ret" "" + + +echo "-- register a new account name --" + +txhash=$(../bin/aergocli --keystore . name new --name="testnametest" \ + --from AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + --password bmttest | jq .hash | sed 's/"//g') + +sleep 1 + +../bin/aergocli receipt get $txhash > receipt.json + +status=$(cat receipt.json | jq .status | sed 's/"//g') + +assert_equals "$status" "SUCCESS" + + +echo "-- call contract --" + +txhash=$(../bin/aergocli --keystore . contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + ${sc_id} resolve '["testnametest"]' --password bmttest | jq .hash | sed 's/"//g') + +sleep 1 + +../bin/aergocli receipt get $txhash > receipt.json + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') + +assert_equals "$status" "SUCCESS" +assert_equals "$ret" "AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R" + + +echo "-- transfer the name --" + +txhash=$(../bin/aergocli --keystore . name update --name="testnametest" \ + --from AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + --to Amh9vfP5My5DpSafe3gcZ1u8DiZNuqHSN2oAWehZW1kgB3XP4kPi \ + --password bmttest | jq .hash | sed 's/"//g') + +sleep 1 + +../bin/aergocli receipt get $txhash > receipt.json + +status=$(cat receipt.json | jq .status | sed 's/"//g') + +assert_equals "$status" "SUCCESS" + + +echo "-- call contract --" + +txhash=$(../bin/aergocli --keystore . contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + ${sc_id} resolve '["testnametest"]' --password bmttest | jq .hash | sed 's/"//g') + +sleep 1 + +../bin/aergocli receipt get $txhash > receipt.json +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') + +assert_equals "$status" "SUCCESS" +assert_equals "$ret" "Amh9vfP5My5DpSafe3gcZ1u8DiZNuqHSN2oAWehZW1kgB3XP4kPi" + + +echo "" +echo "All tests pass" From 9e557b6aea3fe929eeed998b7cb3d8ecdf22363d Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Mon, 8 May 2023 07:28:12 +0000 Subject: [PATCH 028/182] add run_tests.sh --- tests/run_tests.sh | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100755 tests/run_tests.sh diff --git a/tests/run_tests.sh b/tests/run_tests.sh new file mode 100755 index 000000000..29d4ee405 --- /dev/null +++ b/tests/run_tests.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +# open the aergo server in testmode to create the config file +../bin/aergosvr --testmode > logs 2> logs & +pid=$! +# wait it create the config file +sleep 3 +# terminate the server process +kill $pid +# enable the block production on the config file +sed -i 's/^enablebp = false$/enablebp = true/' ~/.aergo/config.toml +# restart the aergo server in testmode +../bin/aergosvr --testmode > logs 2> logs & +pid=$! +sleep 3 + +# run the integration tests +./test-name-service.sh + +# terminate the server process +kill $pid From c3dc31d87279a6c4a8994623ebf1a4a2ade57bbb Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Mon, 8 May 2023 08:05:04 +0000 Subject: [PATCH 029/182] test name resolver on contract query --- tests/run_tests.sh | 3 +++ tests/test-name-service.sh | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 29d4ee405..ab2b6dea1 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -1,5 +1,8 @@ #!/usr/bin/env bash +# delete the aergo folder +rm -r ~/.aergo/ + # open the aergo server in testmode to create the config file ../bin/aergosvr --testmode > logs 2> logs & pid=$! diff --git a/tests/test-name-service.sh b/tests/test-name-service.sh index f83e6a38c..1ad694dd8 100755 --- a/tests/test-name-service.sh +++ b/tests/test-name-service.sh @@ -6,7 +6,6 @@ assert_equals() { if [[ ! "$var" == "$expected" ]]; then echo "Assertion failed: $var != $expected" - echo "File: \"$0\", Line: \"$3\"" exit 1 fi } @@ -159,5 +158,13 @@ assert_equals "$status" "SUCCESS" assert_equals "$ret" "Amh9vfP5My5DpSafe3gcZ1u8DiZNuqHSN2oAWehZW1kgB3XP4kPi" +echo "-- query the contract --" + +result=$(../bin/aergocli contract query ${sc_id} resolve '["testnametest"]' \ + | sed 's/"//g' | sed 's/\\//g' | sed 's/ //g') + +assert_equals "$result" "value:Amh9vfP5My5DpSafe3gcZ1u8DiZNuqHSN2oAWehZW1kgB3XP4kPi" + + echo "" echo "All tests pass" From 2672ab60aee181600d796beb009b1293a755dd97 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Mon, 8 May 2023 19:35:51 +0000 Subject: [PATCH 030/182] fix integration test for Alpine Linux --- tests/run_tests.sh | 7 +++++-- tests/test-name-service.sh | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/tests/run_tests.sh b/tests/run_tests.sh index ab2b6dea1..745192067 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -1,9 +1,9 @@ -#!/usr/bin/env bash # delete the aergo folder -rm -r ~/.aergo/ +rm -rf ~/.aergo/ # open the aergo server in testmode to create the config file +echo "starting the aergo server..." ../bin/aergosvr --testmode > logs 2> logs & pid=$! # wait it create the config file @@ -11,8 +11,10 @@ sleep 3 # terminate the server process kill $pid # enable the block production on the config file +echo "updating the config file..." sed -i 's/^enablebp = false$/enablebp = true/' ~/.aergo/config.toml # restart the aergo server in testmode +echo "restarting the aergo server..." ../bin/aergosvr --testmode > logs 2> logs & pid=$! sleep 3 @@ -21,4 +23,5 @@ sleep 3 ./test-name-service.sh # terminate the server process +echo "closing the aergo server" kill $pid diff --git a/tests/test-name-service.sh b/tests/test-name-service.sh index 1ad694dd8..14661fb09 100755 --- a/tests/test-name-service.sh +++ b/tests/test-name-service.sh @@ -1,4 +1,3 @@ -#!/usr/bin/env bash assert_equals() { local var="$1" @@ -10,6 +9,15 @@ assert_equals() { fi } +assert_contains() { + local var="$1" + local substring="$2" + + if [[ ! "$var" == *"$substring"* ]]; then + echo "Assertion failed: $var does not contain $substring" + exit 1 + fi +} ../bin/aergocli account import --keystore . --if 47zh1byk8MqWkQo5y8dvbrex99ZMdgZqfydar7w2QQgQqc7YrmFsBuMeF1uHWa5TwA1ZwQ7V6 --password bmttest @@ -42,9 +50,9 @@ sleep 1 status=$(cat receipt.json | jq .status | sed 's/"//g') ret=$(cat receipt.json | jq .ret | sed 's/"//g') -assert_equals "$status" "ERROR" -assert_equals "$ret" "[Contract.LuaResolve] Data and checksum don't match" - +assert_equals "$status" "ERROR" +# assert_equals "$ret" "[Contract.LuaResolve] Data and checksum don't match" +assert_contains "$ret" "Data and checksum don't match" echo "-- call contract with a valid address --" From b9db169ede2872202943b3d715f70762ea1cbc35 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Mon, 8 May 2023 22:06:49 +0000 Subject: [PATCH 031/182] [contract] fix toPubkey() toAddress() --- contract/system_module.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/contract/system_module.c b/contract/system_module.c index 1a03b6884..14b732242 100644 --- a/contract/system_module.c +++ b/contract/system_module.c @@ -450,10 +450,12 @@ static int toPubkey(lua_State *L) if (ret == NULL) { lua_pushnil(L); } else { - strPushAndRelease(L, ret); // if the returned string starts with `[`, it's an error if (ret[0] == '[') { + strPushAndRelease(L, ret); luaL_throwerror(L); + } else { + strPushAndRelease(L, ret); } } @@ -474,10 +476,12 @@ static int toAddress(lua_State *L) if (ret == NULL) { lua_pushnil(L); } else { - strPushAndRelease(L, ret); // if the returned string starts with `[`, it's an error if (ret[0] == '[') { + strPushAndRelease(L, ret); luaL_throwerror(L); + } else { + strPushAndRelease(L, ret); } } From 4088dff70fe77648bb34b6bb2e6af860f42ddc00 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 9 May 2023 04:50:06 -0300 Subject: [PATCH 032/182] [name_service] rename luaResolve() to luaNameResolve() --- contract/name_module.c | 2 +- contract/vm_callback.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contract/name_module.c b/contract/name_module.c index 31580be42..4e7f5f7a4 100644 --- a/contract/name_module.c +++ b/contract/name_module.c @@ -14,7 +14,7 @@ static int resolve(lua_State *L) lua_gasuse(L, 100); name = (char *)luaL_checkstring(L, 1); - ret = luaResolve(L, service, name); + ret = luaNameResolve(L, service, name); if (ret == NULL) { lua_pushnil(L); diff --git a/contract/vm_callback.go b/contract/vm_callback.go index a94fe7ba1..a7468dbc2 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -1247,11 +1247,11 @@ func luaIsContract(L *LState, service C.int, contractId *C.char) (C.int, *C.char return C.int(len(cs.curState.GetCodeHash())), nil } -//export luaResolve -func luaResolve(L *LState, service C.int, name_or_address *C.char) *C.char { +//export luaNameResolve +func luaNameResolve(L *LState, service C.int, name_or_address *C.char) *C.char { ctx := contexts[service] if ctx == nil { - return C.CString("[Contract.LuaResolve] contract state not found") + return C.CString("[Contract.LuaNameResolve] contract state not found") } var addr []byte var err error @@ -1263,7 +1263,7 @@ func luaResolve(L *LState, service C.int, name_or_address *C.char) *C.char { addr, err = name.Resolve(ctx.bs, []byte(account), false) } if err != nil { - return C.CString("[Contract.LuaResolve] " + err.Error()) + return C.CString("[Contract.LuaNameResolve] " + err.Error()) } return C.CString(types.EncodeAddress(addr)) } From 324f0f4461cd223c28977385a5e8f817c9a268ae Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 10 May 2023 23:02:28 -0300 Subject: [PATCH 033/182] [contract] fix system.toPubkey() --- contract/vm_callback.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contract/vm_callback.go b/contract/vm_callback.go index 600e63cfd..c8b9e822d 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -1231,7 +1231,7 @@ func luaEvent(L *LState, service C.int, eventName *C.char, args *C.char) *C.char //export luaToPubkey func luaToPubkey(L *LState, address *C.char) *C.char { // check the length of address - if len(address) != types.EncodedAddressLength { + if len(C.GoString(address)) != types.EncodedAddressLength { return C.CString("[Contract.LuaToPubkey] invalid address length") } // decode the address in string format to bytes (public key) From 30a2d0699b71f949316a0b42f34d2a75b3c2ca4c Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 19 Jul 2023 04:30:04 +0000 Subject: [PATCH 034/182] override xpcall() --- contract/vm.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 6 deletions(-) diff --git a/contract/vm.c b/contract/vm.c index 8e30bc646..ad7f830a3 100644 --- a/contract/vm.c +++ b/contract/vm.c @@ -68,27 +68,103 @@ static void preloadModules(lua_State *L) { #endif } +/* override pcall to drop events upon error */ static int pcall(lua_State *L) { - /* Override pcall to drop events upon error */ + int argc = lua_gettop(L); + int status; + + // get the current number of events int service = getLuaExecContext(L); - int status, from; + int num_events = luaGetEventCount(L, service); + + if (argc < 1) { + return luaL_error(L, "pcall: not enough arguments"); + } + + // the stack is like this: + // func arg1 arg2 ... argn - from = luaGetEventCount(L, service); + // call the function + status = lua_pcall(L, argc - 1, LUA_MULTRET, 0); + + // if failed, drop the events + if (status != 0) { + if (vm_is_hardfork(L, 4)) { + luaDropEvent(L, service, num_events); + } + } - luaL_checkany(L, 1); - status = lua_pcall(L, lua_gettop(L) - 1, -1, 0); + // throw the error if out of memory + if (status == LUA_ERRMEM) { + luaL_throwerror(L); + } + + // insert the status at the bottom of the stack lua_pushboolean(L, status == 0); lua_insert(L, 1); + // return the number of items in the stack + return lua_gettop(L); +} + +static int xpcall(lua_State *L) { + int argc = lua_gettop(L); + int errfunc; + int status; + + // get the current number of events + int service = getLuaExecContext(L); + int num_events = luaGetEventCount(L, service); + + if (argc < 2) { + return luaL_error(L, "xpcall: not enough arguments"); + } + + // the stack is like this: + // func errfunc arg1 arg2 ... argn + + // get the error handler + errfunc = 2; + if (!lua_isfunction(L, errfunc)) { + return luaL_error(L, "xpcall: error handler is not a function"); + } + + // move the error handler (position 2) to the top + lua_pushvalue(L, errfunc); + // remove the error handler from its original position + lua_remove(L, errfunc); + // update the error handler position + errfunc = argc; + + // now the stack is like this: + // func arg1 arg2 ... argn errfunc + + // call the function + status = lua_pcall(L, argc - 2, LUA_MULTRET, errfunc); + + // if failed, drop the events if (status != 0) { - luaDropEvent(L, service, from); + if (vm_is_hardfork(L, 4)) { + luaDropEvent(L, service, num_events); + } + } + + // throw the error if out of memory + if (status == LUA_ERRMEM) { + luaL_throwerror(L); } + // insert the status at the bottom of the stack + lua_pushboolean(L, status == 0); + lua_insert(L, 1); + + // return the number of items in the stack return lua_gettop(L); } static const struct luaL_Reg _basefuncs[] = { {"pcall", pcall}, + {"xpcall", xpcall}, {NULL, NULL}}; static void override_basefuncs(lua_State *L) { From 5b6c0a42d3c1d673edb7a932545da56f5b6fb377 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 19 Jul 2023 22:34:27 +0000 Subject: [PATCH 035/182] fix xpcall --- contract/vm.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/contract/vm.c b/contract/vm.c index ad7f830a3..292e7ec3a 100644 --- a/contract/vm.c +++ b/contract/vm.c @@ -123,21 +123,23 @@ static int xpcall(lua_State *L) { // the stack is like this: // func errfunc arg1 arg2 ... argn - // get the error handler + // check the error handler errfunc = 2; if (!lua_isfunction(L, errfunc)) { return luaL_error(L, "xpcall: error handler is not a function"); } - // move the error handler (position 2) to the top - lua_pushvalue(L, errfunc); - // remove the error handler from its original position - lua_remove(L, errfunc); - // update the error handler position - errfunc = argc; + // move the error handler to the first position + lua_pushvalue(L, 1); // function + lua_pushvalue(L, 2); // error handler + lua_replace(L, 1); // 1: error handler + lua_replace(L, 2); // 2: function // now the stack is like this: - // func arg1 arg2 ... argn errfunc + // errfunc func arg1 arg2 ... argn + + // update the error handler position + errfunc = 1; // call the function status = lua_pcall(L, argc - 2, LUA_MULTRET, errfunc); @@ -154,9 +156,18 @@ static int xpcall(lua_State *L) { luaL_throwerror(L); } - // insert the status at the bottom of the stack + // ensure the stack has 1 free slot + if (!lua_checkstack(L, 1)) { + // return: false, "stack overflow" + lua_settop(L, 0); + lua_pushboolean(L, 0); + lua_pushliteral(L, "stack overflow"); + return 2; + } + + // store the status at the bottom of the stack, replacing the error handler lua_pushboolean(L, status == 0); - lua_insert(L, 1); + lua_replace(L, 1); // return the number of items in the stack return lua_gettop(L); From 4ba4b7573d483a40d4494ceac693dc6b17de2e4f Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 28 Jul 2023 00:59:50 +0000 Subject: [PATCH 036/182] add contracts for tests [skip ci] --- .../vm_dummy/test_files/pcall-events-0.lua | 38 ++++++++++++++++ .../vm_dummy/test_files/pcall-events-1.lua | 44 +++++++++++++++++++ .../vm_dummy/test_files/pcall-events-2.lua | 19 ++++++++ .../vm_dummy/test_files/pcall-events-3.lua | 5 +++ 4 files changed, 106 insertions(+) create mode 100644 contract/vm_dummy/test_files/pcall-events-0.lua create mode 100644 contract/vm_dummy/test_files/pcall-events-1.lua create mode 100644 contract/vm_dummy/test_files/pcall-events-2.lua create mode 100644 contract/vm_dummy/test_files/pcall-events-3.lua diff --git a/contract/vm_dummy/test_files/pcall-events-0.lua b/contract/vm_dummy/test_files/pcall-events-0.lua new file mode 100644 index 000000000..e4816b4be --- /dev/null +++ b/contract/vm_dummy/test_files/pcall-events-0.lua @@ -0,0 +1,38 @@ +state.var { + parent = state.value() +} + +function constructor(address) + parent:set(address) +end + +function error_handler(err_msg) + return "oh no! " .. err_msg +end + +function test_pcall() + local s, r = pcall(do_work, parent:get(), "pcall") + assert(s == false, "call not failed") + return r +end + +function test_xpcall() + local s, r = xpcall(do_work, error_handler, parent:get(), "xpcall") + assert(s == false, "call not failed") + return r +end + +function test_contract_pcall() + local s, r = contract.pcall(do_work, parent:get(), "contract.pcall") + assert(s == false, "call not failed") + return r +end + +function do_work(contract_address, caller) + contract.event("inside " .. caller .. " before") + local r = contract.call(contract_address, "call_me") + contract.event("inside " .. caller .. " after") + return r +end + +abi.register(test_pcall, test_xpcall, test_contract_pcall) diff --git a/contract/vm_dummy/test_files/pcall-events-1.lua b/contract/vm_dummy/test_files/pcall-events-1.lua new file mode 100644 index 000000000..e8515ace0 --- /dev/null +++ b/contract/vm_dummy/test_files/pcall-events-1.lua @@ -0,0 +1,44 @@ +state.var { + parent = state.value() +} + +function constructor(address) + parent:set(address) +end + +function error_handler(err_msg) + return "oh no! " .. err_msg +end + +function test_pcall() + contract.event("before pcall") + local s, r = pcall(do_work, parent:get(), "pcall") + contract.event("after pcall") + assert(s == false, "call not failed") + return r +end + +function test_xpcall() + contract.event("before xpcall") + local s, r = xpcall(do_work, error_handler, parent:get(), "xpcall") + contract.event("after xpcall") + assert(s == false, "call not failed") + return r +end + +function test_contract_pcall() + contract.event("before contract.pcall") + local s, r = contract.pcall(do_work, parent:get(), "contract.pcall") + contract.event("after contract.pcall") + assert(s == false, "call not failed") + return r +end + +function do_work(contract_address, caller) + contract.event("inside " .. caller .. " before") + local r = contract.call(contract_address, "call_me") + contract.event("inside " .. caller .. " after") + return r +end + +abi.register(test_pcall, test_xpcall, test_contract_pcall) diff --git a/contract/vm_dummy/test_files/pcall-events-2.lua b/contract/vm_dummy/test_files/pcall-events-2.lua new file mode 100644 index 000000000..03a6b793b --- /dev/null +++ b/contract/vm_dummy/test_files/pcall-events-2.lua @@ -0,0 +1,19 @@ +state.var { + parent = state.value() +} + +function constructor(address) + parent:set(address) +end + +function call_me() + contract.event("contract-2 before call") + -- call contract-3 + local result = contract.call(parent:get(), "call_me") + contract.event("contract-2 after call") + -- raises an error: + assert(1 == 0) + contract.event("contract-2 returning") +end + +abi.register(call_me) diff --git a/contract/vm_dummy/test_files/pcall-events-3.lua b/contract/vm_dummy/test_files/pcall-events-3.lua new file mode 100644 index 000000000..53de91685 --- /dev/null +++ b/contract/vm_dummy/test_files/pcall-events-3.lua @@ -0,0 +1,5 @@ +function call_me() + contract.event("contract-3") +end + +abi.register(call_me) From 5b7e775dd49575e0e118b692c061c3f325f80ed6 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 10 Aug 2023 02:53:56 +0000 Subject: [PATCH 037/182] override pcall and xpcall on V4 --- contract/vm.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/contract/vm.c b/contract/vm.c index 9ffca0b3d..145c021ea 100644 --- a/contract/vm.c +++ b/contract/vm.c @@ -179,7 +179,7 @@ static const struct luaL_Reg _basefuncs[] = { {NULL, NULL}}; static void override_basefuncs(lua_State *L) { - // Override Lua builtins functions. + // override Lua builtin functions lua_getglobal(L, "_G"); luaL_register(L, NULL, _basefuncs); lua_pop(L, 1); @@ -188,25 +188,19 @@ static void override_basefuncs(lua_State *L) { static int loadLibs(lua_State *L) { luaL_openlibs(L); preloadModules(L); - return 0; -} - -static int loadLibsV3(lua_State *L) { - loadLibs(L); - override_basefuncs(L); + if (vm_is_hardfork(L, 4)) { + // override pcall to drop events upon error + override_basefuncs(L); + } return 0; } lua_State *vm_newstate(int hardfork_version) { - int status; lua_State *L = luaL_newstate(hardfork_version); if (L == NULL) return NULL; - if (use_lock) - // Overide pcall to drop events upon error. - status = lua_cpcall(L, loadLibsV3, NULL); - else - status = lua_cpcall(L, loadLibs, NULL); + // hardfork version set before loading modules + int status = lua_cpcall(L, loadLibs, NULL); if (status != 0) return NULL; return L; From d237efba94bd0c1d53ab4db4776dac90be61b507 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 10 Aug 2023 02:10:14 -0300 Subject: [PATCH 038/182] NORMAL and TRANSFER txns should not call a contract --- contract/contract.go | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/contract/contract.go b/contract/contract.go index 8aed7449d..ad3b0515d 100644 --- a/contract/contract.go +++ b/contract/contract.go @@ -91,17 +91,26 @@ func Execute( receiver.AddBalance(txBody.GetAmountBigInt()) } - // check if the receiver is a not contract + // NORMAL and TRANSFER txns should NOT call a contract (after V4) + if bi.ForkVersion >= 4 && + (txBody.Type == types.TxType_NORMAL || + txBody.Type == types.TxType_TRANSFER) && + len(receiver.State().CodeHash) > 0 { + // emit an error + ... + } + + // check if the recipient is a not contract if !receiver.IsDeploy() && len(receiver.State().CodeHash) == 0 { - // Before the chain version 3, any tx with no code hash is - // unconditionally executed as a simple Aergo transfer. Since this - // causes confusion, emit error for call-type tx with a wrong address - // from the chain version 3 by not returning error but fall-through for - // correct gas estimation. - if !(bi.ForkVersion >= 3 && txBody.Type == types.TxType_CALL) { - // Here, the condition for fee delegation TX essentially being - // call-type, is not necessary, because it is rejected from the - // mempool without code hash. + // before the hardfork version 3, all transactions in which the recipient + // is not a contract were executed as a simple Aergo transfer, including + // type CALL and FEEDELEGATION. + // starting from hardfork version 3, transactions expected to CALL a + // contract but without a valid recipient will emit an error. + // FEEDELEGATION txns with invalid recipient are rejected on mempool. + if bi.ForkVersion >= 3 && txBody.Type == types.TxType_CALL { + // continue now and emit an error below for correct gas estimation + } else { return } } From 636dd30ae985a39cbbec6f262ceac8de4f2f2ee7 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 2 Aug 2023 05:16:48 +0000 Subject: [PATCH 039/182] initial changes for V4 hardfork --- config/hardfork.json | 5 +++++ config/hardfork_gen.go | 14 +++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/config/hardfork.json b/config/hardfork.json index f9c27f34f..a1ab454e9 100644 --- a/config/hardfork.json +++ b/config/hardfork.json @@ -8,5 +8,10 @@ "Version": 3, "MainNetHeight": 111499715, "TestNetHeight": 100360545 + }, + { + "Version": 4, + "MainNetHeight": 1000000000, + "TestNetHeight": 1000000000 } ] diff --git a/config/hardfork_gen.go b/config/hardfork_gen.go index b657c3eae..b30a50f7d 100644 --- a/config/hardfork_gen.go +++ b/config/hardfork_gen.go @@ -13,25 +13,30 @@ var ( MainNetHardforkConfig = &HardforkConfig{ V2: types.BlockNo(19611555), V3: types.BlockNo(111499715), + V4: types.BlockNo(1000000000), } TestNetHardforkConfig = &HardforkConfig{ V2: types.BlockNo(18714241), V3: types.BlockNo(100360545), + V4: types.BlockNo(1000000000), } AllEnabledHardforkConfig = &HardforkConfig{ V2: types.BlockNo(0), V3: types.BlockNo(0), + V4: types.BlockNo(0), } ) const hardforkConfigTmpl = `[hardfork] v2 = "{{.Hardfork.V2}}" v3 = "{{.Hardfork.V3}}" +v4 = "{{.Hardfork.V4}}" ` type HardforkConfig struct { V2 types.BlockNo `mapstructure:"v2" description:"a block number of the hardfork version 2"` V3 types.BlockNo `mapstructure:"v3" description:"a block number of the hardfork version 3"` + V4 types.BlockNo `mapstructure:"v4" description:"a block number of the hardfork version 4"` } type HardforkDbConfig map[string]types.BlockNo @@ -56,6 +61,10 @@ func (c *HardforkConfig) IsV3Fork(h types.BlockNo) bool { return isFork(c.V3, h) } +func (c *HardforkConfig) IsV4Fork(h types.BlockNo) bool { + return isFork(c.V4, h) +} + func (c *HardforkConfig) CheckCompatibility(dbCfg HardforkDbConfig, h types.BlockNo) error { if err := c.validate(); err != nil { return err @@ -66,7 +75,10 @@ func (c *HardforkConfig) CheckCompatibility(dbCfg HardforkDbConfig, h types.Bloc if (isFork(c.V3, h) || isFork(dbCfg["V3"], h)) && c.V3 != dbCfg["V3"] { return newForkError("V3", h, c.V3, dbCfg["V3"]) } - return checkOlderNode(3, h, dbCfg) + if (isFork(c.V4, h) || isFork(dbCfg["V4"], h)) && c.V4 != dbCfg["V4"] { + return newForkError("V4", h, c.V4, dbCfg["V4"]) + } + return checkOlderNode(4, h, dbCfg) } func (c *HardforkConfig) Version(h types.BlockNo) int32 { From ec0ffd0c7d40157e52c75ff64b77e2064994ab30 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 2 Aug 2023 22:43:07 +0000 Subject: [PATCH 040/182] fix some tests on hardfork_test.go [skip ci] --- config/hardfork_test.go | 69 ++++++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/config/hardfork_test.go b/config/hardfork_test.go index 90eb6cc05..5580d2925 100644 --- a/config/hardfork_test.go +++ b/config/hardfork_test.go @@ -62,23 +62,34 @@ func TestConfigFromToml(t *testing.T) { cfg := readConfig(` [hardfork] v2 = "9223" +v3 = "13000" +v4 = "14000" `, ) if cfg.V2 != 9223 { t.Errorf("V2 = %d, want %d", cfg.V2, 9223) } + if cfg.V3 != 13000 { + t.Errorf("V3 = %d, want %d", cfg.V3, 13000) + } + if cfg.V4 != 14000 { + t.Errorf("V4 = %d, want %d", cfg.V4, 14000) + } } func TestCompatibility(t *testing.T) { cfg := readConfig(` [hardfork] v2 = "9223" -v3 = "11000"`, +v3 = "11000" +v4 = "14000" +`, ) dbCfg, _ := readDbConfig(` { "V2": 18446744073709551515, - "V3": 18446744073709551615 + "V3": 18446744073709551615, + "V4": 18446744073709551715 }`, ) err := cfg.CheckCompatibility(dbCfg, 10) @@ -89,7 +100,8 @@ v3 = "11000"`, dbCfg, _ = readDbConfig(` { "V2": 9223, - "V3": 10000 + "V3": 10000, + "V4": 14000 }`, ) err = cfg.CheckCompatibility(dbCfg, 10) @@ -100,7 +112,8 @@ v3 = "11000"`, dbCfg, _ = readDbConfig(` { "V2": 9223, - "V3": 10000 + "V3": 10000, + "V4": 14000 }`, ) err = cfg.CheckCompatibility(dbCfg, 9500) @@ -111,7 +124,8 @@ v3 = "11000"`, dbCfg, _ = readDbConfig(` { "V2": 9221, - "V3": 10000 + "V3": 10000, + "V4": 14000 }`, ) err = cfg.CheckCompatibility(dbCfg, 9500) @@ -161,7 +175,9 @@ func TestVersion(t *testing.T) { cfg := readConfig(` [hardfork] v2 = "9223" -v3 = "10000"`, +v3 = "10000" +v4 = "14000" +`, ) tests := []struct { name string @@ -188,13 +204,36 @@ v3 = "10000"`, 9322, 2, }, - /* - { - "greater v3", - 19322, - 3, - }, - */ + { + "before v3", + 9999, + 2, + }, + { + "equal v3", + 10000, + 3, + }, + { + "greater v3", + 10001, + 3, + }, + { + "before v4", + 13999, + 3, + }, + { + "equal v4", + 14000, + 4, + }, + { + "greater v4", + 21001, + 4, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -209,7 +248,9 @@ func TestFixDbConfig(t *testing.T) { cfg := readConfig(` [hardfork] v2 = "9223" -v3 = "10000"`, +v3 = "10000" +v4 = "14000" +`, ) dbConfig, _ := readDbConfig(` { From 44cb2db477b4a3d85d18b0fd66a435ad3419c572 Mon Sep 17 00:00:00 2001 From: kch Date: Thu, 3 Aug 2023 05:14:09 +0000 Subject: [PATCH 041/182] config - fix hardfork test error --- config/hardfork_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/config/hardfork_test.go b/config/hardfork_test.go index 5580d2925..47ca19adb 100644 --- a/config/hardfork_test.go +++ b/config/hardfork_test.go @@ -87,9 +87,9 @@ v4 = "14000" ) dbCfg, _ := readDbConfig(` { - "V2": 18446744073709551515, - "V3": 18446744073709551615, - "V4": 18446744073709551715 + "V2": 18446744073709551415, + "V3": 18446744073709551515, + "V4": 18446744073709551615 }`, ) err := cfg.CheckCompatibility(dbCfg, 10) @@ -159,7 +159,8 @@ v4 = "14000" { "V2": 9223, "VV": 10000, - "V3": 11000 + "V3": 11000, + "V4": 12000 }`, ) err = cfg.CheckCompatibility(dbCfg, 9000) From a04963114e3d7409cf9364e234b5e3ca0f39ad0b Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 10 Aug 2023 06:05:02 +0000 Subject: [PATCH 042/182] use LuaJIT with fix memory gas for V4 --- libtool/src/luajit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtool/src/luajit b/libtool/src/luajit index 530c749d5..58772eda8 160000 --- a/libtool/src/luajit +++ b/libtool/src/luajit @@ -1 +1 @@ -Subproject commit 530c749d5403a3f453c47803d45996406d29d33b +Subproject commit 58772eda8070dd0cba167c28624626df9b79eedf From be5dca37f4aa72f1ffc637a6509eb55b5448e65b Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 10 Aug 2023 06:17:23 +0000 Subject: [PATCH 043/182] add some integration tests for V4 --- tests/config.toml | 1 + tests/run_tests.sh | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/tests/config.toml b/tests/config.toml index 793fe86e8..10b3304d7 100644 --- a/tests/config.toml +++ b/tests/config.toml @@ -81,3 +81,4 @@ enablelocalconf = "false" [hardfork] v2 = "0" v3 = "10000" +v4 = "10000" diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 8239519f3..fb2f3828d 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -19,6 +19,11 @@ pid=$! sleep 2 version=$(../bin/aergocli blockchain | jq .ChainInfo.Chainid.Version | sed 's/"//g') +if [ $version -ne 2 ]; then + echo "Wrong hardfork version!" + echo "Desired: 2, Actual: $version" + exit 1 +fi function set_version() { # stop on errors @@ -35,11 +40,7 @@ function set_version() { kill $pid # save the hardfork config on the config file echo "updating the config file..." - if [ $version -eq 2 ]; then - sed -i "s/^v2 = \"10000\"$/v2 = \"${block_no}\"/" ./aergo-files/config.toml - elif [ $version -eq 3 ]; then - sed -i "s/^v3 = \"10000\"$/v3 = \"${block_no}\"/" ./aergo-files/config.toml - fi + sed -i "s/^v${version} = \"10000\"$/v${version} = \"${block_no}\"/" ./aergo-files/config.toml # restart the aergo server echo "restarting the aergo server..." ../bin/aergosvr --testmode --home ./aergo-files > logs 2> logs & @@ -99,6 +100,15 @@ check ./test-gas-bf.sh check ./test-gas-verify-proof.sh check ./test-gas-per-function-v3.sh +# change the hardfork version +set_version 4 + +check ./test-max-call-depth.sh +check ./test-gas-deploy.sh +check ./test-gas-op.sh +check ./test-gas-bf.sh +check ./test-gas-verify-proof.sh + # terminate the server process echo "" echo "closing the aergo server" From 9bd4c2a1661fea7a9e3f0a4891199f1361cd515f Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 10 Aug 2023 23:23:43 -0300 Subject: [PATCH 044/182] emit error --- contract/contract.go | 3 ++- types/errors.go | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/contract/contract.go b/contract/contract.go index ad3b0515d..ec1544382 100644 --- a/contract/contract.go +++ b/contract/contract.go @@ -97,7 +97,8 @@ func Execute( txBody.Type == types.TxType_TRANSFER) && len(receiver.State().CodeHash) > 0 { // emit an error - ... + err = newVmError(types.ErrTxNotAllowedRecipient) + return } // check if the recipient is a not contract diff --git a/types/errors.go b/types/errors.go index d3ab2c969..2643f3741 100644 --- a/types/errors.go +++ b/types/errors.go @@ -38,6 +38,8 @@ var ( //ErrInvalidRecipient ErrTxInvalidRecipient = errors.New("tx invalid recipient") + ErrTxNotAllowedRecipient = errors.New("tx not allowed recipient") + ErrTxInvalidAmount = errors.New("tx invalid amount") ErrTxInvalidPrice = errors.New("tx invalid price") From 5fa829838f2968e1a5f9dd4a5d40ee1996155207 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 11 Aug 2023 00:38:50 -0300 Subject: [PATCH 045/182] handle TRANSFER txns with contracts --- contract/contract.go | 11 ++++++++--- types/token_unit.go | 4 ++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/contract/contract.go b/contract/contract.go index ec1544382..293f585ba 100644 --- a/contract/contract.go +++ b/contract/contract.go @@ -91,11 +91,16 @@ func Execute( receiver.AddBalance(txBody.GetAmountBigInt()) } - // NORMAL and TRANSFER txns should NOT call a contract (after V4) + // transactions with type NORMAL should not call smart contracts + // transactions with type TRANSFER can only call smart contracts when: + // * the amount is greater than 0 + // * the payload is empty (only transfer to "default" function) if bi.ForkVersion >= 4 && + len(receiver.State().CodeHash) > 0 && (txBody.Type == types.TxType_NORMAL || - txBody.Type == types.TxType_TRANSFER) && - len(receiver.State().CodeHash) > 0 { + (txBody.Type == types.TxType_TRANSFER && + (len(txBody.GetPayload()) > 0 || txBody.GetAmountBigInt().Sign() == 0) + )){ // emit an error err = newVmError(types.ErrTxNotAllowedRecipient) return diff --git a/types/token_unit.go b/types/token_unit.go index 1bf2caf35..18ac87547 100644 --- a/types/token_unit.go +++ b/types/token_unit.go @@ -17,3 +17,7 @@ func NewAmount(amount uint64, unit TokenUnit) *big.Int { func NewZeroAmount() *big.Int { return new(big.Int) } + +func IsZeroAmount(n *big.Int) bool { + return n.Sign() == 0 +} From 35397a0a5ee0504126230fe5a3802f58c203a360 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 11 Aug 2023 03:56:13 +0000 Subject: [PATCH 046/182] fix newline --- contract/contract.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contract/contract.go b/contract/contract.go index 293f585ba..9145d36cb 100644 --- a/contract/contract.go +++ b/contract/contract.go @@ -99,8 +99,7 @@ func Execute( len(receiver.State().CodeHash) > 0 && (txBody.Type == types.TxType_NORMAL || (txBody.Type == types.TxType_TRANSFER && - (len(txBody.GetPayload()) > 0 || txBody.GetAmountBigInt().Sign() == 0) - )){ + (len(txBody.GetPayload()) > 0 || txBody.GetAmountBigInt().Sign() == 0))){ // emit an error err = newVmError(types.ErrTxNotAllowedRecipient) return From e196a1c0dc5976e9fca4862084479e2a8dc573c5 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 11 Aug 2023 05:07:47 +0000 Subject: [PATCH 047/182] integration tests: adjust gas for V4 --- tests/test-gas-bf.sh | 4 +++- tests/test-gas-deploy.sh | 9 ++++++++- tests/test-gas-op.sh | 9 ++++++++- tests/test-gas-verify-proof.sh | 16 ++++++++++++++-- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/tests/test-gas-bf.sh b/tests/test-gas-bf.sh index ef16ba16c..0665d2372 100755 --- a/tests/test-gas-bf.sh +++ b/tests/test-gas-bf.sh @@ -35,7 +35,9 @@ gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') assert_equals "$status" "SUCCESS" #assert_equals "$ret" "{}" -if [ "$fork_version" -eq "3" ]; then +if [ "$fork_version" -eq "4" ]; then + assert_equals "$gasUsed" "57105265" +elif [ "$fork_version" -eq "3" ]; then assert_equals "$gasUsed" "47456046" else assert_equals "$gasUsed" "47456244" diff --git a/tests/test-gas-deploy.sh b/tests/test-gas-deploy.sh index 1361f5b3a..75ba50fe7 100755 --- a/tests/test-gas-deploy.sh +++ b/tests/test-gas-deploy.sh @@ -1,6 +1,8 @@ set -e source common.sh +fork_version=$1 + echo "-- deploy --" @@ -32,4 +34,9 @@ gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') assert_equals "$status" "SUCCESS" #assert_equals "$ret" "{}" -assert_equals "$gasUsed" "117861" + +if [ "$fork_version" -eq "4" ]; then + assert_equals "$gasUsed" "118350" +else + assert_equals "$gasUsed" "117861" +fi diff --git a/tests/test-gas-op.sh b/tests/test-gas-op.sh index df8f51984..790d34809 100755 --- a/tests/test-gas-op.sh +++ b/tests/test-gas-op.sh @@ -1,6 +1,8 @@ set -e source common.sh +fork_version=$1 + echo "-- deploy --" @@ -32,4 +34,9 @@ gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') assert_equals "$status" "SUCCESS" #assert_equals "$ret" "{}" -assert_equals "$gasUsed" "117610" + +if [ "$fork_version" -eq "4" ]; then + assert_equals "$gasUsed" "130048" +else + assert_equals "$gasUsed" "117610" +fi diff --git a/tests/test-gas-verify-proof.sh b/tests/test-gas-verify-proof.sh index 6ff6fa64b..2e4e6cd4c 100755 --- a/tests/test-gas-verify-proof.sh +++ b/tests/test-gas-verify-proof.sh @@ -1,6 +1,8 @@ set -e source common.sh +fork_version=$1 + echo "-- deploy --" @@ -32,7 +34,12 @@ gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') assert_equals "$status" "SUCCESS" #assert_equals "$ret" "{}" -assert_equals "$gasUsed" "154137" + +if [ "$fork_version" -eq "4" ]; then + assert_equals "$gasUsed" "160281" +else + assert_equals "$gasUsed" "154137" +fi echo "-- call 2 --" @@ -49,4 +56,9 @@ gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') assert_equals "$status" "SUCCESS" #assert_equals "$ret" "{}" -assert_equals "$gasUsed" "108404" + +if [ "$fork_version" -eq "4" ]; then + assert_equals "$gasUsed" "108404" +else + assert_equals "$gasUsed" "108404" +fi From 6523350694e2b8f8236426c838ae1fe5ad6a65d7 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 11 Aug 2023 05:15:17 +0000 Subject: [PATCH 048/182] vm_dummy tests: adjust gas for V4 --- contract/vm_dummy/vm_dummy_test.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index ec7ad7cf3..a3b6acdfa 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -3032,6 +3032,9 @@ func TestGasDeploy(t *testing.T) { err = expectGas(code, 0, `"testPcall"`, ``, 117861, SetHardForkVersion(3)) assert.NoError(t, err) + + err = expectGas(code, 0, `"testPcall"`, ``, 118350, SetHardForkVersion(4)) + assert.NoError(t, err) } func TestGasOp(t *testing.T) { @@ -3047,6 +3050,9 @@ func TestGasOp(t *testing.T) { err = expectGas(string(code), 0, `"main"`, ``, 117610, SetHardForkVersion(3)) assert.NoError(t, err) + + err = expectGas(string(code), 0, `"main"`, ``, 130048, SetHardForkVersion(4)) + assert.NoError(t, err) } func TestGasBF(t *testing.T) { @@ -3062,6 +3068,9 @@ func TestGasBF(t *testing.T) { err = expectGas(string(code), 0, `"main"`, ``, 47456046, SetHardForkVersion(3)) assert.NoError(t, err) + + err = expectGas(string(code), 0, `"main"`, ``, 57105265, SetHardForkVersion(4)) + assert.NoError(t, err) } func TestGasLuaCryptoVerifyProof(t *testing.T) { @@ -3083,6 +3092,14 @@ func TestGasLuaCryptoVerifyProof(t *testing.T) { // v3 hex err = expectGas(string(code), 0, `"verifyProofHex"`, ``, 108404, SetHardForkVersion(3)) assert.NoError(t, err) + + // v4 raw + err = expectGas(string(code), 0, `"verifyProofRaw"`, ``, 160281, SetHardForkVersion(4)) + assert.NoError(t, err) + + // v4 hex + err = expectGas(string(code), 0, `"verifyProofHex"`, ``, 108404, SetHardForkVersion(4)) + assert.NoError(t, err) } const ( From 1ba67c0f2e24781cd0b1fdbe3c30bd2520e5d7d3 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 11 Aug 2023 05:31:27 +0000 Subject: [PATCH 049/182] vm_dummy tests: add TestGasPerFunction for V4 --- contract/vm_dummy/vm_dummy_test.go | 36 ++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index a3b6acdfa..bd3ffff84 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -2545,6 +2545,7 @@ func TestGasPerFunction(t *testing.T) { // deploy 2 copies of the contract NewLuaTxDeploy("user", "contract_v2", 0, code), NewLuaTxDeploy("user", "contract_v3", 0, code), + NewLuaTxDeploy("user", "contract_v4", 0, code), ) assert.NoError(t, err) @@ -2552,6 +2553,7 @@ func TestGasPerFunction(t *testing.T) { err = bc.ConnectBlock( NewLuaTxCall("user", "contract_v2", uint64(10e18), `{"Name":"deposit"}`), NewLuaTxCall("user", "contract_v3", uint64(10e18), `{"Name":"deposit"}`), + NewLuaTxCall("user", "contract_v4", uint64(10e18), `{"Name":"deposit"}`), ) assert.NoError(t, err, "sending funds to contracts") @@ -2834,7 +2836,7 @@ func TestGasPerFunction(t *testing.T) { // print the function name and the used gas // for this test: - //fmt.Printf(" { \"%s\", \"\", 0, %d },\n", funcName, usedGas) + //fmt.Printf(" {\"%s\", \"\", 0, %d},\n", funcName, usedGas) // for integration tests (tests/test-gas-per-function-v2.sh): //fmt.Printf("add_test \"%s\" %d\n", funcName, usedGas) } @@ -2864,11 +2866,41 @@ func TestGasPerFunction(t *testing.T) { // print the function name and the used gas // for this test: - //fmt.Printf(" { \"%s\", \"\", 0, %d },\n", funcName, usedGas) + //fmt.Printf(" {\"%s\", \"\", 0, %d},\n", funcName, usedGas) // for integration tests (tests/test-gas-per-function-v3.sh): //fmt.Printf("add_test \"%s\" %d\n", funcName, usedGas) } + // set the hard fork version + bc.HardforkVersion = 4 + + // iterate over the tests + for _, test := range tests_v3 { + funcName := test.funcName + funcArgs := test.funcArgs + amount := test.amount + expectedGas := test.expectedGas + + var payload string + if len(funcArgs) == 0 { + payload = fmt.Sprintf(`{"Name":"run_test", "Args":["%s"]}`, funcName) + } else { + payload = fmt.Sprintf(`{"Name":"run_test", "Args":["%s",%s]}`, funcName, funcArgs) + } + tx := NewLuaTxCall("user", "contract_v4", uint64(amount), payload) + err = bc.ConnectBlock(tx) + assert.NoError(t, err, "while executing %s", funcName) + + usedGas := bc.GetReceipt(tx.Hash()).GetGasUsed() + assert.Equal(t, expectedGas, int64(usedGas), "wrong used gas for %s", funcName) + + // print the function name and the used gas + // for this test: + //fmt.Printf(" {\"%s\", \"\", 0, %d},\n", funcName, usedGas) + // for integration tests (tests/test-gas-per-function-v4.sh): + //fmt.Printf("add_test \"%s\" %d\n", funcName, usedGas) + } + } func TestFeatureLuaCryptoVerifyProof(t *testing.T) { From 4364f7e1a340d3a6e123100be20b5da25a82d829 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 11 Aug 2023 06:30:38 +0000 Subject: [PATCH 050/182] fix gas computation for memory on V4 --- libtool/src/luajit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtool/src/luajit b/libtool/src/luajit index 58772eda8..64377bafc 160000 --- a/libtool/src/luajit +++ b/libtool/src/luajit @@ -1 +1 @@ -Subproject commit 58772eda8070dd0cba167c28624626df9b79eedf +Subproject commit 64377bafc1e0e283c1e48b8d9d602e145e7dc94f From 2161367700c9160001529c779a712d4a97bcc120 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 11 Aug 2023 06:53:58 +0000 Subject: [PATCH 051/182] fix gas-per-function values for V4 --- contract/vm_dummy/vm_dummy_test.go | 126 ++++++++++++++++++- tests/run_tests.sh | 1 + tests/test-gas-per-function-v4.sh | 196 +++++++++++++++++++++++++++++ 3 files changed, 322 insertions(+), 1 deletion(-) create mode 100755 tests/test-gas-per-function-v4.sh diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index bd3ffff84..7465875a9 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -2811,6 +2811,130 @@ func TestGasPerFunction(t *testing.T) { { "contract.event", "", 0, 153263 }, } + tests_v4 := []struct { + funcName string + funcArgs string + amount int64 + expectedGas int64 + }{ + {"comp_ops", "", 0, 143204}, + {"unarytest_n_copy_ops", "", 0, 143117}, + {"unary_ops", "", 0, 143552}, + {"binary_ops", "", 0, 145075}, + {"constant_ops", "", 0, 143032}, + {"upvalue_n_func_ops", "", 0, 144347}, + {"table_ops", "", 0, 144482}, + {"call_n_vararg_ops", "", 0, 145001}, + {"return_ops", "", 0, 143037}, + {"loop_n_branche_ops", "", 0, 146372}, + {"function_header_ops", "", 0, 143016}, + + {"assert", "", 0, 143146}, + {"getfenv", "", 0, 143041}, + {"metatable", "", 0, 143988}, + {"ipairs", "", 0, 143039}, + {"pairs", "", 0, 143039}, + {"next", "", 0, 143087}, + {"rawequal", "", 0, 143216}, + {"rawget", "", 0, 143087}, + {"rawset", "", 0, 143941}, + {"select", "", 0, 143166}, + {"setfenv", "", 0, 143076}, + {"tonumber", "", 0, 143186}, + {"tostring", "", 0, 143457}, + {"type", "", 0, 143285}, + {"unpack", "", 0, 150745}, + {"pcall", "", 0, 146165}, + {"xpcall", "", 0, 146437}, + + {"string.byte", "", 0, 157040}, + {"string.char", "", 0, 160397}, + {"string.dump", "", 0, 150349}, + {"string.find", "", 0, 147808}, + {"string.format", "", 0, 143764}, + {"string.gmatch", "", 0, 143799}, + {"string.gsub", "", 0, 144943}, + {"string.len", "", 0, 143097}, + {"string.lower", "", 0, 148351}, + {"string.match", "", 0, 143313}, + {"string.rep", "", 0, 221928}, + {"string.reverse", "", 0, 148351}, + {"string.sub", "", 0, 145205}, + {"string.upper", "", 0, 148351}, + + {"table.concat", "", 0, 163868}, + {"table.insert", "", 0, 297254}, + {"table.remove", "", 0, 156664}, + {"table.maxn", "", 0, 147962}, + {"table.sort", "", 0, 159866}, + + {"math.abs", "", 0, 143184}, + {"math.ceil", "", 0, 143184}, + {"math.floor", "", 0, 143184}, + {"math.max", "", 0, 143556}, + {"math.min", "", 0, 143556}, + {"math.pow", "", 0, 143544}, + + {"bit.tobit", "", 0, 143079}, + {"bit.tohex", "", 0, 143590}, + {"bit.bnot", "", 0, 143056}, + {"bit.bor", "", 0, 143130}, + {"bit.band", "", 0, 143106}, + {"bit.xor", "", 0, 143106}, + {"bit.lshift", "", 0, 143079}, + {"bit.rshift", "", 0, 143079}, + {"bit.ashift", "", 0, 143079}, + {"bit.rol", "", 0, 143079}, + {"bit.ror", "", 0, 143079}, + {"bit.bswap", "", 0, 143036}, + + {"bignum.number", "", 0, 144912}, + {"bignum.isneg", "", 0, 145144}, + {"bignum.iszero", "", 0, 145144}, + {"bignum.tonumber", "", 0, 145464}, + {"bignum.tostring", "", 0, 145755}, + {"bignum.neg", "", 0, 147208}, + {"bignum.sqrt", "", 0, 148084}, + {"bignum.compare", "", 0, 145409}, + {"bignum.add", "", 0, 146750}, + {"bignum.sub", "", 0, 146695}, + {"bignum.mul", "", 0, 149073}, + {"bignum.div", "", 0, 148563}, + {"bignum.mod", "", 0, 150498}, + {"bignum.pow", "", 0, 149492}, + {"bignum.divmod", "", 0, 154798}, + {"bignum.powmod", "", 0, 154164}, + {"bignum.operators", "", 0, 147416}, + + {"json", "", 0, 151357}, + + {"crypto.sha256", "", 0, 146183}, + {"crypto.ecverify", "", 0, 148036}, + + {"state.set", "", 0, 145915}, + {"state.get", "", 0, 145720}, + {"state.delete", "", 0, 145727}, + + {"system.getSender", "", 0, 144261}, + {"system.getBlockheight", "", 0, 143330}, + {"system.getTxhash", "", 0, 143737}, + {"system.getTimestamp", "", 0, 143330}, + {"system.getContractID", "", 0, 144261}, + {"system.setItem", "", 0, 144194}, + {"system.getItem", "", 0, 144503}, + {"system.getAmount", "", 0, 143408}, + {"system.getCreator", "", 0, 143761}, + {"system.getOrigin", "", 0, 144261}, + + {"contract.send", "", 0, 144321}, + {"contract.balance", "", 0, 144333}, + {"contract.deploy", "", 0, 168092}, + {"contract.call", "", 0, 159738}, + {"contract.pcall", "", 0, 160659}, + {"contract.delegatecall", "", 0, 153795}, + {"contract.event", "", 0, 163452}, + } + // set the hard fork version bc.HardforkVersion = 2 @@ -2875,7 +2999,7 @@ func TestGasPerFunction(t *testing.T) { bc.HardforkVersion = 4 // iterate over the tests - for _, test := range tests_v3 { + for _, test := range tests_v4 { funcName := test.funcName funcArgs := test.funcArgs amount := test.amount diff --git a/tests/run_tests.sh b/tests/run_tests.sh index fb2f3828d..7916d2376 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -108,6 +108,7 @@ check ./test-gas-deploy.sh check ./test-gas-op.sh check ./test-gas-bf.sh check ./test-gas-verify-proof.sh +check ./test-gas-per-function-v4.sh # terminate the server process echo "" diff --git a/tests/test-gas-per-function-v4.sh b/tests/test-gas-per-function-v4.sh new file mode 100755 index 000000000..6613ff97a --- /dev/null +++ b/tests/test-gas-per-function-v4.sh @@ -0,0 +1,196 @@ +set -e +source common.sh + +fork_version=$1 + + +echo "-- deploy --" + +../bin/aergoluac --payload ../contract/vm_dummy/test_files/gas_per_function.lua > payload.out + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + --payload `cat payload.out` | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +address=$(cat receipt.json | jq .contractAddress | sed 's/"//g') + +assert_equals "$status" "CREATED" + + +echo "-- get account's nonce --" + +account_state=$(../bin/aergocli getstate --address AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R) +nonce=$(echo $account_state | jq .nonce | sed 's/"//g') + + +# create an iterable map of function name -> expected gas +declare -a names +declare -A gas + +add_test() { + names+=("$1") + gas["$1"]="$2" +} + +add_test "comp_ops" 143204 +add_test "unarytest_n_copy_ops" 143117 +add_test "unary_ops" 143552 +add_test "binary_ops" 145075 +add_test "constant_ops" 143032 +add_test "upvalue_n_func_ops" 144347 +add_test "table_ops" 144482 +add_test "call_n_vararg_ops" 145001 +add_test "return_ops" 143037 +add_test "loop_n_branche_ops" 146372 +add_test "function_header_ops" 143016 + +add_test "assert" 143146 +add_test "getfenv" 143041 +add_test "metatable" 143988 +add_test "ipairs" 143039 +add_test "pairs" 143039 +add_test "next" 143087 +add_test "rawequal" 143216 +add_test "rawget" 143087 +add_test "rawset" 143941 +add_test "select" 143166 +add_test "setfenv" 143076 +add_test "tonumber" 143186 +add_test "tostring" 143457 +add_test "type" 143285 +add_test "unpack" 150745 +add_test "pcall" 146165 +add_test "xpcall" 146437 + +add_test "string.byte" 157040 +add_test "string.char" 160397 +add_test "string.dump" 150349 +add_test "string.find" 147808 +add_test "string.format" 143764 +add_test "string.gmatch" 143799 +add_test "string.gsub" 144943 +add_test "string.len" 143097 +add_test "string.lower" 148351 +add_test "string.match" 143313 +add_test "string.rep" 221928 +add_test "string.reverse" 148351 +add_test "string.sub" 145205 +add_test "string.upper" 148351 + +add_test "table.concat" 163868 +add_test "table.insert" 297254 +add_test "table.remove" 156664 +add_test "table.maxn" 147962 +add_test "table.sort" 159866 + +add_test "math.abs" 143184 +add_test "math.ceil" 143184 +add_test "math.floor" 143184 +add_test "math.max" 143556 +add_test "math.min" 143556 +add_test "math.pow" 143544 + +add_test "bit.tobit" 143079 +add_test "bit.tohex" 143590 +add_test "bit.bnot" 143056 +add_test "bit.bor" 143130 +add_test "bit.band" 143106 +add_test "bit.xor" 143106 +add_test "bit.lshift" 143079 +add_test "bit.rshift" 143079 +add_test "bit.ashift" 143079 +add_test "bit.rol" 143079 +add_test "bit.ror" 143079 +add_test "bit.bswap" 143036 + +add_test "bignum.number" 144912 +add_test "bignum.isneg" 145144 +add_test "bignum.iszero" 145144 +add_test "bignum.tonumber" 145464 +add_test "bignum.tostring" 145755 +add_test "bignum.neg" 147208 +add_test "bignum.sqrt" 148084 +add_test "bignum.compare" 145409 +add_test "bignum.add" 146750 +add_test "bignum.sub" 146695 +add_test "bignum.mul" 149073 +add_test "bignum.div" 148563 +add_test "bignum.mod" 150498 +add_test "bignum.pow" 149492 +add_test "bignum.divmod" 154798 +add_test "bignum.powmod" 154164 +add_test "bignum.operators" 147416 + +add_test "json" 151357 + +add_test "crypto.sha256" 146183 +add_test "crypto.ecverify" 148036 + +add_test "state.set" 145915 +add_test "state.get" 145720 +add_test "state.delete" 145727 + +add_test "system.getSender" 144261 +add_test "system.getBlockheight" 143330 +add_test "system.getTxhash" 143737 +add_test "system.getTimestamp" 143330 +add_test "system.getContractID" 144261 +add_test "system.setItem" 144194 +add_test "system.getItem" 144503 +add_test "system.getAmount" 143408 +add_test "system.getCreator" 143761 +add_test "system.getOrigin" 144261 + +add_test "contract.send" 144321 +add_test "contract.balance" 144402 +add_test "contract.deploy" 168092 +add_test "contract.call" 159738 +add_test "contract.pcall" 160659 +add_test "contract.delegatecall" 153795 +add_test "contract.event" 163452 + +# as the returned value differs in length (43 or 44) +# due to base58, the computed gas is different. +#add_test "system.getPrevBlockHash" 135132 + +# contract.balance() also use diff gas +# according to the returned string size + +declare -A txhashes +i=0 + +echo "-- send the transactions --" + +for function_name in "${names[@]}"; do + echo -n "." + i=$(($i+1)) + txhash=$(../bin/aergocli --keystore . --password bmttest --nonce $(($nonce+$i)) \ + contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + $address run_test "[\"$function_name\"]" | jq .hash | sed 's/"//g') + txhashes[$function_name]=$txhash +done + +echo "" +echo "-- check the results --" + +for function_name in "${names[@]}"; do + echo $function_name + txhash=${txhashes[$function_name]} + expected_gas=${gas[$function_name]} + + get_receipt $txhash + + status=$(cat receipt.json | jq .status | sed 's/"//g') + used_gas=$(cat receipt.json | jq .gasUsed | sed 's/"//g') + + assert_equals "$status" "SUCCESS" + assert_equals "$used_gas" "$expected_gas" +done + + +# it can have 2 variations of this file +# 1. one test per txn +# 2. multiple tests per txn - to use the pre-loader From f2bf927db58704681e136295e53309bf57f0f3b7 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 6 Sep 2023 05:26:59 +0000 Subject: [PATCH 052/182] add comment on run_tests.sh [skip ci] --- tests/run_tests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 7916d2376..77820eb97 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -103,6 +103,7 @@ check ./test-gas-per-function-v3.sh # change the hardfork version set_version 4 +# run the integration tests - version 4 check ./test-max-call-depth.sh check ./test-gas-deploy.sh check ./test-gas-op.sh From fbaf80918285fdaf9255addf45d34fa69c9ee2be Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 6 Sep 2023 05:55:38 +0000 Subject: [PATCH 053/182] add and update tests for pcall/xpcall --- contract/vm_dummy/vm_dummy_pub_test.go | 4 +- tests/run_tests.sh | 3 + tests/test-gas-per-function-v4.sh | 4 +- tests/test-pcall-events.sh | 141 +++++++++++++++++++++++++ 4 files changed, 148 insertions(+), 4 deletions(-) create mode 100755 tests/test-pcall-events.sh diff --git a/contract/vm_dummy/vm_dummy_pub_test.go b/contract/vm_dummy/vm_dummy_pub_test.go index 6c001b82b..36ec6a6a1 100644 --- a/contract/vm_dummy/vm_dummy_pub_test.go +++ b/contract/vm_dummy/vm_dummy_pub_test.go @@ -378,8 +378,8 @@ func TestGasPerFunction(t *testing.T) { {"tostring", "", 0, 143457}, {"type", "", 0, 143285}, {"unpack", "", 0, 150745}, - {"pcall", "", 0, 146165}, - {"xpcall", "", 0, 146437}, + {"pcall", "", 0, 146105}, + {"xpcall", "", 0, 146377}, {"string.byte", "", 0, 157040}, {"string.char", "", 0, 160397}, diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 77820eb97..ad4dc7b30 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -88,6 +88,7 @@ check ./test-gas-op.sh check ./test-gas-bf.sh check ./test-gas-verify-proof.sh check ./test-gas-per-function-v2.sh +check ./test-pcall-events.sh # change the hardfork version set_version 3 @@ -99,6 +100,7 @@ check ./test-gas-op.sh check ./test-gas-bf.sh check ./test-gas-verify-proof.sh check ./test-gas-per-function-v3.sh +check ./test-pcall-events.sh # change the hardfork version set_version 4 @@ -110,6 +112,7 @@ check ./test-gas-op.sh check ./test-gas-bf.sh check ./test-gas-verify-proof.sh check ./test-gas-per-function-v4.sh +check ./test-pcall-events.sh # terminate the server process echo "" diff --git a/tests/test-gas-per-function-v4.sh b/tests/test-gas-per-function-v4.sh index 6613ff97a..299307f66 100755 --- a/tests/test-gas-per-function-v4.sh +++ b/tests/test-gas-per-function-v4.sh @@ -62,8 +62,8 @@ add_test "tonumber" 143186 add_test "tostring" 143457 add_test "type" 143285 add_test "unpack" 150745 -add_test "pcall" 146165 -add_test "xpcall" 146437 +add_test "pcall" 146105 +add_test "xpcall" 146377 add_test "string.byte" 157040 add_test "string.char" 160397 diff --git a/tests/test-pcall-events.sh b/tests/test-pcall-events.sh new file mode 100755 index 000000000..94e2b54cd --- /dev/null +++ b/tests/test-pcall-events.sh @@ -0,0 +1,141 @@ +set -e +source common.sh + +fork_version=$1 + + +echo "-- deploy --" + +../bin/aergoluac --payload ../contract/vm_dummy/test_files/pcall-events-3.lua > payload.out + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + --payload `cat payload.out` | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +address3=$(cat receipt.json | jq .contractAddress | sed 's/"//g') + +assert_equals "$status" "CREATED" + + +../bin/aergoluac --payload ../contract/vm_dummy/test_files/pcall-events-2.lua > payload.out + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + '["'$address3'"]' --payload `cat payload.out` | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +address2=$(cat receipt.json | jq .contractAddress | sed 's/"//g') + +assert_equals "$status" "CREATED" + + +../bin/aergoluac --payload ../contract/vm_dummy/test_files/pcall-events-1.lua > payload.out + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + '["'$address2'"]' --payload `cat payload.out` | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +address1=$(cat receipt.json | jq .contractAddress | sed 's/"//g') + +assert_equals "$status" "CREATED" + + +../bin/aergoluac --payload ../contract/vm_dummy/test_files/pcall-events-0.lua > payload.out + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + '["'$address2'"]' --payload `cat payload.out` | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +address0=$(cat receipt.json | jq .contractAddress | sed 's/"//g') + +assert_equals "$status" "CREATED" + + +echo "-- pcall --" + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + $address1 test_pcall "[]" | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') +nevents=$(cat receipt.json | jq '.events | length') + +assert_equals "$status" "SUCCESS" +#assert_equals "$ret" "{}" + +if [ "$fork_version" -eq "4" ]; then + assert_equals "$nevents" "2" +else + assert_equals "$nevents" "6" +fi + + +echo "-- xpcall --" + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + $address1 test_xpcall "[]" | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') +nevents=$(cat receipt.json | jq '.events | length') + +assert_equals "$status" "SUCCESS" +#assert_equals "$ret" "{}" + +if [ "$fork_version" -eq "4" ]; then + assert_equals "$nevents" "2" +else + assert_equals "$nevents" "6" +fi + + +echo "-- contract.pcall --" + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + $address1 test_contract_pcall "[]" | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') +nevents=$(cat receipt.json | jq '.events | length') + +assert_equals "$status" "SUCCESS" +#assert_equals "$ret" "{}" + +if [ "$fork_version" -eq "4" ]; then + assert_equals "$nevents" "2" +else + assert_equals "$nevents" "6" +fi + + +#echo "----------- contract-1 event list ------------" +#aergocli event list --address $address1 --recent 1000 + +#echo "----------- contract-2 event list ------------" +#aergocli event list --address $address2 --recent 1000 + +#echo "----------- contract-3 event list ------------" +#aergocli event list --address $address3 --recent 1000 From 047ce807864879018233c256adc15d12a16c574d Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 6 Sep 2023 17:50:57 +0000 Subject: [PATCH 054/182] load name_service module only on V4 --- contract/vm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contract/vm.c b/contract/vm.c index 77f9e0783..482dcf365 100644 --- a/contract/vm.c +++ b/contract/vm.c @@ -37,12 +37,15 @@ static void preloadModules(lua_State *L) { luaopen_system(L); luaopen_contract(L); luaopen_state(L); - luaopen_name(L); luaopen_json(L); luaopen_crypto(L); luaopen_bignum(L); luaopen_utf8(L); + if (vm_is_hardfork(L, 4)) { + luaopen_name(L); + } + if (!isPublic()) { luaopen_db(L); } From 1bad2bc2ba5e6446304ecab068a968e00b29610a Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 6 Sep 2023 18:06:43 +0000 Subject: [PATCH 055/182] load new functions only on V4 --- contract/system_module.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/contract/system_module.c b/contract/system_module.c index 577f6804b..4a0b1640e 100644 --- a/contract/system_module.c +++ b/contract/system_module.c @@ -506,7 +506,29 @@ static int is_fee_delegation(lua_State *L) { return 1; } -static const luaL_Reg sys_lib[] = { +static const luaL_Reg system_lib_v1[] = { + {"print", systemPrint}, + {"setItem", setItem}, + {"getItem", getItem}, + {"getSender", getSender}, + {"getCreator", getCreator}, + {"getTxhash", getTxhash}, + {"getBlockheight", getBlockHeight}, + {"getTimestamp", getTimestamp}, + {"getContractID", getContractID}, + {"getOrigin", getOrigin}, + {"getAmount", getAmount}, + {"getPrevBlockHash", getPrevBlockHash}, + {"date", os_date}, + {"time", os_time}, + {"difftime", os_difftime}, + {"random", lua_random}, + {"isContract", is_contract}, + {"isFeeDelegation", is_fee_delegation}, + {NULL, NULL} +}; + +static const luaL_Reg system_lib_v4[] = { {"print", systemPrint}, {"setItem", setItem}, {"getItem", getItem}, @@ -531,7 +553,11 @@ static const luaL_Reg sys_lib[] = { }; int luaopen_system(lua_State *L) { - luaL_register(L, "system", sys_lib); + if (vm_is_hardfork(L, 4)) { + luaL_register(L, "system", system_lib_v4); + } else { + luaL_register(L, "system", system_lib_v1); + } lua_pop(L, 1); return 1; } From d759d8330f0593dc623dcd4723331388d44ffb6b Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 6 Sep 2023 23:53:34 +0000 Subject: [PATCH 056/182] update tests for name_service --- tests/test-name-service.sh | 86 +++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 20 deletions(-) diff --git a/tests/test-name-service.sh b/tests/test-name-service.sh index 0f895d3ae..c8a3f9851 100755 --- a/tests/test-name-service.sh +++ b/tests/test-name-service.sh @@ -1,6 +1,8 @@ set -e source common.sh +fork_version=$1 + echo "-- deploy contract --" @@ -30,9 +32,15 @@ status=$(cat receipt.json | jq .status | sed 's/"//g') ret=$(cat receipt.json | jq .ret | sed 's/"//g') gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') -assert_equals "$status" "ERROR" -# assert_equals "$ret" "[Contract.LuaResolve] Data and checksum don't match" -assert_contains "$ret" "Data and checksum don't match" +if [ "$fork_version" -eq "4" ]; then + assert_equals "$status" "ERROR" + # assert_equals "$ret" "[Contract.LuaResolve] Data and checksum don't match" + assert_contains "$ret" "Data and checksum don't match" +else + assert_equals "$status" "ERROR" + assert_contains "$ret" "attempt to index global 'name_service'" +fi + echo "-- call contract with a valid address --" @@ -45,8 +53,13 @@ get_receipt $txhash status=$(cat receipt.json | jq .status | sed 's/"//g') ret=$(cat receipt.json | jq .ret | sed 's/"//g') -assert_equals "$status" "SUCCESS" -assert_equals "$ret" "AmgExqUu6J4Za8VjyWMJANxoRaUvwgngGQJgemHgwWvuRSEd3wnE" +if [ "$fork_version" -eq "4" ]; then + assert_equals "$status" "SUCCESS" + assert_equals "$ret" "AmgExqUu6J4Za8VjyWMJANxoRaUvwgngGQJgemHgwWvuRSEd3wnE" +else + assert_equals "$status" "ERROR" + assert_contains "$ret" "attempt to index global 'name_service'" +fi echo "-- call contract with invalid name --" @@ -60,8 +73,13 @@ get_receipt $txhash status=$(cat receipt.json | jq .status | sed 's/"//g') ret=$(cat receipt.json | jq .ret | sed 's/"//g') -assert_equals "$status" "SUCCESS" -assert_equals "$ret" "" +if [ "$fork_version" -eq "4" ]; then + assert_equals "$status" "SUCCESS" + assert_equals "$ret" "" +else + assert_equals "$status" "ERROR" + assert_contains "$ret" "attempt to index global 'name_service'" +fi echo "-- call contract with valid but not set name --" @@ -74,13 +92,25 @@ get_receipt $txhash status=$(cat receipt.json | jq .status | sed 's/"//g') ret=$(cat receipt.json | jq .ret | sed 's/"//g') -assert_equals "$status" "SUCCESS" -assert_equals "$ret" "" +if [ "$fork_version" -eq "4" ]; then + assert_equals "$status" "SUCCESS" + assert_equals "$ret" "" +else + assert_equals "$status" "ERROR" + assert_contains "$ret" "attempt to index global 'name_service'" +fi + + +# use a different account name for each hardfork +account_name="testnamever$fork_version" +# later, it could also: +# - drop the account name, to recreate it later +# - let the account name to expire, by forwarding time echo "-- register a new account name --" -txhash=$(../bin/aergocli --keystore . name new --name="testnametest" \ +txhash=$(../bin/aergocli --keystore . name new --name="$account_name" \ --from AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ --password bmttest | jq .hash | sed 's/"//g') @@ -94,20 +124,25 @@ assert_equals "$status" "SUCCESS" echo "-- call contract --" txhash=$(../bin/aergocli --keystore . contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ - ${address} resolve '["testnametest"]' --password bmttest | jq .hash | sed 's/"//g') + ${address} resolve '["'$account_name'"]' --password bmttest | jq .hash | sed 's/"//g') get_receipt $txhash status=$(cat receipt.json | jq .status | sed 's/"//g') ret=$(cat receipt.json | jq .ret | sed 's/"//g') -assert_equals "$status" "SUCCESS" -assert_equals "$ret" "AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R" +if [ "$fork_version" -eq "4" ]; then + assert_equals "$status" "SUCCESS" + assert_equals "$ret" "AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R" +else + assert_equals "$status" "ERROR" + assert_contains "$ret" "attempt to index global 'name_service'" +fi echo "-- transfer the name --" -txhash=$(../bin/aergocli --keystore . name update --name="testnametest" \ +txhash=$(../bin/aergocli --keystore . name update --name="$account_name" \ --from AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ --to Amh9vfP5My5DpSafe3gcZ1u8DiZNuqHSN2oAWehZW1kgB3XP4kPi \ --password bmttest | jq .hash | sed 's/"//g') @@ -122,20 +157,31 @@ assert_equals "$status" "SUCCESS" echo "-- call contract --" txhash=$(../bin/aergocli --keystore . contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ - ${address} resolve '["testnametest"]' --password bmttest | jq .hash | sed 's/"//g') + ${address} resolve '["'$account_name'"]' --password bmttest | jq .hash | sed 's/"//g') get_receipt $txhash status=$(cat receipt.json | jq .status | sed 's/"//g') ret=$(cat receipt.json | jq .ret | sed 's/"//g') -assert_equals "$status" "SUCCESS" -assert_equals "$ret" "Amh9vfP5My5DpSafe3gcZ1u8DiZNuqHSN2oAWehZW1kgB3XP4kPi" +if [ "$fork_version" -eq "4" ]; then + assert_equals "$status" "SUCCESS" + assert_equals "$ret" "Amh9vfP5My5DpSafe3gcZ1u8DiZNuqHSN2oAWehZW1kgB3XP4kPi" +else + assert_equals "$status" "ERROR" + assert_contains "$ret" "attempt to index global 'name_service'" +fi echo "-- query the contract --" -result=$(../bin/aergocli contract query ${address} resolve '["testnametest"]' \ - | sed 's/"//g' | sed 's/\\//g' | sed 's/ //g') +../bin/aergocli contract query ${address} resolve '["'$account_name'"]' > result.txt 2> result.txt || true +result=$(cat result.txt) -assert_equals "$result" "value:Amh9vfP5My5DpSafe3gcZ1u8DiZNuqHSN2oAWehZW1kgB3XP4kPi" +if [ "$fork_version" -eq "4" ]; then + result=$(echo $result | sed 's/"//g' | sed 's/\\//g' | sed 's/value://g') + assert_equals "$result" "Amh9vfP5My5DpSafe3gcZ1u8DiZNuqHSN2oAWehZW1kgB3XP4kPi" +else + assert_contains "$result" "Error: failed to query contract" + assert_contains "$result" "attempt to index global 'name_service'" +fi From 1cb1785ec8c9e6a96efaa3e82e9350bbd66c4fe4 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 8 Sep 2023 01:06:26 +0000 Subject: [PATCH 057/182] add test for bignum octal, hex and binary --- .../vm_dummy/test_files/bignum_values.lua | 7 ++ contract/vm_dummy/vm_dummy_test.go | 86 +++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 contract/vm_dummy/test_files/bignum_values.lua diff --git a/contract/vm_dummy/test_files/bignum_values.lua b/contract/vm_dummy/test_files/bignum_values.lua new file mode 100644 index 000000000..7c31db65a --- /dev/null +++ b/contract/vm_dummy/test_files/bignum_values.lua @@ -0,0 +1,7 @@ + +function parse_bignum(value) + local val = bignum.number(value) + return bignum.tostring(val) +end + +abi.register(parse_bignum) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index ddfb6f43b..c4848cc18 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -2065,6 +2065,92 @@ func TestTypeBignum(t *testing.T) { require.NoErrorf(t, err, "failed to query") } +func TestBignumValues(t *testing.T) { + code := readLuaCode("bignum_values.lua") + require.NotEmpty(t, code, "failed to read bignum_values.lua") + + bc, err := LoadDummyChain() + require.NoErrorf(t, err, "failed to create dummy chain") + defer bc.Release() + + err = bc.ConnectBlock( + NewLuaTxAccount("user1", 1, types.Aergo), + NewLuaTxDeploy("user1", "contract1", 0, code), + ) + require.NoErrorf(t, err, "failed to deploy") + + // hardfork 2 + + // process octal, hex, binary + + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["01234567"]}`, "", `"342391"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0x123456789abcdef"]}`, "", `"81985529216486895"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0b1010101010101"]}`, "", `"5461"`) + require.NoErrorf(t, err, "failed to query") + + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"01234567"}]}`, "", `"342391"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"0x123456789abcdef"}]}`, "", `"81985529216486895"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"0b1010101010101"}]}`, "", `"5461"`) + require.NoErrorf(t, err, "failed to query") + + + // hardfork 3 + bc.HardforkVersion = 3 + + // block octal, hex and binary + + tx := NewLuaTxCall("user1", "contract1", 0, `{"Name":"parse_bignum", "Args":["01234567"]}`) + err = bc.ConnectBlock(tx) + require.NoErrorf(t, err, "failed to call tx") + receipt := bc.GetReceipt(tx.Hash()) + assert.Equalf(t, `"1234567"`, receipt.GetRet(), "contract Call ret error") + + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["01234567"]}`, "", `"1234567"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0x123456789abcdef"]}`, "bignum invalid number string", `""`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0b1010101010101"]}`, "bignum invalid number string", `""`) + require.NoErrorf(t, err, "failed to query") + + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"01234567"}]}`, "", `"1234567"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"0x123456789abcdef"}]}`, "bignum invalid number string", `""`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"0b1010101010101"}]}`, "bignum invalid number string", `""`) + require.NoErrorf(t, err, "failed to query") + + + // hardfork 4 + bc.HardforkVersion = 4 + + // process hex, binary. block octal + + tx = NewLuaTxCall("user1", "contract1", 0, `{"Name":"parse_bignum", "Args":["01234567"]}`) + err = bc.ConnectBlock(tx) + require.NoErrorf(t, err, "failed to call tx") + receipt = bc.GetReceipt(tx.Hash()) + assert.Equalf(t, `"1234567"`, receipt.GetRet(), "contract Call ret error") + + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["01234567"]}`, "", `"1234567"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0x123456789abcdef"]}`, "", `"81985529216486895"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0b1010101010101"]}`, "", `"5461"`) + require.NoErrorf(t, err, "failed to query") + + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"01234567"}]}`, "", `"1234567"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"0x123456789abcdef"}]}`, "", `"81985529216486895"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"0b1010101010101"}]}`, "", `"5461"`) + require.NoErrorf(t, err, "failed to query") + +} + func checkRandomIntValue(v string, min, max int) error { n, _ := strconv.Atoi(v) if n < min || n > max { From 0a16b5c18224725ab3fbfec9ec917bb98d1285fa Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 27 Sep 2023 04:20:14 +0000 Subject: [PATCH 058/182] compile deployed code to bytecode on V4 --- contract/vm.go | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/contract/vm.go b/contract/vm.go index 992496850..1f20e62f8 100644 --- a/contract/vm.go +++ b/contract/vm.go @@ -1017,17 +1017,33 @@ func PreloadExecutor(bs *state.BlockState, contractState *state.ContractState, p return ce, ce.err } -func setContract(contractState *state.ContractState, contractAddress, payload []byte) ([]byte, []byte, error) { +func setContract(contractState *state.ContractState, contractAddress, payload []byte, ctx *vmContext) ([]byte, []byte, error) { + codePayload := luacUtil.LuaCodePayload(payload) if _, err := codePayload.IsValidFormat(); err != nil { ctrLgr.Warn().Err(err).Str("contract", types.EncodeAddress(contractAddress)).Msg("deploy") return nil, nil, err } code := codePayload.Code() + + // if hardfork version 4 + if ctx.blockInfo.ForkVersion >= 4 { + // the payload must be lua code. compile it to bytecode + var err error + code, err = Compile(string(code), nil) + if err != nil { + ctrLgr.Warn().Err(err).Str("contract", types.EncodeAddress(contractAddress)).Msg("deploy") + return nil, nil, err + } + //} else { + // on previous hardfork versions the payload is bytecode + } + err := contractState.SetCode(code.Bytes()) if err != nil { return nil, nil, err } + contract := getContract(contractState, nil) if contract == nil { err = fmt.Errorf("cannot deploy contract %s", types.EncodeAddress(contractAddress)) @@ -1043,11 +1059,11 @@ func setContract(contractState *state.ContractState, contractAddress, payload [] func Create( contractState *state.ContractState, - code, contractAddress []byte, + payload, contractAddress []byte, ctx *vmContext, ) (string, []*types.Event, *big.Int, error) { - if len(code) == 0 { + if len(payload) == 0 { return "", nil, ctx.usedFee(), errors.New("contract code is required") } @@ -1056,7 +1072,7 @@ func Create( } // save the contract code - contract, args, err := setContract(contractState, contractAddress, code) + contract, args, err := setContract(contractState, contractAddress, payload, ctx) if err != nil { return "", nil, ctx.usedFee(), err } From ff9cf3c9943e57b2b62f34202266fb5ed47dd78f Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 27 Sep 2023 06:28:28 +0000 Subject: [PATCH 059/182] aergocli: deploy as plain code --- cmd/aergocli/cmd/contract.go | 46 +++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/cmd/aergocli/cmd/contract.go b/cmd/aergocli/cmd/contract.go index 0e8bbb2aa..abca9e920 100644 --- a/cmd/aergocli/cmd/contract.go +++ b/cmd/aergocli/cmd/contract.go @@ -70,17 +70,17 @@ func init() { contractCmd.PersistentFlags().Uint64VarP(&gas, "gaslimit", "g", 0, "Gas limit") deployCmd := &cobra.Command{ - Use: `deploy [flags] --payload 'payload string' [args] - aergocli contract deploy [flags] [args] + Use: `deploy [flags] [args] + aergocli contract deploy [flags] --payload 'payload string' [args] - You can pass constructor arguments by passing a JSON string as the optional final parameter, e.g. "[1, 2, 3]".`, - Short: "Deploy a compiled contract to the server", - Args: nArgs([]int{1, 2, 3, 4}), + You can pass arguments to the constructor() function by passing a JSON string as the optional final parameter, e.g. '[1, "test"]'`, + Short: "Deploy a contract to the server", + Args: nArgs([]int{1, 2, 3}), RunE: runDeployCmd, DisableFlagsInUseLine: true, } deployCmd.PersistentFlags().Uint64Var(&nonce, "nonce", 0, "manually set a nonce (default: set nonce automatically)") - deployCmd.PersistentFlags().StringVar(&data, "payload", "", "result of compiling a contract") + deployCmd.PersistentFlags().StringVar(&data, "payload", "", "result of compiling a contract with aergoluac") deployCmd.PersistentFlags().StringVar(&amount, "amount", "0", "amount of token to send with deployment, in aer") deployCmd.PersistentFlags().StringVarP(&contractID, "redeploy", "r", "", "redeploy the contract") deployCmd.Flags().StringVar(&pw, "password", "", "password (optional, will be asked on the terminal if not given)") @@ -164,9 +164,18 @@ func runDeployCmd(cmd *cobra.Command, args []string) error { nonce = state.GetNonce() + 1 } + chainInfo, err := client.GetChainInfo(context.Background(), &types.Empty{}) + if err != nil { + return fmt.Errorf("could not retrieve chain info: %v", err.Error()) + } + var payload []byte if len(data) == 0 { - if len(args) < 3 { + if chainInfo.Id.Version < 4 { + cmd.SilenceUsage = false + return errors.New("for old hardforks use aergoluac and --payload method instead") + } + if len(args) < 2 { cmd.SilenceUsage = false return errors.New("not enough arguments") } @@ -174,21 +183,20 @@ func runDeployCmd(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("failed to read code file: %v", err.Error()) } - var abi []byte - abi, err = ioutil.ReadFile(args[2]) - if err != nil { - return fmt.Errorf("failed to read abi file: %v", err.Error()) - } - if len(args) == 4 { + if len(args) == 3 { var ci types.CallInfo - err = json.Unmarshal([]byte(args[3]), &ci.Args) + err = json.Unmarshal([]byte(args[2]), &ci.Args) if err != nil { - return fmt.Errorf("failed to parse JSON: %v", err.Error()) + return fmt.Errorf("failed to parse arguments (JSON): %v", err.Error()) } - deployArgs = []byte(args[3]) + deployArgs = []byte(args[2]) } - payload = luac.NewLuaCodePayload(luac.NewLuaCode(code, abi), deployArgs) + payload = luac.NewLuaCodePayload(luac.LuaCode(code), deployArgs) } else { + if chainInfo.Id.Version >= 4 { + cmd.SilenceUsage = false + return errors.New("this chain only accepts deploy in plain source code\nuse the other method instead") + } if len(args) == 2 { var ci types.CallInfo err = json.Unmarshal([]byte(args[1]), &ci.Args) @@ -199,6 +207,10 @@ func runDeployCmd(cmd *cobra.Command, args []string) error { } // check if the data is in hex format if isHexString(data) { + if deployArgs != nil { + cmd.SilenceUsage = false + return errors.New("the call arguments are expected to be already on the hex data") + } // the data is expected to be copied from aergoscan view of // the transaction that deployed the contract payload, err = hex.DecodeString(data) From e5c3d542e3d808d63712256d1d604de11b5857b7 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 27 Sep 2023 23:11:10 +0000 Subject: [PATCH 060/182] add bignum.ispositive() --- contract/bignum_module.c | 68 ++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/contract/bignum_module.c b/contract/bignum_module.c index a9b07e953..2045b1ea0 100644 --- a/contract/bignum_module.c +++ b/contract/bignum_module.c @@ -255,6 +255,13 @@ static int Bisneg(lua_State *L) { return 1; } +static int Bispos(lua_State *L) { + mp_num a = Bget(L, 1); + lua_gasuse(L, 10); + lua_pushboolean(L, (mpz_sgn(MPZ(a)) > 0)); + return 1; +} + static int Bnumber(lua_State *L) { lua_gasuse(L, 50); Bget(L, 1); @@ -498,7 +505,41 @@ const char *init_bignum() { return NULL; } -static const luaL_Reg R[] = { +static const luaL_Reg bignum_lib_v2[] = { + { "__add", Badd }, /* __add(x,y) */ + { "__div", Bdiv }, /* __div(x,y) */ + { "__eq", Beq }, /* __eq(x,y) */ + { "__gc", Bgc }, + { "__lt", Blt }, /* __lt(x,y) */ + { "__mod", Bmod }, /* __mod(x,y) */ + { "__mul", Bmul }, /* __mul(x,y) */ + { "__pow", Bpow }, /* __pow(x,y) */ + { "__sub", Bsub }, /* __sub(x,y) */ + { "__tostring", Btostring}, /* __tostring(x) */ + { "__unm", Bneg }, /* __unm(x) */ + { "add", Badd }, + { "compare", Bcompare}, + { "div", Bdiv }, + { "divmod", Bdivmod }, + { "isneg", Bisneg }, + { "iszero", Biszero }, + { "mod", Bmod }, + { "mul", Bmul }, + { "neg", Bneg }, + { "number", Bnumber }, + { "pow", Bpow }, + { "powmod", Bpowmod }, + { "sqrt", Bsqrt }, + { "sub", Bsub }, + { "tonumber", Btonumber}, + { "tostring", Btostring}, + { "isbignum", Bis }, + { "tobyte", Btobyte }, + { "frombyte", Bfrombyte }, + { NULL, NULL } +}; + +static const luaL_Reg bignum_lib_v4[] = { { "__add", Badd }, /* __add(x,y) */ { "__div", Bdiv }, /* __div(x,y) */ { "__eq", Beq }, /* __eq(x,y) */ @@ -515,7 +556,9 @@ static const luaL_Reg R[] = { { "div", Bdiv }, { "divmod", Bdivmod }, { "isneg", Bisneg }, + { "isnegative", Bisneg }, { "iszero", Biszero }, + { "ispositive", Bispos }, { "mod", Bmod }, { "mul", Bmul }, { "neg", Bneg }, @@ -534,17 +577,22 @@ static const luaL_Reg R[] = { LUALIB_API int luaopen_bignum(lua_State *L) { - luaL_newmetatable(L,MYTYPE); - lua_setglobal(L,MYNAME); - luaL_register(L,MYNAME,R); + luaL_newmetatable(L, MYTYPE); + lua_setglobal(L, MYNAME); + + if (vm_is_hardfork(L, 4)) { + luaL_register(L, MYNAME, bignum_lib_v4); + } else { + luaL_register(L, MYNAME, bignum_lib_v2); + } - lua_pushliteral(L,"version"); /* version */ - lua_pushliteral(L,MYVERSION); - lua_settable(L,-3); + lua_pushliteral(L, "version"); /* version */ + lua_pushliteral(L, MYVERSION); + lua_settable(L, -3); - lua_pushliteral(L,"__index"); - lua_pushvalue(L,-2); - lua_settable(L,-3); + lua_pushliteral(L, "__index"); + lua_pushvalue(L, -2); + lua_settable(L, -3); lua_pop(L, 1); return 1; From 309000c56c7d0328fb9543f0a9d94d17c9144ca4 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 28 Sep 2023 00:14:04 +0000 Subject: [PATCH 061/182] add tests --- contract/measure/aef.lua | 18 ++++++++++++++++++ contract/vm_dummy/test_files/type_bignum.lua | 17 ++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/contract/measure/aef.lua b/contract/measure/aef.lua index 7931e25e3..36450f0d6 100644 --- a/contract/measure/aef.lua +++ b/contract/measure/aef.lua @@ -152,6 +152,24 @@ function bignum_fns() local b_b = bignum.number(b) local pi_b = bignum.number(pi) local pi1_b = bignum.number(pi1) + if system.version() >= 4 then + print("bignum.ispositive") + m1k(bignum.ispositive, nines_b) + m1k(bignum.ispositive, nines1_b) + m1k(bignum.ispositive, nines2_b) + m1k(bignum.ispositive, one_b) + m1k(bignum.ispositive, b_b) + m1k(bignum.ispositive, pi_b) + m1k(bignum.ispositive, pi1_b) + print("bignum.isnegative") + m1k(bignum.isnegative, nines_b) + m1k(bignum.isnegative, nines1_b) + m1k(bignum.isnegative, nines2_b) + m1k(bignum.isnegative, one_b) + m1k(bignum.isnegative, b_b) + m1k(bignum.isnegative, pi_b) + m1k(bignum.isnegative, pi1_b) + end print("bignum.isneg") m1k(bignum.isneg, nines_b) m1k(bignum.isneg, nines1_b) diff --git a/contract/vm_dummy/test_files/type_bignum.lua b/contract/vm_dummy/test_files/type_bignum.lua index 280392b9e..63e8c9048 100644 --- a/contract/vm_dummy/test_files/type_bignum.lua +++ b/contract/vm_dummy/test_files/type_bignum.lua @@ -43,8 +43,23 @@ function calcBignum() bg6 = bignum.number(n1) assert(bg3 == bg4 and bg4 == bg5) bg5 = bg1 - bg3 - assert(bignum.isneg(bg5) and bg5 == bignum.neg(bg1)) system.print(bg3, bg5, bg6) + if system.version() >= 4 then + -- ispositive() and isnegative() and iszero() + assert(bignum.isnegative(bg5) and bg5 == bignum.neg(bg1)) + assert(bignum.ispositive(bg1) and bignum.ispositive(bg3)) + assert(not bignum.ispositive(bg5) and not bignum.iszero(bg5)) + assert(not bignum.isnegative(bg1) and not bignum.iszero(bg1)) + -- ispositive() and isneg() and iszero() + assert(bignum.isneg(bg5) and bg5 == bignum.neg(bg1)) + assert(bignum.ispositive(bg1) and bignum.ispositive(bg3)) + assert(not bignum.ispositive(bg5) and not bignum.iszero(bg5)) + assert(not bignum.isneg(bg1) and not bignum.iszero(bg1)) + else + -- isneg() and iszero() + assert(bignum.isneg(bg5) and bg5 == bignum.neg(bg1)) + assert(not bignum.isneg(bg1) and not bignum.iszero(bg1)) + end bg6 = bignum.number(1) assert(bg6 > bg5) a = bignum.number(2) From 5fbcc4079fc75ed0c90f28ae90bdcdc64a6a028c Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 28 Sep 2023 02:37:25 +0000 Subject: [PATCH 062/182] add system.version() --- contract/system_module.c | 42 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/contract/system_module.c b/contract/system_module.c index 2a7917f8a..006b349e2 100644 --- a/contract/system_module.c +++ b/contract/system_module.c @@ -15,7 +15,7 @@ static int systemPrint(lua_State *L) { int service = getLuaExecContext(L); lua_gasuse(L, 100); - jsonValue = lua_util_get_json_from_stack (L, 1, lua_gettop(L), true); + jsonValue = lua_util_get_json_from_stack(L, 1, lua_gettop(L), true); if (jsonValue == NULL) { luaL_throwerror(L); } @@ -50,7 +50,7 @@ int setItemWithPrefix(lua_State *L) { dbKey = getDbKey(L, &keylen); - jsonValue = lua_util_get_json (L, 2, false); + jsonValue = lua_util_get_json(L, 2, false); if (jsonValue == NULL) { luaL_throwerror(L); } @@ -456,7 +456,36 @@ static int is_fee_delegation(lua_State *L) { return 1; } -static const luaL_Reg sys_lib[] = { +static int system_version(lua_State *L) { + lua_gasuse(L, 100); + lua_pushinteger(L, luaL_hardforkversion(L)); + return 1; +} + + +static const luaL_Reg system_lib_v1[] = { + {"print", systemPrint}, + {"setItem", setItem}, + {"getItem", getItem}, + {"getSender", getSender}, + {"getCreator", getCreator}, + {"getTxhash", getTxhash}, + {"getBlockheight", getBlockHeight}, + {"getTimestamp", getTimestamp}, + {"getContractID", getContractID}, + {"getOrigin", getOrigin}, + {"getAmount", getAmount}, + {"getPrevBlockHash", getPrevBlockHash}, + {"date", os_date}, + {"time", os_time}, + {"difftime", os_difftime}, + {"random", lua_random}, + {"isContract", is_contract}, + {"isFeeDelegation", is_fee_delegation}, + {NULL, NULL} +}; + +static const luaL_Reg system_lib_v4[] = { {"print", systemPrint}, {"setItem", setItem}, {"getItem", getItem}, @@ -475,11 +504,16 @@ static const luaL_Reg sys_lib[] = { {"random", lua_random}, {"isContract", is_contract}, {"isFeeDelegation", is_fee_delegation}, + {"version", system_version}, {NULL, NULL} }; int luaopen_system(lua_State *L) { - luaL_register(L, "system", sys_lib); + if (vm_is_hardfork(L, 4)) { + luaL_register(L, "system", system_lib_v4); + } else { + luaL_register(L, "system", system_lib_v1); + } lua_pop(L, 1); return 1; } From d2ac961aec90bb9ed9dda02a7cbf489988fa85a3 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 4 Oct 2023 05:25:49 +0000 Subject: [PATCH 063/182] update integration tests with new method --- tests/test-gas-per-function-v4.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/test-gas-per-function-v4.sh b/tests/test-gas-per-function-v4.sh index 299307f66..b58b8a080 100755 --- a/tests/test-gas-per-function-v4.sh +++ b/tests/test-gas-per-function-v4.sh @@ -6,11 +6,7 @@ fork_version=$1 echo "-- deploy --" -../bin/aergoluac --payload ../contract/vm_dummy/test_files/gas_per_function.lua > payload.out - -txhash=$(../bin/aergocli --keystore . --password bmttest \ - contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ - --payload `cat payload.out` | jq .hash | sed 's/"//g') +deploy ../contract/vm_dummy/test_files/gas_per_function.lua get_receipt $txhash From 78574a027c7fe5ad22bd645acab542482522a7cc Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 4 Oct 2023 21:23:20 +0000 Subject: [PATCH 064/182] update integration tests with new method --- tests/test-name-service.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/test-name-service.sh b/tests/test-name-service.sh index c8a3f9851..8fdb8db29 100755 --- a/tests/test-name-service.sh +++ b/tests/test-name-service.sh @@ -6,11 +6,7 @@ fork_version=$1 echo "-- deploy contract --" -../bin/aergoluac --payload test-name-service.lua > payload.out - -txhash=$(../bin/aergocli --keystore . --password bmttest \ - contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ - --payload `cat payload.out` | jq .hash | sed 's/"//g') +deploy test-name-service.lua get_receipt $txhash From 6bb2c2f4e312ed0e7541255b74716b953de8a851 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 5 Oct 2023 07:34:59 +0000 Subject: [PATCH 065/182] add test for transaction types --- tests/run_tests.sh | 4 + tests/test-transaction-types.sh | 311 ++++++++++++++++++++++++++++++++ 2 files changed, 315 insertions(+) create mode 100755 tests/test-transaction-types.sh diff --git a/tests/run_tests.sh b/tests/run_tests.sh index bb5defb65..6ff4f02fc 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -89,6 +89,7 @@ check ./test-gas-bf.sh check ./test-gas-verify-proof.sh check ./test-gas-per-function-v2.sh check ./test-contract-deploy.sh +check ./test-transaction-types.sh # change the hardfork version set_version 3 @@ -101,6 +102,7 @@ check ./test-gas-bf.sh check ./test-gas-verify-proof.sh check ./test-gas-per-function-v3.sh check ./test-contract-deploy.sh +check ./test-transaction-types.sh # change the hardfork version set_version 4 @@ -112,6 +114,8 @@ check ./test-gas-op.sh check ./test-gas-bf.sh check ./test-gas-verify-proof.sh check ./test-gas-per-function-v4.sh +check ./test-contract-deploy.sh +check ./test-transaction-types.sh # terminate the server process echo "" diff --git a/tests/test-transaction-types.sh b/tests/test-transaction-types.sh new file mode 100755 index 000000000..348ae885d --- /dev/null +++ b/tests/test-transaction-types.sh @@ -0,0 +1,311 @@ +set -e +source common.sh + +fork_version=$1 + + +# contract without "default" function +cat > test-tx-type-1.lua << EOF +function default() + return system.getAmount() +end + +function default2() + return system.getAmount() +end + +abi.payable(default2) +EOF + +# contract with not payable "default" function +cat > test-tx-type-2.lua << EOF +function default() + return system.getAmount() +end + +abi.register(default) +EOF + +# contract with payable "default" function +cat > test-tx-type-3.lua << EOF +function default() + return system.getAmount() +end + +abi.payable(default) +EOF + +echo "-- deploy 1 --" +deploy test-tx-type-1.lua +get_receipt $txhash +status=$(cat receipt.json | jq .status | sed 's/"//g') +no_default=$(cat receipt.json | jq .contractAddress | sed 's/"//g') +assert_equals "$status" "CREATED" + +echo "-- deploy 2 --" +deploy test-tx-type-2.lua +get_receipt $txhash +status=$(cat receipt.json | jq .status | sed 's/"//g') +not_payable=$(cat receipt.json | jq .contractAddress | sed 's/"//g') +assert_equals "$status" "CREATED" + +echo "-- deploy 3 --" +deploy test-tx-type-3.lua +get_receipt $txhash +status=$(cat receipt.json | jq .status | sed 's/"//g') +payable_default=$(cat receipt.json | jq .contractAddress | sed 's/"//g') +assert_equals "$status" "CREATED" + +# delete the contract files +rm test-tx-type-*.lua + + +# get some info +from=AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R +chainIdHash=$(../bin/aergocli blockchain | jq -r '.ChainIdHash') + + +echo "-- TRANSFER type, contract without 'default' function --" + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + sendtx --from $from --to $no_default --amount 1aergo \ + | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') + +assert_equals "$status" "ERROR" +assert_equals "$ret" "'default' is not payable" +#assert_equals "$gasUsed" "117861" + + +echo "-- TRANSFER type, contract with not payable 'default' function --" + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + sendtx --from $from --to $not_payable --amount 1aergo \ + | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') + +assert_equals "$status" "ERROR" +assert_equals "$ret" "'default' is not payable" +#assert_equals "$gasUsed" "117861" + + +echo "-- TRANSFER type, contract with payable 'default' function --" + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + sendtx --from $from --to $payable_default --amount 1aergo \ + | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') + +assert_equals "$status" "SUCCESS" +assert_equals "$ret" "1000000000000000000" +#assert_equals "$gasUsed" "117861" + + +nonce=$(../bin/aergocli getstate --address $from | jq -r '.nonce') + +#echo "-- TRANSFER type, trying to make a call --" + + +echo "-- NORMAL type, contract without 'default' function --" + +nonce=$((nonce + 1)) + +#"Payload": "'$from'", + +jsontx='{ +"Account": "'$from'", +"Recipient": "'$no_default'", +"Amount": "1.23aergo", +"Type": 0, +"Nonce": '$nonce', +"chainIdHash": "'$chainIdHash'"}' + +jsontx=$(../bin/aergocli --keystore . --password bmttest \ + signtx --address $from --jsontx "$jsontx" ) + +txhash=$(../bin/aergocli committx --jsontx "$jsontx" | jq .results[0].hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') + +if [ "$fork_version" -ge "4" ]; then + assert_equals "$status" "ERROR" + assert_equals "$ret" "tx not allowed recipient" + #assert_equals "$gasUsed" "117861" +else + assert_equals "$status" "ERROR" + assert_equals "$ret" "'default' is not payable" + #assert_equals "$gasUsed" "117861" +fi + + +echo "-- NORMAL type, contract with not payable 'default' function --" + +nonce=$((nonce + 1)) + +jsontx='{ +"Account": "'$from'", +"Recipient": "'$not_payable'", +"Amount": "1.23aergo", +"Type": 0, +"Nonce": '$nonce', +"chainIdHash": "'$chainIdHash'"}' + +jsontx=$(../bin/aergocli --keystore . --password bmttest \ + signtx --address $from --jsontx "$jsontx" ) + +txhash=$(../bin/aergocli committx --jsontx "$jsontx" | jq .results[0].hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') + +if [ "$fork_version" -ge "4" ]; then + assert_equals "$status" "ERROR" + assert_equals "$ret" "tx not allowed recipient" + #assert_equals "$gasUsed" "117861" +else + assert_equals "$status" "ERROR" + assert_equals "$ret" "'default' is not payable" + #assert_equals "$gasUsed" "117861" +fi + + +echo "-- NORMAL type, contract with payable 'default' function --" + +nonce=$((nonce + 1)) + +jsontx='{ +"Account": "'$from'", +"Recipient": "'$payable_default'", +"Amount": "1.23aergo", +"Type": 0, +"Nonce": '$nonce', +"chainIdHash": "'$chainIdHash'"}' + +jsontx=$(../bin/aergocli --keystore . --password bmttest \ + signtx --address $from --jsontx "$jsontx" ) + +txhash=$(../bin/aergocli committx --jsontx "$jsontx" | jq .results[0].hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') + +if [ "$fork_version" -ge "4" ]; then + assert_equals "$status" "ERROR" + assert_equals "$ret" "tx not allowed recipient" + #assert_equals "$gasUsed" "117861" +else + assert_equals "$status" "SUCCESS" + assert_equals "$ret" "1230000000000000000" + #assert_equals "$gasUsed" "117861" +fi + + + +echo "-- CALL type, contract without 'default' function (not sending) --" + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + $no_default default | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') + +assert_equals "$status" "ERROR" +assert_equals "$ret" "undefined function: default" +#assert_equals "$gasUsed" "117861" + + +echo "-- CALL type, contract without 'default' function (sending) --" + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + $no_default default --amount 1aergo | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') + +assert_equals "$status" "ERROR" +assert_equals "$ret" "'default' is not payable" +#assert_equals "$gasUsed" "117861" + + +echo "-- CALL type, contract with not payable 'default' function (not sending) --" + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + $not_payable default | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') + +assert_equals "$status" "SUCCESS" +assert_equals "$ret" "0" +#assert_equals "$gasUsed" "117861" + + +echo "-- CALL type, contract with not payable 'default' function (sending) --" + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + $not_payable default --amount 1aergo | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') + +assert_equals "$status" "ERROR" +assert_equals "$ret" "'default' is not payable" +#assert_equals "$gasUsed" "117861" + + +echo "-- CALL type, contract with payable 'default' function --" + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + contract call AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ + $payable_default default --amount 1aergo | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') + +assert_equals "$status" "SUCCESS" +assert_equals "$ret" "1000000000000000000" +#assert_equals "$gasUsed" "117861" From 2f2e1d38a8f3ff170ee8dc4c1a528027f6e03b62 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 6 Oct 2023 03:33:32 +0000 Subject: [PATCH 066/182] add new test cases --- tests/test-transaction-types.sh | 112 ++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 4 deletions(-) diff --git a/tests/test-transaction-types.sh b/tests/test-transaction-types.sh index 348ae885d..a3f149080 100755 --- a/tests/test-transaction-types.sh +++ b/tests/test-transaction-types.sh @@ -121,7 +121,7 @@ nonce=$(../bin/aergocli getstate --address $from | jq -r '.nonce') #echo "-- TRANSFER type, trying to make a call --" -echo "-- NORMAL type, contract without 'default' function --" +echo "-- NORMAL type, contract without 'default' function (not sending) --" nonce=$((nonce + 1)) @@ -129,7 +129,43 @@ nonce=$((nonce + 1)) jsontx='{ "Account": "'$from'", -"Recipient": "'$no_default'", +"Recipient": "'$no_default'", +"Amount": "0", +"Type": 0, +"Nonce": '$nonce', +"chainIdHash": "'$chainIdHash'"}' + +jsontx=$(../bin/aergocli --keystore . --password bmttest \ + signtx --address $from --jsontx "$jsontx" ) + +txhash=$(../bin/aergocli committx --jsontx "$jsontx" | jq .results[0].hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') + +if [ "$fork_version" -ge "4" ]; then + assert_equals "$status" "ERROR" + assert_equals "$ret" "tx not allowed recipient" + #assert_equals "$gasUsed" "117861" +else + assert_equals "$status" "ERROR" + assert_equals "$ret" "undefined function: default" + #assert_equals "$gasUsed" "117861" +fi + + +echo "-- NORMAL type, contract without 'default' function (sending) --" + +nonce=$((nonce + 1)) + +#"Payload": "'$from'", + +jsontx='{ +"Account": "'$from'", +"Recipient": "'$no_default'", "Amount": "1.23aergo", "Type": 0, "Nonce": '$nonce', @@ -157,7 +193,41 @@ else fi -echo "-- NORMAL type, contract with not payable 'default' function --" +echo "-- NORMAL type, contract with not payable 'default' function (not sending) --" + +nonce=$((nonce + 1)) + +jsontx='{ +"Account": "'$from'", +"Recipient": "'$not_payable'", +"Amount": "0", +"Type": 0, +"Nonce": '$nonce', +"chainIdHash": "'$chainIdHash'"}' + +jsontx=$(../bin/aergocli --keystore . --password bmttest \ + signtx --address $from --jsontx "$jsontx" ) + +txhash=$(../bin/aergocli committx --jsontx "$jsontx" | jq .results[0].hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') + +if [ "$fork_version" -ge "4" ]; then + assert_equals "$status" "ERROR" + assert_equals "$ret" "tx not allowed recipient" + #assert_equals "$gasUsed" "117861" +else + assert_equals "$status" "SUCCESS" + assert_equals "$ret" "0" + #assert_equals "$gasUsed" "117861" +fi + + +echo "-- NORMAL type, contract with not payable 'default' function (sending) --" nonce=$((nonce + 1)) @@ -191,7 +261,41 @@ else fi -echo "-- NORMAL type, contract with payable 'default' function --" +echo "-- NORMAL type, contract with payable 'default' function (not sending) --" + +nonce=$((nonce + 1)) + +jsontx='{ +"Account": "'$from'", +"Recipient": "'$payable_default'", +"Amount": "0", +"Type": 0, +"Nonce": '$nonce', +"chainIdHash": "'$chainIdHash'"}' + +jsontx=$(../bin/aergocli --keystore . --password bmttest \ + signtx --address $from --jsontx "$jsontx" ) + +txhash=$(../bin/aergocli committx --jsontx "$jsontx" | jq .results[0].hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') +gasUsed=$(cat receipt.json | jq .gasUsed | sed 's/"//g') + +if [ "$fork_version" -ge "4" ]; then + assert_equals "$status" "ERROR" + assert_equals "$ret" "tx not allowed recipient" + #assert_equals "$gasUsed" "117861" +else + assert_equals "$status" "SUCCESS" + assert_equals "$ret" "0" + #assert_equals "$gasUsed" "117861" +fi + + +echo "-- NORMAL type, contract with payable 'default' function (sending) --" nonce=$((nonce + 1)) From c57a6cbd00260187931affe411a7663ebc522e5e Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 6 Oct 2023 04:05:56 +0000 Subject: [PATCH 067/182] temporarily disable usage of new aergocli deploy --- tests/common.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/common.sh b/tests/common.sh index bd5abe899..e004b3115 100644 --- a/tests/common.sh +++ b/tests/common.sh @@ -2,12 +2,12 @@ get_deploy_args() { contract_file=$1 - if [ "$fork_version" -ge "4" ]; then + #if [ "$fork_version" -ge "4" ]; then deploy_args="$contract_file" - else - ../bin/aergoluac --payload $contract_file > payload.out - deploy_args="--payload `cat payload.out`" - fi + #else + # ../bin/aergoluac --payload $contract_file > payload.out + # deploy_args="--payload `cat payload.out`" + #fi } From 09fa2518774cd30641260da7e4937ffd32c24471 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 6 Oct 2023 04:07:20 +0000 Subject: [PATCH 068/182] use new aergocli deploy method on tests --- tests/common.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/common.sh b/tests/common.sh index e004b3115..bd5abe899 100644 --- a/tests/common.sh +++ b/tests/common.sh @@ -2,12 +2,12 @@ get_deploy_args() { contract_file=$1 - #if [ "$fork_version" -ge "4" ]; then + if [ "$fork_version" -ge "4" ]; then deploy_args="$contract_file" - #else - # ../bin/aergoluac --payload $contract_file > payload.out - # deploy_args="--payload `cat payload.out`" - #fi + else + ../bin/aergoluac --payload $contract_file > payload.out + deploy_args="--payload `cat payload.out`" + fi } From 201c9c0171ff2e801c7e1918ce8586eaee04c947 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 6 Oct 2023 04:23:58 +0000 Subject: [PATCH 069/182] fix contract deploy --- tests/common.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/common.sh b/tests/common.sh index e004b3115..d0884c4b4 100644 --- a/tests/common.sh +++ b/tests/common.sh @@ -3,10 +3,10 @@ get_deploy_args() { contract_file=$1 #if [ "$fork_version" -ge "4" ]; then - deploy_args="$contract_file" + # deploy_args="$contract_file" #else - # ../bin/aergoluac --payload $contract_file > payload.out - # deploy_args="--payload `cat payload.out`" + ../bin/aergoluac --payload $contract_file > payload.out + deploy_args="--payload `cat payload.out`" #fi } From f203e2f5174a9487fb108554f7b2702d7eceae0e Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 6 Oct 2023 06:24:45 +0000 Subject: [PATCH 070/182] use plain code on vm_dummy for V4 --- contract/vm_dummy/vm_dummy.go | 23 +++++++++++++++++ contract/vm_dummy/vm_dummy_dbg.go | 36 --------------------------- contract/vm_dummy/vm_dummy_release.go | 28 --------------------- 3 files changed, 23 insertions(+), 64 deletions(-) delete mode 100644 contract/vm_dummy/vm_dummy_dbg.go delete mode 100644 contract/vm_dummy/vm_dummy_release.go diff --git a/contract/vm_dummy/vm_dummy.go b/contract/vm_dummy/vm_dummy.go index 5de79b039..158386a45 100644 --- a/contract/vm_dummy/vm_dummy.go +++ b/contract/vm_dummy/vm_dummy.go @@ -407,6 +407,19 @@ func NewLuaTxDeploy(sender, recipient string, amount uint64, code string) *luaTx return NewLuaTxDeployBig(sender, recipient, types.NewAmount(amount, types.Aer), code) } +func NewLuaTxDeployBig(sender, recipient string, amount *big.Int, code string) *luaTxDeploy { + return &luaTxDeploy{ + luaTxContractCommon: luaTxContractCommon{ + _sender: contract.StrHash(sender), + _recipient: contract.StrHash(recipient), + _payload: util.NewLuaCodePayload([]byte(code), nil), + _amount: amount, + txId: newTxId(), + }, + cErr: nil, + } +} + /* func contract.StrHash(d string) []byte { // using real address @@ -526,6 +539,16 @@ func (l *luaTxDeploy) run(bs *state.BlockState, bc *DummyChain, bi *types.BlockH if l.cErr != nil { return l.cErr } + if bc.HardforkVersion < 4 { + // compile the plain code to bytecode + payload := util.LuaCodePayload(l._payload) + code := string(payload.Code()) + byteCode, err := contract.Compile(code, nil) + if err != nil { + return err + } + l._payload = util.NewLuaCodePayload(byteCode, payload.Args()) + } return contractFrame(l, bs, bc, receiptTx, func(sender, contractV *state.V, contractId types.AccountID, eContractState *state.ContractState) (string, []*types.Event, *big.Int, error) { contractV.State().SqlRecoveryPoint = 1 diff --git a/contract/vm_dummy/vm_dummy_dbg.go b/contract/vm_dummy/vm_dummy_dbg.go deleted file mode 100644 index 52892417d..000000000 --- a/contract/vm_dummy/vm_dummy_dbg.go +++ /dev/null @@ -1,36 +0,0 @@ -//go:build Debug -// +build Debug - -package vm_dummy - -import ( - "math/big" - - luacUtil "github.com/aergoio/aergo/v2/cmd/aergoluac/util" - "github.com/aergoio/aergo/v2/contract" -) - -func getCompiledABI(code string) ([]byte, error) { - byteCodeAbi, err := contract.Compile(code, nil) - if err != nil { - return nil, err - } - return byteCodeAbi.ABI(), nil -} - -func NewLuaTxDeployBig(sender, recipient string, amount *big.Int, code string) *luaTxDeploy { - abi, err := getCompiledABI(code) - if err != nil { - return &luaTxDeploy{cErr: err} - } - return &luaTxDeploy{ - luaTxContractCommon: luaTxContractCommon{ - _sender: contract.StrHash(sender), - _recipient: contract.StrHash(recipient), - _payload: luacUtil.NewLuaCodePayload(luacUtil.NewLuaCode([]byte(code), abi), nil), - _amount: amount, - txId: newTxId(), - }, - cErr: nil, - } -} diff --git a/contract/vm_dummy/vm_dummy_release.go b/contract/vm_dummy/vm_dummy_release.go deleted file mode 100644 index f0a89f954..000000000 --- a/contract/vm_dummy/vm_dummy_release.go +++ /dev/null @@ -1,28 +0,0 @@ -//go:build !Debug -// +build !Debug - -package vm_dummy - -import ( - "math/big" - - "github.com/aergoio/aergo/v2/cmd/aergoluac/util" - "github.com/aergoio/aergo/v2/contract" -) - -func NewLuaTxDeployBig(sender, recipient string, amount *big.Int, code string) *luaTxDeploy { - byteCode, err := contract.Compile(code, nil) - if err != nil { - return &luaTxDeploy{cErr: err} - } - return &luaTxDeploy{ - luaTxContractCommon: luaTxContractCommon{ - _sender: contract.StrHash(sender), - _recipient: contract.StrHash(recipient), - _payload: util.NewLuaCodePayload(byteCode, nil), - _amount: amount, - txId: newTxId(), - }, - cErr: nil, - } -} From 8da9e06f64d718376600149061f2faff2f63c3b3 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Mon, 16 Oct 2023 11:13:29 +0000 Subject: [PATCH 071/182] update checking of hardfork version to V4 --- contract/vm_callback.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contract/vm_callback.go b/contract/vm_callback.go index 2093af7f2..13c9d4e29 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -1070,7 +1070,7 @@ func transformAmount(amountStr string, ctx *vmContext) (*big.Int, error) { res := index.FindAllIndex(r, -1) for _, pair := range res { parsedAmount := strings.TrimSpace(amountStr[prev:pair[0]]) - if HardforkConfig.IsV3Fork(ctx.blockInfo.No) { + if HardforkConfig.IsV4Fork(ctx.blockInfo.No) { if strings.Contains(parsedAmount,".") && pair[1] - pair[0] == 5 { parsedAmount = parseDecimalAmount(parsedAmount, 18) if parsedAmount == "error" { From bf1f5b1cad78c0eaff641f62119e09377724a433 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 17 Oct 2023 13:49:13 +0000 Subject: [PATCH 072/182] fix test-gas-per-function on V4 --- tests/common.sh | 2 +- tests/test-gas-per-function-v4.sh | 27 ++++++++++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/tests/common.sh b/tests/common.sh index 972ab7381..632e18d1d 100644 --- a/tests/common.sh +++ b/tests/common.sh @@ -69,7 +69,7 @@ get_receipt() { #echo "output: $output" if [[ $output == *"tx not found"* ]]; then - sleep 0.5 + sleep 0.4 counter=$((counter+1)) if [ $counter -gt 10 ]; then echo "Error: tx not found: $txhash" diff --git a/tests/test-gas-per-function-v4.sh b/tests/test-gas-per-function-v4.sh index 6613ff97a..0d8a95978 100755 --- a/tests/test-gas-per-function-v4.sh +++ b/tests/test-gas-per-function-v4.sh @@ -6,11 +6,7 @@ fork_version=$1 echo "-- deploy --" -../bin/aergoluac --payload ../contract/vm_dummy/test_files/gas_per_function.lua > payload.out - -txhash=$(../bin/aergocli --keystore . --password bmttest \ - contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ - --payload `cat payload.out` | jq .hash | sed 's/"//g') +deploy ../contract/vm_dummy/test_files/gas_per_function.lua get_receipt $txhash @@ -20,9 +16,26 @@ address=$(cat receipt.json | jq .contractAddress | sed 's/"//g') assert_equals "$status" "CREATED" +echo "-- transfer funds to the contract --" + +from=AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + sendtx --from $from --to $address --amount 5aergo \ + | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') + +assert_equals "$status" "SUCCESS" +assert_equals "$ret" "{}" + + echo "-- get account's nonce --" -account_state=$(../bin/aergocli getstate --address AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R) +account_state=$(../bin/aergocli getstate --address $from) nonce=$(echo $account_state | jq .nonce | sed 's/"//g') @@ -145,7 +158,7 @@ add_test "system.getCreator" 143761 add_test "system.getOrigin" 144261 add_test "contract.send" 144321 -add_test "contract.balance" 144402 +#add_test "contract.balance" 144402 add_test "contract.deploy" 168092 add_test "contract.call" 159738 add_test "contract.pcall" 160659 From ecf63bff5732a78daa580a398c1fbfadc358c705 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 18 Oct 2023 14:33:28 +0000 Subject: [PATCH 073/182] run vm tests on hardfork V4 --- contract/vm_dummy/vm_dummy_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index 88da6c7c4..db80c4bd1 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -20,7 +20,7 @@ import ( ) const min_version int32 = 2 -const max_version int32 = 3 +const max_version int32 = 4 func TestMaxCallDepth(t *testing.T) { //code := readLuaCode(t, "maxcalldepth_1.lua") From 3aa380a71a652f60b5ba94fead9b5c3c8ae46ca8 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 18 Oct 2023 14:40:39 +0000 Subject: [PATCH 074/182] add tests for toAddress() and toPubKey() --- contract/system_module.c | 2 +- .../vm_dummy/test_files/contract_system.lua | 11 +++++ contract/vm_dummy/vm_dummy_test.go | 47 +++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/contract/system_module.c b/contract/system_module.c index 4a0b1640e..645ec2850 100644 --- a/contract/system_module.c +++ b/contract/system_module.c @@ -545,7 +545,7 @@ static const luaL_Reg system_lib_v4[] = { {"time", os_time}, {"difftime", os_difftime}, {"random", lua_random}, - {"toPubkey", toPubkey}, + {"toPubKey", toPubkey}, {"toAddress", toAddress}, {"isContract", is_contract}, {"isFeeDelegation", is_fee_delegation}, diff --git a/contract/vm_dummy/test_files/contract_system.lua b/contract/vm_dummy/test_files/contract_system.lua index 88383efc7..a4c282fc2 100644 --- a/contract/vm_dummy/test_files/contract_system.lua +++ b/contract/vm_dummy/test_files/contract_system.lua @@ -5,3 +5,14 @@ function testState() end abi.register(testState) + + +function to_address(pubkey) + return system.toAddress(pubkey) +end + +function to_pubkey(address) + return system.toPubKey(address) +end + +abi.register_view(to_address, to_pubkey) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index db80c4bd1..15864d3b5 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -393,6 +393,53 @@ func TestContractSystem(t *testing.T) { exRv := fmt.Sprintf(`["%s","6FbDRScGruVdATaNWzD51xJkTfYCVwxSZDb7gzqCLzwf","AmhNNBNY7XFk4p5ym4CJf8nTcRTEHjWzAeXJfhP71244CjBCAQU3",%d,3,999]`, StrToAddress("user1"), bc.cBlock.Header.Timestamp/1e9) assert.Equal(t, exRv, receipt.GetRet(), "receipt ret error") + if version >= 4 { + + // system.toPubKey() + + err = bc.Query("system", `{"Name":"to_pubkey", "Args":["AmgKtCaGjH4XkXwny2Jb1YH5gdsJGJh78ibWEgLmRWBS5LMfQuTf"]}`, "", `"0x0c3270bb25fea5bf0029b57e78581647a143265810b84940dd24e543ddc618ab91"`) + require.NoErrorf(t, err, "failed to query") + + err = bc.Query("system", `{"Name":"to_pubkey", "Args":["Amhmj6kKZz7mPstBAPJWRe1e8RHP7bZ5pV35XatqTHMWeAVSyMkc"]}`, "", `"0x0cf0d0fd04f44db75d66409346102167d67c40a5d76d46748fc4533f0265d0f83f"`) + require.NoErrorf(t, err, "failed to query") + + err = bc.Query("system", `{"Name":"to_pubkey", "Args":["6FbDRScGruVdATaNWzD51xJkTfYCVwxSZDb7gzqCLzwf"]}`, "invalid address length", "") + require.NoErrorf(t, err, "failed to query") + + err = bc.Query("system", `{"Name":"to_pubkey", "Args":["0x0c3270bb25fea5bf0029b57e78581647a143265810b84940dd24e543ddc618ab91"]}`, "invalid address length", "") + require.NoErrorf(t, err, "failed to query") + + err = bc.Query("system", `{"Name":"to_pubkey", "Args":[""]}`, "invalid address length", "") + require.NoErrorf(t, err, "failed to query") + + err = bc.Query("system", `{"Name":"to_pubkey", "Args":[]}`, "string expected, got nil", "") + require.NoErrorf(t, err, "failed to query") + + // system.toAddress() + + err = bc.Query("system", `{"Name":"to_address", "Args":["0x0c3270bb25fea5bf0029b57e78581647a143265810b84940dd24e543ddc618ab91"]}`, "", `"AmgKtCaGjH4XkXwny2Jb1YH5gdsJGJh78ibWEgLmRWBS5LMfQuTf"`) + require.NoErrorf(t, err, "failed to query") + + err = bc.Query("system", `{"Name":"to_address", "Args":["0x0cf0d0fd04f44db75d66409346102167d67c40a5d76d46748fc4533f0265d0f83f"]}`, "", `"Amhmj6kKZz7mPstBAPJWRe1e8RHP7bZ5pV35XatqTHMWeAVSyMkc"`) + require.NoErrorf(t, err, "failed to query") + + err = bc.Query("system", `{"Name":"to_address", "Args":["0cf0d0fd04f44db75d66409346102167d67c40a5d76d46748fc4533f0265d0f83f"]}`, "", `"Amhmj6kKZz7mPstBAPJWRe1e8RHP7bZ5pV35XatqTHMWeAVSyMkc"`) + require.NoErrorf(t, err, "failed to query") + + err = bc.Query("system", `{"Name":"to_address", "Args":["AmhNNBNY7XFk4p5ym4CJf8nTcRTEHjWzAeXJfhP71244CjBCAQU3"]}`, "invalid public key", "") + require.NoErrorf(t, err, "failed to query") + + err = bc.Query("system", `{"Name":"to_address", "Args":["6FbDRScGruVdATaNWzD51xJkTfYCVwxSZDb7gzqCLzwf"]}`, "invalid public key", "") + require.NoErrorf(t, err, "failed to query") + + err = bc.Query("system", `{"Name":"to_address", "Args":[""]}`, "invalid public key", "") + require.NoErrorf(t, err, "failed to query") + + err = bc.Query("system", `{"Name":"to_address", "Args":[]}`, "string expected, got nil", "") + require.NoErrorf(t, err, "failed to query") + + } + } } From c1fd0f597b522f1fd2634ecf9ed4f2b0a999d521 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 18 Oct 2023 15:22:53 +0000 Subject: [PATCH 075/182] add test for system.version() --- contract/vm_dummy/test_files/contract_system.lua | 7 +++++++ contract/vm_dummy/vm_dummy_test.go | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/contract/vm_dummy/test_files/contract_system.lua b/contract/vm_dummy/test_files/contract_system.lua index 88383efc7..246cfc63b 100644 --- a/contract/vm_dummy/test_files/contract_system.lua +++ b/contract/vm_dummy/test_files/contract_system.lua @@ -5,3 +5,10 @@ function testState() end abi.register(testState) + + +function get_version() + return system.version() +end + +abi.register_view(get_version) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index db80c4bd1..b95b9c69f 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -393,6 +393,18 @@ func TestContractSystem(t *testing.T) { exRv := fmt.Sprintf(`["%s","6FbDRScGruVdATaNWzD51xJkTfYCVwxSZDb7gzqCLzwf","AmhNNBNY7XFk4p5ym4CJf8nTcRTEHjWzAeXJfhP71244CjBCAQU3",%d,3,999]`, StrToAddress("user1"), bc.cBlock.Header.Timestamp/1e9) assert.Equal(t, exRv, receipt.GetRet(), "receipt ret error") + if version >= 4 { + + tx = NewLuaTxCall("user1", "system", 0, `{"Name":"get_version", "Args":[]}`) + err = bc.ConnectBlock(tx) + require.NoErrorf(t, err, "failed to call tx") + + receipt = bc.GetReceipt(tx.Hash()) + expected := fmt.Sprintf(`%d`, version) + assert.Equal(t, expected, receipt.GetRet(), "receipt ret error") + + } + } } From bcc6cec3219fde499306ca1b3bbf72f8570d463a Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 18 Oct 2023 16:04:06 +0000 Subject: [PATCH 076/182] fix tests --- contract/vm_dummy/vm_dummy_test.go | 56 ++++++++++++++++++------------ 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index b4a9bd4af..ac3eecbf6 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -2163,10 +2163,9 @@ func TestTypeBignum(t *testing.T) { } func TestBignumValues(t *testing.T) { - code := readLuaCode("bignum_values.lua") - require.NotEmpty(t, code, "failed to read bignum_values.lua") + code := readLuaCode(t, "bignum_values.lua") - bc, err := LoadDummyChain() + bc, err := LoadDummyChain(SetHardForkVersion(2)) require.NoErrorf(t, err, "failed to create dummy chain") defer bc.Release() @@ -2221,31 +2220,42 @@ func TestBignumValues(t *testing.T) { require.NoErrorf(t, err, "failed to query") - // hardfork 4 - bc.HardforkVersion = 4 + // hardfork 4 and after - // process hex, binary. block octal + for version := int32(4); version <= max_version; version++ { + bc, err = LoadDummyChain(SetHardForkVersion(version)) + require.NoErrorf(t, err, "failed to create dummy chain") + defer bc.Release() - tx = NewLuaTxCall("user1", "contract1", 0, `{"Name":"parse_bignum", "Args":["01234567"]}`) - err = bc.ConnectBlock(tx) - require.NoErrorf(t, err, "failed to call tx") - receipt = bc.GetReceipt(tx.Hash()) - assert.Equalf(t, `"1234567"`, receipt.GetRet(), "contract Call ret error") + err = bc.ConnectBlock( + NewLuaTxAccount("user1", 1, types.Aergo), + NewLuaTxDeploy("user1", "contract1", 0, code), + ) + require.NoErrorf(t, err, "failed to deploy") - err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["01234567"]}`, "", `"1234567"`) - require.NoErrorf(t, err, "failed to query") - err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0x123456789abcdef"]}`, "", `"81985529216486895"`) - require.NoErrorf(t, err, "failed to query") - err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0b1010101010101"]}`, "", `"5461"`) - require.NoErrorf(t, err, "failed to query") + // process hex, binary. block octal - err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"01234567"}]}`, "", `"1234567"`) - require.NoErrorf(t, err, "failed to query") - err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"0x123456789abcdef"}]}`, "", `"81985529216486895"`) - require.NoErrorf(t, err, "failed to query") - err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"0b1010101010101"}]}`, "", `"5461"`) - require.NoErrorf(t, err, "failed to query") + tx = NewLuaTxCall("user1", "contract1", 0, `{"Name":"parse_bignum", "Args":["01234567"]}`) + err = bc.ConnectBlock(tx) + require.NoErrorf(t, err, "failed to call tx") + receipt = bc.GetReceipt(tx.Hash()) + assert.Equalf(t, `"1234567"`, receipt.GetRet(), "contract Call ret error") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["01234567"]}`, "", `"1234567"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0x123456789abcdef"]}`, "", `"81985529216486895"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0b1010101010101"]}`, "", `"5461"`) + require.NoErrorf(t, err, "failed to query") + + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"01234567"}]}`, "", `"1234567"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"0x123456789abcdef"}]}`, "", `"81985529216486895"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"0b1010101010101"}]}`, "", `"5461"`) + require.NoErrorf(t, err, "failed to query") + + } } func checkRandomIntValue(v string, min, max int) error { From 51d25ea96c72bf9df445aec8b53a828ab90f1cd8 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 18 Oct 2023 16:27:35 +0000 Subject: [PATCH 077/182] update integration tests --- tests/test-pcall-events.sh | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/tests/test-pcall-events.sh b/tests/test-pcall-events.sh index 94e2b54cd..98fd7190f 100755 --- a/tests/test-pcall-events.sh +++ b/tests/test-pcall-events.sh @@ -6,11 +6,7 @@ fork_version=$1 echo "-- deploy --" -../bin/aergoluac --payload ../contract/vm_dummy/test_files/pcall-events-3.lua > payload.out - -txhash=$(../bin/aergocli --keystore . --password bmttest \ - contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ - --payload `cat payload.out` | jq .hash | sed 's/"//g') +deploy ../contract/vm_dummy/test_files/pcall-events-3.lua get_receipt $txhash @@ -20,11 +16,11 @@ address3=$(cat receipt.json | jq .contractAddress | sed 's/"//g') assert_equals "$status" "CREATED" -../bin/aergoluac --payload ../contract/vm_dummy/test_files/pcall-events-2.lua > payload.out +get_deploy_args ../contract/vm_dummy/test_files/pcall-events-2.lua txhash=$(../bin/aergocli --keystore . --password bmttest \ contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ - '["'$address3'"]' --payload `cat payload.out` | jq .hash | sed 's/"//g') + $deploy_args '["'$address3'"]' --payload `cat payload.out` | jq .hash | sed 's/"//g') get_receipt $txhash @@ -34,11 +30,11 @@ address2=$(cat receipt.json | jq .contractAddress | sed 's/"//g') assert_equals "$status" "CREATED" -../bin/aergoluac --payload ../contract/vm_dummy/test_files/pcall-events-1.lua > payload.out +get_deploy_args ../contract/vm_dummy/test_files/pcall-events-1.lua txhash=$(../bin/aergocli --keystore . --password bmttest \ contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ - '["'$address2'"]' --payload `cat payload.out` | jq .hash | sed 's/"//g') + $deploy_args '["'$address2'"]' --payload `cat payload.out` | jq .hash | sed 's/"//g') get_receipt $txhash @@ -48,11 +44,11 @@ address1=$(cat receipt.json | jq .contractAddress | sed 's/"//g') assert_equals "$status" "CREATED" -../bin/aergoluac --payload ../contract/vm_dummy/test_files/pcall-events-0.lua > payload.out +get_deploy_args ../contract/vm_dummy/test_files/pcall-events-0.lua txhash=$(../bin/aergocli --keystore . --password bmttest \ contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ - '["'$address2'"]' --payload `cat payload.out` | jq .hash | sed 's/"//g') + $deploy_args '["'$address2'"]' --payload `cat payload.out` | jq .hash | sed 's/"//g') get_receipt $txhash From 9a16e2becddf2c24e2fcdf8768bacd49b279a5e9 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 18 Oct 2023 16:47:20 +0000 Subject: [PATCH 078/182] fix tests --- contract/measure/aef.lua | 3 ++- contract/vm_dummy/test_files/type_bignum.lua | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/contract/measure/aef.lua b/contract/measure/aef.lua index 36450f0d6..c27022c79 100644 --- a/contract/measure/aef.lua +++ b/contract/measure/aef.lua @@ -152,7 +152,8 @@ function bignum_fns() local b_b = bignum.number(b) local pi_b = bignum.number(pi) local pi1_b = bignum.number(pi1) - if system.version() >= 4 then + --if system.version() >= 4 then + if type(bignum.ispositive) == "function" then print("bignum.ispositive") m1k(bignum.ispositive, nines_b) m1k(bignum.ispositive, nines1_b) diff --git a/contract/vm_dummy/test_files/type_bignum.lua b/contract/vm_dummy/test_files/type_bignum.lua index 63e8c9048..a6c1d9647 100644 --- a/contract/vm_dummy/test_files/type_bignum.lua +++ b/contract/vm_dummy/test_files/type_bignum.lua @@ -44,7 +44,8 @@ function calcBignum() assert(bg3 == bg4 and bg4 == bg5) bg5 = bg1 - bg3 system.print(bg3, bg5, bg6) - if system.version() >= 4 then + --if system.version() >= 4 then + if type(bignum.ispositive) == "function" then -- ispositive() and isnegative() and iszero() assert(bignum.isnegative(bg5) and bg5 == bignum.neg(bg1)) assert(bignum.ispositive(bg1) and bignum.ispositive(bg3)) From 22b223c6608a59a5ef249f5db7e391bd2354a8f7 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 18 Oct 2023 17:26:33 +0000 Subject: [PATCH 079/182] fix gas usage on V4 --- contract/vm_dummy/vm_dummy_pub_test.go | 4 ++-- tests/test-gas-per-function-v4.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contract/vm_dummy/vm_dummy_pub_test.go b/contract/vm_dummy/vm_dummy_pub_test.go index 1b42ee665..5dd48ad25 100644 --- a/contract/vm_dummy/vm_dummy_pub_test.go +++ b/contract/vm_dummy/vm_dummy_pub_test.go @@ -350,11 +350,11 @@ func TestGasPerFunction(t *testing.T) { }{ {"comp_ops", "", 0, 143204}, {"unarytest_n_copy_ops", "", 0, 143117}, - {"unary_ops", "", 0, 143552}, + {"unary_ops", "", 0, 148160}, {"binary_ops", "", 0, 145075}, {"constant_ops", "", 0, 143032}, {"upvalue_n_func_ops", "", 0, 144347}, - {"table_ops", "", 0, 144482}, + {"table_ops", "", 0, 149090}, {"call_n_vararg_ops", "", 0, 145001}, {"return_ops", "", 0, 143037}, {"loop_n_branche_ops", "", 0, 146372}, diff --git a/tests/test-gas-per-function-v4.sh b/tests/test-gas-per-function-v4.sh index 0d8a95978..bdcf69e35 100755 --- a/tests/test-gas-per-function-v4.sh +++ b/tests/test-gas-per-function-v4.sh @@ -50,11 +50,11 @@ add_test() { add_test "comp_ops" 143204 add_test "unarytest_n_copy_ops" 143117 -add_test "unary_ops" 143552 +add_test "unary_ops" 148160 add_test "binary_ops" 145075 add_test "constant_ops" 143032 add_test "upvalue_n_func_ops" 144347 -add_test "table_ops" 144482 +add_test "table_ops" 149090 add_test "call_n_vararg_ops" 145001 add_test "return_ops" 143037 add_test "loop_n_branche_ops" 146372 From d3ebf15e7a66a593a6ed02784de8a12b116cd74c Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 25 Oct 2023 13:56:14 +0000 Subject: [PATCH 080/182] move gas functions together --- contract/contract.go | 88 ++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/contract/contract.go b/contract/contract.go index d31563b55..c5e5523a5 100644 --- a/contract/contract.go +++ b/contract/contract.go @@ -78,18 +78,18 @@ func Execute(execCtx context.Context, bs *state.BlockState, cdb ChainAccessor, t ) // compute the base fee - usedFee = TxFee(len(txBody.GetPayload()), bs.GasPrice, bi.ForkVersion) + usedFee = TxFee(len(txPayload), bs.GasPrice, bi.ForkVersion) // check if sender and receiver are not the same if sender.AccountID() != receiver.AccountID() { // check if sender has enough balance - if sender.Balance().Cmp(txBody.GetAmountBigInt()) < 0 { + if sender.Balance().Cmp(txAmount) < 0 { err = types.ErrInsufficientBalance return } // transfer the amount from the sender to the receiver - sender.SubBalance(txBody.GetAmountBigInt()) - receiver.AddBalance(txBody.GetAmountBigInt()) + sender.SubBalance(txAmount) + receiver.AddBalance(txAmount) } // check if the tx is valid and if the code should be executed @@ -151,7 +151,7 @@ func Execute(execCtx context.Context, bs *state.BlockState, cdb ChainAccessor, t rv, events, ctrFee, err = PreCall(ex, bs, sender, contractState, receiver.RP(), gasLimit) } else { // create a new context - ctx := NewVmContext(execCtx, bs, cdb, sender, receiver, contractState, sender.ID(), tx.GetHash(), bi, "", true, false, receiver.RP(), preloadService, txBody.GetAmountBigInt(), gasLimit, isFeeDelegation) + ctx := NewVmContext(execCtx, bs, cdb, sender, receiver, contractState, sender.ID(), tx.GetHash(), bi, "", true, false, receiver.RP(), preloadService, txAmount, gasLimit, isFeeDelegation) // execute the transaction if receiver.IsDeploy() { @@ -202,17 +202,6 @@ func Execute(execCtx context.Context, bs *state.BlockState, cdb ChainAccessor, t return rv, events, usedFee, nil } -// compute the base fee for a transaction -func TxFee(payloadSize int, GasPrice *big.Int, version int32) *big.Int { - if version < 2 { - return fee.PayloadTxFee(payloadSize) - } - // get the amount of gas needed for the payload - txGas := fee.TxGas(payloadSize) - // multiply the amount of gas with the gas price - return new(big.Int).Mul(new(big.Int).SetUint64(txGas), GasPrice) -} - // send a request to preload an executor for the next tx func RequestPreload(bs *state.BlockState, bi *types.BlockHeaderInfo, next, current *types.Tx, preloadService int) { loadReqCh <- &preloadRequest{preloadService, bs, bi, next, current} @@ -322,6 +311,37 @@ func checkExecution(txType types.TxType, amount *big.Int, payloadSize int, versi return true, nil } +func checkRedeploy(sender, receiver *state.V, contractState *state.ContractState) error { + // check if the contract exists + if !receiver.IsContract() || receiver.IsNew() { + receiverAddr := types.EncodeAddress(receiver.ID()) + ctrLgr.Warn().Str("error", "not found contract").Str("contract", receiverAddr).Msg("redeploy") + return newVmError(fmt.Errorf("not found contract %s", receiverAddr)) + } + // get the contract creator + creator, err := contractState.GetData(dbkey.CreatorMeta()) + if err != nil { + return err + } + // check if the sender is the creator + if !bytes.Equal(creator, []byte(types.EncodeAddress(sender.ID()))) { + return newVmError(types.ErrCreatorNotMatch) + } + // no problem found + return nil +} + +// compute the base fee for a transaction +func TxFee(payloadSize int, GasPrice *big.Int, version int32) *big.Int { + if version < 2 { + return fee.PayloadTxFee(payloadSize) + } + // get the amount of gas needed for the payload + txGas := fee.TxGas(payloadSize) + // multiply the amount of gas with the gas price + return new(big.Int).Mul(new(big.Int).SetUint64(txGas), GasPrice) +} + func GasLimit(version int32, isFeeDelegation bool, txGasLimit uint64, payloadSize int, gasPrice, usedFee, senderBalance, receiverBalance *big.Int) (gasLimit uint64, err error) { // 1. no gas limit if useGas(version) != true { @@ -363,34 +383,6 @@ func GasLimit(version int32, isFeeDelegation bool, txGasLimit uint64, payloadSiz return gasLimit, nil } -func CreateContractID(account []byte, nonce uint64) []byte { - h := sha256.New() - h.Write(account) - h.Write([]byte(strconv.FormatUint(nonce, 10))) - recipientHash := h.Sum(nil) // byte array with length 32 - return append([]byte{0x0C}, recipientHash...) // prepend 0x0C to make it same length as account addresses -} - -func checkRedeploy(sender, receiver *state.V, contractState *state.ContractState) error { - // check if the contract exists - if !receiver.IsContract() || receiver.IsNew() { - receiverAddr := types.EncodeAddress(receiver.ID()) - ctrLgr.Warn().Str("error", "not found contract").Str("contract", receiverAddr).Msg("redeploy") - return newVmError(fmt.Errorf("not found contract %s", receiverAddr)) - } - // get the contract creator - creator, err := contractState.GetData(dbkey.CreatorMeta()) - if err != nil { - return err - } - // check if the sender is the creator - if !bytes.Equal(creator, []byte(types.EncodeAddress(sender.ID()))) { - return newVmError(types.ErrCreatorNotMatch) - } - // no problem found - return nil -} - func useGas(version int32) bool { return version >= 2 && PubNet } @@ -402,6 +394,14 @@ func GasUsed(txFee, gasPrice *big.Int, txType types.TxType, version int32) uint6 return new(big.Int).Div(txFee, gasPrice).Uint64() } +func CreateContractID(account []byte, nonce uint64) []byte { + h := sha256.New() + h.Write(account) + h.Write([]byte(strconv.FormatUint(nonce, 10))) + recipientHash := h.Sum(nil) // byte array with length 32 + return append([]byte{0x0C}, recipientHash...) // prepend 0x0C to make it same length as account addresses +} + func SetStateSQLMaxDBSize(size uint64) { if size > stateSQLMaxDBSize { maxSQLDBSize = stateSQLMaxDBSize From abf8c9cfd5afc8140ec326e147c8799ea7561267 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 25 Oct 2023 14:38:28 +0000 Subject: [PATCH 081/182] fix gas on unit test --- contract/vm_dummy/vm_dummy_pub_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/contract/vm_dummy/vm_dummy_pub_test.go b/contract/vm_dummy/vm_dummy_pub_test.go index c2832c2d4..2d246d7e3 100644 --- a/contract/vm_dummy/vm_dummy_pub_test.go +++ b/contract/vm_dummy/vm_dummy_pub_test.go @@ -45,7 +45,8 @@ func TestContractSendF(t *testing.T) { require.NoErrorf(t, err, "failed to connect new block") r := bc.GetReceipt(tx.Hash()) - assert.Equalf(t, int64(105087), int64(r.GetGasUsed()), "gas used not equal") + expectedGas := map[int32]int64{3: 105087, 4: 105087}[version] + assert.Equalf(t, expectedGas, int64(r.GetGasUsed()), "gas used not equal") state, err := bc.GetAccountState("test2") assert.Equalf(t, int64(2), state.GetBalanceBigInt().Int64(), "balance state not equal") @@ -55,7 +56,8 @@ func TestContractSendF(t *testing.T) { require.NoErrorf(t, err, "failed to connect new block") r = bc.GetReceipt(tx.Hash()) - assert.Equalf(t, int64(105179), int64(r.GetGasUsed()), "gas used not equal") + expectedGas = map[int32]int64{3: 105179, 4: 105755}[version] + assert.Equalf(t, expectedGas, int64(r.GetGasUsed()), "gas used not equal") state, err = bc.GetAccountState("test2") assert.Equalf(t, int64(6), state.GetBalanceBigInt().Int64(), "balance state not equal") From 051b3e754e4d296ce49188e78848d56e910c0e1d Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 25 Oct 2023 15:13:41 +0000 Subject: [PATCH 082/182] add test cases for V4 --- contract/contract_test.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/contract/contract_test.go b/contract/contract_test.go index 2689a32f6..a6672fd1d 100644 --- a/contract/contract_test.go +++ b/contract/contract_test.go @@ -124,6 +124,9 @@ func TestCheckExecution(t *testing.T) { {version:3, txType:types.TxType_NORMAL, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:true, isContract:false, expectErr:nil, expectExec:true}, {version:3, txType:types.TxType_DEPLOY, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:true, isContract:false, expectErr:nil, expectExec:true}, {version:3, txType:types.TxType_REDEPLOY, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:true, isContract:false, expectErr:nil, expectExec:true}, + {version:4, txType:types.TxType_NORMAL, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:true, isContract:false, expectErr:nil, expectExec:true}, + {version:4, txType:types.TxType_DEPLOY, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:true, isContract:false, expectErr:nil, expectExec:true}, + {version:4, txType:types.TxType_REDEPLOY, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:true, isContract:false, expectErr:nil, expectExec:true}, // recipient is contract {version:2, txType:types.TxType_NORMAL, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:true, expectErr:nil, expectExec:true}, {version:2, txType:types.TxType_TRANSFER, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:true, expectErr:nil, expectExec:true}, @@ -133,6 +136,18 @@ func TestCheckExecution(t *testing.T) { {version:3, txType:types.TxType_TRANSFER, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:true, expectErr:nil, expectExec:true}, {version:3, txType:types.TxType_CALL, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:true, expectErr:nil, expectExec:true}, {version:3, txType:types.TxType_FEEDELEGATION, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:true, expectErr:nil, expectExec:true}, + {version:4, txType:types.TxType_NORMAL, amount:types.NewAmount(0,types.Aergo), payloadSize:0, isDeploy:false, isContract:true, expectErr:newVmError(types.ErrTxNotAllowedRecipient), expectExec:false}, + {version:4, txType:types.TxType_NORMAL, amount:types.NewAmount(1,types.Aergo), payloadSize:0, isDeploy:false, isContract:true, expectErr:newVmError(types.ErrTxNotAllowedRecipient), expectExec:false}, + {version:4, txType:types.TxType_NORMAL, amount:types.NewAmount(0,types.Aergo), payloadSize:1000, isDeploy:false, isContract:true, expectErr:newVmError(types.ErrTxNotAllowedRecipient), expectExec:false}, + {version:4, txType:types.TxType_NORMAL, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:true, expectErr:newVmError(types.ErrTxNotAllowedRecipient), expectExec:false}, + {version:4, txType:types.TxType_TRANSFER, amount:types.NewAmount(1,types.Aergo), payloadSize:0, isDeploy:false, isContract:true, expectErr:nil, expectExec:true}, + {version:4, txType:types.TxType_TRANSFER, amount:types.NewAmount(0,types.Aergo), payloadSize:0, isDeploy:false, isContract:true, expectErr:newVmError(types.ErrTxNotAllowedRecipient), expectExec:false}, + {version:4, txType:types.TxType_TRANSFER, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:true, expectErr:newVmError(types.ErrTxNotAllowedRecipient), expectExec:false}, + {version:4, txType:types.TxType_TRANSFER, amount:types.NewAmount(0,types.Aergo), payloadSize:1000, isDeploy:false, isContract:true, expectErr:newVmError(types.ErrTxNotAllowedRecipient), expectExec:false}, + {version:4, txType:types.TxType_CALL, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:true, expectErr:nil, expectExec:true}, + {version:4, txType:types.TxType_CALL, amount:types.NewAmount(1,types.Aergo), payloadSize:0, isDeploy:false, isContract:true, expectErr:nil, expectExec:true}, + {version:4, txType:types.TxType_FEEDELEGATION, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:true, expectErr:nil, expectExec:true}, + {version:4, txType:types.TxType_FEEDELEGATION, amount:types.NewAmount(1,types.Aergo), payloadSize:0, isDeploy:false, isContract:true, expectErr:nil, expectExec:true}, // recipient is not a contract {version:2, txType:types.TxType_NORMAL, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:false, expectErr:nil, expectExec:false}, {version:2, txType:types.TxType_TRANSFER, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:false, expectErr:nil, expectExec:false}, @@ -142,6 +157,18 @@ func TestCheckExecution(t *testing.T) { {version:3, txType:types.TxType_TRANSFER, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:false, expectErr:nil, expectExec:false}, {version:3, txType:types.TxType_CALL, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:false, expectErr:nil, expectExec:true}, {version:3, txType:types.TxType_FEEDELEGATION, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:false, expectErr:nil, expectExec:false}, + {version:4, txType:types.TxType_NORMAL, amount:types.NewAmount(0,types.Aergo), payloadSize:0, isDeploy:false, isContract:false, expectErr:nil, expectExec:false}, + {version:4, txType:types.TxType_NORMAL, amount:types.NewAmount(1,types.Aergo), payloadSize:0, isDeploy:false, isContract:false, expectErr:nil, expectExec:false}, + {version:4, txType:types.TxType_NORMAL, amount:types.NewAmount(0,types.Aergo), payloadSize:1000, isDeploy:false, isContract:false, expectErr:nil, expectExec:false}, + {version:4, txType:types.TxType_NORMAL, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:false, expectErr:nil, expectExec:false}, + {version:4, txType:types.TxType_TRANSFER, amount:types.NewAmount(1,types.Aergo), payloadSize:0, isDeploy:false, isContract:false, expectErr:nil, expectExec:false}, + {version:4, txType:types.TxType_TRANSFER, amount:types.NewAmount(0,types.Aergo), payloadSize:0, isDeploy:false, isContract:false, expectErr:nil, expectExec:false}, + {version:4, txType:types.TxType_TRANSFER, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:false, expectErr:nil, expectExec:false}, + {version:4, txType:types.TxType_TRANSFER, amount:types.NewAmount(0,types.Aergo), payloadSize:1000, isDeploy:false, isContract:false, expectErr:nil, expectExec:false}, + {version:4, txType:types.TxType_CALL, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:false, expectErr:nil, expectExec:true}, + {version:4, txType:types.TxType_CALL, amount:types.NewAmount(1,types.Aergo), payloadSize:0, isDeploy:false, isContract:false, expectErr:nil, expectExec:true}, + {version:4, txType:types.TxType_FEEDELEGATION, amount:types.NewAmount(1,types.Aergo), payloadSize:1000, isDeploy:false, isContract:false, expectErr:nil, expectExec:false}, + {version:4, txType:types.TxType_FEEDELEGATION, amount:types.NewAmount(1,types.Aergo), payloadSize:0, isDeploy:false, isContract:false, expectErr:nil, expectExec:false}, } { do_execute, err := checkExecution(test.txType, test.amount, test.payloadSize, test.version, test.isDeploy, test.isContract) assert.Equal(t, test.expectErr, err, "checkExecution(version:%d, txType:%d, amount:%s, payloadSize:%d)", test.version, test.txType, test.amount, test.payloadSize) From 23fe69a9fbbabde239d86ec4eeb815a956dc955f Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 28 Oct 2023 15:14:24 +0000 Subject: [PATCH 083/182] test system.version() on queries --- contract/vm_dummy/vm_dummy_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index b95b9c69f..53ccbef60 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -403,6 +403,9 @@ func TestContractSystem(t *testing.T) { expected := fmt.Sprintf(`%d`, version) assert.Equal(t, expected, receipt.GetRet(), "receipt ret error") + err = bc.Query("system", `{"Name":"get_version", "Args":[]}`, "", expected) + require.NoErrorf(t, err, "failed to query") + } } From 07c60a2be02028c7437d68adac247356e9f8d97d Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sun, 29 Oct 2023 20:39:12 +0000 Subject: [PATCH 084/182] increase max events per txn --- contract/vm_callback.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/contract/vm_callback.go b/contract/vm_callback.go index 17958f96a..582289af4 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -56,7 +56,8 @@ var ( ) const ( - maxEventCnt = 50 + maxEventCntV2 = 50 + maxEventCntV4 = 128 maxEventNameSize = 64 maxEventArgSize = 4096 luaCallCountDeduc = 1000 @@ -68,6 +69,14 @@ func init() { zeroBig = types.NewZeroAmount() } +func maxEventCnt(ctx *vmContext) int32 { + if ctx.blockInfo.ForkVersion >= 4 { + return maxEventCntV4 + } else { + return maxEventCntV2 + } +} + func addUpdateSize(ctx *vmContext, updateSize int64) error { if ctx.IsGasSystem() { return nil @@ -1324,8 +1333,8 @@ func luaEvent(L *LState, service C.int, eventName *C.char, args *C.char) *C.char if ctx.isQuery == true || ctx.nestedView > 0 { return C.CString("[Contract.Event] event not permitted in query") } - if ctx.eventCount >= maxEventCnt { - return C.CString(fmt.Sprintf("[Contract.Event] exceeded the maximum number of events(%d)", maxEventCnt)) + if ctx.eventCount >= maxEventCnt(ctx) { + return C.CString(fmt.Sprintf("[Contract.Event] exceeded the maximum number of events(%d)", maxEventCnt(ctx))) } if len(C.GoString(eventName)) > maxEventNameSize { return C.CString(fmt.Sprintf("[Contract.Event] exceeded the maximum length of event name(%d)", maxEventNameSize)) From b556341b335ff26d4eead3f289ecdc0114ef8065 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Mon, 30 Oct 2023 20:39:39 +0000 Subject: [PATCH 085/182] tests: fix spaces [skip ci] --- contract/vm_dummy/test_files/pcall-events-0.lua | 14 +++++++------- contract/vm_dummy/test_files/pcall-events-1.lua | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/contract/vm_dummy/test_files/pcall-events-0.lua b/contract/vm_dummy/test_files/pcall-events-0.lua index e4816b4be..8979716e3 100644 --- a/contract/vm_dummy/test_files/pcall-events-0.lua +++ b/contract/vm_dummy/test_files/pcall-events-0.lua @@ -12,27 +12,27 @@ end function test_pcall() local s, r = pcall(do_work, parent:get(), "pcall") - assert(s == false, "call not failed") - return r + assert(s == false, "call not failed") + return r end function test_xpcall() local s, r = xpcall(do_work, error_handler, parent:get(), "xpcall") - assert(s == false, "call not failed") - return r + assert(s == false, "call not failed") + return r end function test_contract_pcall() local s, r = contract.pcall(do_work, parent:get(), "contract.pcall") - assert(s == false, "call not failed") - return r + assert(s == false, "call not failed") + return r end function do_work(contract_address, caller) contract.event("inside " .. caller .. " before") local r = contract.call(contract_address, "call_me") contract.event("inside " .. caller .. " after") - return r + return r end abi.register(test_pcall, test_xpcall, test_contract_pcall) diff --git a/contract/vm_dummy/test_files/pcall-events-1.lua b/contract/vm_dummy/test_files/pcall-events-1.lua index e8515ace0..e1096c7b4 100644 --- a/contract/vm_dummy/test_files/pcall-events-1.lua +++ b/contract/vm_dummy/test_files/pcall-events-1.lua @@ -14,31 +14,31 @@ function test_pcall() contract.event("before pcall") local s, r = pcall(do_work, parent:get(), "pcall") contract.event("after pcall") - assert(s == false, "call not failed") - return r + assert(s == false, "call not failed") + return r end function test_xpcall() contract.event("before xpcall") local s, r = xpcall(do_work, error_handler, parent:get(), "xpcall") contract.event("after xpcall") - assert(s == false, "call not failed") - return r + assert(s == false, "call not failed") + return r end function test_contract_pcall() contract.event("before contract.pcall") local s, r = contract.pcall(do_work, parent:get(), "contract.pcall") contract.event("after contract.pcall") - assert(s == false, "call not failed") - return r + assert(s == false, "call not failed") + return r end function do_work(contract_address, caller) contract.event("inside " .. caller .. " before") local r = contract.call(contract_address, "call_me") contract.event("inside " .. caller .. " after") - return r + return r end abi.register(test_pcall, test_xpcall, test_contract_pcall) From 22930d6d73e45dcc20e45fa15690d368436f7cd0 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 31 Oct 2023 00:57:47 +0000 Subject: [PATCH 086/182] disable the 'require' statement on V4 --- libtool/src/luajit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtool/src/luajit b/libtool/src/luajit index 64377bafc..346f41b37 160000 --- a/libtool/src/luajit +++ b/libtool/src/luajit @@ -1 +1 @@ -Subproject commit 64377bafc1e0e283c1e48b8d9d602e145e7dc94f +Subproject commit 346f41b3727a9ca44080f901f027476fb72952bc From 4036fc13f81a27cbe6639d973277e560d7ee0ae1 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 31 Oct 2023 01:17:55 +0000 Subject: [PATCH 087/182] test: fix gas on V4 --- contract/vm_dummy/vm_dummy_pub_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contract/vm_dummy/vm_dummy_pub_test.go b/contract/vm_dummy/vm_dummy_pub_test.go index 2d246d7e3..98bdc66bf 100644 --- a/contract/vm_dummy/vm_dummy_pub_test.go +++ b/contract/vm_dummy/vm_dummy_pub_test.go @@ -620,7 +620,7 @@ func TestGasOp(t *testing.T) { err = expectGas(string(code), 0, `"main"`, ``, 117610, SetHardForkVersion(3)) assert.NoError(t, err) - err = expectGas(string(code), 0, `"main"`, ``, 130048, SetHardForkVersion(4)) + err = expectGas(string(code), 0, `"main"`, ``, 134656, SetHardForkVersion(4)) assert.NoError(t, err) } From 8f91f048d6205343ce223c0ed277f35b36e90d32 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 31 Oct 2023 01:31:11 +0000 Subject: [PATCH 088/182] integration test: fix gas on V4 --- tests/test-gas-op.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-gas-op.sh b/tests/test-gas-op.sh index 6ee1cc2d5..45a9b022c 100755 --- a/tests/test-gas-op.sh +++ b/tests/test-gas-op.sh @@ -32,7 +32,7 @@ assert_equals "$status" "SUCCESS" #assert_equals "$ret" "{}" if [ "$fork_version" -eq "4" ]; then - assert_equals "$gasUsed" "130048" + assert_equals "$gasUsed" "134656" else assert_equals "$gasUsed" "117610" fi From b9d3bb50406d51e085d022222f713f878df31199 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 31 Oct 2023 03:16:15 +0000 Subject: [PATCH 089/182] luajit: fully disable unused modules --- libtool/src/luajit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtool/src/luajit b/libtool/src/luajit index 346f41b37..127dfc1b5 160000 --- a/libtool/src/luajit +++ b/libtool/src/luajit @@ -1 +1 @@ -Subproject commit 346f41b3727a9ca44080f901f027476fb72952bc +Subproject commit 127dfc1b5d06589de21889ab44bc16ccbfad2585 From bff4528c4af87d347ba4e56d38a6433aef7ffe3e Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 28 Oct 2023 18:24:11 +0000 Subject: [PATCH 090/182] add test cases for decimal amounts --- contract/vm_callback.go | 16 ++++----- contract/vm_callback_test.go | 67 ++++++++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 19 deletions(-) diff --git a/contract/vm_callback.go b/contract/vm_callback.go index be1bf8075..b4352d3cc 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -255,7 +255,7 @@ func luaCallContract(L *LState, service C.int, contractId *C.char, fname *C.char aid := types.ToAccountID(cid) // read the amount for the contract call - amountBig, err := transformAmount(C.GoString(amount), ctx) + amountBig, err := transformAmount(C.GoString(amount), ctx.blockInfo.ForkVersion) if err != nil { return -1, C.CString("[Contract.LuaCallContract] invalid amount: " + err.Error()) } @@ -483,7 +483,7 @@ func luaSendAmount(L *LState, service C.int, contractId *C.char, amount *C.char) } // read the amount to be sent - amountBig, err := transformAmount(C.GoString(amount), ctx) + amountBig, err := transformAmount(C.GoString(amount), ctx.blockInfo.ForkVersion) if err != nil { return C.CString("[Contract.LuaSendAmount] invalid amount: " + err.Error()) } @@ -1058,12 +1058,12 @@ func parseDecimalAmount(str string, digits int) string { // transformAmount processes the input string to calculate the total amount, // taking into account the different units ("aergo", "gaer", "aer") -func transformAmount(amountStr string, ctx *vmContext) (*big.Int, error) { +func transformAmount(amountStr string, forkVersion int32) (*big.Int, error) { if len(amountStr) == 0 { return zeroBig, nil } - if ctx.blockInfo.ForkVersion >= 4 { + if forkVersion >= 4 { // Check for amount in decimal format if strings.Contains(amountStr,".") && strings.HasSuffix(amountStr,"aergo") { // Extract the part before the unit @@ -1071,11 +1071,11 @@ func transformAmount(amountStr string, ctx *vmContext) (*big.Int, error) { // Parse the decimal amount decimalAmount = parseDecimalAmount(decimalAmount, 18) if decimalAmount == "error" { - return nil, errors.New(amountStr) + return nil, errors.New("converting error for BigNum: " + amountStr) } amount, valid := new(big.Int).SetString(decimalAmount, 10) if !valid { - return nil, errors.New(amountStr) + return nil, errors.New("converting error for BigNum: " + amountStr) } return amount, nil } @@ -1235,7 +1235,7 @@ func luaDeployContract( ctx.callState[newContract.AccountID()] = cs // read the amount transferred to the contract - amountBig, err := transformAmount(C.GoString(amount), ctx) + amountBig, err := transformAmount(C.GoString(amount), ctx.blockInfo.ForkVersion) if err != nil { return -1, C.CString("[Contract.LuaDeployContract]value not proper format:" + err.Error()) } @@ -1437,7 +1437,7 @@ func luaGovernance(L *LState, service C.int, gType C.char, arg *C.char) *C.char switch gType { case 'S', 'U': var err error - amountBig, err = transformAmount(C.GoString(arg), ctx) + amountBig, err = transformAmount(C.GoString(arg), ctx.blockInfo.ForkVersion) if err != nil { return C.CString("[Contract.LuaGovernance] invalid amount: " + err.Error()) } diff --git a/contract/vm_callback_test.go b/contract/vm_callback_test.go index 5f5b9d84f..9bcae8568 100644 --- a/contract/vm_callback_test.go +++ b/contract/vm_callback_test.go @@ -9,6 +9,9 @@ import ( "github.com/stretchr/testify/assert" ) +const min_version int32 = 2 +const max_version int32 = 4 + func bigIntFromString(str string) *big.Int { bigInt, success := new(big.Int).SetString(str, 10) if !success { @@ -98,13 +101,6 @@ func TestTransformAmount(t *testing.T) { {"100 invalid 200", nil, errors.New("converting error for Integer: 100 invalid 200")}, {"invalid 200", nil, errors.New("converting error for Integer: invalid 200")}, {"100 invalid", nil, errors.New("converting error for Integer: 100 invalid")}, - // Non-Integer Values - {"123.456", nil, errors.New("converting error for Integer: 123.456")}, - {"123.456 aergo", nil, errors.New("converting error for BigNum: 123.456 aergo")}, - {".1", nil, errors.New("converting error for Integer: .1")}, - {".1aergo", nil, errors.New("converting error for BigNum: .1aergo")}, - {".1 aergo", nil, errors.New("converting error for BigNum: .1 aergo")}, - {".10", nil, errors.New("converting error for Integer: .10")}, // Exponents {"1e+18", nil, errors.New("converting error for Integer: 1e+18")}, {"2e18", nil, errors.New("converting error for Integer: 2e18")}, @@ -121,16 +117,65 @@ func TestTransformAmount(t *testing.T) { {"5e+3aergo", nil, errors.New("converting error for BigNum: 5e+3aergo")}, } - for _, tt := range tests { - result, err := transformAmount(tt.amountStr) + for version := min_version; version <= max_version; version++ { + for _, tt := range tests { + result, err := transformAmount(tt.amountStr, version) + + if tt.expectedError != nil { + if assert.Error(t, err, "Expected error: %s", tt.expectedError.Error()) { + assert.Equal(t, tt.expectedError.Error(), err.Error()) + } + } else { + if assert.NoError(t, err) && tt.expectedAmount != nil { + assert.Equal(t, tt.expectedAmount, result) + } + } + } + } + + // Define the test cases for amounts in decimal format + decimal_tests := []struct { + forkVersion int32 + amountStr string + expectedAmount *big.Int + expectedError error + }{ + // V3 - decimal amounts not supported + {3, "123.456", nil, errors.New("converting error for Integer: 123.456")}, + {3, "123.456 aergo", nil, errors.New("converting error for BigNum: 123.456 aergo")}, + {3, ".1", nil, errors.New("converting error for Integer: .1")}, + {3, ".1aergo", nil, errors.New("converting error for BigNum: .1aergo")}, + {3, ".1 aergo", nil, errors.New("converting error for BigNum: .1 aergo")}, + {3, ".10", nil, errors.New("converting error for Integer: .10")}, + // V4 - decimal amounts supported + {4, "123.456aergo", bigIntFromString("123456000000000000000"), nil}, + {4, "123.4aergo", bigIntFromString("123400000000000000000"), nil}, + {4, "123.aergo", bigIntFromString("123000000000000000000"), nil}, + {4, "100.aergo", bigIntFromString("100000000000000000000"), nil}, + {4, "10.aergo", bigIntFromString("10000000000000000000"), nil}, + {4, "1.aergo", bigIntFromString("1000000000000000000"), nil}, + {4, "100.0aergo", bigIntFromString("100000000000000000000"), nil}, + {4, "10.0aergo", bigIntFromString("10000000000000000000"), nil}, + {4, "1.0aergo", bigIntFromString("1000000000000000000"), nil}, + {4, ".1aergo", bigIntFromString("100000000000000000"), nil}, + {4, "0.1aergo", bigIntFromString("100000000000000000"), nil}, + {4, ".01aergo", bigIntFromString("10000000000000000"), nil}, + {4, "0.01aergo", bigIntFromString("10000000000000000"), nil}, + {4, "0.0000000001aergo", bigIntFromString("100000000"), nil}, + + {4, "0.000000000000000000000000001aergo", nil, errors.New("converting error for BigNum: 0.000000000000000000000000001aergo")}, + } + + for _, tt := range decimal_tests { + result, err := transformAmount(tt.amountStr, tt.forkVersion) if tt.expectedError != nil { if assert.Error(t, err, "Expected error: %s", tt.expectedError.Error()) { - assert.Equal(t, tt.expectedError.Error(), err.Error()) + assert.Equal(t, tt.expectedError.Error(), err.Error(), tt.amountStr) } } else { if assert.NoError(t, err) && tt.expectedAmount != nil { - assert.Equal(t, tt.expectedAmount, result) + assert.Equal(t, tt.expectedAmount, result, tt.amountStr) } } } From bede2d28d052b496cd91e2656b4aef0bfc8d6cb3 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 28 Oct 2023 18:44:56 +0000 Subject: [PATCH 091/182] do not allow amounts bigger than num decimals --- contract/vm_callback.go | 4 +++- contract/vm_callback_test.go | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/contract/vm_callback.go b/contract/vm_callback.go index b4352d3cc..845ec79c8 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -1045,7 +1045,8 @@ func parseDecimalAmount(str string, digits int) string { if to_add > 0 { p2 = p2 + strings.Repeat("0", to_add) } else if to_add < 0 { - p2 = p2[0:digits] + //p2 = p2[0:digits] + return "error" } str = p1 + p2 @@ -1068,6 +1069,7 @@ func transformAmount(amountStr string, forkVersion int32) (*big.Int, error) { if strings.Contains(amountStr,".") && strings.HasSuffix(amountStr,"aergo") { // Extract the part before the unit decimalAmount := strings.TrimSuffix(amountStr, "aergo") + decimalAmount = strings.TrimRight(decimalAmount, " ") // Parse the decimal amount decimalAmount = parseDecimalAmount(decimalAmount, 18) if decimalAmount == "error" { diff --git a/contract/vm_callback_test.go b/contract/vm_callback_test.go index 9bcae8568..bcfc096d9 100644 --- a/contract/vm_callback_test.go +++ b/contract/vm_callback_test.go @@ -162,8 +162,45 @@ func TestTransformAmount(t *testing.T) { {4, ".01aergo", bigIntFromString("10000000000000000"), nil}, {4, "0.01aergo", bigIntFromString("10000000000000000"), nil}, {4, "0.0000000001aergo", bigIntFromString("100000000"), nil}, + {4, "0.000000000000000001aergo", bigIntFromString("1"), nil}, + {4, "0.000000000000000123aergo", bigIntFromString("123"), nil}, + {4, "0.000000000000000000aergo", bigIntFromString("0"), nil}, + {4, "0.000000000000123000aergo", bigIntFromString("123000"), nil}, + {4, "0.100000000000000123aergo", bigIntFromString("100000000000000123"), nil}, + {4, "1.000000000000000123aergo", bigIntFromString("1000000000000000123"), nil}, + {4, "123.456000000000000789aergo", bigIntFromString("123456000000000000789"), nil}, + {4, "123.456 aergo", bigIntFromString("123456000000000000000"), nil}, + {4, "123.4 aergo", bigIntFromString("123400000000000000000"), nil}, + {4, "123. aergo", bigIntFromString("123000000000000000000"), nil}, + {4, "100. aergo", bigIntFromString("100000000000000000000"), nil}, + {4, "10. aergo", bigIntFromString("10000000000000000000"), nil}, + {4, "1. aergo", bigIntFromString("1000000000000000000"), nil}, + {4, "100.0 aergo", bigIntFromString("100000000000000000000"), nil}, + {4, "10.0 aergo", bigIntFromString("10000000000000000000"), nil}, + {4, "1.0 aergo", bigIntFromString("1000000000000000000"), nil}, + {4, ".1 aergo", bigIntFromString("100000000000000000"), nil}, + {4, "0.1 aergo", bigIntFromString("100000000000000000"), nil}, + {4, ".01 aergo", bigIntFromString("10000000000000000"), nil}, + {4, "0.01 aergo", bigIntFromString("10000000000000000"), nil}, + {4, "0.0000000001 aergo", bigIntFromString("100000000"), nil}, + {4, "0.000000000000000001 aergo", bigIntFromString("1"), nil}, + {4, "0.000000000000000123 aergo", bigIntFromString("123"), nil}, + {4, "0.000000000000000000 aergo", bigIntFromString("0"), nil}, + {4, "0.000000000000123000 aergo", bigIntFromString("123000"), nil}, + {4, "0.100000000000000123 aergo", bigIntFromString("100000000000000123"), nil}, + {4, "1.000000000000000123 aergo", bigIntFromString("1000000000000000123"), nil}, + {4, "123.456000000000000789 aergo", bigIntFromString("123456000000000000789"), nil}, + + {4, "0.0000000000000000001aergo", nil, errors.New("converting error for BigNum: 0.0000000000000000001aergo")}, {4, "0.000000000000000000000000001aergo", nil, errors.New("converting error for BigNum: 0.000000000000000000000000001aergo")}, + {4, "0.000000000000000123000aergo", nil, errors.New("converting error for BigNum: 0.000000000000000123000aergo")}, + {4, "0.0000000000000000000000aergo", nil, errors.New("converting error for BigNum: 0.0000000000000000000000aergo")}, + + {4, "0.0000000000000000001 aergo", nil, errors.New("converting error for BigNum: 0.0000000000000000001 aergo")}, + {4, "0.000000000000000000000000001 aergo", nil, errors.New("converting error for BigNum: 0.000000000000000000000000001 aergo")}, + {4, "0.000000000000000123000 aergo", nil, errors.New("converting error for BigNum: 0.000000000000000123000 aergo")}, + {4, "0.0000000000000000000000 aergo", nil, errors.New("converting error for BigNum: 0.0000000000000000000000 aergo")}, } for _, tt := range decimal_tests { From 4bc6f8cd760e3b76553ec43b7f8de68ed5cbfabc Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 28 Oct 2023 18:58:34 +0000 Subject: [PATCH 092/182] move function --- contract/vm_callback.go | 62 +++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/contract/vm_callback.go b/contract/vm_callback.go index 845ec79c8..ce8de14a7 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -1030,33 +1030,6 @@ func luaCryptoKeccak256(data unsafe.Pointer, dataLen C.int) (unsafe.Pointer, int } } -func parseDecimalAmount(str string, digits int) string { - idx := strings.Index(str, ".") - if idx == -1 { - return str - } - p1 := str[0:idx] - p2 := str[idx+1:] - if strings.Index(p2, ".") != -1 { - return "error" - } - - to_add := digits - len(p2) - if to_add > 0 { - p2 = p2 + strings.Repeat("0", to_add) - } else if to_add < 0 { - //p2 = p2[0:digits] - return "error" - } - str = p1 + p2 - - str = strings.TrimLeft(str, "0") - if str == "" { - str = "0" - } - return str -} - // transformAmount processes the input string to calculate the total amount, // taking into account the different units ("aergo", "gaer", "aer") func transformAmount(amountStr string, forkVersion int32) (*big.Int, error) { @@ -1128,6 +1101,41 @@ func transformAmount(amountStr string, forkVersion int32) (*big.Int, error) { return totalAmount, nil } +// convert decimal amount into big integer string +func parseDecimalAmount(str string, num_decimals int) string { + // Get the integer and decimal parts + idx := strings.Index(str, ".") + if idx == -1 { + return str + } + p1 := str[0:idx] + p2 := str[idx+1:] + + // Check for another decimal point + if strings.Index(p2, ".") != -1 { + return "error" + } + + // Compute the amount of zero digits to add + to_add := num_decimals - len(p2) + if to_add > 0 { + p2 = p2 + strings.Repeat("0", to_add) + } else if to_add < 0 { + // Do not truncate decimal amounts + return "error" + } + + // Join the integer and decimal parts + str = p1 + p2 + + // Remove leading zeros + str = strings.TrimLeft(str, "0") + if str == "" { + str = "0" + } + return str +} + // parseAndConvert is a helper function to parse the substring as a big integer // and apply the necessary multiplier based on the unit. func parseAndConvert(subStr, unit string, mulUnit *big.Int, fullStr string) (*big.Int, error) { From 617a0be55730a6706534ccc181a921873d230ca0 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 1 Nov 2023 17:24:54 +0000 Subject: [PATCH 093/182] brick: update ParseDecimalAmount --- cmd/brick/context/util.go | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/cmd/brick/context/util.go b/cmd/brick/context/util.go index 5280178df..badf16266 100644 --- a/cmd/brick/context/util.go +++ b/cmd/brick/context/util.go @@ -20,34 +20,46 @@ func ParseFirstWord(input string) (string, string) { func ParseDecimalAmount(str string, digits int) string { - idx := strings.Index(str, ".") - - str = strings.ToLower(str) - if strings.HasSuffix(str, " aergo") { - str = str[:len(str)-6] - if idx == -1 { - return str + strings.Repeat("0", digits) - } + // if there is no 'aergo' unit, just return the amount str + if !strings.HasSuffix(strings.ToLower(str), "aergo") { + return str } + // remove the 'aergo' unit + str = str[:len(str)-5] + // trim trailing spaces + str = strings.TrimRight(str, " ") + + // get the position of the decimal point + idx := strings.Index(str, ".") + + // if not found, just add the leading zeros if idx == -1 { - return str + return str + strings.Repeat("0", digits) } + + // Get the integer and decimal parts p1 := str[0:idx] p2 := str[idx+1:] + + // Check for another decimal point if strings.Index(p2, ".") != -1 { return "error" } + // Compute the amount of zero digits to add to_add := digits - len(p2) if to_add > 0 { p2 = p2 + strings.Repeat("0", to_add) } else if to_add < 0 { - //p2 = p2[0:digits] + // Do not truncate decimal amounts return "error" } + + // Join the integer and decimal parts str = p1 + p2 + // Remove leading zeros str = strings.TrimLeft(str, "0") if str == "" { str = "0" From 9cee33b1bdd40183f5da93eb358e2008b1d80b01 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 2 Nov 2023 16:58:11 +0000 Subject: [PATCH 094/182] add tests for disabled Lua functions --- .../test_files/disabled-functions.lua | 40 +++++++++++++++++++ contract/vm_dummy/vm_dummy_test.go | 21 ++++++++++ 2 files changed, 61 insertions(+) create mode 100644 contract/vm_dummy/test_files/disabled-functions.lua diff --git a/contract/vm_dummy/test_files/disabled-functions.lua b/contract/vm_dummy/test_files/disabled-functions.lua new file mode 100644 index 000000000..9ae8eca95 --- /dev/null +++ b/contract/vm_dummy/test_files/disabled-functions.lua @@ -0,0 +1,40 @@ + +function check_disabled_functions() + + -- check the disabled modules + assert(os == nil, "os is available") + assert(io == nil, "io is available") + assert(debug == nil, "debug is available") + assert(jit == nil, "jit is available") + assert(ffi == nil, "ffi is available") + assert(coroutine == nil, "coroutine is available") + assert(package == nil, "package is available") + + -- check the disabled functions + assert(collectgarbage == nil, "collectgarbage is available") + assert(gcinfo == nil, "gcinfo is available") + assert(module == nil, "module is available") + assert(require == nil, "require is available") + assert(dofile == nil, "dofile is available") + assert(load == nil, "load is available") + assert(loadlib == nil, "loadlib is available") + assert(loadfile == nil, "loadfile is available") + assert(loadstring == nil, "loadstring is available") + assert(print == nil, "print is available") + + local success, result = pcall(function() newproxy() end) + assert(success == false and result:match(".* 'newproxy' not supported"), "newproxy is available") + local success, result = pcall(function() setfenv() end) + assert(success == false and result:match(".* 'setfenv' not supported"), "setfenv is available") + local success, result = pcall(function() getfenv() end) + assert(success == false and result:match(".* 'getfenv' not supported"), "getfenv is available") + + -- make sure the tostring does not return a pointer + local tab = {} + assert(not tostring(type):match("0x[%x]+"), "tostring returns a pointer for function") + assert(not tostring(system):match("0x[%x]+"), "tostring returns a pointer for internal table") + assert(not tostring(tab):match("0x[%x]+"), "tostring returns a pointer for table") + +end + +abi.register(check_disabled_functions) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index ba6dc9b84..79a68a88f 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -22,6 +22,27 @@ import ( const min_version int32 = 2 const max_version int32 = 4 +func TestDisabledFunctions(t *testing.T) { + code := readLuaCode(t, "disabled-functions.lua") + + for version := int32(4); version <= max_version; version++ { + bc, err := LoadDummyChain(SetHardForkVersion(version), SetPubNet()) + require.NoErrorf(t, err, "failed to create dummy chain") + defer bc.Release() + + err = bc.ConnectBlock( + NewLuaTxAccount("user", 1, types.Aergo), + NewLuaTxDeploy("user", "test", 0, code), + ) + assert.NoErrorf(t, err, "failed to deploy contract") + + err = bc.ConnectBlock( + NewLuaTxCall("user", "test", 0, `{"Name":"check_disabled_functions","Args":[]}`), + ) + assert.NoErrorf(t, err, "failed execution") + } +} + func TestMaxCallDepth(t *testing.T) { //code := readLuaCode(t, "maxcalldepth_1.lua") // this contract receives a list of contract IDs to be called From b9532a2c38461ded0cc3385965ca6a679f71e6a7 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 2 Nov 2023 18:23:00 +0000 Subject: [PATCH 095/182] disable more lua functions --- libtool/src/luajit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtool/src/luajit b/libtool/src/luajit index 127dfc1b5..71e7ed2f7 160000 --- a/libtool/src/luajit +++ b/libtool/src/luajit @@ -1 +1 @@ -Subproject commit 127dfc1b5d06589de21889ab44bc16ccbfad2585 +Subproject commit 71e7ed2f759b77e5c056bf65c492ce7eaa87f1cf From ddbe34de9e5fde96eb05e95a9e7070024d5ff6ba Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 2 Nov 2023 18:24:51 +0000 Subject: [PATCH 096/182] fix tests for getfenv and setfenv --- .../test_files/{gas_bf.lua => gas_bf_v2.lua} | 0 contract/vm_dummy/test_files/gas_bf_v4.lua | 361 ++++++++++++++++++ contract/vm_dummy/vm_dummy_pub_test.go | 11 +- tests/test-gas-bf.sh | 8 +- 4 files changed, 372 insertions(+), 8 deletions(-) rename contract/vm_dummy/test_files/{gas_bf.lua => gas_bf_v2.lua} (100%) create mode 100644 contract/vm_dummy/test_files/gas_bf_v4.lua diff --git a/contract/vm_dummy/test_files/gas_bf.lua b/contract/vm_dummy/test_files/gas_bf_v2.lua similarity index 100% rename from contract/vm_dummy/test_files/gas_bf.lua rename to contract/vm_dummy/test_files/gas_bf_v2.lua diff --git a/contract/vm_dummy/test_files/gas_bf_v4.lua b/contract/vm_dummy/test_files/gas_bf_v4.lua new file mode 100644 index 000000000..8ea2169a8 --- /dev/null +++ b/contract/vm_dummy/test_files/gas_bf_v4.lua @@ -0,0 +1,361 @@ +loop_cnt = 1000 +arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 } +tbl = { name = "user2", year = 1981, age = 41 } +long_str = +[[Looks for the first match of pattern in the string s. If it finds a match, then find returns the indices of s where this occurrence starts and ends; otherwise, it returns nil. A third, optional numerical argument init specifies where to start the search; its default value is 1 and can be negative. A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain "find substring" operation, with no characters in pattern being considered "magic". Note that if plain is given, then init must be given as well. +]] +long_str1 = +[[Looks for the first match of pattern in the string s. If it finds a match, then find returns the indices of s where this occurrence starts and ends; otherwise, it returns nil. A third, optional numerical argument init specifies where to start the search; its default value is 1 and can be negative. A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain "find substring" operation, with no characters in pattern being considered "magic". Note that if plain is given, then init must be given as werr. +]] + +function copy_arr(arr) + local a = {} + for i, v in ipairs(arr) do + a[i] = v + end + return a +end + +function m1k(fn, ...) + for i = 1, loop_cnt do + fn(...) + end +end + +function basic_fns() + m1k(assert, true, 'true') + m1k(assert, 1 == 1, 'true') + m1k(assert, 1 ~= 2, 'true') + m1k(assert, long_str == long_str, 'true') + m1k(assert, long_str ~= long_str1, 'true') + local x = { value = 5 } + local mt = { + __add = function(lhs, rhs) + return { value = lhs.value + rhs.value } + end, + __tostring = function(self) + return "Hello Aergo" + end + } + setmetatable(x, mt) + m1k(getmetatable, x) + m1k(ipairs, arr) + m1k(next, tbl) + m1k(next, tbl, "year") + m1k(next, tbl, "name") + m1k(pairs, tbl) + m1k(rawequal, 1, 1) + m1k(rawequal, 1, 2) + m1k(rawequal, 1.4, 2.1) + m1k(rawequal, 1.4, 2) + m1k(rawequal, "hello", "world") + m1k(rawequal, arr, tbl) + m1k(rawequal, arr, arr) + m1k(rawequal, tbl, tbl) + local a = arr + m1k(rawget, a, 1) + m1k(rawget, a, 10) + m1k(rawget, tbl, "age") + local a = copy_arr(arr) + m1k(rawset, a, 1, 0) + m1k(rawset, a, 10, 1) + m1k(rawset, a, 11, -1) + m1k(rawset, tbl, "addr", "aergo") + m1k(rawset, tbl, "age", 42) + m1k(select, '#', 'a', 'b', 'c', 'd') + m1k(select, '#', arr) + m1k(select, '2', 'a', 'b', 'c', 'd') + m1k(select, '2', arr) + m1k(select, '6', arr) + m1k(select, '9', arr) + m1k(setmetatable, x, mt) + m1k(tonumber, 0x10, 16) + m1k(tonumber, '112134', 16) + m1k(tonumber, '112134') + m1k(tonumber, 112134) + m1k(tostring, 'i am a string') + m1k(tostring, 1) + m1k(tostring, 112134) + m1k(tostring, true) + m1k(tostring, nil) + m1k(tostring, 3.14) + m1k(tostring, 3.14159267) + m1k(tostring, x) + m1k(type, '112134') + m1k(type, 112134) + m1k(type, {}) + m1k(type, type) + m1k(unpack, { 1, 2, 3, 4, 5 }, 2, 4) + m1k(unpack, arr, 2, 4) + m1k(unpack, { 1, 2, 3, 4, 5 }) + m1k(unpack, arr) + local a = {} + for i = 1, 100 do + a[i] = i * i + end + m1k(unpack, a, 2, 4) + m1k(unpack, a, 10, 40) + m1k(unpack, a) +end + +function string_fns() + m1k(string.byte, "hello string", 3, 7) + m1k(string.byte, long_str, 3, 7) + m1k(string.byte, long_str, 1, #long_str) + m1k(string.char, 72, 101, 108, 108, 111) + m1k(string.char, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100) + m1k(string.char, string.byte(long_str, 1, #long_str)) + m1k(string.dump, m1k) + m1k(string.dump, basic_fns) + m1k(string.find, long_str, "nume.....") + m1k(string.find, long_str, "we..") + m1k(string.find, long_str, "wi..") + m1k(string.find, long_str, "pattern") + m1k(string.find, long_str, "pattern", 200) + m1k(string.find, "hello world hellow", "hello") + m1k(string.find, "hello world hellow", "hello", 3) + m1k(string.find, long_str, "head") + m1k(string.format, "string.format %d, %.9f, %e, %g: %s", 1, 1.999999999, 10e9, 3.14, "end of string") + m1k(string.format, "string.format %d, %.9f, %e", 1, 1.999999999, 10e9) + s = "hello world from Lua" + m1k(string.gmatch, s, "%a+") + m1k(function() + for w in string.gmatch(s, "%a+") do + end + end) + m1k(string.gsub, s, "(%w+)", "%1 %1") + s2 = s .. ' ' .. s + m1k(string.gsub, s2, "(%w+)", "%1 %1") + m1k(string.gsub, s, "(%w+)%s*(%w+)", "%2 %1") + m1k(string.len, s) + m1k(string.len, s2) + m1k(string.len, long_str) + m1k(string.lower, s) + m1k(string.lower, long_str) + m1k(string.match, s, "(L%w+)") + m1k(string.rep, s, 2) + m1k(string.rep, s, 4) + m1k(string.rep, s, 8) + m1k(string.rep, s, 16) + m1k(string.rep, long_str, 16) + m1k(string.reverse, s) + m1k(string.reverse, s2) + m1k(string.reverse, long_str) + m1k(string.sub, s, 10, 13) + m1k(string.sub, s, 10, -3) + m1k(string.sub, long_str, 10, 13) + m1k(string.sub, long_str, 10, -3) + m1k(string.upper, s) + m1k(string.upper, s2) + m1k(string.upper, long_str) +end + +function table_fns1() + local a = copy_arr(arr) + local a100 = {} + for i = 1, 100 do + a100[i] = i * i + end + m1k(table.concat, a, ',') + m1k(table.concat, a, ',', 3, 7) + m1k(table.concat, a100, ',') + m1k(table.concat, a100, ',', 3, 7) + m1k(table.concat, a100, ',', 3, 32) + local as10 = {} + for i = 1, 10 do + as10[i] = "hello" + end + local as100 = {} + for i = 1, 100 do + as100[i] = "hello" + end + m1k(table.concat, as10, ',') + m1k(table.concat, as10, ',', 3, 7) + m1k(table.concat, as100, ',') + m1k(table.concat, as100, ',', 3, 7) + m1k(table.concat, as100, ',', 3, 32) + for i = 1, 10 do + as10[i] = "h" + end + for i = 1, 100 do + as100[i] = "h" + end + m1k(table.concat, as10, ',') + m1k(table.concat, as10, ',', 3, 7) + m1k(table.concat, as100, ',') + m1k(table.concat, as100, ',', 3, 7) + m1k(table.concat, as100, ',', 3, 32) +end + +function table_fns2() + local a = copy_arr(arr) + local a100 = {} + for i = 1, 100 do + a100[i] = i * i + end + m1k(table.insert, a, 11) + for i = 1, 1000 do + table.remove(a) + end + m1k(table.insert, a, 5, 11) + for i = 1, 1000 do + table.remove(a, 5) + end + --m1k(table.insert, a, 5, -5) + --m1k(table.insert, a, 1, -5) + m1k(table.insert, a100, 11) + for i = 1, 1000 do + table.remove(a100) + end + m1k(table.insert, a100, 5, -5) + for i = 1, 1000 do + table.remove(a100, 5) + end + --m1k(table.insert, a100, 1, -5) +end + +function table_fns3() + local a = copy_arr(arr) + local a100 = {} + for i = 1, 100 do + a100[i] = i * i + end + m1k(table.maxn, a) + m1k(table.maxn, a100) + for i = 1, 1000 do + table.insert(a, i) + end + m1k(table.remove, a) + for i = 1, 1000 do + table.insert(a, 5, i) + end + m1k(table.remove, a, 5) + for i = 1, 1000 do + table.insert(a100, i) + end + m1k(table.remove, a100) + for i = 1, 1000 do + table.insert(a100, 5, i) + end + m1k(table.remove, a100, 5) +end + +function table_fns4() + local a = copy_arr(arr) + local a100 = {} + for i = 1, 100 do + a100[i] = i * i + end + m1k(table.sort, a) + m1k(table.sort, a, function(x, y) return x > y end) + m1k(table.sort, a100) + m1k(table.sort, a100, function(x, y) return x > y end) +end + +function math_fns() + d = {} + for i = 1, loop_cnt do + d[i] = -500 + i + end + for i = 1, loop_cnt, 10 do + d[i] = d[i] + 0.5 + end + for i = 1, loop_cnt, 13 do + d[i] = d[i] + 0.3 + end + for i = 1, loop_cnt, 17 do + d[i] = d[i] + 0.7 + end + f = {} + for i = 1, loop_cnt do + f[i] = -1 + i * 0.002 + end + local md = function(fn, d, ...) + for i, v in ipairs(d) do + fn(v, ...) + end + end + md(math.abs, d) + md(math.ceil, d) + md(math.ceil, f) + md(math.floor, d) + md(math.floor, f) + local filter = function(l, cond) + r = {} + for i, v in ipairs(l) do + if cond(v) then + table.insert(r, v) + end + end + return r + end + ud = filter(d, function(v) return v >= 0 end) + uf = filter(f, function(v) return v >= 0 end) + m1k(math.max, unpack(ud)) + m1k(math.max, unpack(d)) + m1k(math.max, unpack(uf)) + m1k(math.max, unpack(f)) + m1k(math.min, unpack(ud)) + m1k(math.min, unpack(d)) + m1k(math.min, unpack(uf)) + m1k(math.min, unpack(f)) + md(math.pow, d, 2) + md(math.pow, d, 4) + md(math.pow, d, 8) + md(math.pow, f, 2) + md(math.pow, f, 4) + md(math.pow, f, 8) + md(math.pow, ud, 8.4) + md(math.pow, uf, 8.4) +end + +function bit_fns() + m1k(bit.tobit, 0xffffffff) + m1k(bit.tobit, 0xffffffff + 1) + m1k(bit.tobit, 2 ^ 40 + 1234) + m1k(bit.tohex, 1) + m1k(bit.tohex, -1) + m1k(bit.tohex, -1, -8) + m1k(bit.tohex, 0x87654321, 4) + m1k(bit.bnot, 0) + m1k(bit.bnot, 0x12345678) + m1k(bit.bor, 1) + m1k(bit.bor, 1, 2) + m1k(bit.bor, 1, 2, 4) + m1k(bit.bor, 1, 2, 4, 8) + m1k(bit.band, 0x12345678, 0xff) + m1k(bit.band, 0x12345678, 0xff, 0x3f) + m1k(bit.band, 0x12345678, 0xff, 0x3f, 0x1f) + m1k(bit.bxor, 0xa5a5f0f0, 0xaa55ff00) + m1k(bit.bxor, 0xa5a5f0f0, 0xaa55ff00, 0x18000000) + m1k(bit.bxor, 0xa5a5f0f0, 0xaa55ff00, 0x18000000, 0x00000033) + m1k(bit.lshift, 1, 0) + m1k(bit.lshift, 1, 8) + m1k(bit.lshift, 1, 40) + m1k(bit.rshift, 256, 0) + m1k(bit.rshift, 256, 8) + m1k(bit.rshift, 256, 40) + m1k(bit.arshift, 0x87654321, 0) + m1k(bit.arshift, 0x87654321, 12) + m1k(bit.arshift, 0x87654321, 40) + m1k(bit.rol, 0x12345678, 0) + m1k(bit.rol, 0x12345678, 12) + m1k(bit.rol, 0x12345678, 40) + m1k(bit.ror, 0x12345678, 0) + m1k(bit.ror, 0x12345678, 12) + m1k(bit.ror, 0x12345678, 40) + m1k(bit.bswap, 0x12345678) +end + +function main() + basic_fns() + string_fns() + table_fns1() + table_fns2() + table_fns3() + table_fns4() + math_fns() + bit_fns() +end + +abi.register(main) diff --git a/contract/vm_dummy/vm_dummy_pub_test.go b/contract/vm_dummy/vm_dummy_pub_test.go index 98bdc66bf..39f87f693 100644 --- a/contract/vm_dummy/vm_dummy_pub_test.go +++ b/contract/vm_dummy/vm_dummy_pub_test.go @@ -365,7 +365,6 @@ func TestGasPerFunction(t *testing.T) { {"function_header_ops", "", 0, 143016}, {"assert", "", 0, 143146}, - {"getfenv", "", 0, 143041}, {"metatable", "", 0, 143988}, {"ipairs", "", 0, 143039}, {"pairs", "", 0, 143039}, @@ -374,7 +373,6 @@ func TestGasPerFunction(t *testing.T) { {"rawget", "", 0, 143087}, {"rawset", "", 0, 143941}, {"select", "", 0, 143166}, - {"setfenv", "", 0, 143076}, {"tonumber", "", 0, 143186}, {"tostring", "", 0, 143457}, {"type", "", 0, 143285}, @@ -628,18 +626,19 @@ func TestGasBF(t *testing.T) { skipNotOnAmd64(t) var err error - code := readLuaCode(t, "gas_bf.lua") + code2 := readLuaCode(t, "gas_bf_v2.lua") + code4 := readLuaCode(t, "gas_bf_v4.lua") // err = expectGas(t, string(code), 0, `"main"`, ``, 100000, SetHardForkVersion(1)) // assert.NoError(t, err) - err = expectGas(string(code), 0, `"main"`, ``, 47456244, SetHardForkVersion(2)) + err = expectGas(string(code2), 0, `"main"`, ``, 47456244, SetHardForkVersion(2)) assert.NoError(t, err) - err = expectGas(string(code), 0, `"main"`, ``, 47456046, SetHardForkVersion(3)) + err = expectGas(string(code2), 0, `"main"`, ``, 47456046, SetHardForkVersion(3)) assert.NoError(t, err) - err = expectGas(string(code), 0, `"main"`, ``, 57105265, SetHardForkVersion(4)) + err = expectGas(string(code4), 0, `"main"`, ``, 57053355, SetHardForkVersion(4)) assert.NoError(t, err) } diff --git a/tests/test-gas-bf.sh b/tests/test-gas-bf.sh index 252231d28..f66351bc6 100755 --- a/tests/test-gas-bf.sh +++ b/tests/test-gas-bf.sh @@ -6,7 +6,11 @@ fork_version=$1 echo "-- deploy --" -deploy ../contract/vm_dummy/test_files/gas_bf.lua +if [ "$fork_version" -eq "4" ]; then + deploy ../contract/vm_dummy/test_files/gas_bf_v4.lua +else + deploy ../contract/vm_dummy/test_files/gas_bf_v2.lua +fi get_receipt $txhash @@ -32,7 +36,7 @@ assert_equals "$status" "SUCCESS" #assert_equals "$ret" "{}" if [ "$fork_version" -eq "4" ]; then - assert_equals "$gasUsed" "57105265" + assert_equals "$gasUsed" "57053355" elif [ "$fork_version" -eq "3" ]; then assert_equals "$gasUsed" "47456046" else From 643c533362a4b92238757476c48afd75ce7d31f8 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 2 Nov 2023 18:59:32 +0000 Subject: [PATCH 097/182] fix integration test --- tests/test-gas-per-function-v4.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test-gas-per-function-v4.sh b/tests/test-gas-per-function-v4.sh index 0d8a95978..6814d76f9 100755 --- a/tests/test-gas-per-function-v4.sh +++ b/tests/test-gas-per-function-v4.sh @@ -61,7 +61,6 @@ add_test "loop_n_branche_ops" 146372 add_test "function_header_ops" 143016 add_test "assert" 143146 -add_test "getfenv" 143041 add_test "metatable" 143988 add_test "ipairs" 143039 add_test "pairs" 143039 @@ -70,7 +69,6 @@ add_test "rawequal" 143216 add_test "rawget" 143087 add_test "rawset" 143941 add_test "select" 143166 -add_test "setfenv" 143076 add_test "tonumber" 143186 add_test "tostring" 143457 add_test "type" 143285 From 9403750c14e2d1a293c957f70ef8388f8aeb561e Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 7 Nov 2023 17:37:20 +0000 Subject: [PATCH 098/182] disable string.dump() --- contract/vm.c | 8 ++++++++ contract/vm_dummy/test_files/disabled-functions.lua | 1 + contract/vm_dummy/test_files/gas_bf_v4.lua | 2 -- contract/vm_dummy/vm_dummy_pub_test.go | 5 ++--- tests/test-gas-bf.sh | 2 +- tests/test-gas-per-function-v4.sh | 1 - 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/contract/vm.c b/contract/vm.c index 1f3ea6c69..02994fcd2 100644 --- a/contract/vm.c +++ b/contract/vm.c @@ -45,6 +45,14 @@ static void preloadModules(lua_State *L) { luaopen_db(L); } + if (vm_is_hardfork(L, 4)) { + // disable string.dump + lua_getglobal(L, "string"); + lua_pushnil(L); + lua_setfield(L, -2, "dump"); + lua_pop(L, 1); + } + #ifdef MEASURE lua_register(L, "nsec", nsec); luaopen_jit(L); diff --git a/contract/vm_dummy/test_files/disabled-functions.lua b/contract/vm_dummy/test_files/disabled-functions.lua index 9ae8eca95..0962adb0e 100644 --- a/contract/vm_dummy/test_files/disabled-functions.lua +++ b/contract/vm_dummy/test_files/disabled-functions.lua @@ -21,6 +21,7 @@ function check_disabled_functions() assert(loadfile == nil, "loadfile is available") assert(loadstring == nil, "loadstring is available") assert(print == nil, "print is available") + assert(string.dump == nil, "string.dump is available") local success, result = pcall(function() newproxy() end) assert(success == false and result:match(".* 'newproxy' not supported"), "newproxy is available") diff --git a/contract/vm_dummy/test_files/gas_bf_v4.lua b/contract/vm_dummy/test_files/gas_bf_v4.lua index 8ea2169a8..a349d7819 100644 --- a/contract/vm_dummy/test_files/gas_bf_v4.lua +++ b/contract/vm_dummy/test_files/gas_bf_v4.lua @@ -105,8 +105,6 @@ function string_fns() m1k(string.char, 72, 101, 108, 108, 111) m1k(string.char, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100) m1k(string.char, string.byte(long_str, 1, #long_str)) - m1k(string.dump, m1k) - m1k(string.dump, basic_fns) m1k(string.find, long_str, "nume.....") m1k(string.find, long_str, "we..") m1k(string.find, long_str, "wi..") diff --git a/contract/vm_dummy/vm_dummy_pub_test.go b/contract/vm_dummy/vm_dummy_pub_test.go index 39f87f693..358cb6a2f 100644 --- a/contract/vm_dummy/vm_dummy_pub_test.go +++ b/contract/vm_dummy/vm_dummy_pub_test.go @@ -382,7 +382,6 @@ func TestGasPerFunction(t *testing.T) { {"string.byte", "", 0, 157040}, {"string.char", "", 0, 160397}, - {"string.dump", "", 0, 150349}, {"string.find", "", 0, 147808}, {"string.format", "", 0, 143764}, {"string.gmatch", "", 0, 143799}, @@ -450,7 +449,7 @@ func TestGasPerFunction(t *testing.T) { {"system.getSender", "", 0, 144261}, {"system.getBlockheight", "", 0, 143330}, - {"system.getTxhash", "", 0, 143737}, + {"system.getTxhash", "", 0, 143734}, {"system.getTimestamp", "", 0, 143330}, {"system.getContractID", "", 0, 144261}, {"system.setItem", "", 0, 144194}, @@ -638,7 +637,7 @@ func TestGasBF(t *testing.T) { err = expectGas(string(code2), 0, `"main"`, ``, 47456046, SetHardForkVersion(3)) assert.NoError(t, err) - err = expectGas(string(code4), 0, `"main"`, ``, 57053355, SetHardForkVersion(4)) + err = expectGas(string(code4), 0, `"main"`, ``, 47772314, SetHardForkVersion(4)) assert.NoError(t, err) } diff --git a/tests/test-gas-bf.sh b/tests/test-gas-bf.sh index f66351bc6..087aab303 100755 --- a/tests/test-gas-bf.sh +++ b/tests/test-gas-bf.sh @@ -36,7 +36,7 @@ assert_equals "$status" "SUCCESS" #assert_equals "$ret" "{}" if [ "$fork_version" -eq "4" ]; then - assert_equals "$gasUsed" "57053355" + assert_equals "$gasUsed" "47772314" elif [ "$fork_version" -eq "3" ]; then assert_equals "$gasUsed" "47456046" else diff --git a/tests/test-gas-per-function-v4.sh b/tests/test-gas-per-function-v4.sh index 6814d76f9..420b04ee5 100755 --- a/tests/test-gas-per-function-v4.sh +++ b/tests/test-gas-per-function-v4.sh @@ -78,7 +78,6 @@ add_test "xpcall" 146437 add_test "string.byte" 157040 add_test "string.char" 160397 -add_test "string.dump" 150349 add_test "string.find" 147808 add_test "string.format" 143764 add_test "string.gmatch" 143799 From a87e1c2459ce6189d4e53faca61246e2941023bd Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 9 Nov 2023 13:59:15 -0300 Subject: [PATCH 099/182] rollback state on pcall failure --- contract/contract_module.c | 18 ++++++++- contract/vm.c | 78 +++++++++++++++++++++++++++++--------- contract/vm.go | 9 +++++ 3 files changed, 86 insertions(+), 19 deletions(-) diff --git a/contract/contract_module.c b/contract/contract_module.c index b644993bf..c022a0a9c 100644 --- a/contract/contract_module.c +++ b/contract/contract_module.c @@ -27,10 +27,12 @@ static void reset_amount_info (lua_State *L) { } static int set_value(lua_State *L, const char *str) { + set_call_obj(L, str); if (lua_isnil(L, 1)) { return 1; } + switch(lua_type(L, 1)) { case LUA_TNUMBER: { const char *str = lua_tostring(L, 1); @@ -52,6 +54,7 @@ static int set_value(lua_State *L, const char *str) { default: luaL_error(L, "invalid input"); } + lua_setfield(L, -2, amount_str); return 1; @@ -296,14 +299,18 @@ static int modulePcall(lua_State *L) { } if ((ret = lua_pcall(L, argc, LUA_MULTRET, 0)) != 0) { + // if out of memory, throw error if (ret == LUA_ERRMEM) { luaL_throwerror(L); } + // add 'success = false' as the first returned value lua_pushboolean(L, false); lua_insert(L, 1); + // drop the events if (vm_is_hardfork(L, 4)) { luaDropEvent(L, service, num_events); } + // revert the contract state if (start_seq.r0 > 0) { char *errStr = luaClearRecovery(L, service, start_seq.r0, true); if (errStr != NULL) { @@ -313,8 +320,12 @@ static int modulePcall(lua_State *L) { } return 2; } + + // add 'success = true' as the first returned value lua_pushboolean(L, true); lua_insert(L, 1); + + // release the recovery point if (start_seq.r0 == 1) { char *errStr = luaClearRecovery(L, service, start_seq.r0, false); if (errStr != NULL) { @@ -325,6 +336,8 @@ static int modulePcall(lua_State *L) { luaL_throwerror(L); } } + + // return the number of items in the stack return lua_gettop(L); } @@ -342,6 +355,7 @@ static int moduleDeploy(lua_State *L) { lua_gasuse(L, 5000); + // get the amount to transfer to the new contract lua_getfield(L, 1, amount_str); if (lua_isnil(L, -1)) { amount = NULL; @@ -349,7 +363,9 @@ static int moduleDeploy(lua_State *L) { amount = (char *) luaL_checkstring(L, -1); } lua_pop(L, 1); + // get the contract source code or the address to an existing contract contract = (char *) luaL_checkstring(L, 2); + // get the deploy arguments to the constructor function json_args = lua_util_get_json_from_stack(L, 3, lua_gettop(L), false); if (json_args == NULL) { reset_amount_info(L); @@ -363,13 +379,13 @@ static int moduleDeploy(lua_State *L) { strPushAndRelease(L, ret.r1); luaL_throwerror(L); } + free(json_args); reset_amount_info(L); strPushAndRelease(L, ret.r1); if (ret.r0 > 1) { lua_insert(L, -ret.r0); } - return ret.r0; } diff --git a/contract/vm.c b/contract/vm.c index 42ba6d72e..34b4ba2f0 100644 --- a/contract/vm.c +++ b/contract/vm.c @@ -68,58 +68,87 @@ static void preloadModules(lua_State *L) { #endif } -/* override pcall to drop events upon error */ +// overridden version of pcall +// used to rollback state and drop events upon error static int pcall(lua_State *L) { - int argc = lua_gettop(L); - int status; - - // get the current number of events + int argc = lua_gettop(L) - 1; int service = getLuaExecContext(L); int num_events = luaGetEventCount(L, service); + struct luaSetRecoveryPoint_return start_seq; + int ret; if (argc < 1) { return luaL_error(L, "pcall: not enough arguments"); } + lua_gasuse(L, 300); + + start_seq = luaSetRecoveryPoint(L, service); + if (start_seq.r0 < 0) { + strPushAndRelease(L, start_seq.r1); + luaL_throwerror(L); + } + // the stack is like this: // func arg1 arg2 ... argn // call the function - status = lua_pcall(L, argc - 1, LUA_MULTRET, 0); + ret = lua_pcall(L, argc, LUA_MULTRET, 0); // if failed, drop the events - if (status != 0) { + if (ret != 0) { if (vm_is_hardfork(L, 4)) { luaDropEvent(L, service, num_events); } } // throw the error if out of memory - if (status == LUA_ERRMEM) { + if (ret == LUA_ERRMEM) { luaL_throwerror(L); } // insert the status at the bottom of the stack - lua_pushboolean(L, status == 0); + lua_pushboolean(L, ret == 0); lua_insert(L, 1); + // release the recovery point or revert the contract state + if (start_seq.r0 > 0) { + bool is_error = (ret != 0); + char *errStr = luaClearRecovery(L, service, start_seq.r0, is_error); + if (errStr != NULL) { + if (vm_is_hardfork(L, 4)) { + luaDropEvent(L, service, num_events); + } + strPushAndRelease(L, errStr); + luaL_throwerror(L); + } + } + // return the number of items in the stack return lua_gettop(L); } +// overridden version of xpcall +// used to rollback state and drop events upon error static int xpcall(lua_State *L) { - int argc = lua_gettop(L); - int errfunc; - int status; - - // get the current number of events + int argc = lua_gettop(L) - 1; int service = getLuaExecContext(L); int num_events = luaGetEventCount(L, service); + struct luaSetRecoveryPoint_return start_seq; + int ret, errfunc; if (argc < 2) { return luaL_error(L, "xpcall: not enough arguments"); } + lua_gasuse(L, 300); + + start_seq = luaSetRecoveryPoint(L, service); + if (start_seq.r0 < 0) { + strPushAndRelease(L, start_seq.r1); + luaL_throwerror(L); + } + // the stack is like this: // func errfunc arg1 arg2 ... argn @@ -142,17 +171,17 @@ static int xpcall(lua_State *L) { errfunc = 1; // call the function - status = lua_pcall(L, argc - 2, LUA_MULTRET, errfunc); + ret = lua_pcall(L, argc - 1, LUA_MULTRET, errfunc); // if failed, drop the events - if (status != 0) { + if (ret != 0) { if (vm_is_hardfork(L, 4)) { luaDropEvent(L, service, num_events); } } // throw the error if out of memory - if (status == LUA_ERRMEM) { + if (ret == LUA_ERRMEM) { luaL_throwerror(L); } @@ -166,9 +195,22 @@ static int xpcall(lua_State *L) { } // store the status at the bottom of the stack, replacing the error handler - lua_pushboolean(L, status == 0); + lua_pushboolean(L, ret == 0); lua_replace(L, 1); + // release the recovery point or revert the contract state + if (start_seq.r0 > 0) { + bool is_error = (ret != 0); + char *errStr = luaClearRecovery(L, service, start_seq.r0, is_error); + if (errStr != NULL) { + if (vm_is_hardfork(L, 4)) { + luaDropEvent(L, service, num_events); + } + strPushAndRelease(L, errStr); + luaL_throwerror(L); + } + } + // return the number of items in the stack return lua_gettop(L); } diff --git a/contract/vm.go b/contract/vm.go index 5417501ef..2ddd98a61 100644 --- a/contract/vm.go +++ b/contract/vm.go @@ -1370,6 +1370,8 @@ func GetABI(contractState *state.ContractState, bs *state.BlockState) (*types.AB func (re *recoveryEntry) recovery(bs *state.BlockState) error { var zero big.Int cs := re.callState + + // restore the contract balance if re.amount.Cmp(&zero) > 0 { if re.senderState != nil { re.senderState.Balance = new(big.Int).Add(re.senderState.GetBalanceBigInt(), re.amount).Bytes() @@ -1381,6 +1383,8 @@ func (re *recoveryEntry) recovery(bs *state.BlockState) error { if re.onlySend { return nil } + + // restore the contract nonce if re.senderState != nil { re.senderState.Nonce = re.senderNonce } @@ -1388,6 +1392,8 @@ func (re *recoveryEntry) recovery(bs *state.BlockState) error { if cs == nil { return nil } + + // restore the contract state if re.stateRevision != -1 { err := cs.ctrState.Rollback(re.stateRevision) if err != nil { @@ -1401,6 +1407,8 @@ func (re *recoveryEntry) recovery(bs *state.BlockState) error { bs.RemoveCache(cs.ctrState.GetAccountID()) } } + + // restore the contract SQL db state if cs.tx != nil { if re.sqlSaveName == nil { err := cs.tx.rollbackToSavepoint() @@ -1415,6 +1423,7 @@ func (re *recoveryEntry) recovery(bs *state.BlockState) error { } } } + return nil } From c01e9216106da82ffbde68fdc7f9dd3cdb43cd4c Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 9 Nov 2023 18:10:19 +0000 Subject: [PATCH 100/182] fix overridden pcall and xpcall --- contract/vm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contract/vm.c b/contract/vm.c index 34b4ba2f0..aef28defe 100644 --- a/contract/vm.c +++ b/contract/vm.c @@ -71,7 +71,7 @@ static void preloadModules(lua_State *L) { // overridden version of pcall // used to rollback state and drop events upon error static int pcall(lua_State *L) { - int argc = lua_gettop(L) - 1; + int argc = lua_gettop(L); int service = getLuaExecContext(L); int num_events = luaGetEventCount(L, service); struct luaSetRecoveryPoint_return start_seq; @@ -93,7 +93,7 @@ static int pcall(lua_State *L) { // func arg1 arg2 ... argn // call the function - ret = lua_pcall(L, argc, LUA_MULTRET, 0); + ret = lua_pcall(L, argc - 1, LUA_MULTRET, 0); // if failed, drop the events if (ret != 0) { @@ -131,7 +131,7 @@ static int pcall(lua_State *L) { // overridden version of xpcall // used to rollback state and drop events upon error static int xpcall(lua_State *L) { - int argc = lua_gettop(L) - 1; + int argc = lua_gettop(L); int service = getLuaExecContext(L); int num_events = luaGetEventCount(L, service); struct luaSetRecoveryPoint_return start_seq; @@ -171,7 +171,7 @@ static int xpcall(lua_State *L) { errfunc = 1; // call the function - ret = lua_pcall(L, argc - 1, LUA_MULTRET, errfunc); + ret = lua_pcall(L, argc - 2, LUA_MULTRET, errfunc); // if failed, drop the events if (ret != 0) { From be459a5a3b4df8e35d382567b492962fd046144a Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 9 Nov 2023 18:11:35 +0000 Subject: [PATCH 101/182] adjust test of SQL db with pcall --- contract/vm_dummy/vm_dummy_test.go | 36 +++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index db80c4bd1..715a26030 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -1230,17 +1230,47 @@ func TestSqlOnConflict(t *testing.T) { err = bc.ConnectBlock( NewLuaTxCall("user1", "on_conflict", 0, `{"name":"stmt_exec", "args": ["insert into t values (5)"]}`), - NewLuaTxCall("user1", "on_conflict", 0, `{"name":"stmt_exec", "args": ["insert or rollback into t values (5)"]}`).Fail("syntax error"), + NewLuaTxCall("user1", "on_conflict", 0, `{"name":"stmt_exec", "args": ["insert or rollback into t values (6),(5),(7)"]}`).Fail("syntax error"), ) require.NoErrorf(t, err, "failed to call tx") err = bc.Query("on_conflict", `{"name":"get"}`, "", `[1,2,3,4,5]`) require.NoErrorf(t, err, "failed to query") - err = bc.ConnectBlock(NewLuaTxCall("user1", "on_conflict", 0, `{"name":"stmt_exec_pcall", "args": ["insert or fail into t values (6),(7),(5),(8),(9)"]}`)) + err = bc.ConnectBlock(NewLuaTxCall("user1", "on_conflict", 0, `{"name":"stmt_exec", "args": ["insert or abort into t values (6),(7),(5),(8),(9)"]}`).Fail("UNIQUE constraint failed")) require.NoErrorf(t, err, "failed to call tx") - err = bc.Query("on_conflict", `{"name":"get"}`, "", `[1,2,3,4,5,6,7]`) + err = bc.Query("on_conflict", `{"name":"get"}`, "", `[1,2,3,4,5]`) + require.NoErrorf(t, err, "failed to query") + + // successful pcall + err = bc.ConnectBlock(NewLuaTxCall("user1", "on_conflict", 0, `{"name":"stmt_exec_pcall", "args": ["insert into t values (6)"]}`)) + require.NoErrorf(t, err, "failed to call tx") + + err = bc.Query("on_conflict", `{"name":"get"}`, "", `[1,2,3,4,5,6]`) + require.NoErrorf(t, err, "failed to query") + + // pcall fails but the tx succeeds + err = bc.ConnectBlock(NewLuaTxCall("user1", "on_conflict", 0, `{"name":"stmt_exec_pcall", "args": ["insert or fail into t values (7),(5),(8)"]}`)) + require.NoErrorf(t, err, "failed to call tx") + + var expected string + if version >= 4 { + // pcall reverts the changes + expected = `[1,2,3,4,5,6]` + } else { + // pcall does not revert the changes + expected = `[1,2,3,4,5,6,7]` + } + + err = bc.Query("on_conflict", `{"name":"get"}`, "", expected) + require.NoErrorf(t, err, "failed to query") + + // here the tx is reverted + err = bc.ConnectBlock(NewLuaTxCall("user1", "on_conflict", 0, `{"name":"stmt_exec", "args": ["insert or fail into t values (7),(5),(8)"]}`).Fail("UNIQUE constraint failed")) + require.NoErrorf(t, err, "failed to call tx") + + err = bc.Query("on_conflict", `{"name":"get"}`, "", expected) require.NoErrorf(t, err, "failed to query") } From 203c889a8583e48d3f2743bd073cc23ebb7f689e Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 14 Nov 2023 03:15:30 +0000 Subject: [PATCH 102/182] fix: use new hex encode --- contract/vm_callback.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contract/vm_callback.go b/contract/vm_callback.go index e6f20787c..c25c341a8 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -1365,7 +1365,7 @@ func luaToPubkey(L *LState, address *C.char) *C.char { return C.CString("[Contract.LuaToPubkey] invalid address") } // return the public key in hex format - return C.CString("0x" + hex.EncodeToString(pubkey)) + return C.CString("0x" + hex.Encode(pubkey)) } //export luaToAddress From f1107007340b2a3d26daf7ae511ea016964ca6c7 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 16 Nov 2023 00:03:00 -0300 Subject: [PATCH 103/182] add test for rollback on pcall and xpcall --- ...ck_4.lua => feature_pcall_rollback_4a.lua} | 0 .../test_files/feature_pcall_rollback_4b.lua | 128 +++++++++++++++++ .../test_files/feature_pcall_rollback_4c.lua | 132 ++++++++++++++++++ contract/vm_dummy/vm_dummy_test.go | 44 +++++- 4 files changed, 301 insertions(+), 3 deletions(-) rename contract/vm_dummy/test_files/{feature_pcall_rollback_4.lua => feature_pcall_rollback_4a.lua} (100%) create mode 100644 contract/vm_dummy/test_files/feature_pcall_rollback_4b.lua create mode 100644 contract/vm_dummy/test_files/feature_pcall_rollback_4c.lua diff --git a/contract/vm_dummy/test_files/feature_pcall_rollback_4.lua b/contract/vm_dummy/test_files/feature_pcall_rollback_4a.lua similarity index 100% rename from contract/vm_dummy/test_files/feature_pcall_rollback_4.lua rename to contract/vm_dummy/test_files/feature_pcall_rollback_4a.lua diff --git a/contract/vm_dummy/test_files/feature_pcall_rollback_4b.lua b/contract/vm_dummy/test_files/feature_pcall_rollback_4b.lua new file mode 100644 index 000000000..bc1c40929 --- /dev/null +++ b/contract/vm_dummy/test_files/feature_pcall_rollback_4b.lua @@ -0,0 +1,128 @@ +state.var { + resolver = state.value(), + name = state.value(), + values = state.map() +} + +function constructor(resolver_address, contract_name) + -- initialize state variables + resolver:set(resolver_address) + name:set(contract_name) + -- initialize db + db.exec("create table config (value integer primary key) without rowid") + db.exec("insert into config values (0)") + db.exec([[create table products ( + id integer primary key, + name text not null, + price real) + ]]) + db.exec("insert into products (name,price) values ('first', 1234.56)") +end + +function resolve(name) + return contract.call(resolver:get(), "resolve", name) +end + +--[[ + ['set','x',111], + ['pcall','A'] +],[ + ['set','x',222], + ['pcall','A'], + ['fail'] +],[ + ['set','x',333] +]] + +function test(script) + -- get the commands for this function to execute + local commands = table.remove(script, 1) + + -- execute each command + for i, cmd in ipairs(commands) do + local action = cmd[1] + if action == "set" then + contract.event(name:get() .. ".set", cmd[2], cmd[3]) + values[cmd[2]] = cmd[3] + elseif action == "pcall" then + local to_call = cmd[2] + local amount = cmd[3] + if to_call == name:get() then + pcall(test, script) + elseif amount ~= nil then + contract.event(name:get() .. " send " .. to_call, amount) + local address = resolve(to_call) + success, ret = pcall(function() + return contract.call.value(amount)(address, "test", script) + end) + else + local address = resolve(to_call) + success, ret = pcall(contract.call, address, "test", script) + end + --contract.event("result", success, ret) + elseif action == "send" then + local to = cmd[2] + contract.event(name:get() .. " send " .. to, amount) + contract.send(resolve(to), cmd[3]) + elseif action == "deploy" then + local code_or_address = resolve_deploy(cmd[2]) + pcall(contract.deploy, code_or_address, unpack(cmd,3)) + elseif action == "deploy.send" then + contract.event(name:get() .. ".deploy.send", amount) + local code_or_address = resolve_deploy(cmd[3]) + pcall(function() + contract.deploy.value(cmd[2])(code_or_address, unpack(cmd,4)) + end) + elseif action == "db.set" then + db.exec("update config set value = " .. cmd[2]) + elseif action == "db.insert" then + db.exec("insert into products (name,price) values ('another',1234.56)") + elseif action == "fail" then + assert(1 == 0, "failed") + end + end + +end + +function set(key, value) + values[key] = value +end + +function get(key) + return values[key] +end + +function db_reset() + db.exec("update config set value = 0") + db.exec("delete from products where id > 1") +end + +function db_get() + local rs = db.query("select value from config") + if rs:next() then + return rs:get() + else + return "error" + end +end + +function db_count() + local rs = db.query("select count(*) from products") + if rs:next() then + return rs:get() + else + return "error" + end +end + +function default() + -- only receive +end + +function send_back(to) + contract.send(resolve(to), contract.balance()) +end + +abi.payable(constructor, test, default) +abi.register(set, send_back, db_reset) +abi.register_view(get, db_get, db_count) diff --git a/contract/vm_dummy/test_files/feature_pcall_rollback_4c.lua b/contract/vm_dummy/test_files/feature_pcall_rollback_4c.lua new file mode 100644 index 000000000..4e0ed37f2 --- /dev/null +++ b/contract/vm_dummy/test_files/feature_pcall_rollback_4c.lua @@ -0,0 +1,132 @@ +state.var { + resolver = state.value(), + name = state.value(), + values = state.map() +} + +function constructor(resolver_address, contract_name) + -- initialize state variables + resolver:set(resolver_address) + name:set(contract_name) + -- initialize db + db.exec("create table config (value integer primary key) without rowid") + db.exec("insert into config values (0)") + db.exec([[create table products ( + id integer primary key, + name text not null, + price real) + ]]) + db.exec("insert into products (name,price) values ('first', 1234.56)") +end + +function resolve(name) + return contract.call(resolver:get(), "resolve", name) +end + +function error_handler(err_msg) + return "oh no! " .. err_msg +end + +--[[ + ['set','x',111], + ['pcall','A'] +],[ + ['set','x',222], + ['pcall','A'], + ['fail'] +],[ + ['set','x',333] +]] + +function test(script) + -- get the commands for this function to execute + local commands = table.remove(script, 1) + + -- execute each command + for i, cmd in ipairs(commands) do + local action = cmd[1] + if action == "set" then + contract.event(name:get() .. ".set", cmd[2], cmd[3]) + values[cmd[2]] = cmd[3] + elseif action == "pcall" then + local to_call = cmd[2] + local amount = cmd[3] + if to_call == name:get() then + xpcall(test, error_handler, script) + elseif amount ~= nil then + contract.event(name:get() .. " send " .. to_call, amount) + local address = resolve(to_call) + success, ret = xpcall(function() + return contract.call.value(amount)(address, "test", script) + end, error_handler) + else + local address = resolve(to_call) + success, ret = xpcall(contract.call, error_handler, address, "test", script) + end + --contract.event("result", success, ret) + elseif action == "send" then + local to = cmd[2] + contract.event(name:get() .. " send " .. to, amount) + contract.send(resolve(to), cmd[3]) + elseif action == "deploy" then + local code_or_address = resolve_deploy(cmd[2]) + xpcall(contract.deploy, error_handler, code_or_address, unpack(cmd,3)) + elseif action == "deploy.send" then + contract.event(name:get() .. ".deploy.send", amount) + local code_or_address = resolve_deploy(cmd[3]) + xpcall(function() + contract.deploy.value(cmd[2])(code_or_address, unpack(cmd,4)) + end, error_handler) + elseif action == "db.set" then + db.exec("update config set value = " .. cmd[2]) + elseif action == "db.insert" then + db.exec("insert into products (name,price) values ('another',1234.56)") + elseif action == "fail" then + assert(1 == 0, "failed") + end + end + +end + +function set(key, value) + values[key] = value +end + +function get(key) + return values[key] +end + +function db_reset() + db.exec("update config set value = 0") + db.exec("delete from products where id > 1") +end + +function db_get() + local rs = db.query("select value from config") + if rs:next() then + return rs:get() + else + return "error" + end +end + +function db_count() + local rs = db.query("select count(*) from products") + if rs:next() then + return rs:get() + else + return "error" + end +end + +function default() + -- only receive +end + +function send_back(to) + contract.send(resolve(to), contract.balance()) +end + +abi.payable(constructor, test, default) +abi.register(set, send_back, db_reset) +abi.register_view(get, db_get, db_count) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index abc970cff..353e6d770 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -2801,10 +2801,23 @@ func TestFeaturePcallNested(t *testing.T) { // test rollback of state variable and balance func TestPcallStateRollback1(t *testing.T) { - code := readLuaCode(t, "feature_pcall_rollback_4.lua") resolver := readLuaCode(t, "resolver.lua") for version := min_version; version <= max_version; version++ { + + files := make([]string, 0) + files = append(files, "feature_pcall_rollback_4a.lua") // contract.pcall + if version >= 4 { + files = append(files, "feature_pcall_rollback_4b.lua") // pcall + files = append(files, "feature_pcall_rollback_4c.lua") // xpcall + } + + // iterate over all files + for _, file := range files { + + code := readLuaCode(t, file) + + bc, err := LoadDummyChain(SetHardForkVersion(version)) require.NoErrorf(t, err, "failed to create dummy chain") defer bc.Release() @@ -3229,16 +3242,28 @@ func TestPcallStateRollback1(t *testing.T) { map[string]int{"A": 0, "B": 0}, map[string]int64{"A": 3, "B": 0}) + } } } // test rollback of state variable and balance - send separate from call func TestPcallStateRollback2(t *testing.T) { t.Skip("disabled until bug with test is fixed") - code := readLuaCode(t, "feature_pcall_rollback_4.lua") resolver := readLuaCode(t, "resolver.lua") for version := min_version; version <= max_version; version++ { + files := make([]string, 0) + files = append(files, "feature_pcall_rollback_4a.lua") // contract.pcall + if version >= 4 { + files = append(files, "feature_pcall_rollback_4b.lua") // pcall + files = append(files, "feature_pcall_rollback_4c.lua") // xpcall + } + + // iterate over all files + for _, file := range files { + + code := readLuaCode(t, file) + bc, err := LoadDummyChain(SetHardForkVersion(version)) require.NoErrorf(t, err, "failed to create dummy chain") defer bc.Release() @@ -3759,6 +3784,7 @@ func TestPcallStateRollback2(t *testing.T) { map[string]int{"A": 0, "B": 0}, map[string]int64{"A": 3, "B": 0}) + } } } @@ -3766,9 +3792,20 @@ func TestPcallStateRollback2(t *testing.T) { func TestPcallStateRollback3(t *testing.T) { t.Skip("disabled until bug with test is fixed") resolver := readLuaCode(t, "resolver.lua") - code := readLuaCode(t, "feature_pcall_rollback_4.lua") for version := min_version; version <= max_version; version++ { + files := make([]string, 0) + files = append(files, "feature_pcall_rollback_4a.lua") // contract.pcall + if version >= 4 { + files = append(files, "feature_pcall_rollback_4b.lua") // pcall + files = append(files, "feature_pcall_rollback_4c.lua") // xpcall + } + + // iterate over all files + for _, file := range files { + + code := readLuaCode(t, file) + bc, err := LoadDummyChain(SetHardForkVersion(version)) require.NoErrorf(t, err, "failed to create dummy chain") defer bc.Release() @@ -4169,6 +4206,7 @@ func TestPcallStateRollback3(t *testing.T) { testDbStateRollback(t, bc, script, map[string]int{"A": 0, "B": 0}) + } } } From 43ddf0841a32da6340949687fcf830007af486e3 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 16 Nov 2023 00:07:12 -0300 Subject: [PATCH 104/182] format test code --- contract/vm_dummy/vm_dummy_test.go | 2671 ++++++++++++++-------------- 1 file changed, 1335 insertions(+), 1336 deletions(-) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index 353e6d770..76a9dc585 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -2817,430 +2817,429 @@ func TestPcallStateRollback1(t *testing.T) { code := readLuaCode(t, file) + bc, err := LoadDummyChain(SetHardForkVersion(version)) + require.NoErrorf(t, err, "failed to create dummy chain") + defer bc.Release() - bc, err := LoadDummyChain(SetHardForkVersion(version)) - require.NoErrorf(t, err, "failed to create dummy chain") - defer bc.Release() - - // deploy and setup the name resolver - err = bc.ConnectBlock( - NewLuaTxAccount("user", 10, types.Aergo), - NewLuaTxDeploy("user", "resolver", 0, resolver), - NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["A","%s"]}`, nameToAddress("A"))), - NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["B","%s"]}`, nameToAddress("B"))), - NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["C","%s"]}`, nameToAddress("C"))), - ) - require.NoErrorf(t, err, "failed to deploy and setup resolver") + // deploy and setup the name resolver + err = bc.ConnectBlock( + NewLuaTxAccount("user", 10, types.Aergo), + NewLuaTxDeploy("user", "resolver", 0, resolver), + NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["A","%s"]}`, nameToAddress("A"))), + NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["B","%s"]}`, nameToAddress("B"))), + NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["C","%s"]}`, nameToAddress("C"))), + ) + require.NoErrorf(t, err, "failed to deploy and setup resolver") - // deploy the contracts - err = bc.ConnectBlock( - NewLuaTxDeploy("user", "A", 3, code).Constructor(fmt.Sprintf(`["%s","A"]`, nameToAddress("resolver"))), - NewLuaTxDeploy("user", "B", 0, code).Constructor(fmt.Sprintf(`["%s","B"]`, nameToAddress("resolver"))), - NewLuaTxDeploy("user", "C", 0, code).Constructor(fmt.Sprintf(`["%s","C"]`, nameToAddress("resolver"))), - ) - require.NoErrorf(t, err, "failed to deploy the contracts") - - // A -> A -> A (3 calls on the same contract) - - script := `[[ - ['set','x',111], - ['pcall','A'] - ],[ - ['set','x',222], - ['pcall','A'] - ],[ - ['set','x',333] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 333}, nil) - - script = `[[ - ['set','x',111], - ['pcall','A'] - ],[ - ['set','x',222], - ['pcall','A'] - ],[ - ['set','x',333], - ['fail'] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 222}, nil) - - script = `[[ - ['set','x',111], - ['pcall','A'] - ],[ - ['set','x',222], - ['pcall','A'], - ['fail'] - ],[ - ['set','x',333] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111}, nil) - - script = `[[ - ['set','x',111], - ['pcall','A'], - ['fail'] - ],[ - ['set','x',222], - ['pcall','A'] - ],[ - ['set','x',333] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 0}, nil) - - // A -> B -> C (3 different contracts) - - script = `[[ - ['set','x',111], - ['pcall','B',2] - ],[ - ['set','x',222], - ['pcall','C',1] - ],[ - ['set','x',333] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 222, "C": 333}, - map[string]int64{"A": 1, "B": 1, "C": 1}) - - script = `[[ - ['set','x',111], - ['pcall','B',2] - ],[ - ['set','x',222], - ['pcall','C',1] - ],[ - ['set','x',333], - ['fail'] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 222, "C": 0}, - map[string]int64{"A": 1, "B": 2, "C": 0}) - - script = `[[ - ['set','x',111], - ['pcall','B',2] - ],[ - ['set','x',222], - ['pcall','C',1], - ['fail'] - ],[ - ['set','x',333] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 0, "C": 0}, - map[string]int64{"A": 3, "B": 0, "C": 0}) - - script = `[[ - ['set','x',111], - ['pcall','B',2], - ['fail'] - ],[ - ['set','x',222], - ['pcall','C',1] - ],[ - ['set','x',333] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 0, "B": 0, "C": 0}, - map[string]int64{"A": 3, "B": 0, "C": 0}) - - // A -> B -> A (call back to original contract) - - script = `[[ - ['set','x',111], - ['pcall','B',2] - ],[ - ['set','x',222], - ['pcall','A',1] - ],[ - ['set','x',333] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 333, "B": 222}, - map[string]int64{"A": 2, "B": 1}) - - script = `[[ - ['set','x',111], - ['pcall','B',2] - ],[ - ['set','x',222], - ['pcall','A',1] - ],[ - ['set','x',333], - ['fail'] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 222}, - map[string]int64{"A": 1, "B": 2}) - - script = `[[ - ['set','x',111], - ['pcall','B',2] - ],[ - ['set','x',222], - ['pcall','A',1], - ['fail'] - ],[ - ['set','x',333] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 0}, - map[string]int64{"A": 3, "B": 0}) - - script = `[[ - ['set','x',111], - ['pcall','B',2], - ['fail'] - ],[ - ['set','x',222], - ['pcall','A',1] - ],[ - ['set','x',333] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 0, "B": 0}, - map[string]int64{"A": 3, "B": 0}) - - // A -> B -> B - - script = `[[ - ['set','x',111], - ['pcall','B',3] - ],[ - ['set','x',222], - ['pcall','B'] - ],[ - ['set','x',333] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 333}, - map[string]int64{"A": 0, "B": 3}) - - script = `[[ - ['set','x',111], - ['pcall','B',3] - ],[ - ['set','x',222], - ['pcall','B'] - ],[ - ['set','x',333], - ['fail'] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 222}, - map[string]int64{"A": 0, "B": 3}) - - script = `[[ - ['set','x',111], - ['pcall','B',3] - ],[ - ['set','x',222], - ['pcall','B'], - ['fail'] - ],[ - ['set','x',333] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 0}, - map[string]int64{"A": 3, "B": 0}) - - script = `[[ - ['set','x',111], - ['pcall','B',3], - ['fail'] - ],[ - ['set','x',222], - ['pcall','B'] - ],[ - ['set','x',333] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 0, "B": 0}, - map[string]int64{"A": 3, "B": 0}) - - // A -> A -> B - - script = `[[ - ['set','x',111], - ['pcall','A'] - ],[ - ['set','x',222], - ['pcall','B',3] - ],[ - ['set','x',333] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 222, "B": 333}, - map[string]int64{"A": 0, "B": 3}) - - script = `[[ - ['set','x',111], - ['pcall','A'] - ],[ - ['set','x',222], - ['pcall','B',3] - ],[ - ['set','x',333], - ['fail'] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 222, "B": 0}, - map[string]int64{"A": 3, "B": 0}) - - script = `[[ - ['set','x',111], - ['pcall','A'] - ],[ - ['set','x',222], - ['pcall','B',3], - ['fail'] - ],[ - ['set','x',333] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 0}, - map[string]int64{"A": 3, "B": 0}) - - script = `[[ - ['set','x',111], - ['pcall','A'], - ['fail'] - ],[ - ['set','x',222], - ['pcall','B',3] - ],[ - ['set','x',333] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 0, "B": 0}, - map[string]int64{"A": 3, "B": 0}) - - // A -> B -> A -> B -> A (zigzag) - - script = `[[ - ['set','x',111], - ['pcall','B',1] - ],[ - ['set','x',222], - ['pcall','A',1] - ],[ - ['set','x',333], - ['pcall','B',1] - ],[ - ['set','x',444], - ['pcall','A',1] - ],[ - ['set','x',555] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 555, "B": 444}, - map[string]int64{"A": 3, "B": 0}) - - script = `[[ - ['set','x',111], - ['pcall','B',1] - ],[ - ['set','x',222], - ['pcall','A',1] - ],[ - ['set','x',333], - ['pcall','B',1] - ],[ - ['set','x',444], - ['pcall','A',1] - ],[ - ['set','x',555], - ['fail'] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 333, "B": 444}, - map[string]int64{"A": 2, "B": 1}) - - script = `[[ - ['set','x',111], - ['pcall','B',1] - ],[ - ['set','x',222], - ['pcall','A',1] - ],[ - ['set','x',333], - ['pcall','B',1] - ],[ - ['set','x',444], - ['pcall','A',1], - ['fail'] - ],[ - ['set','x',555] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 333, "B": 222}, - map[string]int64{"A": 3, "B": 0}) - - script = `[[ - ['set','x',111], - ['pcall','B',1] - ],[ - ['set','x',222], - ['pcall','A',1] - ],[ - ['set','x',333], - ['pcall','B',1], - ['fail'] - ],[ - ['set','x',444], - ['pcall','A',1] - ],[ - ['set','x',555] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 222}, - map[string]int64{"A": 2, "B": 1}) - - script = `[[ - ['set','x',111], - ['pcall','B',1] - ],[ - ['set','x',222], - ['pcall','A',1], - ['fail'] - ],[ - ['set','x',333], - ['pcall','B',1] - ],[ - ['set','x',444], - ['pcall','A',1] - ],[ - ['set','x',555] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 0}, - map[string]int64{"A": 3, "B": 0}) - - script = `[[ - ['set','x',111], - ['pcall','B',1], - ['fail'] - ],[ - ['set','x',222], - ['pcall','A',1] - ],[ - ['set','x',333], - ['pcall','B',1] - ],[ - ['set','x',444], - ['pcall','A',1] - ],[ - ['set','x',555] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 0, "B": 0}, - map[string]int64{"A": 3, "B": 0}) + // deploy the contracts + err = bc.ConnectBlock( + NewLuaTxDeploy("user", "A", 3, code).Constructor(fmt.Sprintf(`["%s","A"]`, nameToAddress("resolver"))), + NewLuaTxDeploy("user", "B", 0, code).Constructor(fmt.Sprintf(`["%s","B"]`, nameToAddress("resolver"))), + NewLuaTxDeploy("user", "C", 0, code).Constructor(fmt.Sprintf(`["%s","C"]`, nameToAddress("resolver"))), + ) + require.NoErrorf(t, err, "failed to deploy the contracts") + + // A -> A -> A (3 calls on the same contract) + + script := `[[ + ['set','x',111], + ['pcall','A'] + ],[ + ['set','x',222], + ['pcall','A'] + ],[ + ['set','x',333] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 333}, nil) + + script = `[[ + ['set','x',111], + ['pcall','A'] + ],[ + ['set','x',222], + ['pcall','A'] + ],[ + ['set','x',333], + ['fail'] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 222}, nil) + + script = `[[ + ['set','x',111], + ['pcall','A'] + ],[ + ['set','x',222], + ['pcall','A'], + ['fail'] + ],[ + ['set','x',333] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111}, nil) + + script = `[[ + ['set','x',111], + ['pcall','A'], + ['fail'] + ],[ + ['set','x',222], + ['pcall','A'] + ],[ + ['set','x',333] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 0}, nil) + + // A -> B -> C (3 different contracts) + + script = `[[ + ['set','x',111], + ['pcall','B',2] + ],[ + ['set','x',222], + ['pcall','C',1] + ],[ + ['set','x',333] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 222, "C": 333}, + map[string]int64{"A": 1, "B": 1, "C": 1}) + + script = `[[ + ['set','x',111], + ['pcall','B',2] + ],[ + ['set','x',222], + ['pcall','C',1] + ],[ + ['set','x',333], + ['fail'] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 222, "C": 0}, + map[string]int64{"A": 1, "B": 2, "C": 0}) + + script = `[[ + ['set','x',111], + ['pcall','B',2] + ],[ + ['set','x',222], + ['pcall','C',1], + ['fail'] + ],[ + ['set','x',333] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 0, "C": 0}, + map[string]int64{"A": 3, "B": 0, "C": 0}) + + script = `[[ + ['set','x',111], + ['pcall','B',2], + ['fail'] + ],[ + ['set','x',222], + ['pcall','C',1] + ],[ + ['set','x',333] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 0, "B": 0, "C": 0}, + map[string]int64{"A": 3, "B": 0, "C": 0}) + + // A -> B -> A (call back to original contract) + + script = `[[ + ['set','x',111], + ['pcall','B',2] + ],[ + ['set','x',222], + ['pcall','A',1] + ],[ + ['set','x',333] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 333, "B": 222}, + map[string]int64{"A": 2, "B": 1}) + + script = `[[ + ['set','x',111], + ['pcall','B',2] + ],[ + ['set','x',222], + ['pcall','A',1] + ],[ + ['set','x',333], + ['fail'] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 222}, + map[string]int64{"A": 1, "B": 2}) + + script = `[[ + ['set','x',111], + ['pcall','B',2] + ],[ + ['set','x',222], + ['pcall','A',1], + ['fail'] + ],[ + ['set','x',333] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 0}, + map[string]int64{"A": 3, "B": 0}) + + script = `[[ + ['set','x',111], + ['pcall','B',2], + ['fail'] + ],[ + ['set','x',222], + ['pcall','A',1] + ],[ + ['set','x',333] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 0, "B": 0}, + map[string]int64{"A": 3, "B": 0}) + + // A -> B -> B + + script = `[[ + ['set','x',111], + ['pcall','B',3] + ],[ + ['set','x',222], + ['pcall','B'] + ],[ + ['set','x',333] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 333}, + map[string]int64{"A": 0, "B": 3}) + + script = `[[ + ['set','x',111], + ['pcall','B',3] + ],[ + ['set','x',222], + ['pcall','B'] + ],[ + ['set','x',333], + ['fail'] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 222}, + map[string]int64{"A": 0, "B": 3}) + + script = `[[ + ['set','x',111], + ['pcall','B',3] + ],[ + ['set','x',222], + ['pcall','B'], + ['fail'] + ],[ + ['set','x',333] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 0}, + map[string]int64{"A": 3, "B": 0}) + + script = `[[ + ['set','x',111], + ['pcall','B',3], + ['fail'] + ],[ + ['set','x',222], + ['pcall','B'] + ],[ + ['set','x',333] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 0, "B": 0}, + map[string]int64{"A": 3, "B": 0}) + + // A -> A -> B + + script = `[[ + ['set','x',111], + ['pcall','A'] + ],[ + ['set','x',222], + ['pcall','B',3] + ],[ + ['set','x',333] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 222, "B": 333}, + map[string]int64{"A": 0, "B": 3}) + + script = `[[ + ['set','x',111], + ['pcall','A'] + ],[ + ['set','x',222], + ['pcall','B',3] + ],[ + ['set','x',333], + ['fail'] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 222, "B": 0}, + map[string]int64{"A": 3, "B": 0}) + + script = `[[ + ['set','x',111], + ['pcall','A'] + ],[ + ['set','x',222], + ['pcall','B',3], + ['fail'] + ],[ + ['set','x',333] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 0}, + map[string]int64{"A": 3, "B": 0}) + + script = `[[ + ['set','x',111], + ['pcall','A'], + ['fail'] + ],[ + ['set','x',222], + ['pcall','B',3] + ],[ + ['set','x',333] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 0, "B": 0}, + map[string]int64{"A": 3, "B": 0}) + + // A -> B -> A -> B -> A (zigzag) + + script = `[[ + ['set','x',111], + ['pcall','B',1] + ],[ + ['set','x',222], + ['pcall','A',1] + ],[ + ['set','x',333], + ['pcall','B',1] + ],[ + ['set','x',444], + ['pcall','A',1] + ],[ + ['set','x',555] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 555, "B": 444}, + map[string]int64{"A": 3, "B": 0}) + + script = `[[ + ['set','x',111], + ['pcall','B',1] + ],[ + ['set','x',222], + ['pcall','A',1] + ],[ + ['set','x',333], + ['pcall','B',1] + ],[ + ['set','x',444], + ['pcall','A',1] + ],[ + ['set','x',555], + ['fail'] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 333, "B": 444}, + map[string]int64{"A": 2, "B": 1}) + + script = `[[ + ['set','x',111], + ['pcall','B',1] + ],[ + ['set','x',222], + ['pcall','A',1] + ],[ + ['set','x',333], + ['pcall','B',1] + ],[ + ['set','x',444], + ['pcall','A',1], + ['fail'] + ],[ + ['set','x',555] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 333, "B": 222}, + map[string]int64{"A": 3, "B": 0}) + + script = `[[ + ['set','x',111], + ['pcall','B',1] + ],[ + ['set','x',222], + ['pcall','A',1] + ],[ + ['set','x',333], + ['pcall','B',1], + ['fail'] + ],[ + ['set','x',444], + ['pcall','A',1] + ],[ + ['set','x',555] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 222}, + map[string]int64{"A": 2, "B": 1}) + + script = `[[ + ['set','x',111], + ['pcall','B',1] + ],[ + ['set','x',222], + ['pcall','A',1], + ['fail'] + ],[ + ['set','x',333], + ['pcall','B',1] + ],[ + ['set','x',444], + ['pcall','A',1] + ],[ + ['set','x',555] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 0}, + map[string]int64{"A": 3, "B": 0}) + + script = `[[ + ['set','x',111], + ['pcall','B',1], + ['fail'] + ],[ + ['set','x',222], + ['pcall','A',1] + ],[ + ['set','x',333], + ['pcall','B',1] + ],[ + ['set','x',444], + ['pcall','A',1] + ],[ + ['set','x',555] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 0, "B": 0}, + map[string]int64{"A": 3, "B": 0}) } } @@ -3264,525 +3263,525 @@ func TestPcallStateRollback2(t *testing.T) { code := readLuaCode(t, file) - bc, err := LoadDummyChain(SetHardForkVersion(version)) - require.NoErrorf(t, err, "failed to create dummy chain") - defer bc.Release() + bc, err := LoadDummyChain(SetHardForkVersion(version)) + require.NoErrorf(t, err, "failed to create dummy chain") + defer bc.Release() - // deploy and setup the name resolver - err = bc.ConnectBlock( - NewLuaTxAccount("user", 10, types.Aergo), - NewLuaTxDeploy("user", "resolver", 0, resolver), - NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["A","%s"]}`, nameToAddress("A"))), - NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["B","%s"]}`, nameToAddress("B"))), - NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["C","%s"]}`, nameToAddress("C"))), - NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["D","%s"]}`, nameToAddress("D"))), - NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["E","%s"]}`, nameToAddress("E"))), - ) - require.NoErrorf(t, err, "failed to deploy and setup resolver") + // deploy and setup the name resolver + err = bc.ConnectBlock( + NewLuaTxAccount("user", 10, types.Aergo), + NewLuaTxDeploy("user", "resolver", 0, resolver), + NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["A","%s"]}`, nameToAddress("A"))), + NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["B","%s"]}`, nameToAddress("B"))), + NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["C","%s"]}`, nameToAddress("C"))), + NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["D","%s"]}`, nameToAddress("D"))), + NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["E","%s"]}`, nameToAddress("E"))), + ) + require.NoErrorf(t, err, "failed to deploy and setup resolver") - // deploy the contracts - err = bc.ConnectBlock( - NewLuaTxDeploy("user", "A", 3, code).Constructor(fmt.Sprintf(`["%s","A"]`, nameToAddress("resolver"))), - NewLuaTxDeploy("user", "B", 0, code).Constructor(fmt.Sprintf(`["%s","B"]`, nameToAddress("resolver"))), - NewLuaTxDeploy("user", "C", 0, code).Constructor(fmt.Sprintf(`["%s","C"]`, nameToAddress("resolver"))), - ) - require.NoErrorf(t, err, "failed to deploy the contracts") - - // A -> A -> A (3 calls on the same contract) - - script := `[[ - ['set','x',111], - ['send','B',1], - ['pcall','A'] - ],[ - ['set','x',222], - ['send','C',1], - ['pcall','A'] - ],[ - ['set','x',333], - ['send','E',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 333}, - map[string]int64{"A": 0, "B": 1, "C": 1, "E": 1}) - - script = `[[ - ['set','x',111], - ['send','B',1], - ['pcall','A'] - ],[ - ['set','x',222], - ['send','C',1], - ['pcall','A'] - ],[ - ['set','x',333], - ['send','D',1], - ['fail'] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 222}, - map[string]int64{"A": 1, "B": 1, "C": 1, "D": 0}) - - script = `[[ - ['set','x',111], - ['send','B',1], - ['pcall','A'] - ],[ - ['set','x',222], - ['send','C',1], - ['pcall','A'], - ['fail'] - ],[ - ['set','x',333], - ['send','D',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111}, - map[string]int64{"A": 2, "B": 1, "C": 0, "D": 0}) - - script = `[[ - ['set','x',111], - ['send','B',1], - ['pcall','A'], - ['fail'] - ],[ - ['set','x',222], - ['send','C',1], - ['pcall','A'] - ],[ - ['set','x',333], - ['send','D',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 0}, - map[string]int64{"A": 3, "B": 0, "C": 0, "D": 0}) - - // A -> B -> C (3 different contracts) - - script = `[[ - ['set','x',111], - ['send','B',3], - ['pcall','B'] - ],[ - ['set','x',222], - ['send','C',2], - ['pcall','C'] - ],[ - ['set','x',333], - ['send','A',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 222, "C": 333}, - map[string]int64{"A": 1, "B": 1, "C": 1}) - - script = `[[ - ['set','x',111], - ['send','B',3], - ['pcall','B'] - ],[ - ['set','x',222], - ['send','C',2], - ['pcall','C'] - ],[ - ['set','x',333], - ['send','A',1], - ['fail'] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 222, "C": 0}, - map[string]int64{"A": 0, "B": 1, "C": 2}) - - script = `[[ - ['set','x',111], - ['send','B',3], - ['pcall','B'] - ],[ - ['set','x',222], - ['send','C',2], - ['pcall','C'], - ['fail'] - ],[ - ['set','x',333], - ['send','A',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 0, "C": 0}, - map[string]int64{"A": 0, "B": 3, "C": 0}) - - script = `[[ - ['set','x',111], - ['send','B',3], - ['pcall','B'], - ['fail'] - ],[ - ['set','x',222], - ['send','C',2], - ['pcall','C'] - ],[ - ['set','x',333], - ['send','A',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 0, "B": 0, "C": 0}, - map[string]int64{"A": 3, "B": 0, "C": 0}) - - // A -> B -> A (call back to original contract) - - script = `[[ - ['set','x',111], - ['send','B',3], - ['pcall','B'] - ],[ - ['set','x',222], - ['send','A',2], - ['pcall','A'] - ],[ - ['set','x',333], - ['send','B',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 333, "B": 222}, - map[string]int64{"A": 1, "B": 2}) - - script = `[[ - ['set','x',111], - ['send','B',3], - ['pcall','B'] - ],[ - ['set','x',222], - ['send','A',2], - ['pcall','A'] - ],[ - ['set','x',333], - ['send','B',1], - ['fail'] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 222}, - map[string]int64{"A": 2, "B": 1}) - - script = `[[ - ['set','x',111], - ['send','B',3], - ['pcall','B'] - ],[ - ['set','x',222], - ['send','A',2], - ['pcall','A'], - ['fail'] - ],[ - ['set','x',333], - ['send','B',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 0}, - map[string]int64{"A": 0, "B": 3}) - - script = `[[ - ['set','x',111], - ['send','B',3], - ['pcall','B'], - ['fail'] - ],[ - ['set','x',222], - ['send','A',2], - ['pcall','A'] - ],[ - ['set','x',333], - ['send','B',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 0, "B": 0}, - map[string]int64{"A": 3, "B": 0}) - - // A -> B -> B - - script = `[[ - ['set','x',111], - ['send','B',3], - ['pcall','B'] - ],[ - ['set','x',222], - ['send','C',1], - ['pcall','B'] - ],[ - ['set','x',333], - ['send','A',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 333}, - map[string]int64{"A": 1, "B": 1, "C": 1}) - - script = `[[ - ['set','x',111], - ['send','B',3], - ['pcall','B'] - ],[ - ['set','x',222], - ['send','C',1], - ['pcall','B'] - ],[ - ['set','x',333], - ['send','A',1], - ['fail'] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 222}, - map[string]int64{"A": 0, "B": 2, "C": 1}) - - script = `[[ - ['set','x',111], - ['send','B',3], - ['pcall','B'] - ],[ - ['set','x',222], - ['send','C',1], - ['pcall','B'], - ['fail'] - ],[ - ['set','x',333], - ['send','A',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 0}, - map[string]int64{"A": 0, "B": 3, "C": 0}) - - script = `[[ - ['set','x',111], - ['send','B',3], - ['pcall','B'], - ['fail'] - ],[ - ['set','x',222], - ['send','C',1], - ['pcall','B'] - ],[ - ['set','x',333], - ['send','A',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 0, "B": 0}, - map[string]int64{"A": 3, "B": 0, "C": 0}) - - // A -> A -> B - - script = `[[ - ['set','x',111], - ['send','B',2], - ['pcall','A'] - ],[ - ['set','x',222], - ['send','C',1], - ['pcall','B'] - ],[ - ['set','x',333], - ['send','A',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 222, "B": 333}, - map[string]int64{"A": 1, "B": 1, "C": 1}) - - script = `[[ - ['set','x',111], - ['send','B',2], - ['pcall','A'] - ],[ - ['set','x',222], - ['send','C',1], - ['pcall','B'] - ],[ - ['set','x',333], - ['send','A',1], - ['fail'] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 222, "B": 0}, - map[string]int64{"A": 0, "B": 2, "C": 1}) - - script = `[[ - ['set','x',111], - ['send','B',2], - ['pcall','A'] - ],[ - ['set','x',222], - ['send','C',1], - ['pcall','B'], - ['fail'] - ],[ - ['set','x',333], - ['send','A',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 0}, - map[string]int64{"A": 1, "B": 2, "C": 0}) - - script = `[[ - ['set','x',111], - ['send','B',2], - ['pcall','A'], - ['fail'] - ],[ - ['set','x',222], - ['send','C',1], - ['pcall','B'] - ],[ - ['set','x',333], - ['send','A',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 0, "B": 0}, - map[string]int64{"A": 3, "B": 0, "C": 0}) - - // A -> B -> A -> B -> A (zigzag) - - script = `[[ - ['set','x',111], - ['send','B',1], - ['pcall','B'] - ],[ - ['set','x',222], - ['send','A',1], - ['pcall','A'] - ],[ - ['set','x',333], - ['send','B',1], - ['pcall','B'] - ],[ - ['set','x',444], - ['send','A',1], - ['pcall','A'] - ],[ - ['set','x',555], - ['send','B',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 555, "B": 444}, - map[string]int64{"A": 2, "B": 1}) - - script = `[[ - ['set','x',111], - ['send','B',1], - ['pcall','B'] - ],[ - ['set','x',222], - ['send','A',1], - ['pcall','A'] - ],[ - ['set','x',333], - ['send','B',1], - ['pcall','B'] - ],[ - ['set','x',444], - ['send','A',1], - ['pcall','A'] - ],[ - ['set','x',555], - ['send','B',1], - ['fail'] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 333, "B": 444}, - map[string]int64{"A": 3, "B": 0}) - - script = `[[ - ['set','x',111], - ['send','B',1], - ['pcall','B'] - ],[ - ['set','x',222], - ['send','A',1], - ['pcall','A'] - ],[ - ['set','x',333], - ['send','B',1], - ['pcall','B'] - ],[ - ['set','x',444], - ['send','A',1], - ['pcall','A'], - ['fail'] - ],[ - ['set','x',555], - ['send','B',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 333, "B": 222}, - map[string]int64{"A": 2, "B": 1}) - - script = `[[ - ['set','x',111], - ['send','B',1], - ['pcall','B'] - ],[ - ['set','x',222], - ['send','A',1], - ['pcall','A'] - ],[ - ['set','x',333], - ['send','B',1], - ['pcall','B'], - ['fail'] - ],[ - ['set','x',444], - ['send','A',1], - ['pcall','A'] - ],[ - ['set','x',555], - ['send','B',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 222}, - map[string]int64{"A": 3, "B": 0}) - - script = `[[ - ['set','x',111], - ['send','B',1], - ['pcall','B'] - ],[ - ['set','x',222], - ['send','A',1], - ['pcall','A'], - ['fail'] - ],[ - ['set','x',333], - ['send','B',1], - ['pcall','B'] - ],[ - ['set','x',444], - ['send','A',1], - ['pcall','A'] - ],[ - ['set','x',555], - ['send','B',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 0}, - map[string]int64{"A": 2, "B": 1}) - - script = `[[ - ['set','x',111], - ['send','B',1], - ['pcall','B'], - ['fail'] - ],[ - ['set','x',222], - ['send','A',1], - ['pcall','A'] - ],[ - ['set','x',333], - ['send','B',1], - ['pcall','B'] - ],[ - ['set','x',444], - ['send','A',1], - ['pcall','A'] - ],[ - ['set','x',555], - ['send','B',1] - ]]` - testStateRollback(t, bc, script, - map[string]int{"A": 0, "B": 0}, - map[string]int64{"A": 3, "B": 0}) + // deploy the contracts + err = bc.ConnectBlock( + NewLuaTxDeploy("user", "A", 3, code).Constructor(fmt.Sprintf(`["%s","A"]`, nameToAddress("resolver"))), + NewLuaTxDeploy("user", "B", 0, code).Constructor(fmt.Sprintf(`["%s","B"]`, nameToAddress("resolver"))), + NewLuaTxDeploy("user", "C", 0, code).Constructor(fmt.Sprintf(`["%s","C"]`, nameToAddress("resolver"))), + ) + require.NoErrorf(t, err, "failed to deploy the contracts") + + // A -> A -> A (3 calls on the same contract) + + script := `[[ + ['set','x',111], + ['send','B',1], + ['pcall','A'] + ],[ + ['set','x',222], + ['send','C',1], + ['pcall','A'] + ],[ + ['set','x',333], + ['send','E',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 333}, + map[string]int64{"A": 0, "B": 1, "C": 1, "E": 1}) + + script = `[[ + ['set','x',111], + ['send','B',1], + ['pcall','A'] + ],[ + ['set','x',222], + ['send','C',1], + ['pcall','A'] + ],[ + ['set','x',333], + ['send','D',1], + ['fail'] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 222}, + map[string]int64{"A": 1, "B": 1, "C": 1, "D": 0}) + + script = `[[ + ['set','x',111], + ['send','B',1], + ['pcall','A'] + ],[ + ['set','x',222], + ['send','C',1], + ['pcall','A'], + ['fail'] + ],[ + ['set','x',333], + ['send','D',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111}, + map[string]int64{"A": 2, "B": 1, "C": 0, "D": 0}) + + script = `[[ + ['set','x',111], + ['send','B',1], + ['pcall','A'], + ['fail'] + ],[ + ['set','x',222], + ['send','C',1], + ['pcall','A'] + ],[ + ['set','x',333], + ['send','D',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 0}, + map[string]int64{"A": 3, "B": 0, "C": 0, "D": 0}) + + // A -> B -> C (3 different contracts) + + script = `[[ + ['set','x',111], + ['send','B',3], + ['pcall','B'] + ],[ + ['set','x',222], + ['send','C',2], + ['pcall','C'] + ],[ + ['set','x',333], + ['send','A',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 222, "C": 333}, + map[string]int64{"A": 1, "B": 1, "C": 1}) + + script = `[[ + ['set','x',111], + ['send','B',3], + ['pcall','B'] + ],[ + ['set','x',222], + ['send','C',2], + ['pcall','C'] + ],[ + ['set','x',333], + ['send','A',1], + ['fail'] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 222, "C": 0}, + map[string]int64{"A": 0, "B": 1, "C": 2}) + + script = `[[ + ['set','x',111], + ['send','B',3], + ['pcall','B'] + ],[ + ['set','x',222], + ['send','C',2], + ['pcall','C'], + ['fail'] + ],[ + ['set','x',333], + ['send','A',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 0, "C": 0}, + map[string]int64{"A": 0, "B": 3, "C": 0}) + + script = `[[ + ['set','x',111], + ['send','B',3], + ['pcall','B'], + ['fail'] + ],[ + ['set','x',222], + ['send','C',2], + ['pcall','C'] + ],[ + ['set','x',333], + ['send','A',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 0, "B": 0, "C": 0}, + map[string]int64{"A": 3, "B": 0, "C": 0}) + + // A -> B -> A (call back to original contract) + + script = `[[ + ['set','x',111], + ['send','B',3], + ['pcall','B'] + ],[ + ['set','x',222], + ['send','A',2], + ['pcall','A'] + ],[ + ['set','x',333], + ['send','B',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 333, "B": 222}, + map[string]int64{"A": 1, "B": 2}) + + script = `[[ + ['set','x',111], + ['send','B',3], + ['pcall','B'] + ],[ + ['set','x',222], + ['send','A',2], + ['pcall','A'] + ],[ + ['set','x',333], + ['send','B',1], + ['fail'] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 222}, + map[string]int64{"A": 2, "B": 1}) + + script = `[[ + ['set','x',111], + ['send','B',3], + ['pcall','B'] + ],[ + ['set','x',222], + ['send','A',2], + ['pcall','A'], + ['fail'] + ],[ + ['set','x',333], + ['send','B',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 0}, + map[string]int64{"A": 0, "B": 3}) + + script = `[[ + ['set','x',111], + ['send','B',3], + ['pcall','B'], + ['fail'] + ],[ + ['set','x',222], + ['send','A',2], + ['pcall','A'] + ],[ + ['set','x',333], + ['send','B',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 0, "B": 0}, + map[string]int64{"A": 3, "B": 0}) + + // A -> B -> B + + script = `[[ + ['set','x',111], + ['send','B',3], + ['pcall','B'] + ],[ + ['set','x',222], + ['send','C',1], + ['pcall','B'] + ],[ + ['set','x',333], + ['send','A',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 333}, + map[string]int64{"A": 1, "B": 1, "C": 1}) + + script = `[[ + ['set','x',111], + ['send','B',3], + ['pcall','B'] + ],[ + ['set','x',222], + ['send','C',1], + ['pcall','B'] + ],[ + ['set','x',333], + ['send','A',1], + ['fail'] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 222}, + map[string]int64{"A": 0, "B": 2, "C": 1}) + + script = `[[ + ['set','x',111], + ['send','B',3], + ['pcall','B'] + ],[ + ['set','x',222], + ['send','C',1], + ['pcall','B'], + ['fail'] + ],[ + ['set','x',333], + ['send','A',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 0}, + map[string]int64{"A": 0, "B": 3, "C": 0}) + + script = `[[ + ['set','x',111], + ['send','B',3], + ['pcall','B'], + ['fail'] + ],[ + ['set','x',222], + ['send','C',1], + ['pcall','B'] + ],[ + ['set','x',333], + ['send','A',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 0, "B": 0}, + map[string]int64{"A": 3, "B": 0, "C": 0}) + + // A -> A -> B + + script = `[[ + ['set','x',111], + ['send','B',2], + ['pcall','A'] + ],[ + ['set','x',222], + ['send','C',1], + ['pcall','B'] + ],[ + ['set','x',333], + ['send','A',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 222, "B": 333}, + map[string]int64{"A": 1, "B": 1, "C": 1}) + + script = `[[ + ['set','x',111], + ['send','B',2], + ['pcall','A'] + ],[ + ['set','x',222], + ['send','C',1], + ['pcall','B'] + ],[ + ['set','x',333], + ['send','A',1], + ['fail'] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 222, "B": 0}, + map[string]int64{"A": 0, "B": 2, "C": 1}) + + script = `[[ + ['set','x',111], + ['send','B',2], + ['pcall','A'] + ],[ + ['set','x',222], + ['send','C',1], + ['pcall','B'], + ['fail'] + ],[ + ['set','x',333], + ['send','A',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 0}, + map[string]int64{"A": 1, "B": 2, "C": 0}) + + script = `[[ + ['set','x',111], + ['send','B',2], + ['pcall','A'], + ['fail'] + ],[ + ['set','x',222], + ['send','C',1], + ['pcall','B'] + ],[ + ['set','x',333], + ['send','A',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 0, "B": 0}, + map[string]int64{"A": 3, "B": 0, "C": 0}) + + // A -> B -> A -> B -> A (zigzag) + + script = `[[ + ['set','x',111], + ['send','B',1], + ['pcall','B'] + ],[ + ['set','x',222], + ['send','A',1], + ['pcall','A'] + ],[ + ['set','x',333], + ['send','B',1], + ['pcall','B'] + ],[ + ['set','x',444], + ['send','A',1], + ['pcall','A'] + ],[ + ['set','x',555], + ['send','B',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 555, "B": 444}, + map[string]int64{"A": 2, "B": 1}) + + script = `[[ + ['set','x',111], + ['send','B',1], + ['pcall','B'] + ],[ + ['set','x',222], + ['send','A',1], + ['pcall','A'] + ],[ + ['set','x',333], + ['send','B',1], + ['pcall','B'] + ],[ + ['set','x',444], + ['send','A',1], + ['pcall','A'] + ],[ + ['set','x',555], + ['send','B',1], + ['fail'] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 333, "B": 444}, + map[string]int64{"A": 3, "B": 0}) + + script = `[[ + ['set','x',111], + ['send','B',1], + ['pcall','B'] + ],[ + ['set','x',222], + ['send','A',1], + ['pcall','A'] + ],[ + ['set','x',333], + ['send','B',1], + ['pcall','B'] + ],[ + ['set','x',444], + ['send','A',1], + ['pcall','A'], + ['fail'] + ],[ + ['set','x',555], + ['send','B',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 333, "B": 222}, + map[string]int64{"A": 2, "B": 1}) + + script = `[[ + ['set','x',111], + ['send','B',1], + ['pcall','B'] + ],[ + ['set','x',222], + ['send','A',1], + ['pcall','A'] + ],[ + ['set','x',333], + ['send','B',1], + ['pcall','B'], + ['fail'] + ],[ + ['set','x',444], + ['send','A',1], + ['pcall','A'] + ],[ + ['set','x',555], + ['send','B',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 222}, + map[string]int64{"A": 3, "B": 0}) + + script = `[[ + ['set','x',111], + ['send','B',1], + ['pcall','B'] + ],[ + ['set','x',222], + ['send','A',1], + ['pcall','A'], + ['fail'] + ],[ + ['set','x',333], + ['send','B',1], + ['pcall','B'] + ],[ + ['set','x',444], + ['send','A',1], + ['pcall','A'] + ],[ + ['set','x',555], + ['send','B',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 0}, + map[string]int64{"A": 2, "B": 1}) + + script = `[[ + ['set','x',111], + ['send','B',1], + ['pcall','B'], + ['fail'] + ],[ + ['set','x',222], + ['send','A',1], + ['pcall','A'] + ],[ + ['set','x',333], + ['send','B',1], + ['pcall','B'] + ],[ + ['set','x',444], + ['send','A',1], + ['pcall','A'] + ],[ + ['set','x',555], + ['send','B',1] + ]]` + testStateRollback(t, bc, script, + map[string]int{"A": 0, "B": 0}, + map[string]int64{"A": 3, "B": 0}) } } @@ -3806,405 +3805,405 @@ func TestPcallStateRollback3(t *testing.T) { code := readLuaCode(t, file) - bc, err := LoadDummyChain(SetHardForkVersion(version)) - require.NoErrorf(t, err, "failed to create dummy chain") - defer bc.Release() + bc, err := LoadDummyChain(SetHardForkVersion(version)) + require.NoErrorf(t, err, "failed to create dummy chain") + defer bc.Release() - err = bc.ConnectBlock( - NewLuaTxAccount("user", 1, types.Aergo), - NewLuaTxDeploy("user", "resolver", 0, resolver), - NewLuaTxDeploy("user", "A", 0, code).Constructor(fmt.Sprintf(`["%s","A"]`, nameToAddress("resolver"))), - NewLuaTxDeploy("user", "B", 0, code).Constructor(fmt.Sprintf(`["%s","B"]`, nameToAddress("resolver"))), - NewLuaTxDeploy("user", "C", 0, code).Constructor(fmt.Sprintf(`["%s","C"]`, nameToAddress("resolver"))), - ) - require.NoErrorf(t, err, "failed to deploy") + err = bc.ConnectBlock( + NewLuaTxAccount("user", 1, types.Aergo), + NewLuaTxDeploy("user", "resolver", 0, resolver), + NewLuaTxDeploy("user", "A", 0, code).Constructor(fmt.Sprintf(`["%s","A"]`, nameToAddress("resolver"))), + NewLuaTxDeploy("user", "B", 0, code).Constructor(fmt.Sprintf(`["%s","B"]`, nameToAddress("resolver"))), + NewLuaTxDeploy("user", "C", 0, code).Constructor(fmt.Sprintf(`["%s","C"]`, nameToAddress("resolver"))), + ) + require.NoErrorf(t, err, "failed to deploy") - err = bc.ConnectBlock( - NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["A","%s"]}`, nameToAddress("A"))), - NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["B","%s"]}`, nameToAddress("B"))), - NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["C","%s"]}`, nameToAddress("C"))), - ) - require.NoErrorf(t, err, "failed to call resolver contract") - - // A -> A -> A (3 calls on the same contract) - - script := `[[ - ['db.set',111], - ['pcall','A'] - ],[ - ['db.set',222], - ['pcall','A'] - ],[ - ['db.set',333] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 333}) - - script = `[[ - ['db.set',111], - ['pcall','A'] - ],[ - ['db.set',222], - ['pcall','A'] - ],[ - ['db.set',333], - ['fail'] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 222}) - - script = `[[ - ['db.set',111], - ['pcall','A'] - ],[ - ['db.set',222], - ['pcall','A'], - ['fail'] - ],[ - ['db.set',333] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 111}) - - script = `[[ - ['db.set',111], - ['pcall','A'], - ['fail'] - ],[ - ['db.set',222], - ['pcall','A'] - ],[ - ['db.set',333] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 0}) - - // A -> B -> C (3 different contracts) - - script = `[[ - ['db.set',111], - ['pcall','B'] - ],[ - ['db.set',222], - ['pcall','C'] - ],[ - ['db.set',333] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 222, "C": 333}) - - script = `[[ - ['db.set',111], - ['pcall','B'] - ],[ - ['db.set',222], - ['pcall','C'] - ],[ - ['db.set',333], - ['fail'] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 222, "C": 0}) - - script = `[[ - ['db.set',111], - ['pcall','B'] - ],[ - ['db.set',222], - ['pcall','C'], - ['fail'] - ],[ - ['db.set',333] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 0, "C": 0}) - - script = `[[ - ['db.set',111], - ['pcall','B'], - ['fail'] - ],[ - ['db.set',222], - ['pcall','C'] - ],[ - ['db.set',333] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 0, "B": 0, "C": 0}) - - // A -> B -> A (call back to original contract) - - script = `[[ - ['db.set',111], - ['pcall','B'] - ],[ - ['db.set',222], - ['pcall','A'] - ],[ - ['db.set',333] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 333, "B": 222}) - - script = `[[ - ['db.set',111], - ['pcall','B'] - ],[ - ['db.set',222], - ['pcall','A'] - ],[ - ['db.set',333], - ['fail'] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 222}) - - script = `[[ - ['db.set',111], - ['pcall','B'] - ],[ - ['db.set',222], - ['pcall','A'], - ['fail'] - ],[ - ['db.set',333] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 0}) - - script = `[[ - ['db.set',111], - ['pcall','B'], - ['fail'] - ],[ - ['db.set',222], - ['pcall','A'] - ],[ - ['db.set',333] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 0, "B": 0}) - - // A -> B -> B - - script = `[[ - ['db.set',111], - ['pcall','B'] - ],[ - ['db.set',222], - ['pcall','B'] - ],[ - ['db.set',333] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 333}) - - script = `[[ - ['db.set',111], - ['pcall','B'] - ],[ - ['db.set',222], - ['pcall','B'] - ],[ - ['db.set',333], - ['fail'] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 222}) - - script = `[[ - ['db.set',111], - ['pcall','B'] - ],[ - ['db.set',222], - ['pcall','B'], - ['fail'] - ],[ - ['db.set',333] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 0}) - - script = `[[ - ['db.set',111], - ['pcall','B'], - ['fail'] - ],[ - ['db.set',222], - ['pcall','B'] - ],[ - ['db.set',333] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 0, "B": 0}) - - // A -> A -> B - - script = `[[ - ['db.set',111], - ['pcall','A'] - ],[ - ['db.set',222], - ['pcall','B'] - ],[ - ['db.set',333] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 222, "B": 333}) - - script = `[[ - ['db.set',111], - ['pcall','A'] - ],[ - ['db.set',222], - ['pcall','B'] - ],[ - ['db.set',333], - ['fail'] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 222, "B": 0}) - - script = `[[ - ['db.set',111], - ['pcall','A'] - ],[ - ['db.set',222], - ['pcall','B'], - ['fail'] - ],[ - ['db.set',333] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 0}) - - script = `[[ - ['db.set',111], - ['pcall','A'], - ['fail'] - ],[ - ['db.set',222], - ['pcall','B'] - ],[ - ['db.set',333] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 0, "B": 0}) - - // A -> B -> A -> B -> A (zigzag) - - script = `[[ - ['db.set',111], - ['pcall','B'] - ],[ - ['db.set',222], - ['pcall','A'] - ],[ - ['db.set',333], - ['pcall','B'] - ],[ - ['db.set',444], - ['pcall','A'] - ],[ - ['db.set',555] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 555, "B": 444}) - - script = `[[ - ['db.set',111], - ['pcall','B'] - ],[ - ['db.set',222], - ['pcall','A'] - ],[ - ['db.set',333], - ['pcall','B'] - ],[ - ['db.set',444], - ['pcall','A'] - ],[ - ['db.set',555], - ['fail'] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 333, "B": 444}) - - script = `[[ - ['db.set',111], - ['pcall','B'] - ],[ - ['db.set',222], - ['pcall','A'] - ],[ - ['db.set',333], - ['pcall','B'] - ],[ - ['db.set',444], - ['pcall','A'], - ['fail'] - ],[ - ['db.set',555] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 333, "B": 222}) - - script = `[[ - ['db.set',111], - ['pcall','B'] - ],[ - ['db.set',222], - ['pcall','A'] - ],[ - ['db.set',333], - ['pcall','B'], - ['fail'] - ],[ - ['db.set',444], - ['pcall','A'] - ],[ - ['db.set',555] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 222}) - - script = `[[ - ['db.set',111], - ['pcall','B'] - ],[ - ['db.set',222], - ['pcall','A'], - ['fail'] - ],[ - ['db.set',333], - ['pcall','B'] - ],[ - ['db.set',444], - ['pcall','A'] - ],[ - ['db.set',555] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 111, "B": 0}) - - script = `[[ - ['db.set',111], - ['pcall','B'], - ['fail'] - ],[ - ['db.set',222], - ['pcall','A'] - ],[ - ['db.set',333], - ['pcall','B'] - ],[ - ['db.set',444], - ['pcall','A'] - ],[ - ['db.set',555] - ]]` - testDbStateRollback(t, bc, script, - map[string]int{"A": 0, "B": 0}) + err = bc.ConnectBlock( + NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["A","%s"]}`, nameToAddress("A"))), + NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["B","%s"]}`, nameToAddress("B"))), + NewLuaTxCall("user", "resolver", 0, fmt.Sprintf(`{"Name":"set","Args":["C","%s"]}`, nameToAddress("C"))), + ) + require.NoErrorf(t, err, "failed to call resolver contract") + + // A -> A -> A (3 calls on the same contract) + + script := `[[ + ['db.set',111], + ['pcall','A'] + ],[ + ['db.set',222], + ['pcall','A'] + ],[ + ['db.set',333] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 333}) + + script = `[[ + ['db.set',111], + ['pcall','A'] + ],[ + ['db.set',222], + ['pcall','A'] + ],[ + ['db.set',333], + ['fail'] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 222}) + + script = `[[ + ['db.set',111], + ['pcall','A'] + ],[ + ['db.set',222], + ['pcall','A'], + ['fail'] + ],[ + ['db.set',333] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 111}) + + script = `[[ + ['db.set',111], + ['pcall','A'], + ['fail'] + ],[ + ['db.set',222], + ['pcall','A'] + ],[ + ['db.set',333] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 0}) + + // A -> B -> C (3 different contracts) + + script = `[[ + ['db.set',111], + ['pcall','B'] + ],[ + ['db.set',222], + ['pcall','C'] + ],[ + ['db.set',333] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 222, "C": 333}) + + script = `[[ + ['db.set',111], + ['pcall','B'] + ],[ + ['db.set',222], + ['pcall','C'] + ],[ + ['db.set',333], + ['fail'] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 222, "C": 0}) + + script = `[[ + ['db.set',111], + ['pcall','B'] + ],[ + ['db.set',222], + ['pcall','C'], + ['fail'] + ],[ + ['db.set',333] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 0, "C": 0}) + + script = `[[ + ['db.set',111], + ['pcall','B'], + ['fail'] + ],[ + ['db.set',222], + ['pcall','C'] + ],[ + ['db.set',333] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 0, "B": 0, "C": 0}) + + // A -> B -> A (call back to original contract) + + script = `[[ + ['db.set',111], + ['pcall','B'] + ],[ + ['db.set',222], + ['pcall','A'] + ],[ + ['db.set',333] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 333, "B": 222}) + + script = `[[ + ['db.set',111], + ['pcall','B'] + ],[ + ['db.set',222], + ['pcall','A'] + ],[ + ['db.set',333], + ['fail'] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 222}) + + script = `[[ + ['db.set',111], + ['pcall','B'] + ],[ + ['db.set',222], + ['pcall','A'], + ['fail'] + ],[ + ['db.set',333] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 0}) + + script = `[[ + ['db.set',111], + ['pcall','B'], + ['fail'] + ],[ + ['db.set',222], + ['pcall','A'] + ],[ + ['db.set',333] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 0, "B": 0}) + + // A -> B -> B + + script = `[[ + ['db.set',111], + ['pcall','B'] + ],[ + ['db.set',222], + ['pcall','B'] + ],[ + ['db.set',333] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 333}) + + script = `[[ + ['db.set',111], + ['pcall','B'] + ],[ + ['db.set',222], + ['pcall','B'] + ],[ + ['db.set',333], + ['fail'] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 222}) + + script = `[[ + ['db.set',111], + ['pcall','B'] + ],[ + ['db.set',222], + ['pcall','B'], + ['fail'] + ],[ + ['db.set',333] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 0}) + + script = `[[ + ['db.set',111], + ['pcall','B'], + ['fail'] + ],[ + ['db.set',222], + ['pcall','B'] + ],[ + ['db.set',333] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 0, "B": 0}) + + // A -> A -> B + + script = `[[ + ['db.set',111], + ['pcall','A'] + ],[ + ['db.set',222], + ['pcall','B'] + ],[ + ['db.set',333] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 222, "B": 333}) + + script = `[[ + ['db.set',111], + ['pcall','A'] + ],[ + ['db.set',222], + ['pcall','B'] + ],[ + ['db.set',333], + ['fail'] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 222, "B": 0}) + + script = `[[ + ['db.set',111], + ['pcall','A'] + ],[ + ['db.set',222], + ['pcall','B'], + ['fail'] + ],[ + ['db.set',333] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 0}) + + script = `[[ + ['db.set',111], + ['pcall','A'], + ['fail'] + ],[ + ['db.set',222], + ['pcall','B'] + ],[ + ['db.set',333] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 0, "B": 0}) + + // A -> B -> A -> B -> A (zigzag) + + script = `[[ + ['db.set',111], + ['pcall','B'] + ],[ + ['db.set',222], + ['pcall','A'] + ],[ + ['db.set',333], + ['pcall','B'] + ],[ + ['db.set',444], + ['pcall','A'] + ],[ + ['db.set',555] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 555, "B": 444}) + + script = `[[ + ['db.set',111], + ['pcall','B'] + ],[ + ['db.set',222], + ['pcall','A'] + ],[ + ['db.set',333], + ['pcall','B'] + ],[ + ['db.set',444], + ['pcall','A'] + ],[ + ['db.set',555], + ['fail'] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 333, "B": 444}) + + script = `[[ + ['db.set',111], + ['pcall','B'] + ],[ + ['db.set',222], + ['pcall','A'] + ],[ + ['db.set',333], + ['pcall','B'] + ],[ + ['db.set',444], + ['pcall','A'], + ['fail'] + ],[ + ['db.set',555] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 333, "B": 222}) + + script = `[[ + ['db.set',111], + ['pcall','B'] + ],[ + ['db.set',222], + ['pcall','A'] + ],[ + ['db.set',333], + ['pcall','B'], + ['fail'] + ],[ + ['db.set',444], + ['pcall','A'] + ],[ + ['db.set',555] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 222}) + + script = `[[ + ['db.set',111], + ['pcall','B'] + ],[ + ['db.set',222], + ['pcall','A'], + ['fail'] + ],[ + ['db.set',333], + ['pcall','B'] + ],[ + ['db.set',444], + ['pcall','A'] + ],[ + ['db.set',555] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 111, "B": 0}) + + script = `[[ + ['db.set',111], + ['pcall','B'], + ['fail'] + ],[ + ['db.set',222], + ['pcall','A'] + ],[ + ['db.set',333], + ['pcall','B'] + ],[ + ['db.set',444], + ['pcall','A'] + ],[ + ['db.set',555] + ]]` + testDbStateRollback(t, bc, script, + map[string]int{"A": 0, "B": 0}) } } From e5081e4b910ea74c1d17445b7724719b3145df3c Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 21 Nov 2023 13:40:58 +0000 Subject: [PATCH 105/182] disable getmetatable and setmetatable --- contract/vm.c | 10 ++++++++++ contract/vm_dummy/test_files/disabled-functions.lua | 2 ++ contract/vm_dummy/test_files/gas_bf_v4.lua | 11 ----------- contract/vm_dummy/vm_dummy_pub_test.go | 1 - tests/test-gas-per-function-v4.sh | 1 - 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/contract/vm.c b/contract/vm.c index 02994fcd2..c28c5a0a1 100644 --- a/contract/vm.c +++ b/contract/vm.c @@ -46,6 +46,16 @@ static void preloadModules(lua_State *L) { } if (vm_is_hardfork(L, 4)) { + // disable getmetatable + lua_getglobal(L, "_G"); + lua_pushnil(L); + lua_setfield(L, -2, "getmetatable"); + lua_pop(L, 1); + // disable setmetatable + lua_getglobal(L, "_G"); + lua_pushnil(L); + lua_setfield(L, -2, "setmetatable"); + lua_pop(L, 1); // disable string.dump lua_getglobal(L, "string"); lua_pushnil(L); diff --git a/contract/vm_dummy/test_files/disabled-functions.lua b/contract/vm_dummy/test_files/disabled-functions.lua index 0962adb0e..0534a296e 100644 --- a/contract/vm_dummy/test_files/disabled-functions.lua +++ b/contract/vm_dummy/test_files/disabled-functions.lua @@ -21,6 +21,8 @@ function check_disabled_functions() assert(loadfile == nil, "loadfile is available") assert(loadstring == nil, "loadstring is available") assert(print == nil, "print is available") + assert(getmetatable == nil, "getmetatable is available") + assert(setmetatable == nil, "setmetatable is available") assert(string.dump == nil, "string.dump is available") local success, result = pcall(function() newproxy() end) diff --git a/contract/vm_dummy/test_files/gas_bf_v4.lua b/contract/vm_dummy/test_files/gas_bf_v4.lua index a349d7819..72256d065 100644 --- a/contract/vm_dummy/test_files/gas_bf_v4.lua +++ b/contract/vm_dummy/test_files/gas_bf_v4.lua @@ -29,16 +29,6 @@ function basic_fns() m1k(assert, long_str == long_str, 'true') m1k(assert, long_str ~= long_str1, 'true') local x = { value = 5 } - local mt = { - __add = function(lhs, rhs) - return { value = lhs.value + rhs.value } - end, - __tostring = function(self) - return "Hello Aergo" - end - } - setmetatable(x, mt) - m1k(getmetatable, x) m1k(ipairs, arr) m1k(next, tbl) m1k(next, tbl, "year") @@ -68,7 +58,6 @@ function basic_fns() m1k(select, '2', arr) m1k(select, '6', arr) m1k(select, '9', arr) - m1k(setmetatable, x, mt) m1k(tonumber, 0x10, 16) m1k(tonumber, '112134', 16) m1k(tonumber, '112134') diff --git a/contract/vm_dummy/vm_dummy_pub_test.go b/contract/vm_dummy/vm_dummy_pub_test.go index 358cb6a2f..b08801c7f 100644 --- a/contract/vm_dummy/vm_dummy_pub_test.go +++ b/contract/vm_dummy/vm_dummy_pub_test.go @@ -365,7 +365,6 @@ func TestGasPerFunction(t *testing.T) { {"function_header_ops", "", 0, 143016}, {"assert", "", 0, 143146}, - {"metatable", "", 0, 143988}, {"ipairs", "", 0, 143039}, {"pairs", "", 0, 143039}, {"next", "", 0, 143087}, diff --git a/tests/test-gas-per-function-v4.sh b/tests/test-gas-per-function-v4.sh index 420b04ee5..36f11d6dc 100755 --- a/tests/test-gas-per-function-v4.sh +++ b/tests/test-gas-per-function-v4.sh @@ -61,7 +61,6 @@ add_test "loop_n_branche_ops" 146372 add_test "function_header_ops" 143016 add_test "assert" 143146 -add_test "metatable" 143988 add_test "ipairs" 143039 add_test "pairs" 143039 add_test "next" 143087 From cf7bd7d50598b40c72d0c9dd83db4393b68b5170 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 21 Nov 2023 14:08:39 +0000 Subject: [PATCH 106/182] disable rawget, rawset and rawequal --- contract/vm.c | 13 ++++++++++--- .../vm_dummy/test_files/disabled-functions.lua | 3 +++ contract/vm_dummy/test_files/gas_bf_v4.lua | 18 ------------------ .../vm_dummy/test_files/type_sparsetable.lua | 8 +++----- contract/vm_dummy/vm_dummy_pub_test.go | 9 +++------ tests/test-gas-per-function-v4.sh | 3 --- 6 files changed, 19 insertions(+), 35 deletions(-) diff --git a/contract/vm.c b/contract/vm.c index c28c5a0a1..537fb6879 100644 --- a/contract/vm.c +++ b/contract/vm.c @@ -46,15 +46,22 @@ static void preloadModules(lua_State *L) { } if (vm_is_hardfork(L, 4)) { - // disable getmetatable lua_getglobal(L, "_G"); + // disable getmetatable lua_pushnil(L); lua_setfield(L, -2, "getmetatable"); - lua_pop(L, 1); // disable setmetatable - lua_getglobal(L, "_G"); lua_pushnil(L); lua_setfield(L, -2, "setmetatable"); + // disable rawget + lua_pushnil(L); + lua_setfield(L, -2, "rawget"); + // disable rawset + lua_pushnil(L); + lua_setfield(L, -2, "rawset"); + // disable rawequal + lua_pushnil(L); + lua_setfield(L, -2, "rawequal"); lua_pop(L, 1); // disable string.dump lua_getglobal(L, "string"); diff --git a/contract/vm_dummy/test_files/disabled-functions.lua b/contract/vm_dummy/test_files/disabled-functions.lua index 0534a296e..9f57b6c14 100644 --- a/contract/vm_dummy/test_files/disabled-functions.lua +++ b/contract/vm_dummy/test_files/disabled-functions.lua @@ -23,6 +23,9 @@ function check_disabled_functions() assert(print == nil, "print is available") assert(getmetatable == nil, "getmetatable is available") assert(setmetatable == nil, "setmetatable is available") + assert(rawget == nil, "rawget is available") + assert(rawset == nil, "rawset is available") + assert(rawequal == nil, "rawequal is available") assert(string.dump == nil, "string.dump is available") local success, result = pcall(function() newproxy() end) diff --git a/contract/vm_dummy/test_files/gas_bf_v4.lua b/contract/vm_dummy/test_files/gas_bf_v4.lua index 72256d065..16deb499e 100644 --- a/contract/vm_dummy/test_files/gas_bf_v4.lua +++ b/contract/vm_dummy/test_files/gas_bf_v4.lua @@ -34,24 +34,6 @@ function basic_fns() m1k(next, tbl, "year") m1k(next, tbl, "name") m1k(pairs, tbl) - m1k(rawequal, 1, 1) - m1k(rawequal, 1, 2) - m1k(rawequal, 1.4, 2.1) - m1k(rawequal, 1.4, 2) - m1k(rawequal, "hello", "world") - m1k(rawequal, arr, tbl) - m1k(rawequal, arr, arr) - m1k(rawequal, tbl, tbl) - local a = arr - m1k(rawget, a, 1) - m1k(rawget, a, 10) - m1k(rawget, tbl, "age") - local a = copy_arr(arr) - m1k(rawset, a, 1, 0) - m1k(rawset, a, 10, 1) - m1k(rawset, a, 11, -1) - m1k(rawset, tbl, "addr", "aergo") - m1k(rawset, tbl, "age", 42) m1k(select, '#', 'a', 'b', 'c', 'd') m1k(select, '#', arr) m1k(select, '2', 'a', 'b', 'c', 'd') diff --git a/contract/vm_dummy/test_files/type_sparsetable.lua b/contract/vm_dummy/test_files/type_sparsetable.lua index bc6f9173b..b0c404cab 100644 --- a/contract/vm_dummy/test_files/type_sparsetable.lua +++ b/contract/vm_dummy/test_files/type_sparsetable.lua @@ -1,12 +1,10 @@ -function is_table_equal(t1, t2, ignore_mt) +function is_table_equal(t1, t2) local ty1 = type(t1) local ty2 = type(t2) if ty1 ~= ty2 then return false end -- non-table types can be directly compared if ty1 ~= 'table' and ty2 ~= 'table' then return t1 == t2 end - -- as well as tables which have the metamethod __eq - local mt = getmetatable(t1) - if not ignore_mt and mt and mt.__eq then return t1 == t2 end + -- if table, compare each key-value pair for k1, v1 in pairs(t1) do local v2 = t2[k1] if v2 == nil or not is_table_equal(v1, v2) then return false end @@ -23,7 +21,7 @@ function r() t[10000] = "1234" system.setItem("k", t) k = system.getItem("k") - if is_table_equal(t, k, false) then + if is_table_equal(t, k) then return 1 end return 0 diff --git a/contract/vm_dummy/vm_dummy_pub_test.go b/contract/vm_dummy/vm_dummy_pub_test.go index b08801c7f..56f989ac4 100644 --- a/contract/vm_dummy/vm_dummy_pub_test.go +++ b/contract/vm_dummy/vm_dummy_pub_test.go @@ -368,9 +368,6 @@ func TestGasPerFunction(t *testing.T) { {"ipairs", "", 0, 143039}, {"pairs", "", 0, 143039}, {"next", "", 0, 143087}, - {"rawequal", "", 0, 143216}, - {"rawget", "", 0, 143087}, - {"rawset", "", 0, 143941}, {"select", "", 0, 143166}, {"tonumber", "", 0, 143186}, {"tostring", "", 0, 143457}, @@ -448,7 +445,7 @@ func TestGasPerFunction(t *testing.T) { {"system.getSender", "", 0, 144261}, {"system.getBlockheight", "", 0, 143330}, - {"system.getTxhash", "", 0, 143734}, + //{"system.getTxhash", "", 0, 143734}, {"system.getTimestamp", "", 0, 143330}, {"system.getContractID", "", 0, 144261}, {"system.setItem", "", 0, 144194}, @@ -616,7 +613,7 @@ func TestGasOp(t *testing.T) { err = expectGas(string(code), 0, `"main"`, ``, 117610, SetHardForkVersion(3)) assert.NoError(t, err) - err = expectGas(string(code), 0, `"main"`, ``, 134656, SetHardForkVersion(4)) + err = expectGas(string(code), 0, `"main"`, ``, 120832, SetHardForkVersion(4)) assert.NoError(t, err) } @@ -636,7 +633,7 @@ func TestGasBF(t *testing.T) { err = expectGas(string(code2), 0, `"main"`, ``, 47456046, SetHardForkVersion(3)) assert.NoError(t, err) - err = expectGas(string(code4), 0, `"main"`, ``, 47772314, SetHardForkVersion(4)) + err = expectGas(string(code4), 0, `"main"`, ``, 47341329, SetHardForkVersion(4)) assert.NoError(t, err) } diff --git a/tests/test-gas-per-function-v4.sh b/tests/test-gas-per-function-v4.sh index 36f11d6dc..707029a3f 100755 --- a/tests/test-gas-per-function-v4.sh +++ b/tests/test-gas-per-function-v4.sh @@ -64,9 +64,6 @@ add_test "assert" 143146 add_test "ipairs" 143039 add_test "pairs" 143039 add_test "next" 143087 -add_test "rawequal" 143216 -add_test "rawget" 143087 -add_test "rawset" 143941 add_test "select" 143166 add_test "tonumber" 143186 add_test "tostring" 143457 From 53bdc734fc1b0171200709f9c2f206e317d4a105 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 21 Nov 2023 16:43:28 +0000 Subject: [PATCH 107/182] limit metamethod override test to <= V3 --- contract/vm_dummy/test_files/feature_isolation.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/contract/vm_dummy/test_files/feature_isolation.lua b/contract/vm_dummy/test_files/feature_isolation.lua index 84fd6abb6..2244a9a61 100644 --- a/contract/vm_dummy/test_files/feature_isolation.lua +++ b/contract/vm_dummy/test_files/feature_isolation.lua @@ -22,8 +22,10 @@ function override_functions() -- override contract.balance contract.balance = function() return "123" end - -- override the __add metamethod on bignum module - getmetatable(bignum.number(0)).__add = function(x,y) return x-y end + if getmetatable ~= nil then + -- override the __add metamethod on bignum module + getmetatable(bignum.number(0)).__add = function(x,y) return x-y end + end end @@ -37,7 +39,9 @@ function check_local_overridden_functions() assert2(test_sender() == "overridden", "system.getSender() override failed") assert2(test_origin() == "overridden", "system.getOrigin() override failed") assert2(test_balance() == "123", "contract.balance() override failed") - assert2(test_bignum() == bignum.number(3), "metamethod override failed") + if getmetatable ~= nil then + assert2(test_bignum() == bignum.number(3), "metamethod override failed") + end end From fb5c39ec1f665d6b6e6e0508c09340f1e674a8c5 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 25 Nov 2023 15:30:58 +0000 Subject: [PATCH 108/182] fix build --- cmd/brick/exec/multicall.go | 8 ++++---- contract/contract.go | 2 +- contract/vm.go | 6 +++++- contract/vm_dummy/vm_dummy.go | 10 +++++----- contract/vm_dummy/vm_dummy_test.go | 20 ++++++++++---------- 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/cmd/brick/exec/multicall.go b/cmd/brick/exec/multicall.go index d3d1a00f6..bd7a626e9 100644 --- a/cmd/brick/exec/multicall.go +++ b/cmd/brick/exec/multicall.go @@ -5,9 +5,9 @@ import ( "github.com/rs/zerolog" - "github.com/aergoio/aergo/cmd/brick/context" - "github.com/aergoio/aergo/contract" - "github.com/aergoio/aergo/types" + "github.com/aergoio/aergo/v2/cmd/brick/context" + "github.com/aergoio/aergo/v2/contract/vm_dummy" + "github.com/aergoio/aergo/v2/types" ) func init() { @@ -76,7 +76,7 @@ func (c *multicall) Run(args string) (string, uint64, []*types.Event, error) { accountName, payload, expectedError, expectedRes, _ := c.parse(args) - multicallTx := contract.NewLuaTxMultiCall(accountName, payload) + multicallTx := vm_dummy.NewLuaTxMultiCall(accountName, payload) logLevel := zerolog.GlobalLevel() diff --git a/contract/contract.go b/contract/contract.go index a0a8722da..9bca46650 100644 --- a/contract/contract.go +++ b/contract/contract.go @@ -309,7 +309,7 @@ func preloadWorker() { // check if the tx is valid and if the code should be executed func checkExecution(txType types.TxType, amount *big.Int, payloadSize int, version int32, isDeploy, isContract bool) (do_execute bool, err error) { - if txBody.Type == types.TxType_MULTICALL { + if txType == types.TxType_MULTICALL { return true, nil } diff --git a/contract/vm.go b/contract/vm.go index c7b420bc8..908e915ce 100644 --- a/contract/vm.go +++ b/contract/vm.go @@ -180,7 +180,7 @@ func getTraceFile(blkno uint64, tx []byte) *os.File { return f } -func NewVmContext(execCtx context.Context, blockState *state.BlockState, cdb ChainAccessor, sender, reciever *state.V, contractState *state.ContractState, senderID, txHash []byte, bi *types.BlockHeaderInfo, node string, confirmed, query bool, rp uint64, service int, amount *big.Int, gasLimit uint64, feeDelegation bool, isMultiCall bool) *vmContext { +func NewVmContext(execCtx context.Context, blockState *state.BlockState, cdb ChainAccessor, sender, receiver *state.V, contractState *state.ContractState, senderID, txHash []byte, bi *types.BlockHeaderInfo, node string, confirmed, query bool, rp uint64, service int, amount *big.Int, gasLimit uint64, feeDelegation bool, isMultiCall bool) *vmContext { cs := &callState{ctrState: contractState, curState: receiver.State()} @@ -240,6 +240,10 @@ func NewVmContextQuery( return ctx, nil } +func (ctx *vmContext) IsMultiCall() bool { + return ctx.isMultiCall +} + func (ctx *vmContext) IsGasSystem() bool { return fee.GasEnabled(ctx.blockInfo.ForkVersion) && !ctx.isQuery } diff --git a/contract/vm_dummy/vm_dummy.go b/contract/vm_dummy/vm_dummy.go index 2fa95b250..baed5779b 100644 --- a/contract/vm_dummy/vm_dummy.go +++ b/contract/vm_dummy/vm_dummy.go @@ -612,13 +612,13 @@ func NewLuaTxCallFeeDelegate(sender, recipient string, amount uint64, payload st } } -func NewLuaTxMultiCall(sender, code string) *luaTxCall { +func NewLuaTxMultiCall(sender, payload string) *luaTxCall { return &luaTxCall{ luaTxContractCommon: luaTxContractCommon{ - _sender: strHash(sender), - _contract: strHash(""), + _sender: contract.StrHash(sender), + _recipient: contract.StrHash(""), _amount: new(big.Int).SetUint64(0), - _code: []byte(code), + _payload: []byte(payload), txId: newTxId(), multiCall: true, }, @@ -641,7 +641,7 @@ func (l *luaTxCall) run(execCtx context.Context, bs *state.BlockState, bc *Dummy return "", nil, ctrFee, err } - if !ctx.isMultiCall { + if !ctx.IsMultiCall() { err = bs.StageContractState(eContractState) if err != nil { return "", nil, ctrFee, err diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index 6d5e7804a..0aa942f53 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -4547,16 +4547,16 @@ abi.payable(recv_aergo) ` err = bc.ConnectBlock( - NewLuaTxAccount("ac0", 10000000000000000000), - NewLuaTxAccount("ac1", 10000000000000000000), - NewLuaTxAccount("ac2", 10000000000000000000), - NewLuaTxAccount("ac3", 10000000000000000000), - NewLuaTxAccount("ac4", 10000000000000000000), - NewLuaTxAccount("ac5", 10000000000000000000), - NewLuaTxDef("ac0", "tables", 0, definition), - NewLuaTxDef("ac0", "c1", 0, definition), - NewLuaTxDef("ac0", "c2", 0, definition), - NewLuaTxDef("ac0", "c3", 0, definition), + NewLuaTxAccount("ac0", 100, types.Aergo), + NewLuaTxAccount("ac1", 100, types.Aergo), + NewLuaTxAccount("ac2", 100, types.Aergo), + NewLuaTxAccount("ac3", 100, types.Aergo), + NewLuaTxAccount("ac4", 100, types.Aergo), + NewLuaTxAccount("ac5", 100, types.Aergo), + NewLuaTxDeploy("ac0", "tables", 0, definition), + NewLuaTxDeploy("ac0", "c1", 0, definition), + NewLuaTxDeploy("ac0", "c2", 0, definition), + NewLuaTxDeploy("ac0", "c3", 0, definition), ) if err != nil { t.Error(err) From b27419da90998f9e4d4c07992327772297cb68ee Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 25 Nov 2023 15:47:44 +0000 Subject: [PATCH 109/182] use separate lua test file --- .../vm_dummy/test_files/feature_multicall.lua | 90 ++++++++++++++ contract/vm_dummy/vm_dummy_test.go | 111 ++---------------- 2 files changed, 103 insertions(+), 98 deletions(-) create mode 100644 contract/vm_dummy/test_files/feature_multicall.lua diff --git a/contract/vm_dummy/test_files/feature_multicall.lua b/contract/vm_dummy/test_files/feature_multicall.lua new file mode 100644 index 000000000..8dcdfcffa --- /dev/null +++ b/contract/vm_dummy/test_files/feature_multicall.lua @@ -0,0 +1,90 @@ +state.var { + name = state.value(), + last = state.value(), + dict = state.map() +} + +function get_dict() + return {one = 1, two = 2, three = 3} +end + +function get_list() + return {'first', 'second', 'third', 123, 12.5, true} +end + +function get_table() + return { name = "Test", second = 'Te"st', number = 123, bool = true, array = {11,22,33} } +end + +function works() + return 123 +end + +function fails() + assert(false, "this call should fail") +end + +function hello(name) + return 'hello ' .. name +end + +function set_name(val) + name:set(val) + assert(type(val)=='string', "must be string") +end + +function get_name() + return name:get() +end + +function set(key, value) + dict[key] = value +end + +function inc(key) + dict[key] = (dict[key] or 0) + 1 + contract.event("new_value", dict[key]) +end + +function add(value) + local key = (last:get() or 0) + 1 + dict[tostring(key)] = value + last:set(key) +end + +function get(key) + return dict[key] +end + +function sort(list) + table.sort(list) + return list +end + +abi.register(add, set, inc, set_name) +abi.register_view(get_dict, get_list, get_table, works, fails, get, get_name, sort, hello) + +function call(...) + return contract.call(...) +end + +function is_contract(address) + return system.isContract(address) +end + +function sender() + return system.getSender() +end + +function origin() + return system.getOrigin() +end + +abi.register(call) +abi.register_view(is_contract, sender, origin) + +function recv_aergo() + -- does nothing +end + +abi.payable(recv_aergo) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index 0aa942f53..aed1748ea 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -4397,6 +4397,8 @@ func TestContractIsolation(t *testing.T) { ////////////////////////////////////////////////////////////////////// func multicall(t *testing.T, bc *DummyChain, params ...string) { + t.Helper() + var expectedError, expectedResult string account := params[0] payload := params[1] @@ -4412,6 +4414,7 @@ func multicall(t *testing.T, bc *DummyChain, params ...string) { err := bc.ConnectBlock(tx) if err != nil { t.Error(err) + return } if expectedError == "" && expectedResult != "" { @@ -4428,6 +4431,8 @@ func call(t *testing.T, bc *DummyChain, contract string, function string, args string, expectedError string, expectedResult string) { + t.Helper() + callinfo := fmt.Sprintf(`{"Name":"%s", "Args":%s}`, function, args) tx := NewLuaTxCall(account, contract, amount, callinfo).Fail(expectedError) @@ -4435,6 +4440,7 @@ func call(t *testing.T, bc *DummyChain, err := bc.ConnectBlock(tx) if err != nil { t.Error(err) + return } if expectedError == "" && expectedResult != "" { @@ -4447,105 +4453,14 @@ func call(t *testing.T, bc *DummyChain, } func TestComposableTransactions(t *testing.T) { - bc, err := LoadDummyChain() + code := readLuaCode(t, "feature_multicall.lua") + + bc, err := LoadDummyChain(SetHardForkVersion(3)) if err != nil { t.Errorf("failed to create test database: %v", err) } defer bc.Release() - definition := ` -state.var { - name = state.value(), - last = state.value(), - dict = state.map() -} - -function get_dict() - return {one = 1, two = 2, three = 3} -end - -function get_list() - return {'first', 'second', 'third', 123, 12.5, true} -end - -function get_table() - return { name = "Test", second = 'Te"st', number = 123, bool = true, array = {11,22,33} } -end - -function works() - return 123 -end - -function fails() - assert(false, "this call should fail") -end - -function hello(name) - return 'hello ' .. name -end - -function set_name(val) - name:set(val) - assert(type(val)=='string', "must be string") -end - -function get_name() - return name:get() -end - -function set(key, value) - dict[key] = value -end - -function inc(key) - dict[key] = (dict[key] or 0) + 1 - contract.event("new_value", dict[key]) -end - -function add(value) - local key = (last:get() or 0) + 1 - dict[tostring(key)] = value - last:set(key) -end - -function get(key) - return dict[key] -end - -function sort(list) - table.sort(list) - return list -end - -abi.register(add, set, inc, set_name) -abi.register_view(get_dict, get_list, get_table, works, fails, get, get_name, sort, hello) - -function call(...) - return contract.call(...) -end - -function is_contract(address) - return system.isContract(address) -end - -function sender() - return system.getSender() -end - -function origin() - return system.getOrigin() -end - -abi.register(call) -abi.register_view(is_contract, sender, origin) - -function recv_aergo() - -- does nothing -end - -abi.payable(recv_aergo) -` - err = bc.ConnectBlock( NewLuaTxAccount("ac0", 100, types.Aergo), NewLuaTxAccount("ac1", 100, types.Aergo), @@ -4553,10 +4468,10 @@ abi.payable(recv_aergo) NewLuaTxAccount("ac3", 100, types.Aergo), NewLuaTxAccount("ac4", 100, types.Aergo), NewLuaTxAccount("ac5", 100, types.Aergo), - NewLuaTxDeploy("ac0", "tables", 0, definition), - NewLuaTxDeploy("ac0", "c1", 0, definition), - NewLuaTxDeploy("ac0", "c2", 0, definition), - NewLuaTxDeploy("ac0", "c3", 0, definition), + NewLuaTxDeploy("ac0", "tables", 0, code), + NewLuaTxDeploy("ac0", "c1", 0, code), + NewLuaTxDeploy("ac0", "c2", 0, code), + NewLuaTxDeploy("ac0", "c3", 0, code), ) if err != nil { t.Error(err) From 54e792a31cda8f1cafb23a982e01e883503b7a3e Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 25 Nov 2023 17:02:17 +0000 Subject: [PATCH 110/182] fix test --- contract/vm_dummy/vm_dummy_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index aed1748ea..8eddd5b98 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -4462,12 +4462,12 @@ func TestComposableTransactions(t *testing.T) { defer bc.Release() err = bc.ConnectBlock( - NewLuaTxAccount("ac0", 100, types.Aergo), - NewLuaTxAccount("ac1", 100, types.Aergo), - NewLuaTxAccount("ac2", 100, types.Aergo), - NewLuaTxAccount("ac3", 100, types.Aergo), - NewLuaTxAccount("ac4", 100, types.Aergo), - NewLuaTxAccount("ac5", 100, types.Aergo), + NewLuaTxAccount("ac0", 10, types.Aergo), + NewLuaTxAccount("ac1", 10, types.Aergo), + NewLuaTxAccount("ac2", 10, types.Aergo), + NewLuaTxAccount("ac3", 10, types.Aergo), + NewLuaTxAccount("ac4", 10, types.Aergo), + NewLuaTxAccount("ac5", 10, types.Aergo), NewLuaTxDeploy("ac0", "tables", 0, code), NewLuaTxDeploy("ac0", "c1", 0, code), NewLuaTxDeploy("ac0", "c2", 0, code), From cd2700fb52fa3f085c717500c51a417f3a66bdaa Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 25 Nov 2023 19:25:39 +0000 Subject: [PATCH 111/182] update test --- contract/vm_dummy/vm_dummy_test.go | 2417 ++++++++++++++-------------- 1 file changed, 1209 insertions(+), 1208 deletions(-) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index bab242cba..cee29ffd7 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -22,6 +22,8 @@ import ( const min_version int32 = 2 const max_version int32 = 4 +const min_version_multicall int32 = 4 + func TestMaxCallDepth(t *testing.T) { //code := readLuaCode(t, "maxcalldepth_1.lua") // this contract receives a list of contract IDs to be called @@ -4397,32 +4399,32 @@ func TestContractIsolation(t *testing.T) { ////////////////////////////////////////////////////////////////////// func multicall(t *testing.T, bc *DummyChain, params ...string) { - t.Helper() - - var expectedError, expectedResult string - account := params[0] - payload := params[1] - if len(params) > 2 { - expectedError = params[2] - } - if len(params) > 3 { - expectedResult = params[3] - } - - tx := NewLuaTxMultiCall(account, payload).Fail(expectedError) - - err := bc.ConnectBlock(tx) - if err != nil { - t.Error(err) - return - } - - if expectedError == "" && expectedResult != "" { - receipt := bc.GetReceipt(tx.Hash()) - if receipt.GetRet() != expectedResult { - t.Errorf("multicall invalid result - expected: %s got: %s", expectedResult, receipt.GetRet()) - } - } + t.Helper() + + var expectedError, expectedResult string + account := params[0] + payload := params[1] + if len(params) > 2 { + expectedError = params[2] + } + if len(params) > 3 { + expectedResult = params[3] + } + + tx := NewLuaTxMultiCall(account, payload).Fail(expectedError) + + err := bc.ConnectBlock(tx) + if err != nil { + t.Error(err) + return + } + + if expectedError == "" && expectedResult != "" { + receipt := bc.GetReceipt(tx.Hash()) + if receipt.GetRet() != expectedResult { + t.Errorf("multicall invalid result - expected: %s got: %s", expectedResult, receipt.GetRet()) + } + } } @@ -4431,1252 +4433,1251 @@ func call(t *testing.T, bc *DummyChain, contract string, function string, args string, expectedError string, expectedResult string) { - t.Helper() + t.Helper() - callinfo := fmt.Sprintf(`{"Name":"%s", "Args":%s}`, function, args) + callinfo := fmt.Sprintf(`{"Name":"%s", "Args":%s}`, function, args) - tx := NewLuaTxCall(account, contract, amount, callinfo).Fail(expectedError) + tx := NewLuaTxCall(account, contract, amount, callinfo).Fail(expectedError) - err := bc.ConnectBlock(tx) - if err != nil { - t.Error(err) - return - } + err := bc.ConnectBlock(tx) + if err != nil { + t.Error(err) + return + } - if expectedError == "" && expectedResult != "" { - receipt := bc.GetReceipt(tx.Hash()) - if receipt.GetRet() != expectedResult { - t.Errorf("call invalid result - expected: %s got: %s", expectedResult, receipt.GetRet()) - } - } + if expectedError == "" && expectedResult != "" { + receipt := bc.GetReceipt(tx.Hash()) + if receipt.GetRet() != expectedResult { + t.Errorf("call invalid result - expected: %s got: %s", expectedResult, receipt.GetRet()) + } + } } func TestComposableTransactions(t *testing.T) { - code := readLuaCode(t, "feature_multicall.lua") - - bc, err := LoadDummyChain(SetHardForkVersion(3)) - if err != nil { - t.Errorf("failed to create test database: %v", err) - } - defer bc.Release() - - err = bc.ConnectBlock( - NewLuaTxAccount("ac0", 10, types.Aergo), - NewLuaTxAccount("ac1", 10, types.Aergo), - NewLuaTxAccount("ac2", 10, types.Aergo), - NewLuaTxAccount("ac3", 10, types.Aergo), - NewLuaTxAccount("ac4", 10, types.Aergo), - NewLuaTxAccount("ac5", 10, types.Aergo), - NewLuaTxDeploy("ac0", "tables", 0, code), - NewLuaTxDeploy("ac0", "c1", 0, code), - NewLuaTxDeploy("ac0", "c2", 0, code), - NewLuaTxDeploy("ac0", "c3", 0, code), - ) - if err != nil { - t.Error(err) - } - - - multicall(t, bc, "ac1", `[ - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_dict"], - ["store","dict"], - ["set","%dict%","two",22], - ["set","%dict%","four",4], - ["set","%dict%","one",null], - ["get","%dict%","two"], - ["set","%dict%","copy","%last_result%"], - ["return","%dict%"] - ]`, ``, `{"copy":22,"four":4,"three":3,"two":22}`) - - multicall(t, bc, "ac1", `[ - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_list"], - ["store","array"], - ["set","%array%",2,"2nd"], - ["insert","%array%",1,"zero"], - ["insert","%array%","last"], - ["return","%array%"] - ]`, ``, `["zero","first","2nd","third",123,12.5,true,"last"]`) - - multicall(t, bc, "ac1", `[ - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_list"], - ["store","array"], - ["remove","%array%",3], - ["return","%array%","%last_result%"] - ]`, ``, `[["first","second",123,12.5,true],"third"]`) - - - // create new dict or array using fromjson - - multicall(t, bc, "ac1", `[ - ["fromjson","{\"one\":1,\"two\":2}"], - ["set","%last_result%","three",3], - ["return","%last_result%"] - ]`, ``, `{"one":1,"three":3,"two":2}`) - - - // define dict or list using let - - multicall(t, bc, "ac1", `[ - ["let","obj",{"one":1,"two":2}], - ["set","%obj%","three",3], - ["return","%obj%"] - ]`, ``, `{"one":1,"three":3,"two":2}`) - - multicall(t, bc, "ac1", `[ - ["let","list",["one",1,"two",2,2.5,true,false]], - ["set","%list%",4,"three"], - ["insert","%list%",1,"first"], - ["insert","%list%","last"], - ["return","%list%"] - ]`, ``, `["first","one",1,"two","three",2.5,true,false,"last"]`) - - multicall(t, bc, "ac1", `[ - ["let","list",["one",22,3.3,true,false]], - ["get","%list%",1], - ["assert","%last_result%","=","one"], - ["get","%list%",2], - ["assert","%last_result%","=",22], - ["get","%list%",3], - ["assert","%last_result%","=",3.3], - ["get","%list%",4], - ["assert","%last_result%","=",true], - ["get","%list%",5], - ["assert","%last_result%","=",false], - ["return","%list%"] - ]`, ``, `["one",22,3.3,true,false]`) - - - // get_size - - multicall(t, bc, "ac1", `[ - ["let","str","this is a string"], - ["get_size","%str%"], - ["return","%last_result%"] - ]`, ``, `16`) - - multicall(t, bc, "ac1", `[ - ["let","list",["one",1,"two",2,2.5,true,false]], - ["get_size","%list%"], - ["return","%last_result%"] - ]`, ``, `7`) - - multicall(t, bc, "ac1", `[ - ["let","obj",{"one":1,"two":2,"three":3}], - ["get_size","%obj%"], - ["return","%last_result%"] - ]`, ``, `0`) - - - // get_keys - - multicall(t, bc, "ac1", `[ - ["let","obj",{"one":1,"two":2,"three":3}], - ["get_keys","%obj%"], - ["store","keys"], - ["get_size","%keys%"], - ["return","%last_result%","%keys%"] - ]`, ``, `[3,["one","three","two"]]`) - - - - - // BIGNUM - - multicall(t, bc, "ac1", `[ - ["tobignum",123], - ["store","a"], - ["tobignum",123], - ["store","b"], - ["mul","%a%","%b%"], - ["return","%last_result%"] - ]`, ``, `{"_bignum":"15129"}`) - - multicall(t, bc, "ac1", `[ - ["tobignum","500000000000000000000"], - ["store","a"], - ["tobignum","100000"], - ["store","b"], - ["div","%a%","%b%"], - ["return","%last_result%"] - ]`, ``, `{"_bignum":"5000000000000000"}`) - - multicall(t, bc, "ac1", `[ - ["tobignum","500000000000000000000"], - ["store","a"], - ["tobignum","100000"], - ["store","b"], - ["div","%a%","%b%"], - ["tostring","%last_result%"], - ["return","%last_result%"] - ]`, ``, `"5000000000000000"`) - - multicall(t, bc, "ac1", `[ - ["tobignum","500000000000000000000"], - ["store","a"], - - ["tobignum","100000"], - ["div","%a%","%last_result%"], - ["store","a"], - - ["tobignum","1000000000000000"], - ["sub","%a%","%last_result%"], - ["store","a"], - - ["tobignum","1234"], - ["add","%a%","%last_result%"], - ["store","a"], - - ["tobignum","2"], - ["pow","%a%","%last_result%"], - ["sqrt","%last_result%"], - ["store","a"], - - ["tobignum","2"], - ["mod","%a%","10000"], - - ["return","%last_result%"] - ]`, ``, `{"_bignum":"1234"}`) - - multicall(t, bc, "ac1", `[ - ["let","a",25], - ["sqrt","%a%"], - ["return","%last_result%"] - ]`, ``, `{"_bignum":"5"}`) - - multicall(t, bc, "ac1", `[ - ["let","a",25], - ["pow","%a%",0.5], - ["return","%last_result%"] - ]`, ``, `5`) - - - - // STRINGS - - multicall(t, bc, "ac1", `[ - ["format","%s%s%s","hello"," ","world"], - ["return","%last_result%"] - ]`, ``, `"hello world"`) - - multicall(t, bc, "ac1", `[ - ["let","s","hello world"], - ["substr","%s%",1,4], - ["return","%last_result%"] - ]`, ``, `"hell"`) - - multicall(t, bc, "ac1", `[ - ["let","s","hello world"], - ["substr","%s%",-2,-1], - ["return","%last_result%"] - ]`, ``, `"ld"`) - - multicall(t, bc, "ac1", `[ - ["let","s","the amount is 12345"], - ["find","%s%","%d+"], - ["tonumber","%last_result%"], - ["return","%last_result%"] - ]`, ``, `12345`) - - multicall(t, bc, "ac1", `[ - ["let","s","rate: 55 10%"], - ["find","%s%","(%d+)%%"], - ["tonumber","%last_result%"], - ["return","%last_result%"] - ]`, ``, `10`) - - multicall(t, bc, "ac1", `[ - ["let","s","rate: 12%"], - ["find","%s%","%s*(%d+)%%"], - ["tonumber","%last_result%"], - ["return","%last_result%"] - ]`, ``, `12`) - - multicall(t, bc, "ac1", `[ - ["let","s","hello world"], - ["replace","%s%","hello","good bye"], - ["return","%last_result%"] - ]`, ``, `"good bye world"`) - - multicall(t, bc, "ac1", `[ - ["fromjson","{\"name\":\"ticket\",\"value\":12.5,\"amount\":10}"], - ["replace","name = $name, value = $value, amount = $amount","%$(%w+)","%last_result%"], - ["return","%last_result%"] - ]`, ``, `"name = ticket, value = 12.5, amount = 10"`) - - - // IF THEN ELSE - - multicall(t, bc, "ac1", `[ - ["let","s",20], - ["if","%s%",">=",20], - ["let","b","big"], - ["elif","%s%",">=",10], - ["let","b","medium"], - ["else"], - ["let","b","low"], - ["end"], - ["let","c","after"], - ["return","%b%","%c%"] - ]`, ``, `["big","after"]`) - - multicall(t, bc, "ac1", `[ - ["let","s",10], - ["if","%s%",">=",20], - ["let","b","big"], - ["elif","%s%",">=",10], - ["let","b","medium"], - ["else"], - ["let","b","low"], - ["end"], - ["let","c","after"], - ["return","%b%","%c%"] - ]`, ``, `["medium","after"]`) - - multicall(t, bc, "ac1", `[ - ["let","s",5], - ["if","%s%",">=",20], - ["let","b","big"], - ["elif","%s%",">=",10], - ["let","b","medium"], - ["else"], - ["let","b","low"], - ["end"], - ["let","c","after"], - ["return","%b%","%c%"] - ]`, ``, `["low","after"]`) - - multicall(t, bc, "ac1", `[ - ["let","s",20], - ["if","%s%",">=",20], - ["return","big"], - ["elif","%s%",">=",10], - ["return","medium"], - ["else"], - ["return","low"], - ["end"], - ["return","after"] - ]`, ``, `"big"`) - - multicall(t, bc, "ac1", `[ - ["let","s",10], - ["if","%s%",">=",20], - ["return","big"], - ["elif","%s%",">=",10], - ["return","medium"], - ["else"], - ["return","low"], - ["end"], - ["return","after"] - ]`, ``, `"medium"`) - - multicall(t, bc, "ac1", `[ - ["let","s",5], - ["if","%s%",">=",20], - ["return","big"], - ["elif","%s%",">=",10], - ["return","medium"], - ["else"], - ["return","low"], - ["end"], - ["return","after"] - ]`, ``, `"low"`) - - - multicall(t, bc, "ac1", `[ - ["tobignum","500000000000000000000"], - ["store","a"], - ["tobignum","500000000000000000000"], - ["store","b"], - ["if","%a%","=","%b%"], - ["let","b","equal"], - ["else"], - ["let","b","diff"], - ["end"], - ["return","%b%"] - ]`, ``, `"equal"`) - - multicall(t, bc, "ac1", `[ - ["tobignum","500000000000000000000"], - ["store","a"], - ["tobignum","500000000000000000001"], - ["store","b"], - ["if","%a%","=","%b%"], - ["let","b","equal"], - ["else"], - ["let","b","diff"], - ["end"], - ["return","%b%"] - ]`, ``, `"diff"`) - - multicall(t, bc, "ac1", `[ - ["tobignum","500000000000000000001"], - ["store","a"], - ["tobignum","500000000000000000000"], - ["store","b"], - ["if","%a%",">","%b%"], - ["let","b","bigger"], - ["else"], - ["let","b","lower"], - ["end"], - ["return","%b%"] - ]`, ``, `"bigger"`) - - multicall(t, bc, "ac1", `[ - ["tobignum","500000000000000000000"], - ["store","a"], - ["tobignum","500000000000000000001"], - ["store","b"], - ["if","%a%",">","%b%"], - ["let","b","bigger"], - ["else"], - ["let","b","lower"], - ["end"], - ["return","%b%"] - ]`, ``, `"lower"`) - - - multicall(t, bc, "ac1", `[ - ["tobignum","500000000000000000000"], - ["store","a"], - ["tobignum","500000000000000000001"], - ["store","b"], - ["if","%a%","<","%b%","and","1","=","0"], - ["let","b","wrong 1"], - ["elif","%a%","<","%b%","and","1","=","1"], - ["let","b","correct"], - ["else"], - ["let","b","wrong 2"], - ["end"], - ["return","%b%"] - ]`, ``, `"correct"`) - - multicall(t, bc, "ac1", `[ - ["tobignum","500000000000000000000"], - ["store","a"], - ["tobignum","500000000000000000001"], - ["store","b"], - ["if","%a%","<","%b%","and",1,"=",0], - ["let","b","wrong 1"], - ["elif","%a%","<","%b%","and",1,"=",1], - ["let","b","correct"], - ["else"], - ["let","b","wrong 2"], - ["end"], - ["return","%b%"] - ]`, ``, `"correct"`) - - multicall(t, bc, "ac1", `[ - ["tobignum","500000000000000000000"], - ["store","a"], - ["tobignum","500000000000000000001"], - ["store","b"], - ["tobignum","400000000000000000000"], - ["store","c"], - ["if","%a%","<","%b%","and","%a%","<","%c%"], - ["let","b","wrong 1"], - ["elif","%a%",">","%b%","and","%a%",">","%c%"], - ["let","b","wrong 2"], - ["elif","%a%","<","%b%","and","%a%",">","%c%"], - ["let","b","correct"], - ["else"], - ["let","b","wrong 3"], - ["end"], - ["return","%b%"] - ]`, ``, `"correct"`) - - multicall(t, bc, "ac1", `[ - ["tobignum","500000000000000000000"], - ["store","a"], - ["tobignum","500000000000000000001"], - ["store","b"], - ["tobignum","400000000000000000000"], - ["store","c"], - ["tostring",0], - - ["if","%a%",">","%b%","or","%a%","<","%c%"], - ["format","%s%s","%last_result%","1"], - ["end"], - - ["if","%a%","=","%b%","or","%a%","=","%c%"], - ["format","%s%s","%last_result%","2"], - ["end"], - - ["if","%a%","<","%b%","or","%a%","<","%c%"], - ["format","%s%s","%last_result%","3"], - ["end"], - - ["if","%a%",">","%b%","or","%a%",">","%c%"], - ["format","%s%s","%last_result%","4"], - ["end"], - - ["if","%a%","<","%b%","or","%a%",">","%c%"], - ["format","%s%s","%last_result%","5"], - ["end"], - - ["if","%a%","!=","%b%","or","%a%","=","%c%"], - ["format","%s%s","%last_result%","6"], - ["end"], - - ["if","%a%","=","%b%","or","%a%","!=","%c%"], - ["format","%s%s","%last_result%","7"], - ["end"], - - - ["if","%a%",">=","%b%","and","%a%","<=","%c%"], - ["format","%s%s","%last_result%","8"], - ["end"], - - ["if","%a%",">=","%c%","and","%a%","<=","%b%"], - ["format","%s%s","%last_result%","9"], - ["end"], - - ["if","%b%",">=","%a%","and","%b%","<=","%c%"], - ["format","%s%s","%last_result%","A"], - ["end"], - - ["if","%b%",">=","%c%","and","%b%","<=","%a%"], - ["format","%s%s","%last_result%","B"], - ["end"], - - ["if","%c%",">=","%a%","and","%c%","<=","%b%"], - ["format","%s%s","%last_result%","C"], - ["end"], - - ["if","%c%",">=","%b%","and","%c%","<=","%a%"], - ["format","%s%s","%last_result%","D"], - ["end"], - - - ["if","%a%",">=","%b%","and","%a%","<=","%c%","or",1,"=",0], - ["format","%s%s","%last_result%","E"], - ["end"], - - ["if","%a%",">=","%b%","and","%a%","<=","%c%","or",1,"=",1], - ["format","%s%s","%last_result%","F"], - ["end"], - - ["if","%a%",">=","%b%","and","%a%","<=","%c%","and",1,"=",0], - ["format","%s%s","%last_result%","G"], - ["end"], - - ["if","%a%",">=","%b%","and","%a%","<=","%c%","and",1,"=",1], - ["format","%s%s","%last_result%","H"], - ["end"], - - - ["if","%a%",">=","%c%","and","%a%","<=","%b%","or",1,"=",0], - ["format","%s%s","%last_result%","I"], - ["end"], - - ["if","%a%",">=","%c%","and","%a%","<=","%b%","or",1,"=",1], - ["format","%s%s","%last_result%","J"], - ["end"], - - ["if","%a%",">=","%c%","and","%a%","<=","%b%","and",1,"=",0], - ["format","%s%s","%last_result%","K"], - ["end"], + code := readLuaCode(t, "feature_multicall.lua") - ["if","%a%",">=","%c%","and","%a%","<=","%b%","and",1,"=",1], - ["format","%s%s","%last_result%","L"], - ["end"], + for version := min_version_multicall; version <= max_version; version++ { + bc, err := LoadDummyChain(SetHardForkVersion(version)) + require.NoErrorf(t, err, "failed to create dummy chain") + defer bc.Release() + err = bc.ConnectBlock( + NewLuaTxAccount("ac0", 10, types.Aergo), + NewLuaTxAccount("ac1", 10, types.Aergo), + NewLuaTxAccount("ac2", 10, types.Aergo), + NewLuaTxAccount("ac3", 10, types.Aergo), + NewLuaTxAccount("ac4", 10, types.Aergo), + NewLuaTxAccount("ac5", 10, types.Aergo), + NewLuaTxDeploy("ac0", "tables", 0, code), + NewLuaTxDeploy("ac0", "c1", 0, code), + NewLuaTxDeploy("ac0", "c2", 0, code), + NewLuaTxDeploy("ac0", "c3", 0, code), + ) + if err != nil { + t.Error(err) + } - ["if",1,"=",0,"or","%a%",">=","%b%","and","%a%","<=","%c%"], - ["format","%s%s","%last_result%","M"], - ["end"], - ["if",1,"=",1,"or","%a%",">=","%b%","and","%a%","<=","%c%"], - ["format","%s%s","%last_result%","N"], - ["end"], + multicall(t, bc, "ac1", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_dict"], + ["store","dict"], + ["set","%dict%","two",22], + ["set","%dict%","four",4], + ["set","%dict%","one",null], + ["get","%dict%","two"], + ["set","%dict%","copy","%last_result%"], + ["return","%dict%"] + ]`, ``, `{"copy":22,"four":4,"three":3,"two":22}`) + + multicall(t, bc, "ac1", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_list"], + ["store","array"], + ["set","%array%",2,"2nd"], + ["insert","%array%",1,"zero"], + ["insert","%array%","last"], + ["return","%array%"] + ]`, ``, `["zero","first","2nd","third",123,12.5,true,"last"]`) + + multicall(t, bc, "ac1", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_list"], + ["store","array"], + ["remove","%array%",3], + ["return","%array%","%last_result%"] + ]`, ``, `[["first","second",123,12.5,true],"third"]`) + + + // create new dict or array using fromjson + + multicall(t, bc, "ac1", `[ + ["fromjson","{\"one\":1,\"two\":2}"], + ["set","%last_result%","three",3], + ["return","%last_result%"] + ]`, ``, `{"one":1,"three":3,"two":2}`) + + + // define dict or list using let + + multicall(t, bc, "ac1", `[ + ["let","obj",{"one":1,"two":2}], + ["set","%obj%","three",3], + ["return","%obj%"] + ]`, ``, `{"one":1,"three":3,"two":2}`) + + multicall(t, bc, "ac1", `[ + ["let","list",["one",1,"two",2,2.5,true,false]], + ["set","%list%",4,"three"], + ["insert","%list%",1,"first"], + ["insert","%list%","last"], + ["return","%list%"] + ]`, ``, `["first","one",1,"two","three",2.5,true,false,"last"]`) + + multicall(t, bc, "ac1", `[ + ["let","list",["one",22,3.3,true,false]], + ["get","%list%",1], + ["assert","%last_result%","=","one"], + ["get","%list%",2], + ["assert","%last_result%","=",22], + ["get","%list%",3], + ["assert","%last_result%","=",3.3], + ["get","%list%",4], + ["assert","%last_result%","=",true], + ["get","%list%",5], + ["assert","%last_result%","=",false], + ["return","%list%"] + ]`, ``, `["one",22,3.3,true,false]`) + + + // get_size + + multicall(t, bc, "ac1", `[ + ["let","str","this is a string"], + ["get_size","%str%"], + ["return","%last_result%"] + ]`, ``, `16`) + + multicall(t, bc, "ac1", `[ + ["let","list",["one",1,"two",2,2.5,true,false]], + ["get_size","%list%"], + ["return","%last_result%"] + ]`, ``, `7`) + + multicall(t, bc, "ac1", `[ + ["let","obj",{"one":1,"two":2,"three":3}], + ["get_size","%obj%"], + ["return","%last_result%"] + ]`, ``, `0`) + + + // get_keys + + multicall(t, bc, "ac1", `[ + ["let","obj",{"one":1,"two":2,"three":3}], + ["get_keys","%obj%"], + ["store","keys"], + ["get_size","%keys%"], + ["return","%last_result%","%keys%"] + ]`, ``, `[3,["one","three","two"]]`) + + + + + // BIGNUM + + multicall(t, bc, "ac1", `[ + ["tobignum",123], + ["store","a"], + ["tobignum",123], + ["store","b"], + ["mul","%a%","%b%"], + ["return","%last_result%"] + ]`, ``, `{"_bignum":"15129"}`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","100000"], + ["store","b"], + ["div","%a%","%b%"], + ["return","%last_result%"] + ]`, ``, `{"_bignum":"5000000000000000"}`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","100000"], + ["store","b"], + ["div","%a%","%b%"], + ["tostring","%last_result%"], + ["return","%last_result%"] + ]`, ``, `"5000000000000000"`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + + ["tobignum","100000"], + ["div","%a%","%last_result%"], + ["store","a"], + + ["tobignum","1000000000000000"], + ["sub","%a%","%last_result%"], + ["store","a"], + + ["tobignum","1234"], + ["add","%a%","%last_result%"], + ["store","a"], + + ["tobignum","2"], + ["pow","%a%","%last_result%"], + ["sqrt","%last_result%"], + ["store","a"], + + ["tobignum","2"], + ["mod","%a%","10000"], + + ["return","%last_result%"] + ]`, ``, `{"_bignum":"1234"}`) + + multicall(t, bc, "ac1", `[ + ["let","a",25], + ["sqrt","%a%"], + ["return","%last_result%"] + ]`, ``, `{"_bignum":"5"}`) + + multicall(t, bc, "ac1", `[ + ["let","a",25], + ["pow","%a%",0.5], + ["return","%last_result%"] + ]`, ``, `5`) + + + + // STRINGS + + multicall(t, bc, "ac1", `[ + ["format","%s%s%s","hello"," ","world"], + ["return","%last_result%"] + ]`, ``, `"hello world"`) + + multicall(t, bc, "ac1", `[ + ["let","s","hello world"], + ["substr","%s%",1,4], + ["return","%last_result%"] + ]`, ``, `"hell"`) + + multicall(t, bc, "ac1", `[ + ["let","s","hello world"], + ["substr","%s%",-2,-1], + ["return","%last_result%"] + ]`, ``, `"ld"`) + + multicall(t, bc, "ac1", `[ + ["let","s","the amount is 12345"], + ["find","%s%","%d+"], + ["tonumber","%last_result%"], + ["return","%last_result%"] + ]`, ``, `12345`) + + multicall(t, bc, "ac1", `[ + ["let","s","rate: 55 10%"], + ["find","%s%","(%d+)%%"], + ["tonumber","%last_result%"], + ["return","%last_result%"] + ]`, ``, `10`) + + multicall(t, bc, "ac1", `[ + ["let","s","rate: 12%"], + ["find","%s%","%s*(%d+)%%"], + ["tonumber","%last_result%"], + ["return","%last_result%"] + ]`, ``, `12`) + + multicall(t, bc, "ac1", `[ + ["let","s","hello world"], + ["replace","%s%","hello","good bye"], + ["return","%last_result%"] + ]`, ``, `"good bye world"`) + + multicall(t, bc, "ac1", `[ + ["fromjson","{\"name\":\"ticket\",\"value\":12.5,\"amount\":10}"], + ["replace","name = $name, value = $value, amount = $amount","%$(%w+)","%last_result%"], + ["return","%last_result%"] + ]`, ``, `"name = ticket, value = 12.5, amount = 10"`) + + + // IF THEN ELSE + + multicall(t, bc, "ac1", `[ + ["let","s",20], + ["if","%s%",">=",20], + ["let","b","big"], + ["elif","%s%",">=",10], + ["let","b","medium"], + ["else"], + ["let","b","low"], + ["end"], + ["let","c","after"], + ["return","%b%","%c%"] + ]`, ``, `["big","after"]`) + + multicall(t, bc, "ac1", `[ + ["let","s",10], + ["if","%s%",">=",20], + ["let","b","big"], + ["elif","%s%",">=",10], + ["let","b","medium"], + ["else"], + ["let","b","low"], + ["end"], + ["let","c","after"], + ["return","%b%","%c%"] + ]`, ``, `["medium","after"]`) + + multicall(t, bc, "ac1", `[ + ["let","s",5], + ["if","%s%",">=",20], + ["let","b","big"], + ["elif","%s%",">=",10], + ["let","b","medium"], + ["else"], + ["let","b","low"], + ["end"], + ["let","c","after"], + ["return","%b%","%c%"] + ]`, ``, `["low","after"]`) + + multicall(t, bc, "ac1", `[ + ["let","s",20], + ["if","%s%",">=",20], + ["return","big"], + ["elif","%s%",">=",10], + ["return","medium"], + ["else"], + ["return","low"], + ["end"], + ["return","after"] + ]`, ``, `"big"`) + + multicall(t, bc, "ac1", `[ + ["let","s",10], + ["if","%s%",">=",20], + ["return","big"], + ["elif","%s%",">=",10], + ["return","medium"], + ["else"], + ["return","low"], + ["end"], + ["return","after"] + ]`, ``, `"medium"`) + + multicall(t, bc, "ac1", `[ + ["let","s",5], + ["if","%s%",">=",20], + ["return","big"], + ["elif","%s%",">=",10], + ["return","medium"], + ["else"], + ["return","low"], + ["end"], + ["return","after"] + ]`, ``, `"low"`) + + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","500000000000000000000"], + ["store","b"], + ["if","%a%","=","%b%"], + ["let","b","equal"], + ["else"], + ["let","b","diff"], + ["end"], + ["return","%b%"] + ]`, ``, `"equal"`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","500000000000000000001"], + ["store","b"], + ["if","%a%","=","%b%"], + ["let","b","equal"], + ["else"], + ["let","b","diff"], + ["end"], + ["return","%b%"] + ]`, ``, `"diff"`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000001"], + ["store","a"], + ["tobignum","500000000000000000000"], + ["store","b"], + ["if","%a%",">","%b%"], + ["let","b","bigger"], + ["else"], + ["let","b","lower"], + ["end"], + ["return","%b%"] + ]`, ``, `"bigger"`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","500000000000000000001"], + ["store","b"], + ["if","%a%",">","%b%"], + ["let","b","bigger"], + ["else"], + ["let","b","lower"], + ["end"], + ["return","%b%"] + ]`, ``, `"lower"`) + + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","500000000000000000001"], + ["store","b"], + ["if","%a%","<","%b%","and","1","=","0"], + ["let","b","wrong 1"], + ["elif","%a%","<","%b%","and","1","=","1"], + ["let","b","correct"], + ["else"], + ["let","b","wrong 2"], + ["end"], + ["return","%b%"] + ]`, ``, `"correct"`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","500000000000000000001"], + ["store","b"], + ["if","%a%","<","%b%","and",1,"=",0], + ["let","b","wrong 1"], + ["elif","%a%","<","%b%","and",1,"=",1], + ["let","b","correct"], + ["else"], + ["let","b","wrong 2"], + ["end"], + ["return","%b%"] + ]`, ``, `"correct"`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","500000000000000000001"], + ["store","b"], + ["tobignum","400000000000000000000"], + ["store","c"], + ["if","%a%","<","%b%","and","%a%","<","%c%"], + ["let","b","wrong 1"], + ["elif","%a%",">","%b%","and","%a%",">","%c%"], + ["let","b","wrong 2"], + ["elif","%a%","<","%b%","and","%a%",">","%c%"], + ["let","b","correct"], + ["else"], + ["let","b","wrong 3"], + ["end"], + ["return","%b%"] + ]`, ``, `"correct"`) + + multicall(t, bc, "ac1", `[ + ["tobignum","500000000000000000000"], + ["store","a"], + ["tobignum","500000000000000000001"], + ["store","b"], + ["tobignum","400000000000000000000"], + ["store","c"], + ["tostring",0], + + ["if","%a%",">","%b%","or","%a%","<","%c%"], + ["format","%s%s","%last_result%","1"], + ["end"], + + ["if","%a%","=","%b%","or","%a%","=","%c%"], + ["format","%s%s","%last_result%","2"], + ["end"], + + ["if","%a%","<","%b%","or","%a%","<","%c%"], + ["format","%s%s","%last_result%","3"], + ["end"], + + ["if","%a%",">","%b%","or","%a%",">","%c%"], + ["format","%s%s","%last_result%","4"], + ["end"], + + ["if","%a%","<","%b%","or","%a%",">","%c%"], + ["format","%s%s","%last_result%","5"], + ["end"], + + ["if","%a%","!=","%b%","or","%a%","=","%c%"], + ["format","%s%s","%last_result%","6"], + ["end"], + + ["if","%a%","=","%b%","or","%a%","!=","%c%"], + ["format","%s%s","%last_result%","7"], + ["end"], + + + ["if","%a%",">=","%b%","and","%a%","<=","%c%"], + ["format","%s%s","%last_result%","8"], + ["end"], + + ["if","%a%",">=","%c%","and","%a%","<=","%b%"], + ["format","%s%s","%last_result%","9"], + ["end"], + + ["if","%b%",">=","%a%","and","%b%","<=","%c%"], + ["format","%s%s","%last_result%","A"], + ["end"], + + ["if","%b%",">=","%c%","and","%b%","<=","%a%"], + ["format","%s%s","%last_result%","B"], + ["end"], + + ["if","%c%",">=","%a%","and","%c%","<=","%b%"], + ["format","%s%s","%last_result%","C"], + ["end"], + + ["if","%c%",">=","%b%","and","%c%","<=","%a%"], + ["format","%s%s","%last_result%","D"], + ["end"], + + + ["if","%a%",">=","%b%","and","%a%","<=","%c%","or",1,"=",0], + ["format","%s%s","%last_result%","E"], + ["end"], + + ["if","%a%",">=","%b%","and","%a%","<=","%c%","or",1,"=",1], + ["format","%s%s","%last_result%","F"], + ["end"], + + ["if","%a%",">=","%b%","and","%a%","<=","%c%","and",1,"=",0], + ["format","%s%s","%last_result%","G"], + ["end"], + + ["if","%a%",">=","%b%","and","%a%","<=","%c%","and",1,"=",1], + ["format","%s%s","%last_result%","H"], + ["end"], + + + ["if","%a%",">=","%c%","and","%a%","<=","%b%","or",1,"=",0], + ["format","%s%s","%last_result%","I"], + ["end"], + + ["if","%a%",">=","%c%","and","%a%","<=","%b%","or",1,"=",1], + ["format","%s%s","%last_result%","J"], + ["end"], + + ["if","%a%",">=","%c%","and","%a%","<=","%b%","and",1,"=",0], + ["format","%s%s","%last_result%","K"], + ["end"], - ["if",1,"=",0,"or","%a%",">=","%c%","and","%a%","<=","%b%"], - ["format","%s%s","%last_result%","O"], - ["end"], + ["if","%a%",">=","%c%","and","%a%","<=","%b%","and",1,"=",1], + ["format","%s%s","%last_result%","L"], + ["end"], - ["if",1,"=",1,"or","%a%",">=","%c%","and","%a%","<=","%b%"], - ["format","%s%s","%last_result%","P"], - ["end"], + ["if",1,"=",0,"or","%a%",">=","%b%","and","%a%","<=","%c%"], + ["format","%s%s","%last_result%","M"], + ["end"], - ["return","%last_result%"] - ]`, ``, `"0345679IJLNOP"`) + ["if",1,"=",1,"or","%a%",">=","%b%","and","%a%","<=","%c%"], + ["format","%s%s","%last_result%","N"], + ["end"], + ["if",1,"=",0,"or","%a%",">=","%c%","and","%a%","<=","%b%"], + ["format","%s%s","%last_result%","O"], + ["end"], + ["if",1,"=",1,"or","%a%",">=","%c%","and","%a%","<=","%b%"], + ["format","%s%s","%last_result%","P"], + ["end"], - // FOR - - multicall(t, bc, "ac1", `[ - ["for","n",1,5], - ["loop"], - ["return","%n%"] - ]`, ``, `6`) - - multicall(t, bc, "ac1", `[ - ["tonumber","0"], - ["for","n",1,5], - ["add","%last_result%",1], - ["loop"], - ["return","%last_result%"] - ]`, ``, `5`) - - multicall(t, bc, "ac1", `[ - ["tobignum","10000000000000000001"], - ["store","to_add"], - ["tobignum","100000000000000000000"], - - ["for","n",1,3], - ["add","%last_result%","%to_add%"], - ["loop"], - - ["tostring","%last_result%"], - ["return","%last_result%"] - ]`, ``, `"130000000000000000003"`) - - - multicall(t, bc, "ac1", `[ - ["tonumber","0"], - ["for","n",500,10,-5], - ["add","%last_result%",1], - ["loop"], - ["return","%last_result%"] - ]`, ``, `99`) - - - multicall(t, bc, "ac1", `[ - ["tonumber","0"], - ["for","n",5,1,-1], - ["add","%last_result%",1], - ["loop"], - ["return","%last_result%"] - ]`, ``, `5`) - - multicall(t, bc, "ac1", `[ - ["tonumber","0"], - ["for","n",5,1], - ["add","%last_result%",1], - ["loop"], - ["return","%last_result%"] - ]`, ``, `0`) - - multicall(t, bc, "ac1", `[ - ["tonumber","0"], - ["for","n",1,5], - ["add","%last_result%",1], - ["loop"], - ["return","%last_result%"] - ]`, ``, `5`) - - multicall(t, bc, "ac1", `[ - ["tonumber","0"], - ["for","n",1,5,-1], - ["add","%last_result%",1], - ["loop"], - ["return","%last_result%"] - ]`, ``, `0`) - - - - // FOREACH - - multicall(t, bc, "ac1", `[ - ["let","list",[11,22,33]], - ["let","r",0], - ["foreach","item","%list%"], - ["add","%r%","%item%"], - ["store","r"], - ["loop"], - ["return","%r%"] - ]`, ``, `66`) - - multicall(t, bc, "ac1", `[ - ["let","list",[11,22,33]], - ["let","counter",0], - ["foreach","item","%list%"], - ["add","%counter%",1], - ["store","counter"], - ["loop"], - ["return","%counter%"] - ]`, ``, `3`) - - multicall(t, bc, "ac1", `[ - ["let","list",[]], - ["let","counter",0], - ["foreach","item","%list%"], - ["add","%counter%",1], - ["store","counter"], - ["loop"], - ["return","%counter%"] - ]`, ``, `0`) - - multicall(t, bc, "ac1", `[ - ["let","list",["one",1,"two",2,2.5,true,false]], - ["let","counter",0], - ["foreach","item","%list%"], - ["add","%counter%",1], - ["store","counter"], - ["loop"], - ["return","%counter%"] - ]`, ``, `7`) - - multicall(t, bc, "ac1", `[ - ["let","list",[10,21,32]], - ["let","r",0], - ["foreach","item","%list%"], - ["if","%item%","<",30], - ["add","%r%","%item%"], - ["store","r"], - ["end"], - ["loop"], - ["return","%r%"] - ]`, ``, `31`) - - - multicall(t, bc, "ac1", `[ - ["let","str",""], - ["let","obj",{"one":1,"two":2,"three":3}], - ["get_keys","%obj%"], - ["foreach","key","%last_result%"], - ["concat","%str%","%key%"], - ["store","str"], - ["loop"], - ["return","%str%"] - ]`, ``, `"onethreetwo"`) - - - - // FORPAIR - - multicall(t, bc, "ac1", `[ - ["let","str",""], - ["let","sum",0], - ["let","obj",{"one":1,"two":2,"three":3}], - ["forpair","key","value","%obj%"], - ["concat","%str%","%key%"], - ["store","str"], - ["add","%sum%","%value%"], - ["store","sum"], - ["loop"], - ["return","%str%","%sum%"] - ]`, ``, `["onethreetwo",6]`) - - multicall(t, bc, "ac1", `[ - ["let","str",""], - ["let","sum",0], - ["let","obj",{"one":1.5,"two":2.5,"three":3.5,"four":4.5}], - ["forpair","key","value","%obj%"], - ["concat","%str%","%key%"], - ["store","str"], - ["add","%sum%","%value%"], - ["store","sum"], - ["loop"], - ["return","%str%","%sum%"] - ]`, ``, `["fouronethreetwo",12]`) - - multicall(t, bc, "ac1", `[ - ["let","names",[]], - ["let","values",[]], - ["let","obj",{"one":1.5,"two":2.5,"three":3.5,"four":4.5}], - ["forpair","key","value","%obj%"], - ["insert","%names%","%key%"], - ["insert","%values%","%value%"], - ["loop"], - ["return","%names%","%values%"] - ]`, ``, `[["four","one","three","two"],[4.5,1.5,3.5,2.5]]`) - - multicall(t, bc, "ac1", `[ - ["let","names",[]], - ["let","values",[]], - ["let","obj",{"one":1.5,"two":2.5,"three":3.5,"four":4.5}], - ["forpair","key","value","%obj%"], - ["insert","%names%","%key%"], - ["insert","%values%","%value%"], - ["loop"], - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","sort","%values%"], - ["store","values"], - ["return","%names%","%values%"] - ]`, ``, `[["four","one","three","two"],[1.5,2.5,3.5,4.5]]`) - - multicall(t, bc, "ac1", `[ - ["let","obj",{}], - ["let","counter",0], - ["forpair","key","value","%obj%"], - ["add","%counter%",1], - ["store","counter"], - ["loop"], - ["return","%counter%"] - ]`, ``, `0`) - - - - // FOR "BREAK" - - multicall(t, bc, "ac1", `[ - ["let","c",0], - ["for","n",1,10], - ["add","%c%",1], - ["store","c"], - ["if","%n%","=",5], - ["let","n",500], - ["end"], - ["loop"], - ["return","%c%"] - ]`, ``, `5`) - - multicall(t, bc, "ac1", `[ - ["tonumber","0"], - ["for","n",500,10,-5], - ["add","%last_result%",1], - ["if","%n%","=",475], - ["let","n",2], - ["end"], - ["loop"], - ["return","%last_result%"] - ]`, ``, `6`) - - multicall(t, bc, "ac1", `[ - ["let","c",0], - ["for","n",1,10], - ["add","%c%",1], - ["store","c"], - ["if","%n%","=",5], - ["break"], - ["end"], - ["loop"], - ["return","%c%"] - ]`, ``, `5`) - - multicall(t, bc, "ac1", `[ - ["let","c",0], - ["for","n",1,10], - ["add","%c%",1], - ["store","c"], - ["break","if","%n%","=",5], - ["loop"], - ["return","%c%"] - ]`, ``, `5`) - - multicall(t, bc, "ac1", `[ - ["tonumber","0"], - ["for","n",500,10,-5], - ["add","%last_result%",1], - ["if","%n%","=",475], - ["break"], - ["end"], - ["loop"], - ["return","%last_result%"] - ]`, ``, `6`) - - multicall(t, bc, "ac1", `[ - ["tonumber","0"], - ["for","n",500,10,-5], - ["add","%last_result%",1], - ["break","if","%n%","=",475], - ["loop"], - ["return","%last_result%"] - ]`, ``, `6`) - - multicall(t, bc, "ac1", `[ - ["for","n",1,5], - ["loop"], - ["return","%n%"] - ]`, ``, `6`) - - multicall(t, bc, "ac1", `[ - ["for","n",1,5], - ["break"], - ["loop"], - ["return","%n%"] - ]`, ``, `1`) - - multicall(t, bc, "ac1", `[ - ["let","names",[]], - ["let","list",["one","two","three","four"]], - ["foreach","item","%list%"], - ["if","%item%","=","three"], - ["break"], - ["end"], - ["insert","%names%","%item%"], - ["loop"], - ["return","%names%"] - ]`, ``, `["one","two"]`) - - multicall(t, bc, "ac1", `[ - ["let","names",[]], - ["let","list",["one","two","three","four"]], - ["foreach","item","%list%"], - ["break","if","%item%","=","three"], - ["insert","%names%","%item%"], - ["loop"], - ["return","%names%"] - ]`, ``, `["one","two"]`) - - multicall(t, bc, "ac1", `[ - ["let","names",[]], - ["let","obj",{"one":true,"two":false,"three":false,"four":true}], - ["forpair","key","value","%obj%"], - ["if","%value%","=",false], - ["break"], - ["end"], - ["insert","%names%","%key%"], - ["loop"], - ["return","%names%"] - ]`, ``, `["four","one"]`) - - multicall(t, bc, "ac1", `[ - ["let","names",[]], - ["let","obj",{"one":true,"two":false,"three":false,"four":true}], - ["forpair","key","value","%obj%"], - ["break","if","%value%","=",false], - ["insert","%names%","%key%"], - ["loop"], - ["return","%names%"] - ]`, ``, `["four","one"]`) - - - - // RETURN before the end - - multicall(t, bc, "ac1", `[ - ["let","v",123], - ["if","%v%",">",100], - ["return"], - ["end"], - ["let","v",500], - ["return","%v%"] - ]`, ``, ``) - - multicall(t, bc, "ac1", `[ - ["let","v",123], - ["if","%v%",">",200], - ["return"], - ["end"], - ["let","v",500], - ["return","%v%"] - ]`, ``, `500`) - - - - // FULL LOOPS - - multicall(t, bc, "ac1", `[ - ["let","c","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA"], - ["call","%c%","inc","n"], - ["call","%c%","get","n"], - ["if","%last_result%",">=",5], - ["return","%last_result%"], - ["end"], - ["loop"] - ]`, ``, `5`) - - - - - // CALLS - - multicall(t, bc, "ac1", `[ - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","works"], - ["assert","%last_result%","=",123], - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","works"], - ["return","%last_result%"] - ]`, ``, `123`) - - multicall(t, bc, "ac1", `[ - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","works"], - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","fails"] - ]`, `this call should fail`) - - - multicall(t, bc, "ac3", `[ - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set_name","test"], - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_name"], - ["assert","%last_result%","=","test"] - ]`) - - multicall(t, bc, "ac3", `[ - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set_name","wrong"], - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_name"], - ["assert","%last_result%","=","wrong"], - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set_name",123] - ]`, `must be string`) - - multicall(t, bc, "ac3", `[ - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_name"], - ["assert","%last_result%","=","test"], - ["return","%last_result%"] - ]`, ``, `"test"`) - - - multicall(t, bc, "ac3", `[ - ["let","c","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA"], - ["call","%c%","set_name","test2"], - ["call","%c%","get_name"], - ["assert","%last_result%","=","test2"] - ]`) - - - // CALL LOOP - - multicall(t, bc, "ac3", `[ - ["let","list",["first","second","third"]], - ["foreach","item","%list%"], - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","add","%item%"], - ["loop"] - ]`) - - multicall(t, bc, "ac1", `[ - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","1"], - ["assert","%last_result%","=","first"], - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","2"], - ["assert","%last_result%","=","second"], - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","3"], - ["assert","%last_result%","=","third"] - ]`) - - multicall(t, bc, "ac3", `[ - ["let","list",["1st","2nd","3rd"]], - ["let","n",1], - ["foreach","item","%list%"], - ["tostring","%n%"], - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set","%last_result%","%item%"], - ["add","%n%",1], - ["store","n"], - ["loop"] - ]`) - - multicall(t, bc, "ac1", `[ - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","1"], - ["assert","%last_result%","=","1st"], - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","2"], - ["assert","%last_result%","=","2nd"], - ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","3"], - ["assert","%last_result%","=","3rd"] - ]`) - - - - // PCALL - - multicall(t, bc, "ac1", `[ - ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","works"], - ["get","%last_result%",1], - ["assert","%last_result%","=",true], - ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","fails"], - ["get","%last_result%",1], - ["assert","%last_result%","=",false] - ]`) - - multicall(t, bc, "ac3", `[ - ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set_name","1st"], - ["get","%last_result%",1], - ["assert","%last_result%","=",true], - - ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_name"], - ["store","ret"], - ["get","%ret%",1], - ["assert","%last_result%","=",true], - ["get","%ret%",2], - ["assert","%last_result%","=","1st"], - - ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set_name",22], - ["get","%last_result%",1], - ["assert","%last_result%","=",false], - - ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_name"], - ["store","ret"], - ["get","%ret%",1], - ["assert","%last_result%","=",true], - ["get","%ret%",2], - ["assert","%last_result%","=","1st"], - - ["return","%last_result%"] - ]`, ``, `"1st"`) - - - - // MULTICALL ON ACCOUNT ------------------------------------------ - - - //deploy ac0 0 c1 test.lua - //deploy ac0 0 c2 test.lua - //deploy ac0 0 c3 test.lua - - // c1: AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9 - // c2: Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4 - // c3: AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK - - multicall(t, bc, "ac0", `[ - ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","set_name","testing multicall"], - ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","set_name","contract 2"], - ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","set_name","third one"] - ]`) - - multicall(t, bc, "ac0", `[ - ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","get_name"], - ["assert","%last_result%","=","testing multicall"], - ["store","r1"], - ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","get_name"], - ["assert","%last_result%","=","contract 2"], - ["store","r2"], - ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","get_name"], - ["assert","%last_result%","=","third one"], - ["store","r3"], - ["return","%r1%","%r2%","%r3%"] - ]`, ``, `["testing multicall","contract 2","third one"]`) - - multicall(t, bc, "ac0", `[ - ["fromjson","{}"], - ["store","res"], - ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","get_name"], - ["set","%res%","r1","%last_result%"], - ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","get_name"], - ["set","%res%","r2","%last_result%"], - ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","get_name"], - ["set","%res%","r3","%last_result%"], - ["return","%res%"] - ]`, ``, `{"r1":"testing multicall","r2":"contract 2","r3":"third one"}`) - + ["return","%last_result%"] + ]`, ``, `"0345679IJLNOP"`) - multicall(t, bc, "ac0", `[ - ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","set_name","wohooooooo"], - ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","set_name","it works!"], - ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","set_name","it really works!"] - ]`) - multicall(t, bc, "ac0", `[ - ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","get_name"], - ["assert","%last_result%","=","wohooooooo"], - ["store","r1"], - ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","get_name"], - ["assert","%last_result%","=","it works!"], - ["store","r2"], - ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","get_name"], - ["assert","%last_result%","=","it really works!"], - ["store","r3"], - ["return","%r1%","%r2%","%r3%"] - ]`, ``, `["wohooooooo","it works!","it really works!"]`) - multicall(t, bc, "ac0", `[ - ["fromjson","{}"], - ["store","res"], - ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","get_name"], - ["set","%res%","r1","%last_result%"], - ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","get_name"], - ["set","%res%","r2","%last_result%"], - ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","get_name"], - ["set","%res%","r3","%last_result%"], - ["return","%res%"] - ]`, ``, `{"r1":"wohooooooo","r2":"it works!","r3":"it really works!"}`) + + // FOR + + multicall(t, bc, "ac1", `[ + ["for","n",1,5], + ["loop"], + ["return","%n%"] + ]`, ``, `6`) + + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",1,5], + ["add","%last_result%",1], + ["loop"], + ["return","%last_result%"] + ]`, ``, `5`) + + multicall(t, bc, "ac1", `[ + ["tobignum","10000000000000000001"], + ["store","to_add"], + ["tobignum","100000000000000000000"], + + ["for","n",1,3], + ["add","%last_result%","%to_add%"], + ["loop"], + + ["tostring","%last_result%"], + ["return","%last_result%"] + ]`, ``, `"130000000000000000003"`) + + + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",500,10,-5], + ["add","%last_result%",1], + ["loop"], + ["return","%last_result%"] + ]`, ``, `99`) + + + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",5,1,-1], + ["add","%last_result%",1], + ["loop"], + ["return","%last_result%"] + ]`, ``, `5`) + + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",5,1], + ["add","%last_result%",1], + ["loop"], + ["return","%last_result%"] + ]`, ``, `0`) + + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",1,5], + ["add","%last_result%",1], + ["loop"], + ["return","%last_result%"] + ]`, ``, `5`) + + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",1,5,-1], + ["add","%last_result%",1], + ["loop"], + ["return","%last_result%"] + ]`, ``, `0`) + + + + // FOREACH + + multicall(t, bc, "ac1", `[ + ["let","list",[11,22,33]], + ["let","r",0], + ["foreach","item","%list%"], + ["add","%r%","%item%"], + ["store","r"], + ["loop"], + ["return","%r%"] + ]`, ``, `66`) + + multicall(t, bc, "ac1", `[ + ["let","list",[11,22,33]], + ["let","counter",0], + ["foreach","item","%list%"], + ["add","%counter%",1], + ["store","counter"], + ["loop"], + ["return","%counter%"] + ]`, ``, `3`) + + multicall(t, bc, "ac1", `[ + ["let","list",[]], + ["let","counter",0], + ["foreach","item","%list%"], + ["add","%counter%",1], + ["store","counter"], + ["loop"], + ["return","%counter%"] + ]`, ``, `0`) + + multicall(t, bc, "ac1", `[ + ["let","list",["one",1,"two",2,2.5,true,false]], + ["let","counter",0], + ["foreach","item","%list%"], + ["add","%counter%",1], + ["store","counter"], + ["loop"], + ["return","%counter%"] + ]`, ``, `7`) + + multicall(t, bc, "ac1", `[ + ["let","list",[10,21,32]], + ["let","r",0], + ["foreach","item","%list%"], + ["if","%item%","<",30], + ["add","%r%","%item%"], + ["store","r"], + ["end"], + ["loop"], + ["return","%r%"] + ]`, ``, `31`) + + + multicall(t, bc, "ac1", `[ + ["let","str",""], + ["let","obj",{"one":1,"two":2,"three":3}], + ["get_keys","%obj%"], + ["foreach","key","%last_result%"], + ["concat","%str%","%key%"], + ["store","str"], + ["loop"], + ["return","%str%"] + ]`, ``, `"onethreetwo"`) + + + + // FORPAIR + + multicall(t, bc, "ac1", `[ + ["let","str",""], + ["let","sum",0], + ["let","obj",{"one":1,"two":2,"three":3}], + ["forpair","key","value","%obj%"], + ["concat","%str%","%key%"], + ["store","str"], + ["add","%sum%","%value%"], + ["store","sum"], + ["loop"], + ["return","%str%","%sum%"] + ]`, ``, `["onethreetwo",6]`) + + multicall(t, bc, "ac1", `[ + ["let","str",""], + ["let","sum",0], + ["let","obj",{"one":1.5,"two":2.5,"three":3.5,"four":4.5}], + ["forpair","key","value","%obj%"], + ["concat","%str%","%key%"], + ["store","str"], + ["add","%sum%","%value%"], + ["store","sum"], + ["loop"], + ["return","%str%","%sum%"] + ]`, ``, `["fouronethreetwo",12]`) + + multicall(t, bc, "ac1", `[ + ["let","names",[]], + ["let","values",[]], + ["let","obj",{"one":1.5,"two":2.5,"three":3.5,"four":4.5}], + ["forpair","key","value","%obj%"], + ["insert","%names%","%key%"], + ["insert","%values%","%value%"], + ["loop"], + ["return","%names%","%values%"] + ]`, ``, `[["four","one","three","two"],[4.5,1.5,3.5,2.5]]`) + + multicall(t, bc, "ac1", `[ + ["let","names",[]], + ["let","values",[]], + ["let","obj",{"one":1.5,"two":2.5,"three":3.5,"four":4.5}], + ["forpair","key","value","%obj%"], + ["insert","%names%","%key%"], + ["insert","%values%","%value%"], + ["loop"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","sort","%values%"], + ["store","values"], + ["return","%names%","%values%"] + ]`, ``, `[["four","one","three","two"],[1.5,2.5,3.5,4.5]]`) + + multicall(t, bc, "ac1", `[ + ["let","obj",{}], + ["let","counter",0], + ["forpair","key","value","%obj%"], + ["add","%counter%",1], + ["store","counter"], + ["loop"], + ["return","%counter%"] + ]`, ``, `0`) + + + + // FOR "BREAK" + + multicall(t, bc, "ac1", `[ + ["let","c",0], + ["for","n",1,10], + ["add","%c%",1], + ["store","c"], + ["if","%n%","=",5], + ["let","n",500], + ["end"], + ["loop"], + ["return","%c%"] + ]`, ``, `5`) + + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",500,10,-5], + ["add","%last_result%",1], + ["if","%n%","=",475], + ["let","n",2], + ["end"], + ["loop"], + ["return","%last_result%"] + ]`, ``, `6`) + + multicall(t, bc, "ac1", `[ + ["let","c",0], + ["for","n",1,10], + ["add","%c%",1], + ["store","c"], + ["if","%n%","=",5], + ["break"], + ["end"], + ["loop"], + ["return","%c%"] + ]`, ``, `5`) + + multicall(t, bc, "ac1", `[ + ["let","c",0], + ["for","n",1,10], + ["add","%c%",1], + ["store","c"], + ["break","if","%n%","=",5], + ["loop"], + ["return","%c%"] + ]`, ``, `5`) + + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",500,10,-5], + ["add","%last_result%",1], + ["if","%n%","=",475], + ["break"], + ["end"], + ["loop"], + ["return","%last_result%"] + ]`, ``, `6`) + + multicall(t, bc, "ac1", `[ + ["tonumber","0"], + ["for","n",500,10,-5], + ["add","%last_result%",1], + ["break","if","%n%","=",475], + ["loop"], + ["return","%last_result%"] + ]`, ``, `6`) + + multicall(t, bc, "ac1", `[ + ["for","n",1,5], + ["loop"], + ["return","%n%"] + ]`, ``, `6`) + + multicall(t, bc, "ac1", `[ + ["for","n",1,5], + ["break"], + ["loop"], + ["return","%n%"] + ]`, ``, `1`) + + multicall(t, bc, "ac1", `[ + ["let","names",[]], + ["let","list",["one","two","three","four"]], + ["foreach","item","%list%"], + ["if","%item%","=","three"], + ["break"], + ["end"], + ["insert","%names%","%item%"], + ["loop"], + ["return","%names%"] + ]`, ``, `["one","two"]`) + + multicall(t, bc, "ac1", `[ + ["let","names",[]], + ["let","list",["one","two","three","four"]], + ["foreach","item","%list%"], + ["break","if","%item%","=","three"], + ["insert","%names%","%item%"], + ["loop"], + ["return","%names%"] + ]`, ``, `["one","two"]`) + + multicall(t, bc, "ac1", `[ + ["let","names",[]], + ["let","obj",{"one":true,"two":false,"three":false,"four":true}], + ["forpair","key","value","%obj%"], + ["if","%value%","=",false], + ["break"], + ["end"], + ["insert","%names%","%key%"], + ["loop"], + ["return","%names%"] + ]`, ``, `["four","one"]`) + + multicall(t, bc, "ac1", `[ + ["let","names",[]], + ["let","obj",{"one":true,"two":false,"three":false,"four":true}], + ["forpair","key","value","%obj%"], + ["break","if","%value%","=",false], + ["insert","%names%","%key%"], + ["loop"], + ["return","%names%"] + ]`, ``, `["four","one"]`) + + + + // RETURN before the end + + multicall(t, bc, "ac1", `[ + ["let","v",123], + ["if","%v%",">",100], + ["return"], + ["end"], + ["let","v",500], + ["return","%v%"] + ]`, ``, ``) + + multicall(t, bc, "ac1", `[ + ["let","v",123], + ["if","%v%",">",200], + ["return"], + ["end"], + ["let","v",500], + ["return","%v%"] + ]`, ``, `500`) + + + + // FULL LOOPS + + multicall(t, bc, "ac1", `[ + ["let","c","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA"], + ["call","%c%","inc","n"], + ["call","%c%","get","n"], + ["if","%last_result%",">=",5], + ["return","%last_result%"], + ["end"], + ["loop"] + ]`, ``, `5`) + + + + + // CALLS + + multicall(t, bc, "ac1", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","works"], + ["assert","%last_result%","=",123], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","works"], + ["return","%last_result%"] + ]`, ``, `123`) + + multicall(t, bc, "ac1", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","works"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","fails"] + ]`, `this call should fail`) + + + multicall(t, bc, "ac3", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set_name","test"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_name"], + ["assert","%last_result%","=","test"] + ]`) + + multicall(t, bc, "ac3", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set_name","wrong"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_name"], + ["assert","%last_result%","=","wrong"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set_name",123] + ]`, `must be string`) + + multicall(t, bc, "ac3", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_name"], + ["assert","%last_result%","=","test"], + ["return","%last_result%"] + ]`, ``, `"test"`) + + + multicall(t, bc, "ac3", `[ + ["let","c","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA"], + ["call","%c%","set_name","test2"], + ["call","%c%","get_name"], + ["assert","%last_result%","=","test2"] + ]`) + + + // CALL LOOP + + multicall(t, bc, "ac3", `[ + ["let","list",["first","second","third"]], + ["foreach","item","%list%"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","add","%item%"], + ["loop"] + ]`) + + multicall(t, bc, "ac1", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","1"], + ["assert","%last_result%","=","first"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","2"], + ["assert","%last_result%","=","second"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","3"], + ["assert","%last_result%","=","third"] + ]`) + + multicall(t, bc, "ac3", `[ + ["let","list",["1st","2nd","3rd"]], + ["let","n",1], + ["foreach","item","%list%"], + ["tostring","%n%"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set","%last_result%","%item%"], + ["add","%n%",1], + ["store","n"], + ["loop"] + ]`) + + multicall(t, bc, "ac1", `[ + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","1"], + ["assert","%last_result%","=","1st"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","2"], + ["assert","%last_result%","=","2nd"], + ["call","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get","3"], + ["assert","%last_result%","=","3rd"] + ]`) + + + + // PCALL + + multicall(t, bc, "ac1", `[ + ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","works"], + ["get","%last_result%",1], + ["assert","%last_result%","=",true], + ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","fails"], + ["get","%last_result%",1], + ["assert","%last_result%","=",false] + ]`) + + multicall(t, bc, "ac3", `[ + ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set_name","1st"], + ["get","%last_result%",1], + ["assert","%last_result%","=",true], + + ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_name"], + ["store","ret"], + ["get","%ret%",1], + ["assert","%last_result%","=",true], + ["get","%ret%",2], + ["assert","%last_result%","=","1st"], + + ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","set_name",22], + ["get","%last_result%",1], + ["assert","%last_result%","=",false], + + ["pcall","AmhbUWkqenFtgKLnbDd1NXHce7hn35pcHWYRWBnq5vauLfEQXXRA","get_name"], + ["store","ret"], + ["get","%ret%",1], + ["assert","%last_result%","=",true], + ["get","%ret%",2], + ["assert","%last_result%","=","1st"], + + ["return","%last_result%"] + ]`, ``, `"1st"`) + + + + // MULTICALL ON ACCOUNT ------------------------------------------ + + + //deploy ac0 0 c1 test.lua + //deploy ac0 0 c2 test.lua + //deploy ac0 0 c3 test.lua + + // c1: AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9 + // c2: Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4 + // c3: AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK + + multicall(t, bc, "ac0", `[ + ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","set_name","testing multicall"], + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","set_name","contract 2"], + ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","set_name","third one"] + ]`) + + multicall(t, bc, "ac0", `[ + ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","get_name"], + ["assert","%last_result%","=","testing multicall"], + ["store","r1"], + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","get_name"], + ["assert","%last_result%","=","contract 2"], + ["store","r2"], + ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","get_name"], + ["assert","%last_result%","=","third one"], + ["store","r3"], + ["return","%r1%","%r2%","%r3%"] + ]`, ``, `["testing multicall","contract 2","third one"]`) + + multicall(t, bc, "ac0", `[ + ["fromjson","{}"], + ["store","res"], + ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","get_name"], + ["set","%res%","r1","%last_result%"], + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","get_name"], + ["set","%res%","r2","%last_result%"], + ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","get_name"], + ["set","%res%","r3","%last_result%"], + ["return","%res%"] + ]`, ``, `{"r1":"testing multicall","r2":"contract 2","r3":"third one"}`) + multicall(t, bc, "ac0", `[ + ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","set_name","wohooooooo"], + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","set_name","it works!"], + ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","set_name","it really works!"] + ]`) - // aergo BALANCE and SEND + multicall(t, bc, "ac0", `[ + ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","get_name"], + ["assert","%last_result%","=","wohooooooo"], + ["store","r1"], + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","get_name"], + ["assert","%last_result%","=","it works!"], + ["store","r2"], + ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","get_name"], + ["assert","%last_result%","=","it really works!"], + ["store","r3"], + ["return","%r1%","%r2%","%r3%"] + ]`, ``, `["wohooooooo","it works!","it really works!"]`) - multicall(t, bc, "ac5", `[ - ["balance"], - ["tostring","%last_result%"], - ["assert","%last_result%","=","10000000000000000000"], - ["return","%last_result%"] - ]`, ``, `"10000000000000000000"`) + multicall(t, bc, "ac0", `[ + ["fromjson","{}"], + ["store","res"], + ["call","AmhXhR3Eguhu5qjVoqcg7aCFMpw1GGZJfqDDqfy6RsTP7MrpWeJ9","get_name"], + ["set","%res%","r1","%last_result%"], + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","get_name"], + ["set","%res%","r2","%last_result%"], + ["call","AmgtL32d1M56xGENKDnDqXFzkrYJwWidzSMtay3F8fFDU1VAEdvK","get_name"], + ["set","%res%","r3","%last_result%"], + ["return","%res%"] + ]`, ``, `{"r1":"wohooooooo","r2":"it works!","r3":"it really works!"}`) - multicall(t, bc, "ac2", `[ - ["balance"], - ["tostring","%last_result%"], - ["assert","%last_result%","=","10000000000000000000"], - ["balance","AmgHyfkUt5iuXJKZNTrdthtXWLLJCrKWdJ6H6Yshn6ZR285Wr2Hc"], - ["tostring","%last_result%"], - ["assert","%last_result%","=","0"], - ["send","AmgHyfkUt5iuXJKZNTrdthtXWLLJCrKWdJ6H6Yshn6ZR285Wr2Hc","3000000000000000000"], + // aergo BALANCE and SEND - ["balance","AmgHyfkUt5iuXJKZNTrdthtXWLLJCrKWdJ6H6Yshn6ZR285Wr2Hc"], - ["tostring","%last_result%"], - ["assert","%last_result%","=","3000000000000000000"], + multicall(t, bc, "ac5", `[ + ["balance"], + ["tostring","%last_result%"], + ["assert","%last_result%","=","10000000000000000000"], + ["return","%last_result%"] + ]`, ``, `"10000000000000000000"`) - ["balance"], - ["tostring","%last_result%"], - ["assert","%last_result%","=","7000000000000000000"], + multicall(t, bc, "ac2", `[ + ["balance"], + ["tostring","%last_result%"], + ["assert","%last_result%","=","10000000000000000000"], - ["return","%last_result%"] - ]`, ``, `"7000000000000000000"`) + ["balance","AmgHyfkUt5iuXJKZNTrdthtXWLLJCrKWdJ6H6Yshn6ZR285Wr2Hc"], + ["tostring","%last_result%"], + ["assert","%last_result%","=","0"], + ["send","AmgHyfkUt5iuXJKZNTrdthtXWLLJCrKWdJ6H6Yshn6ZR285Wr2Hc","3000000000000000000"], + ["balance","AmgHyfkUt5iuXJKZNTrdthtXWLLJCrKWdJ6H6Yshn6ZR285Wr2Hc"], + ["tostring","%last_result%"], + ["assert","%last_result%","=","3000000000000000000"], - // SECURITY CHECKS + ["balance"], + ["tostring","%last_result%"], + ["assert","%last_result%","=","7000000000000000000"], - // it should not be possible to call the code from another account + ["return","%last_result%"] + ]`, ``, `"7000000000000000000"`) - // a. from an account (via multicall, using the 'call' command) - multicall(t, bc, "ac1", `[ - ["call","AmgeSw3M3V3orBMjf1j98kGne4WycnmQWVTJe6MYNrQ2wuVz3Li2","execute",[["add",11,22],["return","%last_result%"]]], - ["return","%last_result%"] - ]`, `nd contract`) + // SECURITY CHECKS - // b. from an account (via a call tx) + // it should not be possible to call the code from another account - call(t, bc, "ac1", 0, "ac1", "execute", `[[["add",11,22],["return","%last_result%"]]]`, `nd contract`, ``) + // a. from an account (via multicall, using the 'call' command) - call(t, bc, "ac1", 0, "ac2", "execute", `[[["add",11,22],["return","%last_result%"]]]`, `nd contract`, ``) + multicall(t, bc, "ac1", `[ + ["call","AmgeSw3M3V3orBMjf1j98kGne4WycnmQWVTJe6MYNrQ2wuVz3Li2","execute",[["add",11,22],["return","%last_result%"]]], + ["return","%last_result%"] + ]`, `nd contract`) - // c. from a contract (calling back) + // b. from an account (via a call tx) - multicall(t, bc, "ac1", `[ - ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","call","AmgMPiyZYr19kQ1kHFNiGenez1CRTBqNWqppj6gGZGEP6qszDGe1","execute",[["add",11,22],["return","%last_result%"]]], - ["return","%last_result%"] - ]`, `nd contract`) + call(t, bc, "ac1", 0, "ac1", "execute", `[[["add",11,22],["return","%last_result%"]]]`, `nd contract`, ``) + call(t, bc, "ac1", 0, "ac2", "execute", `[[["add",11,22],["return","%last_result%"]]]`, `nd contract`, ``) - // d. from a contract (calling another account) - multicall(t, bc, "ac1", `[ - ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","call","AmgeSw3M3V3orBMjf1j98kGne4WycnmQWVTJe6MYNrQ2wuVz3Li2","execute",[["add",11,22],["return","%last_result%"]]], - ["return","%last_result%"] - ]`, `nd contract`) + // c. from a contract (calling back) + multicall(t, bc, "ac1", `[ + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","call","AmgMPiyZYr19kQ1kHFNiGenez1CRTBqNWqppj6gGZGEP6qszDGe1","execute",[["add",11,22],["return","%last_result%"]]], + ["return","%last_result%"] + ]`, `nd contract`) - // e. from a contract (via a call txn) - call(t, bc, "ac1", 0, "c2", "call", `["AmgMPiyZYr19kQ1kHFNiGenez1CRTBqNWqppj6gGZGEP6qszDGe1","execute",[["add",11,22],["return","%last_result%"]]]`, `nd contract`, ``) + // d. from a contract (calling another account) - call(t, bc, "ac1", 0, "c2", "call", `["AmgeSw3M3V3orBMjf1j98kGne4WycnmQWVTJe6MYNrQ2wuVz3Li2","execute",[["add",11,22],["return","%last_result%"]]]`, `nd contract`, ``) + multicall(t, bc, "ac1", `[ + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","call","AmgeSw3M3V3orBMjf1j98kGne4WycnmQWVTJe6MYNrQ2wuVz3Li2","execute",[["add",11,22],["return","%last_result%"]]], + ["return","%last_result%"] + ]`, `nd contract`) - // system.isContract() should return false on user accounts + // e. from a contract (via a call txn) - call(t, bc, "ac1", 0, "c2", "is_contract", `["AmgMPiyZYr19kQ1kHFNiGenez1CRTBqNWqppj6gGZGEP6qszDGe1"]`, ``, `false`) + call(t, bc, "ac1", 0, "c2", "call", `["AmgMPiyZYr19kQ1kHFNiGenez1CRTBqNWqppj6gGZGEP6qszDGe1","execute",[["add",11,22],["return","%last_result%"]]]`, `nd contract`, ``) - call(t, bc, "ac1", 0, "c2", "is_contract", `["AmgeSw3M3V3orBMjf1j98kGne4WycnmQWVTJe6MYNrQ2wuVz3Li2"]`, ``, `false`) + call(t, bc, "ac1", 0, "c2", "call", `["AmgeSw3M3V3orBMjf1j98kGne4WycnmQWVTJe6MYNrQ2wuVz3Li2","execute",[["add",11,22],["return","%last_result%"]]]`, `nd contract`, ``) - multicall(t, bc, "ac1", `[ - ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","is_contract","AmgMPiyZYr19kQ1kHFNiGenez1CRTBqNWqppj6gGZGEP6qszDGe1"], - ["assert","%last_result%","=",false], - ["return","%last_result%"] - ]`, ``, `false`) - multicall(t, bc, "ac1", `[ - ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","is_contract","AmgeSw3M3V3orBMjf1j98kGne4WycnmQWVTJe6MYNrQ2wuVz3Li2"], - ["assert","%last_result%","=",false], - ["return","%last_result%"] - ]`, ``, `false`) + // system.isContract() should return false on user accounts + call(t, bc, "ac1", 0, "c2", "is_contract", `["AmgMPiyZYr19kQ1kHFNiGenez1CRTBqNWqppj6gGZGEP6qszDGe1"]`, ``, `false`) - // on a contract called by multicall, the system.getSender() and system.getOrigin() must be the same + call(t, bc, "ac1", 0, "c2", "is_contract", `["AmgeSw3M3V3orBMjf1j98kGne4WycnmQWVTJe6MYNrQ2wuVz3Li2"]`, ``, `false`) - multicall(t, bc, "ac1", `[ - ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","sender"], - ["store","sender"], - ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","origin"], - ["store","origin"], - ["assert","%sender%","=","%origin%"], - ["return","%sender%"] - ]`, ``, `"AmgMPiyZYr19kQ1kHFNiGenez1CRTBqNWqppj6gGZGEP6qszDGe1"`) + multicall(t, bc, "ac1", `[ + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","is_contract","AmgMPiyZYr19kQ1kHFNiGenez1CRTBqNWqppj6gGZGEP6qszDGe1"], + ["assert","%last_result%","=",false], + ["return","%last_result%"] + ]`, ``, `false`) + multicall(t, bc, "ac1", `[ + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","is_contract","AmgeSw3M3V3orBMjf1j98kGne4WycnmQWVTJe6MYNrQ2wuVz3Li2"], + ["assert","%last_result%","=",false], + ["return","%last_result%"] + ]`, ``, `false`) + + // on a contract called by multicall, the system.getSender() and system.getOrigin() must be the same + + multicall(t, bc, "ac1", `[ + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","sender"], + ["store","sender"], + ["call","Amh8PekqkDmLiwE6FUX6JejjWk3R54cmTaa1Tc1VHZmTRJMruWe4","origin"], + ["store","origin"], + ["assert","%sender%","=","%origin%"], + ["return","%sender%"] + ]`, ``, `"AmgMPiyZYr19kQ1kHFNiGenez1CRTBqNWqppj6gGZGEP6qszDGe1"`) + + } } // ---------------------------------------------------------------------------- From dc3102fa50b8df8e12093397b9632c697e3edd97 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 8 Dec 2023 03:26:36 +0000 Subject: [PATCH 112/182] fix luajit branch --- libtool/src/luajit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtool/src/luajit b/libtool/src/luajit index 4941d7293..d64278c3b 160000 --- a/libtool/src/luajit +++ b/libtool/src/luajit @@ -1 +1 @@ -Subproject commit 4941d7293b4d8d1f29492c00b9a7921c5141fac1 +Subproject commit d64278c3bac3dedb74f7117231ab996ce5630b15 From fb3f70ece95ef417900d40f5caefc47b3869b45f Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 8 Dec 2023 16:42:41 +0000 Subject: [PATCH 113/182] fix gas on integration test --- tests/test-gas-bf.sh | 2 +- tests/test-gas-op.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test-gas-bf.sh b/tests/test-gas-bf.sh index 087aab303..18393f73a 100755 --- a/tests/test-gas-bf.sh +++ b/tests/test-gas-bf.sh @@ -36,7 +36,7 @@ assert_equals "$status" "SUCCESS" #assert_equals "$ret" "{}" if [ "$fork_version" -eq "4" ]; then - assert_equals "$gasUsed" "47772314" + assert_equals "$gasUsed" "47341329" elif [ "$fork_version" -eq "3" ]; then assert_equals "$gasUsed" "47456046" else diff --git a/tests/test-gas-op.sh b/tests/test-gas-op.sh index 45a9b022c..47ca43769 100755 --- a/tests/test-gas-op.sh +++ b/tests/test-gas-op.sh @@ -32,7 +32,7 @@ assert_equals "$status" "SUCCESS" #assert_equals "$ret" "{}" if [ "$fork_version" -eq "4" ]; then - assert_equals "$gasUsed" "134656" + assert_equals "$gasUsed" "120832" else assert_equals "$gasUsed" "117610" fi From 10ba4648e89352d4888ba215874c50f87468ee84 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 13 Dec 2023 19:59:56 +0000 Subject: [PATCH 114/182] fix build after state refactoring --- contract/contract.go | 4 ++-- contract/vm_dummy/vm_dummy.go | 8 ++++---- state/contract.go | 16 ++++++++-------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/contract/contract.go b/contract/contract.go index 4e63d0bbc..f34693d70 100644 --- a/contract/contract.go +++ b/contract/contract.go @@ -118,9 +118,9 @@ func Execute( // open the contract state var contractState *state.ContractState if isMultiCall { - contractState = bs.GetMultiCallState(sender.AccountID(), sender.State()) + contractState = state.GetMultiCallState(sender.AccountID(), sender.State()) } else { - contractState, err := state.OpenContractState(receiver.AccountID(), receiver.State(), bs.StateDB) + contractState, err = state.OpenContractState(receiver.AccountID(), receiver.State(), bs.StateDB) } if err != nil { return diff --git a/contract/vm_dummy/vm_dummy.go b/contract/vm_dummy/vm_dummy.go index 191b750ec..d1a23092f 100644 --- a/contract/vm_dummy/vm_dummy.go +++ b/contract/vm_dummy/vm_dummy.go @@ -463,11 +463,11 @@ func contractFrame(l luaTxContract, bs *state.BlockState, cdb contract.ChainAcce contractId := types.ToAccountID(l.recipient()) - var contractState *state.V + var contractState *state.AccountState if l.isMultiCall() { contractState = creatorState } else { - contractState, err := state.GetAccountState(l.recipient(), bs.StateDB) + contractState, err = state.GetAccountState(l.recipient(), bs.StateDB) } if err != nil { return err @@ -475,9 +475,9 @@ func contractFrame(l luaTxContract, bs *state.BlockState, cdb contract.ChainAcce var eContractState *state.ContractState if l.isMultiCall() { - eContractState = bs.GetMultiCallState(creatorId, creatorState.State()) + eContractState = state.GetMultiCallState(creatorId, creatorState.State()) } else { - eContractState, err := state.OpenContractState(contractId, contractState.State(), bs.StateDB) + eContractState, err = state.OpenContractState(contractId, contractState.State(), bs.StateDB) } if err != nil { return err diff --git a/state/contract.go b/state/contract.go index c3fb7112a..0b657c112 100644 --- a/state/contract.go +++ b/state/contract.go @@ -11,14 +11,6 @@ import ( "github.com/aergoio/aergo/v2/types" ) -func (states *StateDB) GetMultiCallState(aid types.AccountID, st *types.State) (*ContractState) { - res := &ContractState{ - State: st, - account: aid, - } - return res -} - type ContractState struct { *types.State account types.AccountID @@ -172,6 +164,14 @@ func (cs *ContractState) cache() *statedb.StateBuffer { //---------------------------------------------------------------// // global functions +func GetMultiCallState(aid types.AccountID, st *types.State) (*ContractState) { + res := &ContractState{ + State: st, + account: aid, + } + return res +} + func OpenContractStateAccount(aid types.AccountID, states *statedb.StateDB) (*ContractState, error) { st, err := states.GetAccountState(aid) if err != nil { From 713d0decd13ac3718aa4d45f8bf9ca5bb585e729 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 14 Dec 2023 20:40:03 +0000 Subject: [PATCH 115/182] compile the multicall code on demand --- contract/vm.go | 18 +- contract/vm_multicall.go | 585 +++++++++++++++++++-------------------- 2 files changed, 293 insertions(+), 310 deletions(-) diff --git a/contract/vm.go b/contract/vm.go index 6adfb5766..5cd3f4377 100644 --- a/contract/vm.go +++ b/contract/vm.go @@ -1357,13 +1357,23 @@ func getContract(contractState *state.ContractState, bs *state.BlockState) []byt } func getMultiCallContract(contractState *state.ContractState) []byte { - code := luacUtil.LuaCode(multicall_payload) - if !code.IsValidFormat() { - ctrLgr.Warn().Msg("multicall_payload") + + if multicall_payload == nil { + var err error + multicall_payload, err = Compile(multicall_code, nil) + if err != nil { + ctrLgr.Error().Err(err).Msg("multicall_payload") + return nil + } + } + + if !multicall_payload.IsValidFormat() { + ctrLgr.Error().Msg("multicall_payload: invalid format") return nil } + contractState.SetMultiCallCode(multicall_payload) - return code.ByteCode() + return multicall_payload.ByteCode() } func GetABI(contractState *state.ContractState, bs *state.BlockState) (*types.ABI, error) { diff --git a/contract/vm_multicall.go b/contract/vm_multicall.go index 378565256..6dd79ed2f 100644 --- a/contract/vm_multicall.go +++ b/contract/vm_multicall.go @@ -1,309 +1,282 @@ package contract -var multicall_payload = []byte { - 0x9a,0x12,0x00,0x00,0x1b,0x4c,0x4a,0x02,0x0a,0x25,0x02,0x00,0x03,0x00,0x02, - 0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00, - 0x00,0x00,0x09,0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63,0x74, - 0x37,0x02,0x01,0x04,0x00,0x03,0x00,0x07,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01, - 0x39,0x01,0x02,0x01,0x12,0x03,0x00,0x00,0x42,0x01,0x02,0x02,0x47,0x03,0x01,0x00, - 0x43,0x01,0x00,0x00,0x0a,0x76,0x61,0x6c,0x75,0x65,0x09,0x63,0x61,0x6c,0x6c,0x0d, - 0x63,0x6f,0x6e,0x74,0x72,0x61,0x63,0x74,0x41,0x02,0x00,0x05,0x00,0x03,0x01,0x08, - 0x34,0x00,0x03,0x00,0x36,0x01,0x00,0x00,0x36,0x03,0x01,0x00,0x39,0x03,0x02,0x03, - 0x47,0x04,0x00,0x00,0x41,0x01,0x01,0x00,0x3f,0x01,0x00,0x00,0x4c,0x00,0x02,0x00, - 0x09,0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63,0x74,0x0a,0x70, - 0x63,0x61,0x6c,0x6c,0x03,0x80,0x80,0xc0,0x99,0x04,0x53,0x02,0x01,0x07,0x00,0x04, - 0x01,0x0b,0x34,0x01,0x03,0x00,0x36,0x02,0x00,0x00,0x36,0x04,0x01,0x00,0x39,0x04, - 0x02,0x04,0x39,0x04,0x03,0x04,0x12,0x06,0x00,0x00,0x42,0x04,0x02,0x02,0x47,0x05, - 0x01,0x00,0x41,0x02,0x01,0x00,0x3f,0x02,0x00,0x00,0x4c,0x01,0x02,0x00,0x0a,0x76, - 0x61,0x6c,0x75,0x65,0x09,0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61, - 0x63,0x74,0x0a,0x70,0x63,0x61,0x6c,0x6c,0x03,0x80,0x80,0xc0,0x99,0x04,0x42,0x00, - 0x01,0x06,0x00,0x04,0x00,0x07,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x36,0x03, - 0x02,0x00,0x39,0x03,0x03,0x03,0x12,0x05,0x00,0x00,0x42,0x03,0x02,0x00,0x43,0x01, - 0x00,0x00,0x0c,0x62,0x61,0x6c,0x61,0x6e,0x63,0x65,0x0d,0x63,0x6f,0x6e,0x74,0x72, - 0x61,0x63,0x74,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x0b,0x62,0x69,0x67,0x6e,0x75, - 0x6d,0x29,0x00,0x02,0x06,0x00,0x02,0x00,0x05,0x36,0x02,0x00,0x00,0x39,0x02,0x01, - 0x02,0x12,0x04,0x00,0x00,0x12,0x05,0x01,0x00,0x44,0x02,0x03,0x00,0x09,0x73,0x65, - 0x6e,0x64,0x0d,0x63,0x6f,0x6e,0x74,0x72,0x61,0x63,0x74,0x43,0x00,0x03,0x07,0x00, - 0x02,0x00,0x0a,0x0f,0x00,0x02,0x00,0x58,0x03,0x05,0x80,0x36,0x03,0x00,0x00,0x12, - 0x05,0x01,0x00,0x12,0x06,0x02,0x00,0x42,0x03,0x03,0x02,0x12,0x01,0x03,0x00,0x36, - 0x03,0x01,0x00,0x3c,0x01,0x00,0x03,0x4b,0x00,0x01,0x00,0x09,0x76,0x61,0x72,0x73, - 0x13,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x62,0x69,0x67,0x6e,0x75,0x6d,0x2c, - 0x00,0x01,0x03,0x00,0x02,0x00,0x05,0x36,0x01,0x00,0x00,0x36,0x02,0x00,0x00,0x39, - 0x02,0x01,0x02,0x3c,0x02,0x00,0x01,0x4b,0x00,0x01,0x00,0x10,0x6c,0x61,0x73,0x74, - 0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x09,0x76,0x61,0x72,0x73,0x0f,0x00,0x02,0x03, - 0x00,0x00,0x00,0x02,0x38,0x02,0x01,0x00,0x4c,0x02,0x02,0x00,0x0f,0x00,0x03,0x03, - 0x00,0x00,0x00,0x02,0x3c,0x02,0x01,0x00,0x4b,0x00,0x01,0x00,0x28,0x02,0x00,0x03, - 0x00,0x02,0x00,0x05,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00, - 0x41,0x00,0x00,0x01,0x4b,0x00,0x01,0x00,0x0b,0x69,0x6e,0x73,0x65,0x72,0x74,0x0a, - 0x74,0x61,0x62,0x6c,0x65,0x24,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00, - 0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x0b,0x72,0x65, - 0x6d,0x6f,0x76,0x65,0x0a,0x74,0x61,0x62,0x6c,0x65,0x0f,0x00,0x01,0x02,0x00,0x00, - 0x00,0x02,0x15,0x01,0x00,0x00,0x4c,0x01,0x02,0x00,0x55,0x00,0x01,0x09,0x00,0x03, - 0x01,0x0f,0x34,0x01,0x00,0x00,0x36,0x02,0x00,0x00,0x12,0x04,0x00,0x00,0x42,0x02, - 0x02,0x04,0x48,0x05,0x03,0x80,0x15,0x07,0x01,0x00,0x16,0x07,0x00,0x07,0x3c,0x05, - 0x07,0x01,0x46,0x05,0x03,0x03,0x52,0x05,0xfb,0x7f,0x36,0x02,0x01,0x00,0x39,0x02, - 0x02,0x02,0x12,0x04,0x01,0x00,0x42,0x02,0x02,0x01,0x4c,0x01,0x02,0x00,0x09,0x73, - 0x6f,0x72,0x74,0x0a,0x74,0x61,0x62,0x6c,0x65,0x0a,0x70,0x61,0x69,0x72,0x73,0x02, - 0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x20,0x02,0x01,0x00,0x4c,0x02,0x02,0x00, - 0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x21,0x02,0x01,0x00,0x4c,0x02,0x02,0x00, - 0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x22,0x02,0x01,0x00,0x4c,0x02,0x02,0x00, - 0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x23,0x02,0x01,0x00,0x4c,0x02,0x02,0x00, - 0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x25,0x02,0x01,0x00,0x4c,0x02,0x02,0x00, - 0x0f,0x00,0x02,0x03,0x00,0x00,0x00,0x02,0x24,0x02,0x01,0x00,0x4c,0x02,0x02,0x00, - 0x23,0x00,0x01,0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01, - 0x12,0x03,0x00,0x00,0x44,0x01,0x02,0x00,0x09,0x73,0x71,0x72,0x74,0x0b,0x62,0x69, - 0x67,0x6e,0x75,0x6d,0x32,0x02,0x00,0x04,0x00,0x02,0x01,0x06,0x36,0x00,0x00,0x00, - 0x39,0x00,0x01,0x00,0x34,0x02,0x03,0x00,0x47,0x03,0x00,0x00,0x3f,0x03,0x00,0x00, - 0x44,0x00,0x02,0x00,0x0b,0x63,0x6f,0x6e,0x63,0x61,0x74,0x0a,0x74,0x61,0x62,0x6c, - 0x65,0x03,0x80,0x80,0xc0,0x99,0x04,0x25,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36, - 0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x0b, - 0x66,0x6f,0x72,0x6d,0x61,0x74,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x22,0x02,0x00, - 0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00, - 0x00,0x43,0x00,0x00,0x00,0x08,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67, - 0x24,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00,0x00,0x39,0x00,0x01,0x00, - 0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x0a,0x6d,0x61,0x74,0x63,0x68,0x0b,0x73, - 0x74,0x72,0x69,0x6e,0x67,0x23,0x02,0x00,0x03,0x00,0x02,0x00,0x04,0x36,0x00,0x00, - 0x00,0x39,0x00,0x01,0x00,0x47,0x02,0x00,0x00,0x43,0x00,0x00,0x00,0x09,0x67,0x73, - 0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x25,0x00,0x01,0x04,0x00,0x02,0x00, - 0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03,0x00,0x00,0x44,0x01,0x02, - 0x00,0x0b,0x6e,0x75,0x6d,0x62,0x65,0x72,0x0b,0x62,0x69,0x67,0x6e,0x75,0x6d,0x1c, - 0x00,0x01,0x04,0x00,0x01,0x00,0x03,0x36,0x01,0x00,0x00,0x12,0x03,0x00,0x00,0x44, - 0x01,0x02,0x00,0x0d,0x74,0x6f,0x6e,0x75,0x6d,0x62,0x65,0x72,0x1c,0x00,0x01,0x04, - 0x00,0x01,0x00,0x03,0x36,0x01,0x00,0x00,0x12,0x03,0x00,0x00,0x44,0x01,0x02,0x00, - 0x0d,0x74,0x6f,0x73,0x74,0x72,0x69,0x6e,0x67,0x23,0x00,0x01,0x04,0x00,0x02,0x00, - 0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03,0x00,0x00,0x44,0x01,0x02, - 0x00,0x0b,0x65,0x6e,0x63,0x6f,0x64,0x65,0x09,0x6a,0x73,0x6f,0x6e,0x23,0x00,0x01, - 0x04,0x00,0x02,0x00,0x04,0x36,0x01,0x00,0x00,0x39,0x01,0x01,0x01,0x12,0x03,0x00, - 0x00,0x44,0x01,0x02,0x00,0x0b,0x64,0x65,0x63,0x6f,0x64,0x65,0x09,0x6a,0x73,0x6f, - 0x6e,0x70,0x02,0x00,0x08,0x00,0x05,0x01,0x0e,0x36,0x00,0x00,0x00,0x36,0x02,0x01, - 0x00,0x47,0x04,0x00,0x00,0x41,0x02,0x00,0x02,0x27,0x03,0x02,0x00,0x36,0x04,0x03, - 0x00,0x39,0x04,0x04,0x04,0x34,0x06,0x03,0x00,0x47,0x07,0x00,0x00,0x3f,0x07,0x00, - 0x00,0x42,0x04,0x02,0x02,0x26,0x03,0x04,0x03,0x42,0x00,0x03,0x01,0x4b,0x00,0x01, - 0x00,0x0b,0x65,0x6e,0x63,0x6f,0x64,0x65,0x09,0x6a,0x73,0x6f,0x6e,0x17,0x61,0x73, - 0x73,0x65,0x72,0x74,0x69,0x6f,0x6e,0x20,0x66,0x61,0x69,0x6c,0x65,0x64,0x3a,0x20, - 0x09,0x65,0x76,0x61,0x6c,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x03,0x80,0x80,0xc0, - 0x99,0x04,0x8e,0x02,0x00,0x01,0x09,0x00,0x08,0x00,0x36,0x36,0x01,0x00,0x00,0x12, - 0x03,0x00,0x00,0x42,0x01,0x02,0x02,0x07,0x01,0x01,0x00,0x58,0x01,0x21,0x80,0x15, - 0x01,0x00,0x00,0x29,0x02,0x03,0x00,0x03,0x02,0x01,0x00,0x58,0x01,0x2c,0x80,0x36, - 0x01,0x01,0x00,0x39,0x01,0x02,0x01,0x12,0x03,0x00,0x00,0x29,0x04,0x01,0x00,0x29, - 0x05,0x01,0x00,0x42,0x01,0x04,0x02,0x07,0x01,0x03,0x00,0x58,0x01,0x24,0x80,0x36, - 0x01,0x01,0x00,0x39,0x01,0x02,0x01,0x12,0x03,0x00,0x00,0x29,0x04,0xff,0xff,0x29, - 0x05,0xff,0xff,0x42,0x01,0x04,0x02,0x07,0x01,0x03,0x00,0x58,0x01,0x1c,0x80,0x36, - 0x01,0x01,0x00,0x39,0x01,0x02,0x01,0x12,0x03,0x00,0x00,0x29,0x04,0x02,0x00,0x29, - 0x05,0xfe,0xff,0x42,0x01,0x04,0x02,0x36,0x02,0x04,0x00,0x38,0x02,0x01,0x02,0x0a, - 0x02,0x00,0x00,0x58,0x02,0x12,0x80,0x36,0x02,0x04,0x00,0x38,0x00,0x01,0x02,0x58, - 0x01,0x0f,0x80,0x36,0x01,0x00,0x00,0x12,0x03,0x00,0x00,0x42,0x01,0x02,0x02,0x07, - 0x01,0x05,0x00,0x58,0x01,0x0a,0x80,0x36,0x01,0x06,0x00,0x12,0x03,0x00,0x00,0x42, - 0x01,0x02,0x04,0x48,0x04,0x04,0x80,0x36,0x06,0x07,0x00,0x12,0x08,0x05,0x00,0x42, - 0x06,0x02,0x02,0x3c,0x06,0x04,0x00,0x46,0x04,0x03,0x03,0x52,0x04,0xfa,0x7f,0x4c, - 0x00,0x02,0x00,0x10,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x61,0x72,0x67,0x0a, - 0x70,0x61,0x69,0x72,0x73,0x0a,0x74,0x61,0x62,0x6c,0x65,0x09,0x76,0x61,0x72,0x73, - 0x06,0x25,0x08,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x09,0x74,0x79, - 0x70,0x65,0xc8,0x09,0x00,0x01,0x18,0x00,0x1a,0x01,0x83,0x02,0x2b,0x01,0x02,0x00, - 0x2b,0x02,0x01,0x00,0x2c,0x03,0x0b,0x00,0x2b,0x0c,0x01,0x00,0x29,0x0d,0x01,0x00, - 0x15,0x0e,0x00,0x00,0x03,0x0d,0x0e,0x00,0x58,0x0e,0xfa,0x80,0x55,0x0e,0xf9,0x80, - 0x38,0x0e,0x0d,0x00,0x34,0x0f,0x00,0x00,0x36,0x10,0x00,0x00,0x12,0x12,0x0e,0x00, - 0x42,0x10,0x02,0x04,0x58,0x13,0x08,0x80,0x09,0x13,0x00,0x00,0x58,0x15,0x02,0x80, - 0x3c,0x14,0x13,0x0f,0x58,0x15,0x04,0x80,0x36,0x15,0x01,0x00,0x12,0x17,0x14,0x00, - 0x42,0x15,0x02,0x02,0x3c,0x15,0x13,0x0f,0x45,0x13,0x03,0x03,0x52,0x13,0xf6,0x7f, - 0x36,0x10,0x02,0x00,0x39,0x10,0x03,0x10,0x12,0x12,0x0f,0x00,0x29,0x13,0x01,0x00, - 0x42,0x10,0x03,0x02,0x36,0x11,0x04,0x00,0x38,0x11,0x10,0x11,0x0f,0x00,0x11,0x00, - 0x58,0x12,0x0e,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x0c,0x80,0x12,0x12,0x11,0x00, - 0x36,0x14,0x05,0x00,0x12,0x16,0x0f,0x00,0x42,0x14,0x02,0x00,0x41,0x12,0x00,0x02, - 0x36,0x13,0x06,0x00,0x38,0x13,0x10,0x13,0x0e,0x00,0x13,0x00,0x58,0x13,0xb5,0x80, - 0x36,0x13,0x07,0x00,0x3d,0x12,0x08,0x13,0x58,0x12,0xb2,0x80,0x07,0x10,0x09,0x00, - 0x58,0x12,0x08,0x80,0x36,0x12,0x0a,0x00,0x36,0x14,0x05,0x00,0x12,0x16,0x0f,0x00, - 0x42,0x14,0x02,0x00,0x41,0x12,0x00,0x02,0x12,0x01,0x12,0x00,0x12,0x02,0x01,0x00, - 0x58,0x12,0xa8,0x80,0x07,0x10,0x0b,0x00,0x58,0x12,0x0e,0x80,0x0f,0x00,0x01,0x00, - 0x58,0x12,0x02,0x80,0x2b,0x01,0x01,0x00,0x58,0x12,0xa2,0x80,0x0e,0x00,0x02,0x00, - 0x58,0x12,0xa0,0x80,0x36,0x12,0x0a,0x00,0x36,0x14,0x05,0x00,0x12,0x16,0x0f,0x00, - 0x42,0x14,0x02,0x00,0x41,0x12,0x00,0x02,0x12,0x01,0x12,0x00,0x12,0x02,0x01,0x00, - 0x58,0x12,0x98,0x80,0x07,0x10,0x0c,0x00,0x58,0x12,0x08,0x80,0x0e,0x00,0x01,0x00, - 0x58,0x12,0x02,0x80,0x13,0x01,0x02,0x00,0x58,0x12,0x92,0x80,0x2b,0x01,0x01,0x00, - 0x58,0x12,0x01,0x80,0x2b,0x01,0x02,0x00,0x58,0x12,0x8e,0x80,0x07,0x10,0x0d,0x00, - 0x58,0x12,0x02,0x80,0x2b,0x01,0x02,0x00,0x58,0x12,0x8a,0x80,0x07,0x10,0x0e,0x00, - 0x58,0x12,0x06,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x04,0x80,0x27,0x05,0x0f,0x00, - 0x34,0x07,0x00,0x00,0x3a,0x08,0x02,0x0f,0x58,0x12,0x82,0x80,0x07,0x10,0x10,0x00, - 0x58,0x12,0x0e,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x0c,0x80,0x3a,0x05,0x02,0x0f, - 0x3a,0x07,0x03,0x0f,0x36,0x12,0x04,0x00,0x39,0x12,0x11,0x12,0x12,0x14,0x07,0x00, - 0x42,0x12,0x02,0x02,0x12,0x08,0x12,0x00,0x36,0x12,0x07,0x00,0x3a,0x13,0x01,0x08, - 0x38,0x13,0x13,0x07,0x3c,0x13,0x05,0x12,0x58,0x12,0x72,0x80,0x07,0x10,0x12,0x00, - 0x58,0x12,0x1f,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x1d,0x80,0x12,0x03,0x0d,0x00, - 0x27,0x06,0x13,0x00,0x3a,0x04,0x01,0x0f,0x3a,0x0a,0x03,0x0f,0x3a,0x12,0x04,0x0f, - 0x0c,0x0b,0x12,0x00,0x58,0x13,0x01,0x80,0x29,0x0b,0x01,0x00,0x36,0x12,0x07,0x00, - 0x3a,0x13,0x02,0x0f,0x3c,0x13,0x04,0x12,0x29,0x12,0x00,0x00,0x01,0x12,0x0b,0x00, - 0x58,0x12,0x04,0x80,0x36,0x12,0x07,0x00,0x38,0x12,0x04,0x12,0x00,0x0a,0x12,0x00, - 0x58,0x12,0x09,0x80,0x29,0x12,0x00,0x00,0x01,0x0b,0x12,0x00,0x58,0x12,0x04,0x80, - 0x36,0x12,0x07,0x00,0x38,0x12,0x04,0x12,0x00,0x12,0x0a,0x00,0x58,0x12,0x02,0x80, - 0x2b,0x0c,0x01,0x00,0x58,0x12,0x01,0x80,0x2b,0x0c,0x02,0x00,0x58,0x12,0x51,0x80, - 0x07,0x10,0x14,0x00,0x58,0x12,0x12,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x10,0x80, - 0x36,0x12,0x02,0x00,0x39,0x12,0x03,0x12,0x12,0x14,0x0f,0x00,0x29,0x15,0x01,0x00, - 0x42,0x12,0x03,0x02,0x07,0x12,0x09,0x00,0x58,0x12,0x07,0x80,0x36,0x12,0x0a,0x00, - 0x36,0x14,0x05,0x00,0x12,0x16,0x0f,0x00,0x42,0x14,0x02,0x00,0x41,0x12,0x00,0x02, - 0x12,0x0c,0x12,0x00,0x58,0x12,0x3f,0x80,0x2b,0x0c,0x02,0x00,0x58,0x12,0x3d,0x80, - 0x07,0x10,0x15,0x00,0x58,0x12,0x2b,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x29,0x80, - 0x07,0x06,0x16,0x00,0x58,0x12,0x0d,0x80,0x16,0x09,0x00,0x09,0x15,0x12,0x08,0x00, - 0x03,0x09,0x12,0x00,0x58,0x12,0x33,0x80,0x36,0x12,0x07,0x00,0x38,0x13,0x09,0x08, - 0x3c,0x13,0x04,0x12,0x36,0x12,0x07,0x00,0x38,0x13,0x09,0x08,0x38,0x13,0x13,0x07, - 0x3c,0x13,0x05,0x12,0x12,0x0d,0x03,0x00,0x58,0x12,0x2a,0x80,0x07,0x06,0x13,0x00, - 0x58,0x12,0x16,0x80,0x36,0x12,0x07,0x00,0x36,0x13,0x07,0x00,0x38,0x13,0x04,0x13, - 0x20,0x13,0x0b,0x13,0x3c,0x13,0x04,0x12,0x29,0x12,0x00,0x00,0x01,0x12,0x0b,0x00, - 0x58,0x12,0x04,0x80,0x36,0x12,0x07,0x00,0x38,0x12,0x04,0x12,0x00,0x0a,0x12,0x00, - 0x58,0x12,0x1c,0x80,0x29,0x12,0x00,0x00,0x01,0x0b,0x12,0x00,0x58,0x12,0x05,0x80, - 0x36,0x12,0x07,0x00,0x38,0x12,0x04,0x12,0x01,0x12,0x0a,0x00,0x58,0x12,0x01,0x80, - 0x58,0x12,0x14,0x80,0x12,0x0d,0x03,0x00,0x58,0x12,0x12,0x80,0x29,0x0d,0x00,0x00, - 0x58,0x12,0x10,0x80,0x07,0x10,0x17,0x00,0x58,0x12,0x06,0x80,0x0f,0x00,0x01,0x00, - 0x58,0x12,0x04,0x80,0x36,0x12,0x05,0x00,0x12,0x14,0x0f,0x00,0x44,0x12,0x02,0x00, - 0x58,0x12,0x08,0x80,0x0f,0x00,0x01,0x00,0x58,0x12,0x06,0x80,0x36,0x12,0x18,0x00, - 0x2b,0x14,0x01,0x00,0x27,0x15,0x19,0x00,0x12,0x16,0x10,0x00,0x26,0x15,0x16,0x15, - 0x42,0x12,0x03,0x01,0x0f,0x00,0x01,0x00,0x58,0x12,0x11,0x80,0x06,0x10,0x0e,0x00, - 0x58,0x12,0x02,0x80,0x07,0x10,0x10,0x00,0x58,0x12,0x0d,0x80,0x12,0x03,0x0d,0x00, - 0x27,0x06,0x16,0x00,0x3a,0x04,0x01,0x0f,0x29,0x09,0x01,0x00,0x36,0x12,0x07,0x00, - 0x3a,0x13,0x01,0x08,0x3c,0x13,0x04,0x12,0x3a,0x12,0x01,0x08,0x0a,0x12,0x00,0x00, - 0x58,0x12,0x02,0x80,0x2b,0x0c,0x01,0x00,0x58,0x12,0x01,0x80,0x2b,0x0c,0x02,0x00, - 0x0f,0x00,0x0c,0x00,0x58,0x12,0x09,0x80,0x55,0x12,0x07,0x80,0x16,0x0d,0x00,0x0d, - 0x38,0x0e,0x0d,0x00,0x0a,0x0e,0x00,0x00,0x58,0x12,0x03,0x80,0x3a,0x12,0x01,0x0e, - 0x07,0x12,0x15,0x00,0x58,0x12,0xf8,0x7f,0x2b,0x0c,0x01,0x00,0x16,0x0d,0x00,0x0d, - 0x58,0x0e,0x03,0x7f,0x4b,0x00,0x01,0x00,0x18,0x63,0x6f,0x6d,0x6d,0x61,0x6e,0x64, - 0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x3a,0x20,0x0b,0x61,0x73,0x73, - 0x65,0x72,0x74,0x0b,0x72,0x65,0x74,0x75,0x72,0x6e,0x09,0x65,0x61,0x63,0x68,0x09, - 0x6c,0x6f,0x6f,0x70,0x0a,0x62,0x72,0x65,0x61,0x6b,0x0b,0x6e,0x75,0x6d,0x62,0x65, - 0x72,0x08,0x66,0x6f,0x72,0x0d,0x67,0x65,0x74,0x5f,0x6b,0x65,0x79,0x73,0x0c,0x66, - 0x6f,0x72,0x70,0x61,0x69,0x72,0x07,0x5f,0x5f,0x0c,0x66,0x6f,0x72,0x65,0x61,0x63, - 0x68,0x08,0x65,0x6e,0x64,0x09,0x65,0x6c,0x73,0x65,0x09,0x65,0x6c,0x69,0x66,0x09, - 0x65,0x76,0x61,0x6c,0x07,0x69,0x66,0x10,0x6c,0x61,0x73,0x74,0x5f,0x72,0x65,0x73, - 0x75,0x6c,0x74,0x09,0x76,0x61,0x72,0x73,0x09,0x73,0x6b,0x69,0x70,0x0b,0x75,0x6e, - 0x70,0x61,0x63,0x6b,0x0b,0x61,0x63,0x74,0x69,0x6f,0x6e,0x0b,0x72,0x65,0x6d,0x6f, - 0x76,0x65,0x0a,0x74,0x61,0x62,0x6c,0x65,0x10,0x70,0x72,0x6f,0x63,0x65,0x73,0x73, - 0x5f,0x61,0x72,0x67,0x0b,0x69,0x70,0x61,0x69,0x72,0x73,0x02,0xc7,0x04,0x02,0x00, - 0x0d,0x00,0x0f,0x01,0x7b,0x34,0x00,0x03,0x00,0x47,0x01,0x00,0x00,0x3f,0x01,0x00, - 0x00,0x3a,0x01,0x01,0x00,0x3a,0x02,0x02,0x00,0x3a,0x03,0x03,0x00,0x2b,0x04,0x01, - 0x00,0x2b,0x05,0x01,0x00,0x36,0x06,0x00,0x00,0x39,0x06,0x01,0x06,0x12,0x08,0x02, - 0x00,0x29,0x09,0x01,0x00,0x29,0x0a,0x01,0x00,0x42,0x06,0x04,0x02,0x07,0x06,0x02, - 0x00,0x58,0x06,0x07,0x80,0x2b,0x04,0x02,0x00,0x36,0x06,0x00,0x00,0x39,0x06,0x01, - 0x06,0x12,0x08,0x02,0x00,0x29,0x09,0x02,0x00,0x42,0x06,0x03,0x02,0x12,0x02,0x06, - 0x00,0x0b,0x01,0x00,0x00,0x58,0x06,0x03,0x80,0x06,0x02,0x03,0x00,0x58,0x06,0x01, - 0x80,0x58,0x06,0x3b,0x80,0x07,0x02,0x03,0x00,0x58,0x06,0x06,0x80,0x04,0x01,0x03, - 0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02, - 0x00,0x58,0x06,0x33,0x80,0x07,0x02,0x04,0x00,0x58,0x06,0x06,0x80,0x00,0x03,0x01, - 0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02, - 0x00,0x58,0x06,0x2b,0x80,0x07,0x02,0x05,0x00,0x58,0x06,0x06,0x80,0x02,0x03,0x01, - 0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02, - 0x00,0x58,0x06,0x23,0x80,0x07,0x02,0x06,0x00,0x58,0x06,0x06,0x80,0x00,0x01,0x03, - 0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02, - 0x00,0x58,0x06,0x1b,0x80,0x07,0x02,0x07,0x00,0x58,0x06,0x06,0x80,0x02,0x01,0x03, - 0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01,0x80,0x2b,0x05,0x02, - 0x00,0x58,0x06,0x13,0x80,0x07,0x02,0x08,0x00,0x58,0x06,0x0b,0x80,0x36,0x06,0x00, - 0x00,0x39,0x06,0x08,0x06,0x12,0x08,0x01,0x00,0x12,0x09,0x03,0x00,0x42,0x06,0x03, - 0x02,0x0b,0x06,0x00,0x00,0x58,0x06,0x02,0x80,0x2b,0x05,0x01,0x00,0x58,0x06,0x01, - 0x80,0x2b,0x05,0x02,0x00,0x58,0x06,0x06,0x80,0x36,0x06,0x09,0x00,0x2b,0x08,0x01, - 0x00,0x27,0x09,0x0a,0x00,0x12,0x0a,0x02,0x00,0x26,0x09,0x0a,0x09,0x42,0x06,0x03, - 0x01,0x0f,0x00,0x04,0x00,0x58,0x06,0x01,0x80,0x13,0x05,0x05,0x00,0x15,0x06,0x00, - 0x00,0x29,0x07,0x03,0x00,0x01,0x07,0x06,0x00,0x58,0x06,0x1c,0x80,0x3a,0x02,0x04, - 0x00,0x36,0x06,0x0b,0x00,0x36,0x08,0x0c,0x00,0x12,0x0a,0x00,0x00,0x29,0x0b,0x05, - 0x00,0x15,0x0c,0x00,0x00,0x42,0x08,0x04,0x00,0x41,0x06,0x00,0x02,0x07,0x02,0x0d, - 0x00,0x58,0x07,0x05,0x80,0x0d,0x07,0x05,0x00,0x58,0x07,0x01,0x80,0x12,0x07,0x06, - 0x00,0x4c,0x07,0x02,0x00,0x58,0x07,0x0d,0x80,0x07,0x02,0x0e,0x00,0x58,0x07,0x05, - 0x80,0x0c,0x07,0x05,0x00,0x58,0x07,0x01,0x80,0x12,0x07,0x06,0x00,0x4c,0x07,0x02, - 0x00,0x58,0x07,0x06,0x80,0x36,0x07,0x09,0x00,0x2b,0x09,0x01,0x00,0x27,0x0a,0x0a, - 0x00,0x12,0x0b,0x02,0x00,0x26,0x0a,0x0b,0x0a,0x42,0x07,0x03,0x01,0x4c,0x05,0x02, - 0x00,0x07,0x6f,0x72,0x08,0x61,0x6e,0x64,0x0b,0x75,0x6e,0x70,0x61,0x63,0x6b,0x09, - 0x65,0x76,0x61,0x6c,0x19,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x20,0x6e,0x6f, - 0x74,0x20,0x6b,0x6e,0x6f,0x77,0x6e,0x3a,0x20,0x0b,0x61,0x73,0x73,0x65,0x72,0x74, - 0x0a,0x6d,0x61,0x74,0x63,0x68,0x07,0x3c,0x3d,0x06,0x3c,0x07,0x3e,0x3d,0x06,0x3e, - 0x06,0x3d,0x06,0x21,0x08,0x73,0x75,0x62,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x03, - 0x80,0x80,0xc0,0x99,0x04,0xab,0x05,0x00,0x02,0x0e,0x00,0x18,0x02,0x73,0x36,0x02, - 0x00,0x00,0x12,0x04,0x00,0x00,0x42,0x02,0x02,0x02,0x06,0x02,0x01,0x00,0x58,0x02, - 0x04,0x80,0x36,0x02,0x02,0x00,0x12,0x04,0x00,0x00,0x42,0x02,0x02,0x02,0x12,0x00, - 0x02,0x00,0x36,0x02,0x03,0x00,0x36,0x04,0x01,0x00,0x39,0x04,0x04,0x04,0x12,0x06, - 0x00,0x00,0x27,0x07,0x05,0x00,0x42,0x04,0x03,0x02,0x0a,0x04,0x00,0x00,0x58,0x04, - 0x02,0x80,0x2b,0x04,0x01,0x00,0x58,0x05,0x01,0x80,0x2b,0x04,0x02,0x00,0x27,0x05, - 0x06,0x00,0x42,0x02,0x03,0x01,0x36,0x02,0x01,0x00,0x39,0x02,0x07,0x02,0x12,0x04, - 0x00,0x00,0x27,0x05,0x08,0x00,0x27,0x06,0x09,0x00,0x42,0x02,0x04,0x03,0x36,0x04, - 0x03,0x00,0x29,0x06,0x01,0x00,0x02,0x03,0x06,0x00,0x58,0x06,0x02,0x80,0x2b,0x06, - 0x01,0x00,0x58,0x07,0x01,0x80,0x2b,0x06,0x02,0x00,0x27,0x07,0x0a,0x00,0x42,0x04, - 0x03,0x01,0x09,0x03,0x00,0x00,0x58,0x04,0x48,0x80,0x2b,0x04,0x00,0x00,0x12,0x07, - 0x01,0x00,0x39,0x05,0x0b,0x01,0x42,0x05,0x02,0x02,0x07,0x05,0x0c,0x00,0x58,0x05, - 0x02,0x80,0x29,0x04,0x12,0x00,0x58,0x05,0x06,0x80,0x36,0x05,0x0d,0x00,0x39,0x05, - 0x0e,0x05,0x12,0x07,0x01,0x00,0x27,0x08,0x0f,0x00,0x42,0x05,0x03,0x02,0x12,0x04, - 0x05,0x00,0x36,0x05,0x03,0x00,0x29,0x07,0x00,0x00,0x03,0x07,0x04,0x00,0x58,0x07, - 0x03,0x80,0x29,0x07,0x12,0x00,0x02,0x04,0x07,0x00,0x58,0x07,0x02,0x80,0x2b,0x07, - 0x01,0x00,0x58,0x08,0x01,0x80,0x2b,0x07,0x02,0x00,0x27,0x08,0x10,0x00,0x42,0x05, - 0x03,0x01,0x36,0x05,0x01,0x00,0x39,0x05,0x04,0x05,0x27,0x07,0x11,0x00,0x12,0x08, - 0x00,0x00,0x27,0x09,0x11,0x00,0x26,0x07,0x09,0x07,0x27,0x08,0x12,0x00,0x42,0x05, - 0x03,0x03,0x15,0x07,0x06,0x00,0x21,0x07,0x07,0x04,0x29,0x08,0x00,0x00,0x01,0x08, - 0x07,0x00,0x58,0x08,0x08,0x80,0x12,0x08,0x06,0x00,0x36,0x09,0x01,0x00,0x39,0x09, - 0x13,0x09,0x27,0x0b,0x11,0x00,0x12,0x0c,0x07,0x00,0x42,0x09,0x03,0x02,0x26,0x06, - 0x09,0x08,0x58,0x08,0x0a,0x80,0x29,0x08,0x00,0x00,0x01,0x07,0x08,0x00,0x58,0x08, - 0x07,0x80,0x36,0x08,0x01,0x00,0x39,0x08,0x14,0x08,0x12,0x0a,0x06,0x00,0x29,0x0b, - 0x01,0x00,0x12,0x0c,0x04,0x00,0x42,0x08,0x04,0x02,0x12,0x06,0x08,0x00,0x12,0x08, - 0x05,0x00,0x12,0x09,0x06,0x00,0x26,0x00,0x09,0x08,0x36,0x08,0x01,0x00,0x39,0x08, - 0x07,0x08,0x12,0x0a,0x00,0x00,0x27,0x0b,0x15,0x00,0x27,0x0c,0x09,0x00,0x29,0x0d, - 0x01,0x00,0x42,0x08,0x05,0x02,0x12,0x00,0x08,0x00,0x15,0x08,0x00,0x00,0x09,0x08, - 0x01,0x00,0x58,0x08,0x01,0x80,0x27,0x00,0x11,0x00,0x36,0x04,0x16,0x00,0x39,0x04, - 0x17,0x04,0x12,0x06,0x00,0x00,0x44,0x04,0x02,0x00,0x0b,0x6e,0x75,0x6d,0x62,0x65, - 0x72,0x0b,0x62,0x69,0x67,0x6e,0x75,0x6d,0x07,0x30,0x2a,0x08,0x73,0x75,0x62,0x08, - 0x72,0x65,0x70,0x11,0x28,0x25,0x64,0x2b,0x29,0x25,0x2e,0x28,0x25,0x64,0x2b,0x29, - 0x06,0x30,0x20,0x74,0x6f,0x6b,0x65,0x6e,0x20,0x77,0x69,0x74,0x68,0x20,0x69,0x6e, - 0x76,0x61,0x6c,0x69,0x64,0x20,0x64,0x65,0x63,0x69,0x6d,0x61,0x6c,0x73,0x0d,0x64, - 0x65,0x63,0x69,0x6d,0x61,0x6c,0x73,0x09,0x63,0x61,0x6c,0x6c,0x0d,0x63,0x6f,0x6e, - 0x74,0x72,0x61,0x63,0x74,0x0a,0x61,0x65,0x72,0x67,0x6f,0x0a,0x6c,0x6f,0x77,0x65, - 0x72,0x1a,0x74,0x68,0x65,0x20,0x61,0x6d,0x6f,0x75,0x6e,0x74,0x20,0x69,0x73,0x20, - 0x69,0x6e,0x76,0x61,0x6c,0x69,0x64,0x05,0x07,0x25,0x2e,0x09,0x67,0x73,0x75,0x62, - 0x2a,0x74,0x68,0x65,0x20,0x61,0x6d,0x6f,0x75,0x6e,0x74,0x20,0x63,0x6f,0x6e,0x74, - 0x61,0x69,0x6e,0x73,0x20,0x69,0x6e,0x76,0x61,0x6c,0x69,0x64,0x20,0x63,0x68,0x61, - 0x72,0x61,0x63,0x74,0x65,0x72,0x0c,0x5b,0x5e,0x30,0x2d,0x39,0x2e,0x5d,0x0a,0x6d, - 0x61,0x74,0x63,0x68,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x0d,0x74,0x6f,0x73,0x74, - 0x72,0x69,0x6e,0x67,0x0b,0x73,0x74,0x72,0x69,0x6e,0x67,0x09,0x74,0x79,0x70,0x65, - 0x02,0x00,0xba,0x05,0x03,0x00,0x03,0x00,0x4f,0x00,0x53,0x34,0x00,0x00,0x00,0x37, - 0x00,0x00,0x00,0x35,0x00,0x01,0x00,0x37,0x00,0x02,0x00,0x35,0x00,0x04,0x00,0x33, - 0x01,0x03,0x00,0x3d,0x01,0x05,0x00,0x33,0x01,0x06,0x00,0x3d,0x01,0x07,0x00,0x33, - 0x01,0x08,0x00,0x3d,0x01,0x09,0x00,0x33,0x01,0x0a,0x00,0x3d,0x01,0x0b,0x00,0x33, - 0x01,0x0c,0x00,0x3d,0x01,0x0d,0x00,0x33,0x01,0x0e,0x00,0x3d,0x01,0x0f,0x00,0x33, - 0x01,0x10,0x00,0x3d,0x01,0x11,0x00,0x33,0x01,0x12,0x00,0x3d,0x01,0x13,0x00,0x33, - 0x01,0x14,0x00,0x3d,0x01,0x15,0x00,0x33,0x01,0x16,0x00,0x3d,0x01,0x17,0x00,0x33, - 0x01,0x18,0x00,0x3d,0x01,0x19,0x00,0x33,0x01,0x1a,0x00,0x3d,0x01,0x1b,0x00,0x33, - 0x01,0x1c,0x00,0x3d,0x01,0x1d,0x00,0x33,0x01,0x1e,0x00,0x3d,0x01,0x1f,0x00,0x33, - 0x01,0x20,0x00,0x3d,0x01,0x21,0x00,0x33,0x01,0x22,0x00,0x3d,0x01,0x23,0x00,0x33, - 0x01,0x24,0x00,0x3d,0x01,0x25,0x00,0x33,0x01,0x26,0x00,0x3d,0x01,0x27,0x00,0x33, - 0x01,0x28,0x00,0x3d,0x01,0x29,0x00,0x33,0x01,0x2a,0x00,0x3d,0x01,0x2b,0x00,0x33, - 0x01,0x2c,0x00,0x3d,0x01,0x2d,0x00,0x33,0x01,0x2e,0x00,0x3d,0x01,0x2f,0x00,0x33, - 0x01,0x30,0x00,0x3d,0x01,0x31,0x00,0x33,0x01,0x32,0x00,0x3d,0x01,0x33,0x00,0x33, - 0x01,0x34,0x00,0x3d,0x01,0x35,0x00,0x33,0x01,0x36,0x00,0x3d,0x01,0x37,0x00,0x33, - 0x01,0x38,0x00,0x3d,0x01,0x39,0x00,0x33,0x01,0x3a,0x00,0x3d,0x01,0x3b,0x00,0x33, - 0x01,0x3c,0x00,0x3d,0x01,0x3d,0x00,0x33,0x01,0x3e,0x00,0x3d,0x01,0x3f,0x00,0x33, - 0x01,0x40,0x00,0x3d,0x01,0x41,0x00,0x33,0x01,0x42,0x00,0x3d,0x01,0x43,0x00,0x37, - 0x00,0x44,0x00,0x33,0x00,0x45,0x00,0x37,0x00,0x46,0x00,0x33,0x00,0x47,0x00,0x37, - 0x00,0x48,0x00,0x33,0x00,0x49,0x00,0x37,0x00,0x4a,0x00,0x33,0x00,0x4b,0x00,0x37, - 0x00,0x4c,0x00,0x36,0x00,0x4d,0x00,0x39,0x00,0x4e,0x00,0x36,0x02,0x48,0x00,0x42, - 0x00,0x02,0x01,0x4b,0x00,0x01,0x00,0x0d,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72, - 0x08,0x61,0x62,0x69,0x13,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x62,0x69,0x67, - 0x6e,0x75,0x6d,0x00,0x09,0x65,0x76,0x61,0x6c,0x00,0x0c,0x65,0x78,0x65,0x63,0x75, - 0x74,0x65,0x00,0x10,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x61,0x72,0x67,0x00, - 0x0b,0x61,0x63,0x74,0x69,0x6f,0x6e,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x00,0x0d, - 0x66,0x72,0x6f,0x6d,0x6a,0x73,0x6f,0x6e,0x00,0x0b,0x74,0x6f,0x6a,0x73,0x6f,0x6e, - 0x00,0x0d,0x74,0x6f,0x73,0x74,0x72,0x69,0x6e,0x67,0x00,0x0d,0x74,0x6f,0x6e,0x75, - 0x6d,0x62,0x65,0x72,0x00,0x0d,0x74,0x6f,0x62,0x69,0x67,0x6e,0x75,0x6d,0x00,0x0c, - 0x72,0x65,0x70,0x6c,0x61,0x63,0x65,0x00,0x09,0x66,0x69,0x6e,0x64,0x00,0x0b,0x73, - 0x75,0x62,0x73,0x74,0x72,0x00,0x0b,0x66,0x6f,0x72,0x6d,0x61,0x74,0x00,0x0b,0x63, - 0x6f,0x6e,0x63,0x61,0x74,0x00,0x09,0x73,0x71,0x72,0x74,0x00,0x08,0x6d,0x6f,0x64, - 0x00,0x08,0x70,0x6f,0x77,0x00,0x08,0x64,0x69,0x76,0x00,0x08,0x6d,0x75,0x6c,0x00, - 0x08,0x73,0x75,0x62,0x00,0x08,0x61,0x64,0x64,0x00,0x0d,0x67,0x65,0x74,0x5f,0x6b, - 0x65,0x79,0x73,0x00,0x0d,0x67,0x65,0x74,0x5f,0x73,0x69,0x7a,0x65,0x00,0x0b,0x72, - 0x65,0x6d,0x6f,0x76,0x65,0x00,0x0b,0x69,0x6e,0x73,0x65,0x72,0x74,0x00,0x08,0x73, - 0x65,0x74,0x00,0x08,0x67,0x65,0x74,0x00,0x0a,0x73,0x74,0x6f,0x72,0x65,0x00,0x08, - 0x6c,0x65,0x74,0x00,0x09,0x73,0x65,0x6e,0x64,0x00,0x0c,0x62,0x61,0x6c,0x61,0x6e, - 0x63,0x65,0x00,0x0f,0x70,0x63,0x61,0x6c,0x6c,0x2d,0x73,0x65,0x6e,0x64,0x00,0x0a, - 0x70,0x63,0x61,0x6c,0x6c,0x00,0x0e,0x63,0x61,0x6c,0x6c,0x2d,0x73,0x65,0x6e,0x64, - 0x00,0x09,0x63,0x61,0x6c,0x6c,0x01,0x00,0x00,0x00,0x09,0x73,0x6b,0x69,0x70,0x01, - 0x00,0x06,0x0b,0x69,0x6e,0x73,0x65,0x72,0x74,0x02,0x08,0x6c,0x65,0x74,0x02,0x0a, - 0x73,0x74,0x6f,0x72,0x65,0x02,0x09,0x73,0x65,0x6e,0x64,0x02,0x08,0x73,0x65,0x74, - 0x02,0x0b,0x61,0x73,0x73,0x65,0x72,0x74,0x02,0x09,0x76,0x61,0x72,0x73,0x00,0x7b, - 0x22,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x22,0x3a,0x22,0x30,0x2e,0x32,0x22,0x2c, - 0x22,0x6c,0x61,0x6e,0x67,0x75,0x61,0x67,0x65,0x22,0x3a,0x22,0x6c,0x75,0x61,0x22, - 0x2c,0x22,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x73,0x22,0x3a,0x5b,0x7b,0x22, - 0x6e,0x61,0x6d,0x65,0x22,0x3a,0x22,0x65,0x78,0x65,0x63,0x75,0x74,0x65,0x22,0x2c, - 0x22,0x61,0x72,0x67,0x75,0x6d,0x65,0x6e,0x74,0x73,0x22,0x3a,0x5b,0x7b,0x22,0x6e, - 0x61,0x6d,0x65,0x22,0x3a,0x22,0x63,0x61,0x6c,0x6c,0x73,0x22,0x7d,0x5d,0x7d,0x5d, - 0x7d, +import ( + luacUtil "github.com/aergoio/aergo/v2/cmd/aergoluac/util" +) + +var multicall_payload luacUtil.LuaCode + +const multicall_code = ` +vars = {} + +skip = {store=true,let=true,set=true,insert=true,assert=true,send=true} + +action = { + + -- contract call + call = function (...) return contract.call(...) end, + ["call-send"] = function (amount,...) return contract.call.value(amount)(...) end, + ["pcall"] = function (...) return {pcall(contract.call,...)} end, + ["pcall-send"] = function (amount,...) return {pcall(contract.call.value(amount),...)} end, + + -- aergo balance and transfer + balance = function (address) return bignum.number(contract.balance(address)) end, + send = function (address,amount) return contract.send(address, amount) end, + + -- variables + let = function (x,y,z) if z then y = convert_bignum(y,z) end vars[x] = y end, + store = function (n) vars[n] = vars['last_result'] end, + + -- tables + get = function (o,k) return o[k] end, + set = function (o,k,v) o[k] = v end, + insert = function (...) table.insert(...) end, -- inserts at the end if no pos informed + remove = function (...) return table.remove(...) end, -- returns the removed item + get_size = function (x) return #x end, + get_keys = function (obj) + local list = {} + for key,_ in pairs(obj) do + list[#list + 1] = key + end + table.sort(list) -- for a deterministic output + return list + end, + + -- math + add = function (x,y) return x+y end, + sub = function (x,y) return x-y end, + mul = function (x,y) return x*y end, + div = function (x,y) return x/y end, + pow = function (x,y) return x^y end, + mod = function (x,y) return x%y end, + sqrt = function (x) return bignum.sqrt(x) end, -- use pow(0.5) for numbers + + -- strings + concat = function (...) return table.concat({...}) end, + format = function (...) return string.format(...) end, -- for concat: ['format','%s%s','%val1%','%val2%'] + substr = function (...) return string.sub(...) end, + find = function (...) return string.match(...) end, + replace = function (...) return string.gsub(...) end, + + -- conversions + tobignum = function (x) return bignum.number(x) end, + tonumber = function (x) return tonumber(x) end, + tostring = function (x) return tostring(x) end, -- bignum to string + tojson = function (x) return json.encode(x) end, + fromjson = function (x) return json.decode(x) end, -- create tables + + -- assertion + assert = function (...) assert(eval(...),"assertion failed: " .. json.encode({...})) end, + } + +function process_arg(arg) + if type(arg) == 'string' then + if #arg >= 3 and string.sub(arg, 1, 1) == '%' and string.sub(arg, -1, -1) == '%' then + local varname = string.sub(arg, 2, -2) + if vars[varname] ~= nil then + arg = vars[varname] + end + end + elseif type(arg) == 'table' then + for k,v in pairs(arg) do arg[k] = process_arg(v) end + end + return arg +end + +function execute(calls) + + local if_on = true + local if_done = false + + local for_cmdpos + local for_var, for_var2, for_type + local for_obj, for_list, for_pos + local for_last, for_increment + local skip_for = false + + local cmdpos = 1 + while cmdpos <= #calls do + local call = calls[cmdpos] + local args = {} -- use a copy of the list because of loops + + -- copy values and process variables + for i,arg in ipairs(call) do + if i == 1 then + args[i] = arg + else + args[i] = process_arg(arg) + end + end + + -- process the command + local cmd = table.remove(args, 1) + local fn = action[cmd] + if fn and if_on then + local result = fn(unpack(args)) + if not skip[cmd] then + vars['last_result'] = result + end + + -- if elif else end + elseif cmd == "if" then + if_on = eval(unpack(args)) + if_done = if_on + elseif cmd == "elif" then + if if_on then + if_on = false + elseif not if_done then + if_on = eval(unpack(args)) + if_done = if_on + end + elseif cmd == "else" then + if_on = (not if_on) and (not if_done) + elseif cmd == "end" then + if_on = true + + -- for foreach forpair break loop + elseif cmd == "foreach" and if_on then + for_var2 = "__" + for_obj = {} + for_list = args[2] + elseif cmd == "forpair" and if_on then + for_var2 = args[2] + for_obj = args[3] + for_list = action["get_keys"](for_obj) + vars[for_var2] = for_obj[for_list[1]] + elseif cmd == "for" and if_on then + for_cmdpos = cmdpos + for_type = "number" + for_var = args[1] + for_last = args[3] + for_increment = args[4] or 1 + vars[for_var] = args[2] + skip_for = ((for_increment > 0 and vars[for_var] > for_last) or (for_increment < 0 and vars[for_var] < for_last)) + elseif cmd == "break" and if_on then + if table.remove(args, 1) == "if" then + skip_for = eval(unpack(args)) + else + skip_for = true + end + elseif cmd == "loop" and if_on then + if for_type == "each" then + for_pos = for_pos + 1 + if for_pos <= #for_list then + vars[for_var] = for_list[for_pos] + vars[for_var2] = for_obj[for_list[for_pos]] + cmdpos = for_cmdpos + end + elseif for_type == "number" then + vars[for_var] = vars[for_var] + for_increment + if (for_increment > 0 and vars[for_var] > for_last) or (for_increment < 0 and vars[for_var] < for_last) then + -- quit loop (continue to the next command) + else + cmdpos = for_cmdpos + end + else + cmdpos = 0 + end + + -- return + elseif cmd == "return" and if_on then + return unpack(args) -- or the array itself + elseif if_on then + assert(false, "command not found: " .. cmd) + end + + if if_on and (cmd == "foreach" or cmd == "forpair") then + for_cmdpos = cmdpos + for_type = "each" + for_var = args[1] + for_pos = 1 + vars[for_var] = for_list[1] + skip_for = (for_list[1] == nil) -- if the list is empty or it is a dictionary + end + + if skip_for then + repeat + cmdpos = cmdpos + 1 + call = calls[cmdpos] + until call == nil or call[1] == "loop" + skip_for = false + end + + cmdpos = cmdpos + 1 + end + +end + +function eval(...) + local args = {...} + local v1 = args[1] + local op = args[2] + local v2 = args[3] + local neg = false + local matches = false + if string.sub(op,1,1) == "!" then + neg = true + op = string.sub(op, 2) + end + if v1 == nil and op ~= "=" then + -- does not match + elseif op == "=" then + matches = v1 == v2 + elseif op == ">" then + matches = v1 > v2 + elseif op == ">=" then + matches = v1 >= v2 + elseif op == "<" then + matches = v1 < v2 + elseif op == "<=" then + matches = v1 <= v2 + elseif op == "match" then + matches = string.match(v1, v2) ~= nil + else + assert(false, "operator not known: " .. op) + end + if neg then matches = not matches end + if #args > 3 then + op = args[4] + local matches2 = eval(unpack(args, 5, #args)) + if op == "and" then + return (matches and matches2) + elseif op == "or" then + return (matches or matches2) + else + assert(false, "operator not known: " .. op) + end + end + return matches +end + +function convert_bignum(x, token) + if type(x) ~= 'string' then + x = tostring(x) + end + assert(string.match(x, '[^0-9.]') == nil, "the amount contains invalid character") + local _, count = string.gsub(x, "%.", "") + assert(count <= 1, "the amount is invalid") + if count == 1 then + local num_decimals + if token:lower() == 'aergo' then + num_decimals = 18 + else + num_decimals = contract.call(token, "decimals") + end + assert(num_decimals >= 0 and num_decimals <= 18, "token with invalid decimals") + local p1, p2 = string.match('0' .. x .. '0', '(%d+)%.(%d+)') + local to_add = num_decimals - #p2 + if to_add > 0 then + p2 = p2 .. string.rep('0', to_add) + elseif to_add < 0 then + p2 = string.sub(p2, 1, num_decimals) + end + x = p1 .. p2 + x = string.gsub(x, '0*', '', 1) -- remove leading zeros + if #x == 0 then x = '0' end + end + return bignum.number(x) +end + +abi.register(execute) +` From dca3d141cfb5e1f348a184ec4fcb26b39102e8cc Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 16 Dec 2023 03:12:45 +0000 Subject: [PATCH 116/182] add MULTICALL to aergo-protobuf --- aergo-protobuf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aergo-protobuf b/aergo-protobuf index 0c3579cd4..0ebd3322c 160000 --- a/aergo-protobuf +++ b/aergo-protobuf @@ -1 +1 @@ -Subproject commit 0c3579cd42f830eb787715a78895d971b8ee5fce +Subproject commit 0ebd3322cd33af95a70d24590d7e3a488ac8f01e From 1848b80c795977d21e481d3bd64a1a3e87112410 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sun, 17 Dec 2023 16:08:14 -0300 Subject: [PATCH 117/182] aergocli: add multicall command --- cmd/aergocli/cmd/contract.go | 58 +++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/cmd/aergocli/cmd/contract.go b/cmd/aergocli/cmd/contract.go index 010b7f6ac..3d978c64b 100644 --- a/cmd/aergocli/cmd/contract.go +++ b/cmd/aergocli/cmd/contract.go @@ -3,6 +3,7 @@ package cmd import ( "bytes" "context" + "math/big" "encoding/json" "errors" "fmt" @@ -101,6 +102,19 @@ func init() { callCmd.PersistentFlags().BoolVar(&feeDelegation, "delegation", false, "request fee delegation to contract") callCmd.Flags().StringVar(&pw, "password", "", "password (optional, will be asked on the terminal if not given)") + multicallCmd := &cobra.Command{ + Use: `multicall [flags]