Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add contract.gasLeft() #255

Draft
wants to merge 6 commits into
base: topic/hardfork-v4
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions contract/contract_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -280,6 +280,14 @@ static int moduleBalance(lua_State *L) {
return 1;
}

static int moduleGasLeft(lua_State *L) {
char str[64];
// do not charge gas for this call for easier calculations
snprintf(str, sizeof(str), "%llu", lua_gasget(L));
lua_pushstring(L, str);
return 1;
}

static int modulePcall(lua_State *L) {
int argc = lua_gettop(L) - 1;
int service = getLuaExecContext(L);
Expand Down Expand Up @@ -492,7 +500,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},
Expand All @@ -506,7 +527,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);
Expand Down
42 changes: 42 additions & 0 deletions contract/vm_dummy/test_files/contract_gasleft.lua
Original file line number Diff line number Diff line change
@@ -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)
10 changes: 10 additions & 0 deletions contract/vm_dummy/test_files/loop.lua
Original file line number Diff line number Diff line change
@@ -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)
42 changes: 42 additions & 0 deletions contract/vm_dummy/vm_dummy_pub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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":"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":"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
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 = `["18446744073709548612","18446744073709543257","18446744073709536656","18446744073709535921"]`
require.Equalf(t, expected, receipt.GetRet(), "contract call ret error")

}
}