From 19d246446b246e0a02f6c844ae64b63f434ca710 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 23 Jun 2022 02:47:24 -0300 Subject: [PATCH 001/101] [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 002/101] [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 9ed69370c09e7e856e7e339c5632857f5ff35e7b Mon Sep 17 00:00:00 2001 From: Sung-Jae Woo Date: Thu, 6 Oct 2022 15:58:57 +0900 Subject: [PATCH 003/101] [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 004/101] [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 005/101] [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 006/101] [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 007/101] [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 008/101] [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 009/101] [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 010/101] [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 011/101] [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 012/101] [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 013/101] [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 014/101] [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 015/101] [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 016/101] [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 017/101] 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 018/101] 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 019/101] 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 020/101] 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 021/101] [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 022/101] [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 023/101] [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 024/101] 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 025/101] 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 026/101] 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 027/101] 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 028/101] 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 9bd4c2a1661fea7a9e3f0a4891199f1361cd515f Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 10 Aug 2023 23:23:43 -0300 Subject: [PATCH 029/101] 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 030/101] 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 031/101] 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 fbaf80918285fdaf9255addf45d34fa69c9ee2be Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 6 Sep 2023 05:55:38 +0000 Subject: [PATCH 032/101] 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 033/101] 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 034/101] 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 035/101] 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 036/101] 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 037/101] 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 038/101] 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 039/101] 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 040/101] 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 041/101] 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 042/101] 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 043/101] 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 044/101] 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 045/101] 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 09fa2518774cd30641260da7e4937ffd32c24471 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 6 Oct 2023 04:07:20 +0000 Subject: [PATCH 046/101] 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 f203e2f5174a9487fb108554f7b2702d7eceae0e Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 6 Oct 2023 06:24:45 +0000 Subject: [PATCH 047/101] 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 048/101] 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 3aa380a71a652f60b5ba94fead9b5c3c8ae46ca8 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 18 Oct 2023 14:40:39 +0000 Subject: [PATCH 049/101] 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 050/101] 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 051/101] 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 052/101] 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 053/101] 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 054/101] 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 051b3e754e4d296ce49188e78848d56e910c0e1d Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Wed, 25 Oct 2023 15:13:41 +0000 Subject: [PATCH 055/101] 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 056/101] 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 057/101] 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 058/101] 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 059/101] 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 060/101] 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 061/101] 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 062/101] 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 063/101] 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 064/101] 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 065/101] 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 066/101] 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 067/101] 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 068/101] 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 069/101] 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 070/101] 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 071/101] 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 072/101] 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 073/101] 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 074/101] 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 075/101] 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 076/101] 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 077/101] 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 078/101] 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 079/101] 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 080/101] 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 fb3f70ece95ef417900d40f5caefc47b3869b45f Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 8 Dec 2023 16:42:41 +0000 Subject: [PATCH 081/101] 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 ff8d96393b21ad9d27aec38e5bf28cd2ef88b343 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 30 Jan 2024 16:48:17 +0000 Subject: [PATCH 082/101] fix missing import --- cmd/brick/exec/getstateAccount.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/brick/exec/getstateAccount.go b/cmd/brick/exec/getstateAccount.go index e9f791c25..81bdc8f98 100644 --- a/cmd/brick/exec/getstateAccount.go +++ b/cmd/brick/exec/getstateAccount.go @@ -2,6 +2,7 @@ package exec import ( "fmt" + "math/big" "github.com/aergoio/aergo/v2/cmd/brick/context" "github.com/aergoio/aergo/v2/contract/vm_dummy" From 70358cbfc6b07cc6996d3ffaf47115ae05292c80 Mon Sep 17 00:00:00 2001 From: waltzforzizi Date: Tue, 9 Apr 2024 11:37:31 +0000 Subject: [PATCH 083/101] remove getreceipts re-generate proto files --- go.mod | 1 + go.sum | 2 + rpc/grpcserver.go | 78 ----------------------- rpc/web3/v1.go | 75 ---------------------- types/account.pb.go | 2 +- types/admin.pb.go | 2 +- types/aergo_raft.pb.go | 2 +- types/blockchain.pb.go | 2 +- types/jsonrpc/receipt.go | 26 -------- types/metric.pb.go | 2 +- types/node.pb.go | 2 +- types/p2p.pb.go | 8 +-- types/pmap.pb.go | 2 +- types/polarrpc.pb.go | 2 +- types/rpc.pb.go | 134 +-------------------------------------- 15 files changed, 16 insertions(+), 324 deletions(-) diff --git a/go.mod b/go.mod index 599db1817..70a9f29bd 100644 --- a/go.mod +++ b/go.mod @@ -167,6 +167,7 @@ require ( golang.org/x/text v0.13.0 // indirect golang.org/x/tools v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 // indirect google.golang.org/grpc/examples v0.0.0-20230724170852-2aa261560586 // indirect gopkg.in/yaml.v2 v2.3.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index a3ded517e..cf6966fd7 100644 --- a/go.sum +++ b/go.sum @@ -1276,6 +1276,8 @@ google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y= google.golang.org/grpc/examples v0.0.0-20230724170852-2aa261560586 h1:3cBl7oDZlRZ9VAnaA9QglQNOY+ZP2wZJyGpiz1uuAuU= google.golang.org/grpc/examples v0.0.0-20230724170852-2aa261560586/go.mod h1:YYPcVQPFEuZQrEwqV6D//WM2s4HnWXtvFr/kII5NKbI= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= diff --git a/rpc/grpcserver.go b/rpc/grpcserver.go index 0dd0ea9b7..a6253b18f 100644 --- a/rpc/grpcserver.go +++ b/rpc/grpcserver.go @@ -1067,84 +1067,6 @@ func (rpc *AergoRPCService) GetReceipt(ctx context.Context, in *types.SingleByte return rsp.Receipt, rsp.Err } -func (rpc *AergoRPCService) GetReceipts(ctx context.Context, in *types.ReceiptsParams) (*types.ReceiptsPaged, error) { - if err := rpc.checkAuth(ctx, ReadBlockChain); err != nil { - return nil, err - } - - var result interface{} - var err error - if cap(in.Hashornumber) == 0 { - return nil, status.Errorf(codes.InvalidArgument, "Received no bytes") - } - - if len(in.Hashornumber) == 32 { - result, err = rpc.hub.RequestFuture(message.ChainSvc, &message.GetReceipts{BlockHash: in.Hashornumber}, - defaultActorTimeout, "rpc.(*AergoRPCService).GetReceipts#2").Result() - } else if len(in.Hashornumber) == 8 { - number := uint64(binary.LittleEndian.Uint64(in.Hashornumber)) - result, err = rpc.hub.RequestFuture(message.ChainSvc, &message.GetReceiptsByNo{BlockNo: number}, - defaultActorTimeout, "rpc.(*AergoRPCService).GetReceipts#1").Result() - } else { - return nil, status.Errorf(codes.InvalidArgument, "Invalid input. Should be a 32 byte hash or up to 8 byte number.") - } - - if err != nil { - return nil, err - } - - getPaging := func(data *types.Receipts, size uint32, offset uint32) *types.ReceiptsPaged { - allReceipts := data.Get() - total := uint32(len(allReceipts)) - - var fetchSize uint32 - if size > uint32(1000) { - fetchSize = uint32(1000) - } else if size == uint32(0) { - fetchSize = 100 - } else { - fetchSize = size - } - - var receipts []*types.Receipt - if offset >= uint32(len(allReceipts)) { - receipts = []*types.Receipt{} - } else { - limit := offset + fetchSize - if limit > uint32(len(allReceipts)) { - limit = uint32(len(allReceipts)) - } - receipts = allReceipts[offset:limit] - } - - return &types.ReceiptsPaged{ - Receipts: receipts, - BlockNo: data.GetBlockNo(), - Total: total, - Size: fetchSize, - Offset: offset, - } - } - - switch result.(type) { - case message.GetReceiptsRsp: - rsp, ok := result.(message.GetReceiptsRsp) - if !ok { - return nil, status.Errorf(codes.Internal, "internal type (%v) error", reflect.TypeOf(result)) - } - return getPaging(rsp.Receipts, in.Paging.Size, in.Paging.Offset), rsp.Err - - case message.GetReceiptsByNoRsp: - rsp, ok := result.(message.GetReceiptsByNoRsp) - if !ok { - return nil, status.Errorf(codes.Internal, "internal type (%v) error", reflect.TypeOf(result)) - } - return getPaging(rsp.Receipts, in.Paging.Size, in.Paging.Offset), rsp.Err - } - - return nil, status.Errorf(codes.Internal, "unexpected result type %s, expected %s", reflect.TypeOf(result), "message.GetReceipts") -} - func (rpc *AergoRPCService) GetABI(ctx context.Context, in *types.SingleBytes) (*types.ABI, error) { if err := rpc.checkAuth(ctx, ReadBlockChain); err != nil { return nil, err diff --git a/rpc/web3/v1.go b/rpc/web3/v1.go index 92272aa1d..53ddf89d6 100644 --- a/rpc/web3/v1.go +++ b/rpc/web3/v1.go @@ -42,7 +42,6 @@ func (api *Web3APIv1) NewHandler() { "/getBlockMetadata": api.GetBlockMetadata, "/getTx": api.GetTX, "/getReceipt": api.GetReceipt, - "/getReceipts": api.GetReceipts, "/queryContract": api.QueryContract, "/listEvents": api.ListEvents, "/getABI": api.GetABI, @@ -667,80 +666,6 @@ func (api *Web3APIv1) GetReceipt() (handler http.Handler, ok bool) { return stringResponseHandler(jsonrpc.MarshalJSON(result), nil), true } -func (api *Web3APIv1) GetReceipts() (handler http.Handler, ok bool) { - values, err := url.ParseQuery(api.request.URL.RawQuery) - if err != nil { - return commonResponseHandler(&types.Empty{}, err), true - } - - request := &types.ReceiptsParams{} - request.Paging = &types.PageParams{} - - hash := values.Get("hash") - if hash != "" { - hashBytes, err := base58.Decode(hash) - if err != nil { - return commonResponseHandler(&types.Empty{}, err), true - } - request.Hashornumber = hashBytes - } - - number := values.Get("number") - if number != "" { - numberValue, err := strconv.ParseUint(number, 10, 64) - if err != nil { - return commonResponseHandler(&types.Empty{}, err), true - } - number := uint64(numberValue) // Replace with your actual value - byteValue := make([]byte, 8) - binary.LittleEndian.PutUint64(byteValue, number) - request.Hashornumber = byteValue - } - - size := values.Get("size") - if size != "" { - sizeValue, parseErr := strconv.ParseUint(size, 10, 64) - if parseErr != nil { - return commonResponseHandler(&types.Empty{}, parseErr), true - - } - request.Paging.Size = uint32(sizeValue) - if request.Paging.Size > 100 { - request.Paging.Size = 100 - } - } - - offset := values.Get("offset") - if offset != "" { - offsetValue, parseErr := strconv.ParseUint(offset, 10, 64) - if parseErr != nil { - return commonResponseHandler(&types.Empty{}, parseErr), true - } - request.Paging.Offset = uint32(offsetValue) - } - - result, err := api.rpc.GetReceipts(api.request.Context(), request) - if err != nil { - errStr := err.Error() - - strBlockNo := strings.TrimPrefix(errStr, "empty : blockNo=") - if strBlockNo == errStr { - return commonResponseHandler(&types.Empty{}, err), true - } - - blockNo, err := strconv.ParseUint(strBlockNo, 10, 64) - if err != nil { - return commonResponseHandler(&types.Empty{}, err), true - } - - receipts := &jsonrpc.InOutReceipts{} - receipts.BlockNo = blockNo - return stringResponseHandler(jsonrpc.MarshalJSON(receipts), nil), true - } - - output := jsonrpc.ConvReceiptsPaged(result) - return stringResponseHandler(jsonrpc.MarshalJSON(output), nil), true -} func (api *Web3APIv1) GetTX() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) diff --git a/types/account.pb.go b/types/account.pb.go index 08ea66579..44c8e5bd7 100644 --- a/types/account.pb.go +++ b/types/account.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.31.0 // protoc v3.15.8 // source: account.proto diff --git a/types/admin.pb.go b/types/admin.pb.go index f15e7256f..b59d1579e 100644 --- a/types/admin.pb.go +++ b/types/admin.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.31.0 // protoc v3.15.8 // source: admin.proto diff --git a/types/aergo_raft.pb.go b/types/aergo_raft.pb.go index 6d7b06911..f12b05da9 100644 --- a/types/aergo_raft.pb.go +++ b/types/aergo_raft.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.31.0 // protoc v3.15.8 // source: aergo_raft.proto diff --git a/types/blockchain.pb.go b/types/blockchain.pb.go index c41e59e91..d1e20db85 100644 --- a/types/blockchain.pb.go +++ b/types/blockchain.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.31.0 // protoc v3.15.8 // source: blockchain.proto diff --git a/types/jsonrpc/receipt.go b/types/jsonrpc/receipt.go index ed89262c6..b57514ba6 100644 --- a/types/jsonrpc/receipt.go +++ b/types/jsonrpc/receipt.go @@ -102,32 +102,6 @@ type InOutReceipts struct { BlockNo uint64 `json:"blockNo,omitempty"` } -func ConvReceiptsPaged(msg *types.ReceiptsPaged) *InOutReceiptsPaged { - if msg == nil { - return nil - } - - rp := &InOutReceiptsPaged{} - rp.Total = msg.GetTotal() - rp.Offset = msg.GetOffset() - rp.Size = msg.GetSize() - rp.BlockNo = msg.GetBlockNo() - rp.Receipts = make([]*types.Receipt, len(msg.Get())) - for i, receipt := range msg.Get() { - rp.Receipts[i] = receipt - } - - return rp -} - -type InOutReceiptsPaged struct { - Total uint32 `json:"total,omitempty"` - Offset uint32 `json:"offset,omitempty"` - Size uint32 `json:"size,omitempty"` - Receipts []*types.Receipt `json:"receipts"` - BlockNo uint64 `json:"blockNo,omitempty"` -} - func ConvEvents(msg *types.EventList) *InOutEventList { if msg == nil { return nil diff --git a/types/metric.pb.go b/types/metric.pb.go index 6d8ea03f8..b7f7139c6 100644 --- a/types/metric.pb.go +++ b/types/metric.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.31.0 // protoc v3.15.8 // source: metric.proto diff --git a/types/node.pb.go b/types/node.pb.go index b7516ae53..bd47652dc 100644 --- a/types/node.pb.go +++ b/types/node.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.31.0 // protoc v3.15.8 // source: node.proto diff --git a/types/p2p.pb.go b/types/p2p.pb.go index 8373d61de..d1613e510 100644 --- a/types/p2p.pb.go +++ b/types/p2p.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.31.0 // protoc v3.15.8 // source: p2p.proto @@ -40,11 +40,11 @@ const ( // ALREADY_EXISTS ResultStatus_ALREADY_EXISTS ResultStatus = 6 // PERMISSION_DENIED - ResultStatus_PERMISSION_DENIED ResultStatus = 7 - ResultStatus_RESOURCE_EXHAUSTED ResultStatus = 8 + ResultStatus_PERMISSION_DENIED ResultStatus = 7 + ResultStatus_RESOURCE_EXHAUSTED ResultStatus = 8 ResultStatus_FAILED_PRECONDITION ResultStatus = 9 // ABORTED - ResultStatus_ABORTED ResultStatus = 10 + ResultStatus_ABORTED ResultStatus = 10 ResultStatus_OUT_OF_RANGE ResultStatus = 11 // UNIMPLEMENTED indicates operation is not implemented or not // supported/enabled in this service. diff --git a/types/pmap.pb.go b/types/pmap.pb.go index b3155e1b8..b67701619 100644 --- a/types/pmap.pb.go +++ b/types/pmap.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.31.0 // protoc v3.15.8 // source: pmap.proto diff --git a/types/polarrpc.pb.go b/types/polarrpc.pb.go index 0c249db0d..862a33d0f 100644 --- a/types/polarrpc.pb.go +++ b/types/polarrpc.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.31.0 // protoc v3.15.8 // source: polarrpc.proto diff --git a/types/rpc.pb.go b/types/rpc.pb.go index 555294b2a..1d7ef4d10 100644 --- a/types/rpc.pb.go +++ b/types/rpc.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.31.0 // protoc v3.15.8 // source: rpc.proto @@ -2657,138 +2657,6 @@ func (x *EnterpriseConfig) GetValues() []string { return nil } -type ReceiptsParams struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Hashornumber []byte `protobuf:"bytes,1,opt,name=hashornumber,proto3" json:"hashornumber,omitempty"` - Paging *PageParams `protobuf:"bytes,2,opt,name=paging,proto3" json:"paging,omitempty"` -} - -func (x *ReceiptsParams) Reset() { - *x = ReceiptsParams{} - if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ReceiptsParams) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ReceiptsParams) ProtoMessage() {} - -func (x *ReceiptsParams) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -func (*ReceiptsParams) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{16} -} - -func (x *ReceiptsParams) GetHashornumber() []byte { - if x != nil { - return x.Hashornumber - } - return nil -} - -func (x *ReceiptsParams) GetPaging() *PageParams { - if x != nil { - return x.Paging - } - return nil -} - -type ReceiptsPaged struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total,omitempty"` - Offset uint32 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"` - Size uint32 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` - Receipts []*Receipt `protobuf:"bytes,4,opt,name=body,proto3" json:"receipts,omitempty"` - BlockNo BlockNo `protobuf:"bytes,4,opt,name=body,proto3" json:"blockNo,omitempty"` -} - -func (x *ReceiptsPaged) Reset() { - *x = ReceiptsPaged{} - if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ReceiptsPaged) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ReceiptsPaged) ProtoMessage() {} - -func (x *ReceiptsPaged) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -func (*ReceiptsPaged) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{15} -} - -func (x *ReceiptsPaged) GetTotal() uint32 { - if x != nil { - return x.Total - } - return 0 -} - -func (x *ReceiptsPaged) GetOffset() uint32 { - if x != nil { - return x.Offset - } - return 0 -} - -func (x *ReceiptsPaged) GetSize() uint32 { - if x != nil { - return x.Size - } - return 0 -} - -func (x *ReceiptsPaged) Get() []*Receipt { - if x != nil { - return x.Receipts - } - return nil -} - -func (x *ReceiptsPaged) GetBlockNo() uint64 { - if x != nil { - return x.BlockNo - } - return 0 -} - var File_rpc_proto protoreflect.FileDescriptor var file_rpc_proto_rawDesc = []byte{ From a2895257d38121ad9e87b3098130b6d4b128eb24 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 16 May 2024 01:45:07 +0000 Subject: [PATCH 084/101] add tests for '0' and '9' --- contract/vm_dummy/vm_dummy_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index fdfa7916c..07541ac16 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -2406,6 +2406,10 @@ func TestBignumValues(t *testing.T) { // process octal, hex, binary + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0"]}`, "", `"0"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["9"]}`, "", `"9"`) + require.NoErrorf(t, err, "failed to query") 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"`) @@ -2413,6 +2417,10 @@ func TestBignumValues(t *testing.T) { 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":"0"}]}`, "", `"0"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"9"}]}`, "", `"9"`) + 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"`) @@ -2432,6 +2440,10 @@ func TestBignumValues(t *testing.T) { receipt := bc.GetReceipt(tx.Hash()) assert.Equalf(t, `"1234567"`, receipt.GetRet(), "contract Call ret error") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0"]}`, "", `"0"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["9"]}`, "", `"9"`) + require.NoErrorf(t, err, "failed to query") 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", `""`) @@ -2439,6 +2451,10 @@ func TestBignumValues(t *testing.T) { 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":"0"}]}`, "", `"0"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"9"}]}`, "", `"9"`) + 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", `""`) @@ -2468,6 +2484,10 @@ func TestBignumValues(t *testing.T) { receipt = bc.GetReceipt(tx.Hash()) assert.Equalf(t, `"1234567"`, receipt.GetRet(), "contract Call ret error") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0"]}`, "", `"0"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["9"]}`, "", `"9"`) + require.NoErrorf(t, err, "failed to query") 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"`) @@ -2475,6 +2495,10 @@ func TestBignumValues(t *testing.T) { 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":"0"}]}`, "", `"0"`) + require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":[{"_bignum":"9"}]}`, "", `"9"`) + 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"`) From 019df80cd8cbb8fc2402513882cc4fa9e625c2e5 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 16 May 2024 02:11:47 +0000 Subject: [PATCH 085/101] add tests with 2 trailing zeros --- contract/vm_dummy/vm_dummy_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index 07541ac16..0c0abdfc7 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -2410,6 +2410,8 @@ func TestBignumValues(t *testing.T) { require.NoErrorf(t, err, "failed to query") err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["9"]}`, "", `"9"`) require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0055"]}`, "", `"55"`) + require.NoErrorf(t, err, "failed to query") 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"`) @@ -2444,6 +2446,8 @@ func TestBignumValues(t *testing.T) { require.NoErrorf(t, err, "failed to query") err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["9"]}`, "", `"9"`) require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0055"]}`, "", `"55"`) + require.NoErrorf(t, err, "failed to query") 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", `""`) @@ -2488,6 +2492,8 @@ func TestBignumValues(t *testing.T) { require.NoErrorf(t, err, "failed to query") err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["9"]}`, "", `"9"`) require.NoErrorf(t, err, "failed to query") + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0055"]}`, "", `"55"`) + require.NoErrorf(t, err, "failed to query") 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"`) From 2d9b53cd3df573db9c5f87bacc15442213fb2f47 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 16 May 2024 02:18:58 +0000 Subject: [PATCH 086/101] fix test --- 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 0c0abdfc7..75735cce4 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -2410,7 +2410,7 @@ func TestBignumValues(t *testing.T) { require.NoErrorf(t, err, "failed to query") err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["9"]}`, "", `"9"`) require.NoErrorf(t, err, "failed to query") - err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0055"]}`, "", `"55"`) + err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["0055"]}`, "", `"45"`) require.NoErrorf(t, err, "failed to query") err = bc.Query("contract1", `{"Name":"parse_bignum", "Args":["01234567"]}`, "", `"342391"`) require.NoErrorf(t, err, "failed to query") From 9fc308e27c337b3eb86900676f6ab5f1fb267402 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 17 May 2024 02:17:01 +0000 Subject: [PATCH 087/101] tests: adjust expected gas --- contract/vm_dummy/vm_dummy_pub_test.go | 10 +++++----- tests/test-gas-bf.sh | 2 +- tests/test-gas-per-function-v4.sh | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/contract/vm_dummy/vm_dummy_pub_test.go b/contract/vm_dummy/vm_dummy_pub_test.go index 8bca60202..527777ba3 100644 --- a/contract/vm_dummy/vm_dummy_pub_test.go +++ b/contract/vm_dummy/vm_dummy_pub_test.go @@ -354,11 +354,11 @@ func TestGasPerFunction(t *testing.T) { }{ {"comp_ops", "", 0, 143204}, {"unarytest_n_copy_ops", "", 0, 143117}, - {"unary_ops", "", 0, 148160}, + {"unary_ops", "", 0, 143552}, {"binary_ops", "", 0, 145075}, {"constant_ops", "", 0, 143032}, {"upvalue_n_func_ops", "", 0, 144347}, - {"table_ops", "", 0, 149090}, + {"table_ops", "", 0, 144482}, {"call_n_vararg_ops", "", 0, 145001}, {"return_ops", "", 0, 143037}, {"loop_n_branche_ops", "", 0, 146372}, @@ -373,8 +373,8 @@ func TestGasPerFunction(t *testing.T) { {"tostring", "", 0, 143457}, {"type", "", 0, 143285}, {"unpack", "", 0, 150745}, - {"pcall", "", 0, 146105}, - {"xpcall", "", 0, 146377}, + {"pcall", "", 0, 147905}, + {"xpcall", "", 0, 148177}, {"string.byte", "", 0, 157040}, {"string.char", "", 0, 160397}, @@ -633,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"`, ``, 47341329, SetHardForkVersion(4)) + err = expectGas(string(code4), 0, `"main"`, ``, 47342481, SetHardForkVersion(4)) assert.NoError(t, err) } diff --git a/tests/test-gas-bf.sh b/tests/test-gas-bf.sh index b53601521..bcffba363 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" "47341329" + assert_equals "$gasUsed" "47342481" 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 a3b3b97f1..89701753b 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" 148160 +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" 149090 +add_test "table_ops" 144482 add_test "call_n_vararg_ops" 145001 add_test "return_ops" 143037 add_test "loop_n_branche_ops" 146372 @@ -69,8 +69,8 @@ add_test "tonumber" 143186 add_test "tostring" 143457 add_test "type" 143285 add_test "unpack" 150745 -add_test "pcall" 146105 -add_test "xpcall" 146377 +add_test "pcall" 147905 +add_test "xpcall" 148177 add_test "string.byte" 157040 add_test "string.char" 160397 From c97c0992ef262d333a9a88573294374580bc9d70 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 18 May 2024 02:52:27 +0000 Subject: [PATCH 088/101] fix functional tests --- tests/test-pcall-events.sh | 6 +++--- tests/test-transaction-types.sh | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test-pcall-events.sh b/tests/test-pcall-events.sh index 98fd7190f..206f83f9f 100755 --- a/tests/test-pcall-events.sh +++ b/tests/test-pcall-events.sh @@ -20,7 +20,7 @@ get_deploy_args ../contract/vm_dummy/test_files/pcall-events-2.lua txhash=$(../bin/aergocli --keystore . --password bmttest \ contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ - $deploy_args '["'$address3'"]' --payload `cat payload.out` | jq .hash | sed 's/"//g') + $deploy_args '["'$address3'"]' | jq .hash | sed 's/"//g') get_receipt $txhash @@ -34,7 +34,7 @@ get_deploy_args ../contract/vm_dummy/test_files/pcall-events-1.lua txhash=$(../bin/aergocli --keystore . --password bmttest \ contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ - $deploy_args '["'$address2'"]' --payload `cat payload.out` | jq .hash | sed 's/"//g') + $deploy_args '["'$address2'"]' | jq .hash | sed 's/"//g') get_receipt $txhash @@ -48,7 +48,7 @@ get_deploy_args ../contract/vm_dummy/test_files/pcall-events-0.lua txhash=$(../bin/aergocli --keystore . --password bmttest \ contract deploy AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R \ - $deploy_args '["'$address2'"]' --payload `cat payload.out` | jq .hash | sed 's/"//g') + $deploy_args '["'$address2'"]' | jq .hash | sed 's/"//g') get_receipt $txhash diff --git a/tests/test-transaction-types.sh b/tests/test-transaction-types.sh index a3f149080..e08259fb4 100755 --- a/tests/test-transaction-types.sh +++ b/tests/test-transaction-types.sh @@ -62,7 +62,7 @@ rm test-tx-type-*.lua # get some info from=AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R -chainIdHash=$(../bin/aergocli blockchain | jq -r '.ChainIdHash') +chainIdHash=$(../bin/aergocli blockchain | jq -r '.chainIdHash') echo "-- TRANSFER type, contract without 'default' function --" From 8de354a739114b5810bdfdb3234b14954782fe83 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 31 May 2024 18:23:38 -0300 Subject: [PATCH 089/101] add blacklist to mempool --- mempool/blacklist.go | 73 ++++++++++++++++++++++++++++++++++++++++++++ mempool/mempool.go | 6 ++++ 2 files changed, 79 insertions(+) create mode 100644 mempool/blacklist.go diff --git a/mempool/blacklist.go b/mempool/blacklist.go new file mode 100644 index 000000000..6cb1ccec4 --- /dev/null +++ b/mempool/blacklist.go @@ -0,0 +1,73 @@ +package mempool + +import ( + "sync" +) + +type blacklistConf struct { + sync.RWMutex + sourcelist []string // account address (b58 encoded like Am...) or id (32 bytes in hex = 64 bytes) + blocked map[string]bool // all above converted to account id (32 bytes) + mp *MemPool // for log +} + +func newBlacklistConf(mp *MemPool, addresses []string) *blacklistConf { + out := &blacklistConf{} + out.mp = mp + out.SetBlacklist(addresses) + return out +} + +func (b *blacklistConf) GetBlacklist() []string { + b.RLock() + defer b.RUnlock() + ret := make([]string, len(b.sourcelist)) + copy(ret, b.sourcelist) + return ret +} + +func (b *blacklistConf) SetBlacklist(addresses []string) { + b.Lock() + defer b.Unlock() + b.sourcelist := make([]string, len(addresses)) + copy(b.sourcelist, addresses) + b.blocked = make(map[string]bool) + for _, v := range addresses { + b.mp.Debug().Str("address", v).Msg("set account blacklist") + key, err := toKey(v) + if err == nil { + b.blocked[key] = true + } else { + b.mp.Debug().Str("address", v).Msg("invalid account address or id for blacklist") + } + } +} + +func (b *blacklistConf) Check(address string) bool { + if b == nil { + return true + } + key, err := toKey(address) + if err != nil { + return false + } + b.RLock() + defer b.RUnlock() + return b.blocked[key] +} + +func toKey(address string) (string, error) { + var key []byte + var err error + if len(address) == 64 { + key, err = hex.Decode(address) + } else { + var addr []byte + addr, err = types.DecodeAddress(address) + if err != nil { + return nil, err + } + key = common.Hasher(addr) + } + return string(key), err +} diff --git a/mempool/mempool.go b/mempool/mempool.go index bb490544b..9ef29570a 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -74,6 +74,7 @@ type MemPool struct { acceptChainIdHash []byte isPublic bool whitelist *whitelistConf + blacklist *blacklistConf // followings are for test testConfig bool deadtx int @@ -306,6 +307,7 @@ func (mp *MemPool) Statistics() *map[string]interface{} { "dead": mp.deadtx, "config": mp.cfg.Mempool, } + ret["blacklist"] = mp.blacklist.GetBlacklist() if !mp.isPublic { ret["whitelist"] = mp.whitelist.GetWhitelist() ret["whitelist_on"] = mp.whitelist.GetOn() @@ -607,6 +609,7 @@ func (mp *MemPool) nextBlockVersion() int32 { } // check tx sanity +// check if sender is on blacklist // check if sender has enough balance // check if recipient is valid name // check tx account is lower than known value @@ -614,6 +617,9 @@ func (mp *MemPool) validateTx(tx types.Transaction, account types.Address) error if !mp.whitelist.Check(types.EncodeAddress(account)) { return types.ErrTxNotAllowedAccount } + if mp.blacklist.Check(types.EncodeAddress(account)) { + return types.ErrTxNotAllowedAccount + } ns, err := mp.getAccountState(account) if err != nil { return err From 07a5428231e50ec8b1be610d43cb8f6676ae8a92 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 31 May 2024 18:48:43 -0300 Subject: [PATCH 090/101] initialize blacklist if present on config --- config/config.go | 1 + config/types.go | 4 ++++ mempool/blacklist.go | 13 ++++++++++--- mempool/mempool.go | 3 +++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/config/config.go b/config/config.go index bec2f5896..3c427b831 100644 --- a/config/config.go +++ b/config/config.go @@ -157,6 +157,7 @@ func (ctx *ServerContext) GetDefaultMempoolConfig() *MempoolConfig { FadeoutPeriod: types.DefaultEvictPeriod, VerifierNumber: runtime.NumCPU(), DumpFilePath: ctx.ExpandPathEnv("$HOME/mempool.dump"), + Blacklist: nil, } } diff --git a/config/types.go b/config/types.go index 39705da54..b48996557 100644 --- a/config/types.go +++ b/config/types.go @@ -127,6 +127,7 @@ type MempoolConfig struct { FadeoutPeriod int `mapstructure:"fadeoutperiod" description:"time period for evict transactions(in hour)"` VerifierNumber int `mapstructure:"verifiers" description:"number of concurrent verifier"` DumpFilePath string `mapstructure:"dumpfilepath" description:"file path for recording mempool at process termintation"` + Blacklist []string `mapstructure:"blacklist" description:"List of account addresses or ids to be blocked"` } // ConsensusConfig defines configurations for consensus service @@ -258,6 +259,9 @@ enablefadeout = {{.Mempool.EnableFadeout}} fadeoutperiod = {{.Mempool.FadeoutPeriod}} verifiers = {{.Mempool.VerifierNumber}} dumpfilepath = "{{.Mempool.DumpFilePath}}" +blacklist = [{{range .Mempool.Blacklist}} +"{{.}}", {{end}} +] [consensus] enablebp = {{.Consensus.EnableBp}} diff --git a/mempool/blacklist.go b/mempool/blacklist.go index 6cb1ccec4..e620d3a4a 100644 --- a/mempool/blacklist.go +++ b/mempool/blacklist.go @@ -2,6 +2,10 @@ package mempool import ( "sync" + + "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/internal/common" + "github.com/aergoio/aergo/v2/internal/enc/hex" ) type blacklistConf struct { @@ -19,6 +23,9 @@ func newBlacklistConf(mp *MemPool, addresses []string) *blacklistConf { } func (b *blacklistConf) GetBlacklist() []string { + if b == nil { + return []string{} + } b.RLock() defer b.RUnlock() ret := make([]string, len(b.sourcelist)) @@ -29,7 +36,7 @@ func (b *blacklistConf) GetBlacklist() []string { func (b *blacklistConf) SetBlacklist(addresses []string) { b.Lock() defer b.Unlock() - b.sourcelist := make([]string, len(addresses)) + b.sourcelist = make([]string, len(addresses)) copy(b.sourcelist, addresses) b.blocked = make(map[string]bool) for _, v := range addresses { @@ -45,7 +52,7 @@ func (b *blacklistConf) SetBlacklist(addresses []string) { func (b *blacklistConf) Check(address string) bool { if b == nil { - return true + return false } key, err := toKey(address) if err != nil { @@ -65,7 +72,7 @@ func toKey(address string) (string, error) { var addr []byte addr, err = types.DecodeAddress(address) if err != nil { - return nil, err + return "", err } key = common.Hasher(addr) } diff --git a/mempool/mempool.go b/mempool/mempool.go index 9ef29570a..d35a618eb 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -110,6 +110,9 @@ func NewMemPoolService(cfg *cfg.Config, cs *chain.ChainService) *MemPool { } else if cfg.Mempool.FadeoutPeriod > 0 { evictPeriod = time.Duration(cfg.Mempool.FadeoutPeriod) * time.Hour } + if cfg.Mempool.Blacklist != nil { + actor.blacklist = newBlacklistConf(actor, cfg.Mempool.Blacklist) + } return actor } From 86c17e2387ea78befe03cd3e7ee44d48d31a3b9c Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 1 Jun 2024 09:48:12 -0300 Subject: [PATCH 091/101] config: block deploy --- config/config.go | 1 + config/types.go | 2 ++ mempool/mempool.go | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/config/config.go b/config/config.go index 3c427b831..8c23b2d0b 100644 --- a/config/config.go +++ b/config/config.go @@ -157,6 +157,7 @@ func (ctx *ServerContext) GetDefaultMempoolConfig() *MempoolConfig { FadeoutPeriod: types.DefaultEvictPeriod, VerifierNumber: runtime.NumCPU(), DumpFilePath: ctx.ExpandPathEnv("$HOME/mempool.dump"), + BlockDeploy: false, Blacklist: nil, } } diff --git a/config/types.go b/config/types.go index b48996557..f5e6944e6 100644 --- a/config/types.go +++ b/config/types.go @@ -127,6 +127,7 @@ type MempoolConfig struct { FadeoutPeriod int `mapstructure:"fadeoutperiod" description:"time period for evict transactions(in hour)"` VerifierNumber int `mapstructure:"verifiers" description:"number of concurrent verifier"` DumpFilePath string `mapstructure:"dumpfilepath" description:"file path for recording mempool at process termintation"` + BlockDeploy bool `mapstructure:"blockdeploy" description:"block the deployment of new contracts"` Blacklist []string `mapstructure:"blacklist" description:"List of account addresses or ids to be blocked"` } @@ -259,6 +260,7 @@ enablefadeout = {{.Mempool.EnableFadeout}} fadeoutperiod = {{.Mempool.FadeoutPeriod}} verifiers = {{.Mempool.VerifierNumber}} dumpfilepath = "{{.Mempool.DumpFilePath}}" +blockdeploy = {{.Mempool.BlockDeploy}} blacklist = [{{range .Mempool.Blacklist}} "{{.}}", {{end}} ] diff --git a/mempool/mempool.go b/mempool/mempool.go index d35a618eb..e7fca6de3 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -75,6 +75,7 @@ type MemPool struct { isPublic bool whitelist *whitelistConf blacklist *blacklistConf + blockDeploy bool // followings are for test testConfig bool deadtx int @@ -103,6 +104,7 @@ func NewMemPoolService(cfg *cfg.Config, cs *chain.ChainService) *MemPool { status: initial, verifier: nil, quit: make(chan bool), + blockDeploy: cfg.Mempool.BlockDeploy, } actor.BaseComponent = component.NewBaseComponent(message.MemPoolSvc, actor, log.NewLogger("mempool")) if cfg.Mempool.EnableFadeout == false { @@ -666,6 +668,9 @@ func (mp *MemPool) validateTx(tx types.Transaction, account types.Address) error if tx.GetBody().GetRecipient() != nil { return types.ErrTxInvalidRecipient } + if mp.blockDeploy { + return types.ErrTxInvalidType + } case types.TxType_GOVERNANCE: id := tx.GetBody().GetRecipient() aergoState, err := mp.getAccountState(id) From 3217eff262d2256f2768f99cc0eb0d4e07e5ffe3 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 1 Jun 2024 11:50:54 -0300 Subject: [PATCH 092/101] block call to contracts --- blacklist/blacklist.go | 59 +++++++++++++++++++++++++++++++ contract/vm.go | 11 ++++++ mempool/blacklist.go | 80 ------------------------------------------ mempool/mempool.go | 7 ++-- 4 files changed, 73 insertions(+), 84 deletions(-) create mode 100644 blacklist/blacklist.go delete mode 100644 mempool/blacklist.go diff --git a/blacklist/blacklist.go b/blacklist/blacklist.go new file mode 100644 index 000000000..373b608d2 --- /dev/null +++ b/blacklist/blacklist.go @@ -0,0 +1,59 @@ +package blacklist + +import ( + "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/internal/common" + "github.com/aergoio/aergo/v2/internal/enc/hex" +) + +type Blacklist struct { + sourcelist []string // account address (b58 encoded like Am...) or id (32 bytes in hex = 64 bytes) + blocked map[string]bool // all above converted to account id (32 bytes) +} + +var globalBlacklist *Blacklist + +// Initialize sets up the blacklist with the given addresses. +// This function should be called only once at the start. +func Initialize(addresses []string) { + conf := &Blacklist{} + conf.sourcelist = make([]string, len(addresses)) + copy(conf.sourcelist, addresses) + conf.blocked = make(map[string]bool) + for _, v := range addresses { + key, err := toKey(v) + if err == nil { + conf.blocked[key] = true + } else { + // Handle invalid address, log or take other actions as needed + } + } + globalBlacklist = conf +} + +func Check(address string) bool { + if globalBlacklist == nil { + return false + } + key, err := toKey(address) + if err != nil { + return false + } + return globalBlacklist.blocked[key] +} + +func toKey(address string) (string, error) { + var key []byte + var err error + if len(address) == 64 { + key, err = hex.Decode(address) + } else { + var addr []byte + addr, err = types.DecodeAddress(address) + if err != nil { + return "", err + } + key = common.Hasher(addr) + } + return string(key), err +} diff --git a/contract/vm.go b/contract/vm.go index 11a23cf1f..b52b354f0 100644 --- a/contract/vm.go +++ b/contract/vm.go @@ -44,6 +44,7 @@ import ( "github.com/aergoio/aergo/v2/state/statedb" "github.com/aergoio/aergo/v2/types" "github.com/aergoio/aergo/v2/types/dbkey" + "github.com/aergoio/aergo/v2/blacklist" jsoniter "github.com/json-iterator/go" ) @@ -292,6 +293,16 @@ func newExecutor( } ctx.callDepth++ + if blacklist.Check(types.EncodeAddress(contractId)) { + ce := &executor{ + code: contract, + ctx: ctx, + } + ce.err = fmt.Errorf("contract not available") + ctrLgr.Error().Err(ce.err).Str("contract", types.EncodeAddress(contractId)).Msg("blocked contract") + return ce + } + ce := &executor{ code: contract, L: GetLState(), diff --git a/mempool/blacklist.go b/mempool/blacklist.go deleted file mode 100644 index e620d3a4a..000000000 --- a/mempool/blacklist.go +++ /dev/null @@ -1,80 +0,0 @@ -package mempool - -import ( - "sync" - - "github.com/aergoio/aergo/v2/types" - "github.com/aergoio/aergo/v2/internal/common" - "github.com/aergoio/aergo/v2/internal/enc/hex" -) - -type blacklistConf struct { - sync.RWMutex - sourcelist []string // account address (b58 encoded like Am...) or id (32 bytes in hex = 64 bytes) - blocked map[string]bool // all above converted to account id (32 bytes) - mp *MemPool // for log -} - -func newBlacklistConf(mp *MemPool, addresses []string) *blacklistConf { - out := &blacklistConf{} - out.mp = mp - out.SetBlacklist(addresses) - return out -} - -func (b *blacklistConf) GetBlacklist() []string { - if b == nil { - return []string{} - } - b.RLock() - defer b.RUnlock() - ret := make([]string, len(b.sourcelist)) - copy(ret, b.sourcelist) - return ret -} - -func (b *blacklistConf) SetBlacklist(addresses []string) { - b.Lock() - defer b.Unlock() - b.sourcelist = make([]string, len(addresses)) - copy(b.sourcelist, addresses) - b.blocked = make(map[string]bool) - for _, v := range addresses { - b.mp.Debug().Str("address", v).Msg("set account blacklist") - key, err := toKey(v) - if err == nil { - b.blocked[key] = true - } else { - b.mp.Debug().Str("address", v).Msg("invalid account address or id for blacklist") - } - } -} - -func (b *blacklistConf) Check(address string) bool { - if b == nil { - return false - } - key, err := toKey(address) - if err != nil { - return false - } - b.RLock() - defer b.RUnlock() - return b.blocked[key] -} - -func toKey(address string) (string, error) { - var key []byte - var err error - if len(address) == 64 { - key, err = hex.Decode(address) - } else { - var addr []byte - addr, err = types.DecodeAddress(address) - if err != nil { - return "", err - } - key = common.Hasher(addr) - } - return string(key), err -} diff --git a/mempool/mempool.go b/mempool/mempool.go index e7fca6de3..87815a6e1 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -35,6 +35,7 @@ import ( "github.com/aergoio/aergo/v2/state/statedb" "github.com/aergoio/aergo/v2/types" "github.com/aergoio/aergo/v2/types/message" + "github.com/aergoio/aergo/v2/blacklist" ) const ( @@ -74,7 +75,6 @@ type MemPool struct { acceptChainIdHash []byte isPublic bool whitelist *whitelistConf - blacklist *blacklistConf blockDeploy bool // followings are for test testConfig bool @@ -113,7 +113,7 @@ func NewMemPoolService(cfg *cfg.Config, cs *chain.ChainService) *MemPool { evictPeriod = time.Duration(cfg.Mempool.FadeoutPeriod) * time.Hour } if cfg.Mempool.Blacklist != nil { - actor.blacklist = newBlacklistConf(actor, cfg.Mempool.Blacklist) + blacklist.Initialize(cfg.Mempool.Blacklist) } return actor } @@ -312,7 +312,6 @@ func (mp *MemPool) Statistics() *map[string]interface{} { "dead": mp.deadtx, "config": mp.cfg.Mempool, } - ret["blacklist"] = mp.blacklist.GetBlacklist() if !mp.isPublic { ret["whitelist"] = mp.whitelist.GetWhitelist() ret["whitelist_on"] = mp.whitelist.GetOn() @@ -622,7 +621,7 @@ func (mp *MemPool) validateTx(tx types.Transaction, account types.Address) error if !mp.whitelist.Check(types.EncodeAddress(account)) { return types.ErrTxNotAllowedAccount } - if mp.blacklist.Check(types.EncodeAddress(account)) { + if blacklist.Check(types.EncodeAddress(account)) { return types.ErrTxNotAllowedAccount } ns, err := mp.getAccountState(account) From b8f67f7e6f5f8a35eb76fac37dafe2517232bcd2 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 1 Jun 2024 12:08:53 -0300 Subject: [PATCH 093/101] check error when creating contract executor --- contract/vm.go | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/contract/vm.go b/contract/vm.go index b52b354f0..bb340eaf5 100644 --- a/contract/vm.go +++ b/contract/vm.go @@ -828,11 +828,13 @@ func Call( ce := newExecutor(contract, contractAddress, ctx, &ci, ctx.curContract.amount, false, false, contractState) defer ce.close() - startTime := time.Now() - // execute the contract call - ce.call(callMaxInstLimit, nil) - vmExecTime := time.Now().Sub(startTime).Microseconds() - vmLogger.Trace().Int64("execµs", vmExecTime).Stringer("txHash", types.LogBase58(ce.ctx.txHash)).Msg("tx execute time in vm") + if ce.err == nil { + startTime := time.Now() + // execute the contract call + ce.call(callMaxInstLimit, nil) + vmExecTime := time.Now().Sub(startTime).Microseconds() + vmLogger.Trace().Int64("execµs", vmExecTime).Stringer("txHash", types.LogBase58(ce.ctx.txHash)).Msg("tx execute time in vm") + } // check if there is an error err = ce.err @@ -975,8 +977,10 @@ func Create( ce := newExecutor(contract, contractAddress, ctx, &ci, ctx.curContract.amount, true, false, contractState) defer ce.close() - // call the constructor - ce.call(callMaxInstLimit, nil) + if err == nil { + // call the constructor + ce.call(callMaxInstLimit, nil) + } // check if the call failed err = ce.err @@ -1103,7 +1107,9 @@ func Query(contractAddress []byte, bs *state.BlockState, cdb ChainAccessor, cont } }() - ce.call(queryMaxInstLimit, nil) + if err == nil { + ce.call(queryMaxInstLimit, nil) + } return []byte(ce.jsonRet), ce.err } @@ -1177,7 +1183,9 @@ func CheckFeeDelegation(contractAddress []byte, bs *state.BlockState, bi *types. } }() - ce.call(queryMaxInstLimit, nil) + if err == nil { + ce.call(queryMaxInstLimit, nil) + } if ce.err != nil { return ce.err From 1d8fbbd927c672b44a99869506c2f8ce5167523a Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 1 Jun 2024 23:57:14 +0000 Subject: [PATCH 094/101] brick: deploy contract bytecode in hex --- contract/vm_dummy/vm_dummy.go | 38 ++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/contract/vm_dummy/vm_dummy.go b/contract/vm_dummy/vm_dummy.go index 0f56ebf31..199cfd08c 100644 --- a/contract/vm_dummy/vm_dummy.go +++ b/contract/vm_dummy/vm_dummy.go @@ -20,6 +20,7 @@ import ( "github.com/aergoio/aergo/v2/contract" "github.com/aergoio/aergo/v2/contract/system" "github.com/aergoio/aergo/v2/fee" + "github.com/aergoio/aergo/v2/internal/enc/hex" "github.com/aergoio/aergo/v2/internal/enc/base58" "github.com/aergoio/aergo/v2/state" "github.com/aergoio/aergo/v2/state/statedb" @@ -403,6 +404,7 @@ func hash(id uint64) []byte { type luaTxDeploy struct { luaTxContractCommon + isCompiled bool cErr error } @@ -413,14 +415,30 @@ func NewLuaTxDeploy(sender, recipient string, amount uint64, code string) *luaTx } func NewLuaTxDeployBig(sender, recipient string, amount *big.Int, code string) *luaTxDeploy { + var payload []byte + var isCompiled bool + var err error + + if isHexString(code) { + payload, err = hex.Decode(code) + if err != nil { + return &luaTxDeploy{cErr: err} + } + isCompiled = true + } else { + payload = util.NewLuaCodePayload([]byte(code), nil) + isCompiled = false + } + return &luaTxDeploy{ luaTxContractCommon: luaTxContractCommon{ _sender: contract.StrHash(sender), _recipient: contract.StrHash(recipient), - _payload: util.NewLuaCodePayload([]byte(code), nil), + _payload: payload, _amount: amount, txId: newTxId(), }, + isCompiled: isCompiled, cErr: nil, } } @@ -453,7 +471,7 @@ func (l *luaTxDeploy) okMsg() string { } func (l *luaTxDeploy) Constructor(args string) *luaTxDeploy { - if len(args) == 0 || strings.Compare(args, "[]") == 0 || l.cErr != nil { + if len(args) == 0 || strings.Compare(args, "[]") == 0 || l.isCompiled || l.cErr != nil { return l } l._payload = util.NewLuaCodePayload(util.LuaCodePayload(l._payload).Code(), []byte(args)) @@ -547,7 +565,7 @@ func (l *luaTxDeploy) run(execCtx context.Context, bs *state.BlockState, bc *Dum if l.cErr != nil { return l.cErr } - if bc.HardforkVersion < 4 { + if bc.HardforkVersion < 4 && !l.isCompiled { // compile the plain code to bytecode payload := util.LuaCodePayload(l._payload) code := string(payload.Code()) @@ -756,3 +774,17 @@ func (bc *DummyChain) QueryOnly(contract_name, queryInfo string, expectedErr str func StrToAddress(name string) string { return types.EncodeAddress(contract.StrHash(name)) } + +func isHexString(s string) bool { + // check is the input has even number of characters + if len(s)%2 != 0 { + return false + } + // check if the input contains only hex characters + for _, c := range s { + if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { + return false + } + } + return true +} From 4fda0c48a4f3747b6e904e9eea7ab57872d94f0f Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sun, 2 Jun 2024 00:26:20 +0000 Subject: [PATCH 095/101] move IsHexString to hex package --- cmd/aergocli/cmd/contract.go | 16 +--------------- contract/vm_dummy/vm_dummy.go | 16 +--------------- internal/enc/hex/hex.go | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/cmd/aergocli/cmd/contract.go b/cmd/aergocli/cmd/contract.go index e95f53bcd..e68f6dfca 100644 --- a/cmd/aergocli/cmd/contract.go +++ b/cmd/aergocli/cmd/contract.go @@ -130,20 +130,6 @@ func init() { rootCmd.AddCommand(contractCmd) } -func isHexString(s string) bool { - // check is the input has even number of characters - if len(s)%2 != 0 { - return false - } - // check if the input contains only hex characters - for _, c := range s { - if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { - return false - } - } - return true -} - func runDeployCmd(cmd *cobra.Command, args []string) error { var err error var code []byte @@ -206,7 +192,7 @@ func runDeployCmd(cmd *cobra.Command, args []string) error { deployArgs = []byte(args[1]) } // check if the data is in hex format - if isHexString(data) { + if hex.IsHexString(data) { if deployArgs != nil { cmd.SilenceUsage = false return errors.New("the call arguments are expected to be already on the hex data") diff --git a/contract/vm_dummy/vm_dummy.go b/contract/vm_dummy/vm_dummy.go index 199cfd08c..84da470ec 100644 --- a/contract/vm_dummy/vm_dummy.go +++ b/contract/vm_dummy/vm_dummy.go @@ -419,7 +419,7 @@ func NewLuaTxDeployBig(sender, recipient string, amount *big.Int, code string) * var isCompiled bool var err error - if isHexString(code) { + if hex.IsHexString(code) { payload, err = hex.Decode(code) if err != nil { return &luaTxDeploy{cErr: err} @@ -774,17 +774,3 @@ func (bc *DummyChain) QueryOnly(contract_name, queryInfo string, expectedErr str func StrToAddress(name string) string { return types.EncodeAddress(contract.StrHash(name)) } - -func isHexString(s string) bool { - // check is the input has even number of characters - if len(s)%2 != 0 { - return false - } - // check if the input contains only hex characters - for _, c := range s { - if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { - return false - } - } - return true -} diff --git a/internal/enc/hex/hex.go b/internal/enc/hex/hex.go index 6c484ee4d..fa2ea8525 100644 --- a/internal/enc/hex/hex.go +++ b/internal/enc/hex/hex.go @@ -9,3 +9,17 @@ func Encode(b []byte) string { func Decode(s string) ([]byte, error) { return hex.DecodeString(s) } + +func IsHexString(s string) bool { + // check is the input has even number of characters + if len(s)%2 != 0 { + return false + } + // check if the input contains only hex characters + for _, c := range s { + if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { + return false + } + } + return true +} From ed5671d0a9ccb4a6d70d24d505edd716d633baee Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sun, 2 Jun 2024 00:33:56 +0000 Subject: [PATCH 096/101] vm_test: increase timeout for long test --- contract/vm_dummy/vm_dummy_pub_test.go | 8 ++++---- 1 file 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 527777ba3..69416ef87 100644 --- a/contract/vm_dummy/vm_dummy_pub_test.go +++ b/contract/vm_dummy/vm_dummy_pub_test.go @@ -624,16 +624,16 @@ func TestGasBF(t *testing.T) { code2 := readLuaCode(t, "gas_bf_v2.lua") code4 := readLuaCode(t, "gas_bf_v4.lua") - // err = expectGas(t, string(code), 0, `"main"`, ``, 100000, SetHardForkVersion(1)) + // err = expectGas(t, string(code), 0, `"main"`, ``, 100000, SetHardForkVersion(1), SetTimeout(500)) // assert.NoError(t, err) - err = expectGas(string(code2), 0, `"main"`, ``, 47456244, SetHardForkVersion(2)) + err = expectGas(string(code2), 0, `"main"`, ``, 47456244, SetHardForkVersion(2), SetTimeout(500)) assert.NoError(t, err) - err = expectGas(string(code2), 0, `"main"`, ``, 47456046, SetHardForkVersion(3)) + err = expectGas(string(code2), 0, `"main"`, ``, 47456046, SetHardForkVersion(3), SetTimeout(500)) assert.NoError(t, err) - err = expectGas(string(code4), 0, `"main"`, ``, 47342481, SetHardForkVersion(4)) + err = expectGas(string(code4), 0, `"main"`, ``, 47342481, SetHardForkVersion(4), SetTimeout(500)) assert.NoError(t, err) } From 6b2e10778ab51d4136574f6996d2f2ea9bcff542 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sun, 2 Jun 2024 01:10:41 +0000 Subject: [PATCH 097/101] aergoluac: add feature of decode payload --- cmd/aergoluac/main.go | 14 ++++- cmd/aergoluac/util/luac_util.go | 93 +++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/cmd/aergoluac/main.go b/cmd/aergoluac/main.go index d305fd093..1c4c120b3 100644 --- a/cmd/aergoluac/main.go +++ b/cmd/aergoluac/main.go @@ -17,6 +17,7 @@ var ( rootCmd *cobra.Command abiFile string payload bool + decode bool version bool ) @@ -24,7 +25,7 @@ var githash = "No git hash provided" func init() { rootCmd = &cobra.Command{ - Use: "aergoluac --payload srcfile\n aergoluac --abi abifile srcfile bcfile", + Use: "aergoluac --payload srcfile\n aergoluac srcfile bcfile\n aergoluac --abi abifile srcfile bcfile\n aergoluac --decode payloadfile", Short: "Compile a lua contract", Long: "Compile a lua contract. This command makes a bytecode file and a ABI file or prints a payload data.", RunE: func(cmd *cobra.Command, args []string) error { @@ -34,7 +35,14 @@ func init() { cmd.Printf("Aergoluac %s\n", githash) return nil } - if payload { + + if decode { + if len(args) == 0 { + err = util.DecodeFromStdin() + } else { + err = util.DecodeFromFile(args[0]) + } + } else if payload { if len(args) == 0 { err = util.DumpFromStdin() } else { @@ -46,11 +54,13 @@ func init() { } err = util.CompileFromFile(args[0], args[1], abiFile) } + return err }, } rootCmd.PersistentFlags().StringVarP(&abiFile, "abi", "a", "", "abi filename") rootCmd.PersistentFlags().BoolVar(&payload, "payload", false, "print the compilation result consisting of bytecode and abi") + rootCmd.PersistentFlags().BoolVar(&decode, "decode", false, "extract raw bytecode and abi from payload (hex or base58)") rootCmd.PersistentFlags().BoolVar(&version, "version", false, "print the version number of aergoluac") } diff --git a/cmd/aergoluac/util/luac_util.go b/cmd/aergoluac/util/luac_util.go index 20b038260..9fc9daa89 100644 --- a/cmd/aergoluac/util/luac_util.go +++ b/cmd/aergoluac/util/luac_util.go @@ -20,6 +20,8 @@ import ( "runtime" "unsafe" + "github.com/aergoio/aergo/v2/internal/enc/hex" + "github.com/aergoio/aergo/v2/internal/enc/base58" "github.com/aergoio/aergo/v2/cmd/aergoluac/encoding" ) @@ -130,6 +132,97 @@ func dumpToBytes(L *C.lua_State) LuaCode { return NewLuaCode(C.GoBytes(unsafe.Pointer(c), C.int(lc)), C.GoBytes(unsafe.Pointer(a), C.int(la))) } +func Decode(srcFileName string, payload string) error { + var decoded []byte + var err error + + // check if the payload is in hex format + if hex.IsHexString(payload) { + // the data is expected to be copied from aergoscan view of + // the transaction that deployed the contract + decoded, err = hex.Decode(payload) + } else { + // the data is the output of aergoluac + decoded, err = encoding.DecodeCode(payload) + if err != nil { + // the data is extracted from JSON transaction from aergocli + decoded, err = base58.Decode(payload) + } + } + if err != nil { + return fmt.Errorf("failed to decode payload 1: %v", err.Error()) + } + + data := LuaCodePayload(decoded) + _, err = data.IsValidFormat() + if err != nil { + return fmt.Errorf("failed to decode payload 2: %v", err.Error()) + } + + contract := data.Code() + if !contract.IsValidFormat() { + // the data is the output of aergoluac, so it does not contain deploy arguments + contract = LuaCode(decoded) + data = NewLuaCodePayload(contract, []byte{}) + } + + err = os.WriteFile(srcFileName + "-bytecode", contract.ByteCode(), 0644); + if err != nil { + return fmt.Errorf("failed to write bytecode file: %v", err.Error()) + } + + err = os.WriteFile(srcFileName + "-abi", contract.ABI(), 0644); + if err != nil { + return fmt.Errorf("failed to write ABI file: %v", err.Error()) + } + + var deployArgs []byte + if data.HasArgs() { + deployArgs = data.Args() + } + err = os.WriteFile(srcFileName + "-deploy-arguments", deployArgs, 0644); + if err != nil { + return fmt.Errorf("failed to write deploy-arguments file: %v", err.Error()) + } + + fmt.Println("done.") + return nil +} + +func DecodeFromFile(srcFileName string) error { + payload, err := os.ReadFile(srcFileName) + if err != nil { + return fmt.Errorf("failed to read payload file: %v", err.Error()) + } + return Decode(srcFileName, string(payload)) +} + +func DecodeFromStdin() error { + fi, err := os.Stdin.Stat() + if err != nil { + return err + } + var buf []byte + if (fi.Mode() & os.ModeCharDevice) == 0 { + buf, err = ioutil.ReadAll(os.Stdin) + if err != nil { + return err + } + } else { + var bBuf bytes.Buffer + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + bBuf.WriteString(scanner.Text() + "\n") + } + if err = scanner.Err(); err != nil { + return err + } + buf = bBuf.Bytes() + } + return Decode("contract", string(buf)) +} + + type LuaCode []byte const byteCodeLenLen = 4 From 479d46cdcfec84a65500cb3b2b5db6c4a036d7c4 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 4 Jun 2024 03:57:52 -0300 Subject: [PATCH 098/101] support uppercase unit on decimal amounts --- contract/vm_callback.go | 4 ++-- contract/vm_callback_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/contract/vm_callback.go b/contract/vm_callback.go index 9d952d79f..b28c2fedf 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -956,9 +956,9 @@ func transformAmount(amountStr string, forkVersion int32) (*big.Int, error) { if forkVersion >= 4 { // Check for amount in decimal format - if strings.Contains(amountStr,".") && strings.HasSuffix(amountStr,"aergo") { + if strings.Contains(amountStr,".") && strings.HasSuffix(strings.ToLower(amountStr),"aergo") { // Extract the part before the unit - decimalAmount := strings.TrimSuffix(amountStr, "aergo") + decimalAmount := amountStr[:len(amountStr)-5] decimalAmount = strings.TrimRight(decimalAmount, " ") // Parse the decimal amount decimalAmount = parseDecimalAmount(decimalAmount, 18) diff --git a/contract/vm_callback_test.go b/contract/vm_callback_test.go index bcfc096d9..ceeec753e 100644 --- a/contract/vm_callback_test.go +++ b/contract/vm_callback_test.go @@ -3,6 +3,7 @@ package contract import ( "errors" "math/big" + "strings" "testing" "github.com/aergoio/aergo/v2/types" @@ -130,6 +131,19 @@ func TestTransformAmount(t *testing.T) { assert.Equal(t, tt.expectedAmount, result) } } + + // now in uppercase + result, err = transformAmount(strings.ToUpper(tt.amountStr), version) + + if tt.expectedError != nil { + if assert.Error(t, err, "Expected error: %s", tt.expectedError.Error()) { + assert.Equal(t, strings.ToUpper(tt.expectedError.Error()), strings.ToUpper(err.Error())) + } + } else { + if assert.NoError(t, err) && tt.expectedAmount != nil { + assert.Equal(t, tt.expectedAmount, result) + } + } } } @@ -215,6 +229,19 @@ func TestTransformAmount(t *testing.T) { assert.Equal(t, tt.expectedAmount, result, tt.amountStr) } } + + // now in uppercase + result, err = transformAmount(strings.ToUpper(tt.amountStr), tt.forkVersion) + + if tt.expectedError != nil { + if assert.Error(t, err, "Expected error: %s", tt.expectedError.Error()) { + assert.Equal(t, strings.ToUpper(tt.expectedError.Error()), strings.ToUpper(err.Error()), tt.amountStr) + } + } else { + if assert.NoError(t, err) && tt.expectedAmount != nil { + assert.Equal(t, tt.expectedAmount, result, tt.amountStr) + } + } } } From 9bd52206c3dfa900565720f2c7f7d8f31c8544e2 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sun, 7 Jul 2024 18:49:39 +0000 Subject: [PATCH 099/101] make bytecode handling more clear --- contract/vm.go | 50 +++++++++++++++++++++++---------------- contract/vm_callback.go | 18 +++++++------- state/statedb/contract.go | 17 ++++++------- 3 files changed, 48 insertions(+), 37 deletions(-) diff --git a/contract/vm.go b/contract/vm.go index 452e1c7c5..2a9aa047c 100644 --- a/contract/vm.go +++ b/contract/vm.go @@ -792,9 +792,9 @@ func Call( var err error var ci types.CallInfo - // get contract - contract := getContract(contractState, ctx.bs) - if contract != nil { + // get contract code + bytecode := getContractCode(contractState, ctx.bs) + if bytecode != nil { if len(payload) > 0 { // get call arguments err = getCallInfo(&ci, payload, contractAddress) @@ -814,7 +814,7 @@ func Call( // create a new executor contexts[ctx.service] = ctx - ce := newExecutor(contract, contractAddress, ctx, &ci, ctx.curContract.amount, false, false, contractState) + ce := newExecutor(bytecode, contractAddress, ctx, &ci, ctx.curContract.amount, false, false, contractState) defer ce.close() startTime := time.Now() @@ -892,33 +892,43 @@ func setRandomSeed(ctx *vmContext) { } func setContract(contractState *statedb.ContractState, contractAddress, payload []byte, ctx *vmContext) ([]byte, []byte, error) { + // the payload contains: + // on V3: bytecode + ABI + constructor arguments + // on V4: lua code + constructor arguments 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() + code := codePayload.Code() // type: LuaCode + var bytecodeABI []byte // 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) + bytecodeABI, err = Compile(string(code), nil) if err != nil { ctrLgr.Warn().Err(err).Str("contract", types.EncodeAddress(contractAddress)).Msg("deploy") return nil, nil, err } - //} else { + } else { // on previous hardfork versions the payload is bytecode + bytecodeABI = code } - err := contractState.SetCode(code.Bytes()) + // save the bytecode to the contract state + err := contractState.SetCode(bytecodeABI) if err != nil { return nil, nil, err } - contract := getContract(contractState, nil) - if contract == nil { + // extract the bytecode + bytecode := luacUtil.LuaCode(bytecodeABI).ByteCode() + + // check if it was properly stored + savedBytecode := getContractCode(contractState, nil) + if savedBytecode == nil || !bytes.Equal(savedBytecode, bytecode) { err = fmt.Errorf("cannot deploy contract %s", types.EncodeAddress(contractAddress)) ctrLgr.Warn().Str("error", "cannot load contract").Str( "contract", @@ -927,7 +937,7 @@ func setContract(contractState *statedb.ContractState, contractAddress, payload return nil, nil, err } - return contract, codePayload.Args(), nil + return bytecode, codePayload.Args(), nil } func Create( @@ -945,7 +955,7 @@ func Create( } // save the contract code - contract, args, err := setContract(contractState, contractAddress, payload, ctx) + bytecode, args, err := setContract(contractState, contractAddress, payload, ctx) if err != nil { return "", nil, ctx.usedFee(), err } @@ -976,7 +986,7 @@ func Create( } // create a new executor for the constructor - ce := newExecutor(contract, contractAddress, ctx, &ci, ctx.curContract.amount, true, false, contractState) + ce := newExecutor(bytecode, contractAddress, ctx, &ci, ctx.curContract.amount, true, false, contractState) defer ce.close() // call the constructor @@ -1072,8 +1082,8 @@ func freeContextSlot(ctx *vmContext) { func Query(contractAddress []byte, bs *state.BlockState, cdb ChainAccessor, contractState *statedb.ContractState, queryInfo []byte) (res []byte, err error) { var ci types.CallInfo - contract := getContract(contractState, bs) - if contract != nil { + bytecode := getContractCode(contractState, bs) + if bytecode != nil { err = getCallInfo(&ci, queryInfo, contractAddress) } else { addr := types.EncodeAddress(contractAddress) @@ -1099,7 +1109,7 @@ func Query(contractAddress []byte, bs *state.BlockState, cdb ChainAccessor, cont ctrLgr.Debug().Str("abi", string(queryInfo)).Str("contract", types.EncodeAddress(contractAddress)).Msg("query") } - ce := newExecutor(contract, contractAddress, ctx, &ci, ctx.curContract.amount, false, false, contractState) + ce := newExecutor(bytecode, contractAddress, ctx, &ci, ctx.curContract.amount, false, false, contractState) defer ce.close() defer func() { if dbErr := ce.closeQuerySql(); dbErr != nil { @@ -1140,8 +1150,8 @@ func CheckFeeDelegation(contractAddress []byte, bs *state.BlockState, bi *types. return fmt.Errorf("%s function is not declared of fee delegation", ci.Name) } - contract := getContract(contractState, bs) - if contract == nil { + bytecode := getContractCode(contractState, bs) + if bytecode == nil { addr := types.EncodeAddress(contractAddress) ctrLgr.Warn().Str("error", "not found contract").Str("contract", addr).Msg("checkFeeDelegation") err = fmt.Errorf("not found contract %s", addr) @@ -1173,7 +1183,7 @@ func CheckFeeDelegation(contractAddress []byte, bs *state.BlockState, bi *types. ci.Args = append([]interface{}{ci.Name}, ci.Args...) ci.Name = checkFeeDelegationFn - ce := newExecutor(contract, contractAddress, ctx, &ci, ctx.curContract.amount, false, true, contractState) + ce := newExecutor(bytecode, contractAddress, ctx, &ci, ctx.curContract.amount, false, true, contractState) defer ce.close() defer func() { if dbErr := ce.rollbackToSavepoint(); dbErr != nil { @@ -1209,7 +1219,7 @@ func getCode(contractState *statedb.ContractState, bs *state.BlockState) ([]byte return code, nil } -func getContract(contractState *statedb.ContractState, bs *state.BlockState) []byte { +func getContractCode(contractState *statedb.ContractState, bs *state.BlockState) []byte { code, err := getCode(contractState, bs) if err != nil { return nil diff --git a/contract/vm_callback.go b/contract/vm_callback.go index b28c2fedf..96072bff0 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -238,8 +238,8 @@ func luaCallContract(L *LState, service C.int, contractId *C.char, fname *C.char } // check if the contract exists - callee := getContract(cs.ctrState, ctx.bs) - if callee == nil { + bytecode := getContractCode(cs.ctrState, ctx.bs) + if bytecode == nil { return -1, C.CString("[Contract.LuaCallContract] cannot find contract " + C.GoString(contractId)) } @@ -256,7 +256,7 @@ func luaCallContract(L *LState, service C.int, contractId *C.char, fname *C.char // get the remaining gas from the parent LState ctx.refreshRemainingGas(L) // create a new executor with the remaining gas on the child LState - ce := newExecutor(callee, cid, ctx, &ci, amountBig, false, false, cs.ctrState) + ce := newExecutor(bytecode, cid, ctx, &ci, amountBig, false, false, cs.ctrState) defer func() { // close the executor, closes also the child LState ce.close() @@ -358,8 +358,8 @@ func luaDelegateCallContract(L *LState, service C.int, contractId *C.char, } // check if the contract exists - contract := getContract(contractState, ctx.bs) - if contract == nil { + bytecode := getContractCode(contractState, ctx.bs) + if bytecode == nil { return -1, C.CString("[Contract.LuaDelegateCallContract] cannot find contract " + contractIdStr) } @@ -374,7 +374,7 @@ func luaDelegateCallContract(L *LState, service C.int, contractId *C.char, // get the remaining gas from the parent LState ctx.refreshRemainingGas(L) // create a new executor with the remaining gas on the child LState - ce := newExecutor(contract, cid, ctx, &ci, zeroBig, false, false, contractState) + ce := newExecutor(bytecode, cid, ctx, &ci, zeroBig, false, false, contractState) defer func() { // close the executor, closes also the child LState ce.close() @@ -495,15 +495,15 @@ func luaSendAmount(L *LState, service C.int, contractId *C.char, amount *C.char) ci.Name = "default" // get the contract code - code := getContract(cs.ctrState, ctx.bs) - if code == nil { + bytecode := getContractCode(cs.ctrState, ctx.bs) + if bytecode == nil { return C.CString("[Contract.LuaSendAmount] cannot find contract:" + C.GoString(contractId)) } // get the remaining gas from the parent LState ctx.refreshRemainingGas(L) // create a new executor with the remaining gas on the child LState - ce := newExecutor(code, cid, ctx, &ci, amountBig, false, false, cs.ctrState) + ce := newExecutor(bytecode, cid, ctx, &ci, amountBig, false, false, cs.ctrState) defer func() { // close the executor, closes also the child LState ce.close() diff --git a/state/statedb/contract.go b/state/statedb/contract.go index 21f315ae2..3963f28c6 100644 --- a/state/statedb/contract.go +++ b/state/statedb/contract.go @@ -18,17 +18,17 @@ type ContractState struct { store db.DB } -func (cs *ContractState) SetCode(code []byte) error { - codeHash := common.Hasher(code) - storedCode, err := cs.GetRawKV(codeHash[:]) - if err == nil && !bytes.Equal(code, storedCode) { - err = cs.SetRawKV(codeHash[:], code) +func (cs *ContractState) SetCode(bytecode []byte) error { + bytecodeHash := common.Hasher(bytecode) + storedBytecode, err := cs.GetRawKV(bytecodeHash[:]) + if err == nil && !bytes.Equal(storedBytecode, bytecode) { + err = cs.SetRawKV(bytecodeHash[:], bytecode) } if err != nil { return err } - cs.State.CodeHash = codeHash[:] - cs.code = code + cs.State.CodeHash = bytecodeHash[:] + cs.code = bytecode return nil } @@ -42,7 +42,8 @@ func (cs *ContractState) GetCode() ([]byte, error) { // not defined. do nothing. return nil, nil } - err := loadData(cs.store, cs.State.GetCodeHash(), &cs.code) + // load the code into the contract state + err := loadData(cs.store, codeHash, &cs.code) if err != nil { return nil, err } From 20798f805b9286a10575f5e7902d750e8eeecd15 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sun, 7 Jul 2024 19:55:04 +0000 Subject: [PATCH 100/101] save the source code on contract state --- aergo-protobuf | 2 +- contract/vm.go | 9 +++++--- contract/vm_callback.go | 24 ++++++++++--------- contract/vm_state.go | 2 +- state/account.go | 2 +- state/statedb/contract.go | 42 ++++++++++++++++++++++++++++------ state/statedb/contract_test.go | 2 +- types/blockchain.pb.go | 8 +++++++ 8 files changed, 66 insertions(+), 25 deletions(-) diff --git a/aergo-protobuf b/aergo-protobuf index 0c3579cd4..4053eda7e 160000 --- a/aergo-protobuf +++ b/aergo-protobuf @@ -1 +1 @@ -Subproject commit 0c3579cd42f830eb787715a78895d971b8ee5fce +Subproject commit 4053eda7ec0f47f0afdd553f0f9f7fd24c539af1 diff --git a/contract/vm.go b/contract/vm.go index 2a9aa047c..c771be2d4 100644 --- a/contract/vm.go +++ b/contract/vm.go @@ -902,12 +902,15 @@ func setContract(contractState *statedb.ContractState, contractAddress, payload } code := codePayload.Code() // type: LuaCode + var sourceCode []byte var bytecodeABI []byte + var err error + // if hardfork version 4 if ctx.blockInfo.ForkVersion >= 4 { // the payload must be lua code. compile it to bytecode - var err error - bytecodeABI, err = Compile(string(code), nil) + sourceCode = code + bytecodeABI, err = Compile(string(sourceCode), nil) if err != nil { ctrLgr.Warn().Err(err).Str("contract", types.EncodeAddress(contractAddress)).Msg("deploy") return nil, nil, err @@ -918,7 +921,7 @@ func setContract(contractState *statedb.ContractState, contractAddress, payload } // save the bytecode to the contract state - err := contractState.SetCode(bytecodeABI) + err = contractState.SetCode(sourceCode, bytecodeABI) if err != nil { return nil, nil, err } diff --git a/contract/vm_callback.go b/contract/vm_callback.go index 96072bff0..9dc66009c 100644 --- a/contract/vm_callback.go +++ b/contract/vm_callback.go @@ -1102,7 +1102,8 @@ func luaDeployContract( bs := ctx.bs // contract code - var code []byte + var codeABI []byte + var sourceCode []byte // check if contract name or address is given cid, err := getAddressNameResolved(contractStr, bs) @@ -1113,20 +1114,21 @@ func luaDeployContract( return -1, C.CString("[Contract.LuaDeployContract]" + err.Error()) } // read the contract code - code, err = contractState.GetCode() + codeABI, err = contractState.GetCode() if err != nil { return -1, C.CString("[Contract.LuaDeployContract]" + err.Error()) - } else if len(code) == 0 { + } else if len(codeABI) == 0 { return -1, C.CString("[Contract.LuaDeployContract]: not found code") } + sourceCode = contractState.GetSourceCode() } // compile contract code if not found - if len(code) == 0 { + if len(codeABI) == 0 { if ctx.blockInfo.ForkVersion >= 2 { - code, err = Compile(contractStr, L) + codeABI, err = Compile(contractStr, L) } else { - code, err = Compile(contractStr, nil) + codeABI, err = Compile(contractStr, nil) } if err != nil { if C.luaL_hasuncatchablerror(L) != C.int(0) && @@ -1135,12 +1137,12 @@ func luaDeployContract( } else if err == ErrVmStart { return -1, C.CString("[Contract.LuaDeployContract] get luaState error") } - return -1, C.CString("[Contract.LuaDeployContract]compile error:" + err.Error()) } + sourceCode = []byte(contractStr) } - err = ctx.addUpdateSize(int64(len(code))) + err = ctx.addUpdateSize(int64(len(codeABI) + len(sourceCode))) if err != nil { return -1, C.CString("[Contract.LuaDeployContract]:" + err.Error()) } @@ -1205,10 +1207,10 @@ func luaDeployContract( ctx.curContract = prevContractInfo }() - runCode := util.LuaCode(code).ByteCode() + bytecode := util.LuaCode(codeABI).ByteCode() // save the contract code - err = contractState.SetCode(code) + err = contractState.SetCode(sourceCode, codeABI) if err != nil { return -1, C.CString("[Contract.LuaDeployContract]:" + err.Error()) } @@ -1222,7 +1224,7 @@ func luaDeployContract( // get the remaining gas from the parent LState ctx.refreshRemainingGas(L) // create a new executor with the remaining gas on the child LState - ce := newExecutor(runCode, newContract.ID(), ctx, &ci, amountBig, true, false, contractState) + ce := newExecutor(bytecode, newContract.ID(), ctx, &ci, amountBig, true, false, contractState) defer func() { // close the executor, which will close the child LState ce.close() diff --git a/contract/vm_state.go b/contract/vm_state.go index 0ba69e75e..27e2bd62f 100644 --- a/contract/vm_state.go +++ b/contract/vm_state.go @@ -118,7 +118,7 @@ func (re *recoveryEntry) recovery(bs *state.BlockState) error { return newDbSystemError(err) } if re.isDeploy { - err := cs.ctrState.SetCode(nil) + err := cs.ctrState.SetCode(nil, nil) if err != nil { return newDbSystemError(err) } diff --git a/state/account.go b/state/account.go index a2948721a..973aa2a65 100644 --- a/state/account.go +++ b/state/account.go @@ -102,7 +102,7 @@ func (as *AccountState) IsNew() bool { } func (as *AccountState) IsContract() bool { - return len(as.State().CodeHash) > 0 + return len(as.State().CodeHash) > 0 || len(as.State().SourceHash) > 0 } func (as *AccountState) IsDeploy() bool { diff --git a/state/statedb/contract.go b/state/statedb/contract.go index 3963f28c6..75a895f91 100644 --- a/state/statedb/contract.go +++ b/state/statedb/contract.go @@ -1,8 +1,6 @@ package statedb import ( - "bytes" - "github.com/aergoio/aergo-lib/db" "github.com/aergoio/aergo/v2/internal/common" "github.com/aergoio/aergo/v2/internal/enc/proto" @@ -18,17 +16,33 @@ type ContractState struct { store db.DB } -func (cs *ContractState) SetCode(bytecode []byte) error { +func (cs *ContractState) SetCode(sourceCode []byte, bytecode []byte) error { + var err error + + // hash the bytecode bytecodeHash := common.Hasher(bytecode) - storedBytecode, err := cs.GetRawKV(bytecodeHash[:]) - if err == nil && !bytes.Equal(storedBytecode, bytecode) { - err = cs.SetRawKV(bytecodeHash[:], bytecode) - } + // save the bytecode to the database + err = cs.SetRawKV(bytecodeHash[:], bytecode) if err != nil { return err } + // update the contract state cs.State.CodeHash = bytecodeHash[:] + // update the contract bytecode cs.code = bytecode + + if sourceCode != nil { + // hash the source code + sourceCodeHash := common.Hasher(sourceCode) + // save the source code to the database + err = cs.SetRawKV(sourceCodeHash[:], sourceCode) + if err != nil { + return err + } + // update the contract state + cs.State.SourceHash = sourceCodeHash[:] + } + return nil } @@ -50,6 +64,20 @@ func (cs *ContractState) GetCode() ([]byte, error) { return cs.code, nil } +func (cs *ContractState) GetSourceCode() []byte { + sourceCodeHash := cs.GetSourceHash() + if sourceCodeHash == nil { + return nil + } + // load the source code from the database + var sourceCode []byte + err := loadData(cs.store, sourceCodeHash, &sourceCode) + if err != nil { + return nil + } + return sourceCode +} + func (cs *ContractState) GetAccountID() types.AccountID { return cs.account } diff --git a/state/statedb/contract_test.go b/state/statedb/contract_test.go index 6761e1608..ebaa74f84 100644 --- a/state/statedb/contract_test.go +++ b/state/statedb/contract_test.go @@ -17,7 +17,7 @@ func TestContractStateCode(t *testing.T) { assert.NoError(t, err, "could not open contract state") // set code - err = contractState.SetCode(testBytes) + err = contractState.SetCode(nil, testBytes) assert.NoError(t, err, "set code to contract state") // get code diff --git a/types/blockchain.pb.go b/types/blockchain.pb.go index c41e59e91..39b38d07b 100644 --- a/types/blockchain.pb.go +++ b/types/blockchain.pb.go @@ -668,6 +668,7 @@ type State struct { CodeHash []byte `protobuf:"bytes,3,opt,name=codeHash,proto3" json:"codeHash,omitempty"` StorageRoot []byte `protobuf:"bytes,4,opt,name=storageRoot,proto3" json:"storageRoot,omitempty"` SqlRecoveryPoint uint64 `protobuf:"varint,5,opt,name=sqlRecoveryPoint,proto3" json:"sqlRecoveryPoint,omitempty"` + SourceHash []byte `protobuf:"bytes,6,opt,name=sourceHash,proto3" json:"sourceHash,omitempty"` } func (x *State) Reset() { @@ -723,6 +724,13 @@ func (x *State) GetCodeHash() []byte { return nil } +func (x *State) GetSourceHash() []byte { + if x != nil { + return x.SourceHash + } + return nil +} + func (x *State) GetStorageRoot() []byte { if x != nil { return x.StorageRoot From fedc0c3cc6406cd04c689bb5acd2d980900b3e8d Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 9 Jul 2024 05:00:04 +0000 Subject: [PATCH 101/101] apply luajit fixes --- libtool/src/luajit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtool/src/luajit b/libtool/src/luajit index 50ac3e6eb..3a1fec133 160000 --- a/libtool/src/luajit +++ b/libtool/src/luajit @@ -1 +1 @@ -Subproject commit 50ac3e6eb7b6d5e5f148e77f28001addb3383eab +Subproject commit 3a1fec1334431340038a5a6c62e65be1f7a36f78