From 0b0033027311a1580feb44fb9519a60dd4614ca5 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 23 Sep 2023 05:07:59 +0000 Subject: [PATCH 1/4] implement contract.gasLeft() --- contract/contract_module.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/contract/contract_module.c b/contract/contract_module.c index b1c7aff9a..db9225f48 100644 --- a/contract/contract_module.c +++ b/contract/contract_module.c @@ -281,6 +281,12 @@ static int moduleBalance(lua_State *L) { return 1; } +static int moduleGasLeft(lua_State *L) { + // do not charge gas for this call for easier calculations + lua_pushinteger(L, lua_gasget(L)); + return 1; +} + static int modulePcall(lua_State *L) { int argc = lua_gettop(L) - 1; int service = getLuaExecContext(L); @@ -493,7 +499,20 @@ static const luaL_Reg deploy_call_meta[] = { {NULL, NULL} }; -static const luaL_Reg contract_lib[] = { +static const luaL_Reg contract_lib_v3[] = { + {"balance", moduleBalance}, + {"send", moduleSend}, + {"pcall", modulePcall}, + {"event", moduleEvent}, + {"stake", moduleStake}, + {"unstake", moduleUnstake}, + {"vote", moduleVote}, + {"voteDao", moduleVoteDao}, + {NULL, NULL} +}; + +static const luaL_Reg contract_lib_v4[] = { + {"gasLeft", moduleGasLeft}, {"balance", moduleBalance}, {"send", moduleSend}, {"pcall", modulePcall}, @@ -507,7 +526,11 @@ static const luaL_Reg contract_lib[] = { int luaopen_contract(lua_State *L) { - luaL_register(L, contract_str, contract_lib); + if (vm_is_hardfork(L, 4)) { + luaL_register(L, contract_str, contract_lib_v4); + } else { + luaL_register(L, contract_str, contract_lib_v3); + } lua_createtable(L, 0, 3); luaL_register(L, NULL, call_methods); From 66324ccd04b4c030298afbbec685ad3fb04cc916 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 24 Oct 2023 20:17:09 +0000 Subject: [PATCH 2/4] contract.gasLeft() returning string --- contract/contract_module.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/contract/contract_module.c b/contract/contract_module.c index db9225f48..1f60b5217 100644 --- a/contract/contract_module.c +++ b/contract/contract_module.c @@ -46,7 +46,7 @@ static int set_value(lua_State *L, const char *str) { luaL_error(L, "not enough memory"); } lua_pushstring(L, str); - free (str); + free(str); break; } default: @@ -282,8 +282,10 @@ static int moduleBalance(lua_State *L) { } static int moduleGasLeft(lua_State *L) { + char str[64]; // do not charge gas for this call for easier calculations - lua_pushinteger(L, lua_gasget(L)); + snprintf(str, sizeof(str), "%llu", lua_gasget(L)); + lua_pushstring(L, str); return 1; } From 55ebee4e2d9ff1cd6d8c914c448753a7f7b8e4fb Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 16 Nov 2023 02:50:56 -0300 Subject: [PATCH 3/4] add test for contract.gasLeft() --- .../vm_dummy/test_files/contract_gasleft.lua | 42 +++++++++++++++++++ contract/vm_dummy/test_files/loop.lua | 10 +++++ contract/vm_dummy/vm_dummy_pub_test.go | 42 +++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 contract/vm_dummy/test_files/contract_gasleft.lua create mode 100644 contract/vm_dummy/test_files/loop.lua diff --git a/contract/vm_dummy/test_files/contract_gasleft.lua b/contract/vm_dummy/test_files/contract_gasleft.lua new file mode 100644 index 000000000..654752f81 --- /dev/null +++ b/contract/vm_dummy/test_files/contract_gasleft.lua @@ -0,0 +1,42 @@ + +function test1() + local gas_before = bignum.number(contract.gasLeft()) + local a = 0 + for i = 1,10 do + a = a + i + end + local gas_after = bignum.number(contract.gasLeft()) + local used_gas = gas_before - gas_after + return gas_before, gas_after, used_gas +end + +function test2(...) + local gas_before = bignum.number(contract.gasLeft()) + contract.call(...) + local gas_after = bignum.number(contract.gasLeft()) + local used_gas = gas_before - gas_after + return gas_before, gas_after, used_gas +end + +function test3(address) + local g1 = contract.gasLeft() + local g2, g3 = contract.call(address, "test") + local g4 = contract.gasLeft() + return g1, g2, g3, g4 +end + +function callback() + return contract.gasLeft() +end + +abi.register(test1, test2, test3, callback) + +--- this is used in another contract + +function test() + local g1 = contract.gasLeft() + local g2 = contract.call(system.getSender(), "callback") + return g1, g2 +end + +abi.register(test) diff --git a/contract/vm_dummy/test_files/loop.lua b/contract/vm_dummy/test_files/loop.lua new file mode 100644 index 000000000..5748fd770 --- /dev/null +++ b/contract/vm_dummy/test_files/loop.lua @@ -0,0 +1,10 @@ + +function loop(n) + local a = 0 + for i = 1,n do + a = a + i + end + return a +end + +abi.register(loop) diff --git a/contract/vm_dummy/vm_dummy_pub_test.go b/contract/vm_dummy/vm_dummy_pub_test.go index 544d60c0b..4e1eb95b2 100644 --- a/contract/vm_dummy/vm_dummy_pub_test.go +++ b/contract/vm_dummy/vm_dummy_pub_test.go @@ -794,3 +794,45 @@ func TestTypeBigTable(t *testing.T) { require.NoErrorf(t, err, "failed to call tx") } } + +func TestContractGasLeft(t *testing.T) { + code1 := readLuaCode(t, "contract_gasleft.lua") + code2 := readLuaCode(t, "loop.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("user1", 1, types.Aergo), + NewLuaTxDeploy("user1", "A", 0, code1), + NewLuaTxDeploy("user1", "B", 0, code1), + NewLuaTxDeploy("user1", "loop", 0, code2), + ) + require.NoErrorf(t, err, "failed to connect new block") + + tx := NewLuaTxCall("user1", "A", 0, `{"Name":"test1", "Args":[]}`) + err = bc.ConnectBlock(tx) + require.NoErrorf(t, err, "failed to connect new block") + receipt := bc.GetReceipt(tx.Hash()) + expected := `[{"_bignum":"0"},{"_bignum":"0"},{"_bignum":"0"}]` + require.Equalf(t, expected, receipt.GetRet(), "contract call ret error") + + tx = NewLuaTxCall("user1", "A", 0, fmt.Sprintf(`{"Name":"test2", "Args":["%s","loop",10]}`, nameToAddress("loop"))) + err = bc.ConnectBlock(tx) + require.NoErrorf(t, err, "failed to connect new block") + receipt = bc.GetReceipt(tx.Hash()) + expected := `[{"_bignum":"0"},{"_bignum":"0"},{"_bignum":"0"}]` + require.Equalf(t, expected, receipt.GetRet(), "contract call ret error") + + // make an external call and a callback, like this: A -> B -> A + tx = NewLuaTxCall("user1", "A", 0, fmt.Sprintf(`{"Name":"test3", "Args":["%s"]}`, nameToAddress("B"))) + err = bc.ConnectBlock(tx) + require.NoErrorf(t, err, "failed to connect new block") + receipt = bc.GetReceipt(tx.Hash()) + expected := `["0","0","0","0"]` + require.Equalf(t, expected, receipt.GetRet(), "contract call ret error") + + } +} From 2899d84811b0b20049b96ec3e6c0f1dfdf33a070 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Thu, 16 Nov 2023 05:55:35 +0000 Subject: [PATCH 4/4] test: fix gas amount --- contract/vm_dummy/vm_dummy_pub_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contract/vm_dummy/vm_dummy_pub_test.go b/contract/vm_dummy/vm_dummy_pub_test.go index 4e1eb95b2..cc210f4c4 100644 --- a/contract/vm_dummy/vm_dummy_pub_test.go +++ b/contract/vm_dummy/vm_dummy_pub_test.go @@ -816,14 +816,14 @@ func TestContractGasLeft(t *testing.T) { err = bc.ConnectBlock(tx) require.NoErrorf(t, err, "failed to connect new block") receipt := bc.GetReceipt(tx.Hash()) - expected := `[{"_bignum":"0"},{"_bignum":"0"},{"_bignum":"0"}]` + expected := `[{"_bignum":"18446744073709548605"},{"_bignum":"18446744073709548172"},{"_bignum":"433"}]` require.Equalf(t, expected, receipt.GetRet(), "contract call ret error") tx = NewLuaTxCall("user1", "A", 0, fmt.Sprintf(`{"Name":"test2", "Args":["%s","loop",10]}`, nameToAddress("loop"))) err = bc.ConnectBlock(tx) require.NoErrorf(t, err, "failed to connect new block") receipt = bc.GetReceipt(tx.Hash()) - expected := `[{"_bignum":"0"},{"_bignum":"0"},{"_bignum":"0"}]` + expected = `[{"_bignum":"18446744073709547285"},{"_bignum":"18446744073709543337"},{"_bignum":"3948"}]` require.Equalf(t, expected, receipt.GetRet(), "contract call ret error") // make an external call and a callback, like this: A -> B -> A @@ -831,7 +831,7 @@ func TestContractGasLeft(t *testing.T) { err = bc.ConnectBlock(tx) require.NoErrorf(t, err, "failed to connect new block") receipt = bc.GetReceipt(tx.Hash()) - expected := `["0","0","0","0"]` + expected = `["18446744073709548612","18446744073709543257","18446744073709536656","18446744073709535921"]` require.Equalf(t, expected, receipt.GetRet(), "contract call ret error") }