From 885016845e2662007146164ca37723b40a8f2973 Mon Sep 17 00:00:00 2001 From: ThinhNX Date: Mon, 20 May 2024 14:05:29 +0700 Subject: [PATCH 1/3] feat(Gnovm/std): GasUsed --- gnovm/stdlibs/native.go | 19 ++++++++++ gnovm/stdlibs/std/gas_used.go | 24 +++++++++++++ gnovm/stdlibs/std/gas_used_test.go | 56 ++++++++++++++++++++++++++++++ gnovm/stdlibs/std/native.gno | 1 + 4 files changed, 100 insertions(+) create mode 100644 gnovm/stdlibs/std/gas_used.go create mode 100644 gnovm/stdlibs/std/gas_used_test.go diff --git a/gnovm/stdlibs/native.go b/gnovm/stdlibs/native.go index 3b1ab719e72..a04427c6994 100644 --- a/gnovm/stdlibs/native.go +++ b/gnovm/stdlibs/native.go @@ -482,6 +482,25 @@ var nativeFuncs = [...]nativeFunc{ )) }, }, + { + "std", + "GasUsed", + []gno.FieldTypeExpr{}, + []gno.FieldTypeExpr{ + {Name: gno.N("r0"), Type: gno.X("int64")}, + }, + func(m *gno.Machine) { + r0 := libs_std.GasUsed( + m, + ) + + m.PushValue(gno.Go2GnoValue( + m.Alloc, + m.Store, + reflect.ValueOf(&r0).Elem(), + )) + }, + }, { "std", "origSend", diff --git a/gnovm/stdlibs/std/gas_used.go b/gnovm/stdlibs/std/gas_used.go new file mode 100644 index 00000000000..7aa5b23d8b9 --- /dev/null +++ b/gnovm/stdlibs/std/gas_used.go @@ -0,0 +1,24 @@ +package std + +/* + ref: https://github.com/gnolang/gno/issues/1998 + this file contains std functions for query gas cost, gas used etc... +*/ +import ( + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" +) + +var ( + gasUsedInvoked = "GasUsedCalled" + /* + Consider where to save this config + gasCostDefault = store.DefaultGasConfig() + */ + defaultInvokerGasUsedCost = int64(10) +) + +// DefaultCost will be consumed whenever GasUsed is called, now set it ReadCostPerByte +func GasUsed(m *gno.Machine) int64 { + m.GasMeter.ConsumeGas(int64(defaultInvokerGasUsedCost), gasUsedInvoked) + return m.GasMeter.GasConsumedToLimit() +} diff --git a/gnovm/stdlibs/std/gas_used_test.go b/gnovm/stdlibs/std/gas_used_test.go new file mode 100644 index 00000000000..5242bb7f8ba --- /dev/null +++ b/gnovm/stdlibs/std/gas_used_test.go @@ -0,0 +1,56 @@ +package std + +import ( + "testing" + + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" + "github.com/gnolang/gno/tm2/pkg/store" + "github.com/stretchr/testify/assert" +) + +// Focus on test gasToConsume() +func TestGasUsed(t *testing.T) { + t.Parallel() + m := gno.NewMachine("gasToConsume", nil) + testTable := []struct { + tcName string + gasToConsume int64 + gasLimit int64 + expectPastLimit bool + invokeCost int64 + }{ + {"Test GasUsed Get", 10, 100, false, defaultInvokerGasUsedCost}, + {"Test GasUsed Invoke Cost", 4, 4 + defaultInvokerGasUsedCost, false, defaultInvokerGasUsedCost}, + {"Test GasUsed Past Limit", 4, 4, true, defaultInvokerGasUsedCost}, + // this case is OutOfGas's behavior + // {"Test GasUsed Get When Out Of Gas", 40, 4, true, cf.ReadCostPerByte}, + } + for _, tc := range testTable { + t.Run(tc.tcName, func(t *testing.T) { + m.GasMeter = store.NewGasMeter(tc.gasLimit) + if tc.expectPastLimit { + m.GasMeter.ConsumeGas(tc.gasToConsume, tc.tcName) + // After consume gasToConsume, the remaining gas is lower than invokeCost + // then GasUsed() should panic(OutOfGas) + beforeInvoke := m.GasMeter.Remaining() + assert.Panics(t, func() { + GasUsed(m) + }) + afterInvoke := m.GasMeter.Remaining() + // Check if GasMeter() acts as expected + assert.Equal(t, tc.expectPastLimit, m.GasMeter.IsOutOfGas()) + // Check if GasUsed() will not consume invokeCost + assert.Equal(t, beforeInvoke, afterInvoke) + } else { + m.GasMeter.ConsumeGas(tc.gasToConsume, tc.tcName) + beforeInvoke := m.GasMeter.Remaining() + result := GasUsed(m) + afterInvoke := m.GasMeter.Remaining() + // Check if GasUsed() invoked the invokeCost + assert.Equal(t, beforeInvoke-afterInvoke, tc.invokeCost) + // Check if the process consumes ecxactly amount of gas + assert.Equal(t, tc.gasToConsume+tc.invokeCost, result) + } + }) + } +} diff --git a/gnovm/stdlibs/std/native.gno b/gnovm/stdlibs/std/native.gno index 8043df49882..dd95d4561c8 100644 --- a/gnovm/stdlibs/std/native.gno +++ b/gnovm/stdlibs/std/native.gno @@ -5,6 +5,7 @@ func IsOriginCall() bool // injected func CurrentRealmPath() string // injected func GetChainID() string // injected func GetHeight() int64 // injected +func GasUsed() int64 // injected func GetOrigSend() Coins { den, amt := origSend() From 35bc6fd6774d9da27208c4bcdcaeb7d851467767 Mon Sep 17 00:00:00 2001 From: ThinhNX Date: Mon, 20 May 2024 14:29:47 +0700 Subject: [PATCH 2/3] fix cost --- gnovm/stdlibs/std/gas_used.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnovm/stdlibs/std/gas_used.go b/gnovm/stdlibs/std/gas_used.go index 7aa5b23d8b9..b0cf4100c95 100644 --- a/gnovm/stdlibs/std/gas_used.go +++ b/gnovm/stdlibs/std/gas_used.go @@ -14,7 +14,7 @@ var ( Consider where to save this config gasCostDefault = store.DefaultGasConfig() */ - defaultInvokerGasUsedCost = int64(10) + defaultInvokerGasUsedCost = int64(3) ) // DefaultCost will be consumed whenever GasUsed is called, now set it ReadCostPerByte From fe2af64300729dee66e5b4efd18d0fa88e6038f1 Mon Sep 17 00:00:00 2001 From: ThinhNX Date: Mon, 20 May 2024 14:54:11 +0700 Subject: [PATCH 3/3] change default gas config --- gnovm/stdlibs/std/gas_used.go | 8 +++++--- gnovm/stdlibs/std/gas_used_test.go | 7 ++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/gnovm/stdlibs/std/gas_used.go b/gnovm/stdlibs/std/gas_used.go index b0cf4100c95..cbc4763419c 100644 --- a/gnovm/stdlibs/std/gas_used.go +++ b/gnovm/stdlibs/std/gas_used.go @@ -6,19 +6,21 @@ package std */ import ( gno "github.com/gnolang/gno/gnovm/pkg/gnolang" + "github.com/gnolang/gno/tm2/pkg/store" ) var ( gasUsedInvoked = "GasUsedCalled" /* Consider where to save this config - gasCostDefault = store.DefaultGasConfig() + defaultGasConfig = store.DefaultGasConfig() */ - defaultInvokerGasUsedCost = int64(3) + // defaultGasConfig = int64(1000) + defaultInvokeCost = store.DefaultGasConfig().ReadCostFlat ) // DefaultCost will be consumed whenever GasUsed is called, now set it ReadCostPerByte func GasUsed(m *gno.Machine) int64 { - m.GasMeter.ConsumeGas(int64(defaultInvokerGasUsedCost), gasUsedInvoked) + m.GasMeter.ConsumeGas(defaultInvokeCost, gasUsedInvoked) return m.GasMeter.GasConsumedToLimit() } diff --git a/gnovm/stdlibs/std/gas_used_test.go b/gnovm/stdlibs/std/gas_used_test.go index 5242bb7f8ba..c89dbc8a3e3 100644 --- a/gnovm/stdlibs/std/gas_used_test.go +++ b/gnovm/stdlibs/std/gas_used_test.go @@ -12,6 +12,7 @@ import ( func TestGasUsed(t *testing.T) { t.Parallel() m := gno.NewMachine("gasToConsume", nil) + gasCostConfig := store.DefaultGasConfig().ReadCostFlat testTable := []struct { tcName string gasToConsume int64 @@ -19,9 +20,9 @@ func TestGasUsed(t *testing.T) { expectPastLimit bool invokeCost int64 }{ - {"Test GasUsed Get", 10, 100, false, defaultInvokerGasUsedCost}, - {"Test GasUsed Invoke Cost", 4, 4 + defaultInvokerGasUsedCost, false, defaultInvokerGasUsedCost}, - {"Test GasUsed Past Limit", 4, 4, true, defaultInvokerGasUsedCost}, + {"Test GasUsed Get", 10, 100000, false, gasCostConfig}, + {"Test GasUsed Invoke Cost", 4, 4 + gasCostConfig, false, gasCostConfig}, + {"Test GasUsed Past Limit", 4, 4, true, gasCostConfig}, // this case is OutOfGas's behavior // {"Test GasUsed Get When Out Of Gas", 40, 4, true, cf.ReadCostPerByte}, }