From ba5cac7405ef16aaa50b057776666d103eb0b4da Mon Sep 17 00:00:00 2001 From: piux2 <90544084+piux2@users.noreply.github.com> Date: Mon, 11 Dec 2023 02:27:02 -0800 Subject: [PATCH 01/15] consolidate vm gas consumption with the rest --- gno.land/pkg/gnoland/app.go | 5 +- gno.land/pkg/sdk/vm/ante.go | 44 ++++++ gno.land/pkg/sdk/vm/ante_test.go | 211 +++++++++++++++++++++++++++++ gno.land/pkg/sdk/vm/common_test.go | 2 +- gno.land/pkg/sdk/vm/gas.go | 48 +++++++ gno.land/pkg/sdk/vm/handler.go | 33 +---- gno.land/pkg/sdk/vm/keeper.go | 42 ++++-- tm2/pkg/sdk/auth/ante.go | 9 +- 8 files changed, 353 insertions(+), 41 deletions(-) create mode 100644 gno.land/pkg/sdk/vm/ante.go create mode 100644 gno.land/pkg/sdk/vm/ante_test.go create mode 100644 gno.land/pkg/sdk/vm/gas.go diff --git a/gno.land/pkg/gnoland/app.go b/gno.land/pkg/gnoland/app.go index 412930e51dd..f34a3753d9a 100644 --- a/gno.land/pkg/gnoland/app.go +++ b/gno.land/pkg/gnoland/app.go @@ -60,6 +60,7 @@ func NewAppWithOptions(cfg *AppOptions) (abci.Application, error) { baseKey := store.NewStoreKey("base") // Create BaseApp. + // TODO: Add a flag to set min gas prices for the node, by default it does not check. baseApp := sdk.NewBaseApp("gnoland", cfg.Logger, cfg.DB, baseKey, mainKey) baseApp.SetAppVersion("dev") @@ -79,8 +80,10 @@ func NewAppWithOptions(cfg *AppOptions) (abci.Application, error) { baseApp.SetInitChainer(InitChainer(baseApp, acctKpr, bankKpr, cfg.SkipFailingGenesisTxs)) // Set AnteHandler + vmah := vm.NewAnteHandler(vmKpr) authOptions := auth.AnteOptions{ VerifyGenesisSignatures: false, // for development + AnteHandlerChain: []sdk.AnteHandler{vmah}, } authAnteHandler := auth.NewAnteHandler( acctKpr, bankKpr, auth.DefaultSigVerificationGasConsumer, authOptions) @@ -131,7 +134,7 @@ func NewApp(dataRootDir string, skipFailingGenesisTxs bool, logger log.Logger, m } cfg.Logger = logger - + cfg.SkipFailingGenesisTxs = skipFailingGenesisTxs return NewAppWithOptions(cfg) } diff --git a/gno.land/pkg/sdk/vm/ante.go b/gno.land/pkg/sdk/vm/ante.go new file mode 100644 index 00000000000..97b216329c3 --- /dev/null +++ b/gno.land/pkg/sdk/vm/ante.go @@ -0,0 +1,44 @@ +package vm + +import ( + "github.com/gnolang/gno/tm2/pkg/sdk" + "github.com/gnolang/gno/tm2/pkg/std" +) + +// It returns a AnteHandler function that can be chained togateher in app to check pre condition before put it the mempool and propergate to other nodes. +// It checks there is enough gas to execute the transaction in TxCheck and Simulation mode. +// XXX: We only abort the tx due to the insufficient gas. Should we even allow it pass ante handler to prevent censorship? In other word, should we only keep the min gas price as the check to drop a transaction? +func NewAnteHandler(vmKpr *VMKeeper) sdk.AnteHandler { + return func( + ctx sdk.Context, tx std.Tx, simulate bool, + ) (newCtx sdk.Context, res sdk.Result, abort bool) { + // skip the check for Deliver Mode Gas and Msg Executions + if ctx.Mode() == sdk.RunTxModeDeliver { + return ctx, res, false + } + // XXXX: check vm gas here for CheckTx and Simulation node. + + vmh := NewHandler(vmKpr) + msgs := tx.GetMsgs() + + for _, msg := range msgs { + // match message route + msgRoute := msg.Route() + if msgRoute == RouterKey { + // XXX: When there is no enough gas left in gas meter, it will stop the transaction in CheckTx() before passing the tx to mempool and broadcasting to other nodes. + // Same message will be processed sencond time in DeliverTx(). It should be ok for now, since CheckTx and DeliverTx execution are in different contexts that are not linked to each other. + + res = vmh.Process(ctx, msg) + } + + // we don't abort the transaction when there is a message execution failer. the failed message should be allowed to propergate to other nodes. + // We dont not want to censor the tx for VM execution failures just by one node. + // XXX: Do not uncomment this. Do not remvove this either to prevent someone accidentally add this check. + // if !res.IsOK() { + // return ctx, res, true + // } + } + + return ctx, res, false + } +} diff --git a/gno.land/pkg/sdk/vm/ante_test.go b/gno.land/pkg/sdk/vm/ante_test.go new file mode 100644 index 00000000000..d6170790693 --- /dev/null +++ b/gno.land/pkg/sdk/vm/ante_test.go @@ -0,0 +1,211 @@ +package vm + +import ( + "testing" + + bft "github.com/gnolang/gno/tm2/pkg/bft/types" + "github.com/gnolang/gno/tm2/pkg/crypto" + "github.com/gnolang/gno/tm2/pkg/sdk" + "github.com/gnolang/gno/tm2/pkg/sdk/auth" + "github.com/gnolang/gno/tm2/pkg/std" + "github.com/gnolang/gno/tm2/pkg/store" + "github.com/jaekwon/testify/assert" +) + +// The gas consumed is counted only towards the execution of gno messages +// We only abort the tx due to the insufficient gas. + +func TestAddPkgSimulateGas(t *testing.T) { + // setup + success := true + ctx, tx, anteHandler := setup(success) + // simulation should not fail even if gas wanted is low + + ctx = ctx.WithMode(sdk.RunTxModeSimulate) + simulate := true + + tx.Fee.GasWanted = 1 + gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) + gctx, res, abort := anteHandler(gctx, tx, simulate) + gasSimulate := gctx.GasMeter().GasConsumed() + + assert.False(t, abort) + assert.True(t, res.IsOK()) + assert.Equal(t, gasSimulate, int64(94055)) +} + +// failed tx will not aborted +func TestAddPkgSimulateFailedGas(t *testing.T) { + // setup + success := false + ctx, tx, anteHandler := setup(success) + // simulation should not fail even if gas wanted is low + + ctx = ctx.WithMode(sdk.RunTxModeSimulate) + simulate := true + + tx.Fee.GasWanted = 1 + gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) + gctx, res, abort := anteHandler(gctx, tx, simulate) + gasSimulate := gctx.GasMeter().GasConsumed() + + assert.False(t, abort) + assert.True(t, res.IsOK()) + assert.Equal(t, gasSimulate, int64(18989)) +} + +func TestAddPkgCheckTxGas(t *testing.T) { + success := true + ctx, tx, anteHandler := setup(success) + // Testing case with enough gas and succcful message execution + + ctx = ctx.WithMode(sdk.RunTxModeCheck) + simulate := false + tx.Fee.GasWanted = 500000 + gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) + gctx, res, abort := anteHandler(gctx, tx, simulate) + gasCheck := gctx.GasMeter().GasConsumed() + + assert.False(t, abort) + assert.True(t, res.IsOK()) + assert.Equal(t, gasCheck, int64(94055)) +} + +// CheckTx only abort when there is no enough gas meter. +func TestAddPkgCheckTxNoGas(t *testing.T) { + success := true + ctx, tx, anteHandler := setup(success) + // Testing case with enough gas and succcful message execution + ctx = ctx.WithMode(sdk.RunTxModeCheck) + simulate := false + tx.Fee.GasWanted = 3000 + gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) + + var res sdk.Result + abort := false + + defer func() { + if r := recover(); r != nil { + switch r.(type) { + case store.OutOfGasException: + res.Error = sdk.ABCIError(std.ErrOutOfGas("")) + abort = true + default: + t.Errorf("should panic on OutOfGasException only") + } + assert.True(t, abort) + assert.False(t, res.IsOK()) + gasCheck := gctx.GasMeter().GasConsumed() + assert.Equal(t, gasCheck, int64(3231)) + } else { + t.Errorf("should panic") + } + }() + gctx, res, abort = anteHandler(gctx, tx, simulate) +} + +// failed tx execution should pass the vm.AnteHandler +func TestAddPkgCheckTxFailedGas(t *testing.T) { + success := false + ctx, tx, anteHandler := setup(success) + + ctx = ctx.WithMode(sdk.RunTxModeCheck) + simulate := false + tx.Fee.GasWanted = 500000 + gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) + gctx, res, abort := anteHandler(gctx, tx, simulate) + gasCheck := gctx.GasMeter().GasConsumed() + + assert.False(t, abort) + assert.True(t, res.IsOK()) + assert.Equal(t, gasCheck, int64(18989)) +} + +// For deliver Tx ante handler does not check gas consumption and does not consume gas +func TestAddPkgDeliverTxGas(t *testing.T) { + success := true + ctx, tx, anteHandler := setup(success) + + var simulate bool + + ctx = ctx.WithMode(sdk.RunTxModeDeliver) + simulate = false + tx.Fee.GasWanted = 1 + gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) + gasDeliver := gctx.GasMeter().GasConsumed() + gctx, res, abort := anteHandler(gctx, tx, simulate) + assert.False(t, abort) + assert.True(t, res.IsOK()) + assert.Equal(t, gasDeliver, int64(0)) +} + +// // For deliver Tx, ante handler does not check gas consumption and does not consume gas +func TestAddPkgDeliverTxFailGas(t *testing.T) { + success := true + ctx, tx, anteHandler := setup(success) + + var simulate bool + + ctx = ctx.WithMode(sdk.RunTxModeDeliver) + simulate = false + tx.Fee.GasWanted = 1 + gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) + gasDeliver := gctx.GasMeter().GasConsumed() + gctx, res, abort := anteHandler(gctx, tx, simulate) + assert.False(t, abort) + assert.True(t, res.IsOK()) + assert.Equal(t, gasDeliver, int64(0)) +} + +func setup(success bool) (sdk.Context, sdk.Tx, sdk.AnteHandler) { + // setup + env := setupTestEnv() + ctx := env.ctx + // conduct base gas meter tests from a non-genesis block since genesis block use infinite gas meter instead. + ctx = ctx.WithBlockHeader(&bft.Header{Height: int64(1)}) + anteHandler := NewAnteHandler(env.vmk) + // Createa an account with 10M gnot (10gnot) + addr := crypto.AddressFromPreimage([]byte("test1")) + acc := env.acck.NewAccountWithAddress(ctx, addr) + env.acck.SetAccount(ctx, acc) + env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) + // success message + var files []*std.MemFile + if success { + files = []*std.MemFile{ + { + Name: "hello.gno", + Body: `package hello + +import "std" + +func Echo() string { + return "hello world" +}`, + }, + } + } else { + // falied message + files = []*std.MemFile{ + { + Name: "hello.gno", + Body: `package hello + + import "std" + + func Echo() UnknowType { + return "hello world" + }`, + }, + } + } + + pkgPath := "gno.land/r/hello" + // creat messages and a transaction + msg := NewMsgAddPackage(addr, pkgPath, files) + msgs := []std.Msg{msg} + fee := std.NewFee(500000, std.MustParseCoin("1ugnot")) + tx := std.NewTx(msgs, fee, []std.Signature{}, "") + + return ctx, tx, anteHandler +} diff --git a/gno.land/pkg/sdk/vm/common_test.go b/gno.land/pkg/sdk/vm/common_test.go index 60a92906cb6..28bf02a1869 100644 --- a/gno.land/pkg/sdk/vm/common_test.go +++ b/gno.land/pkg/sdk/vm/common_test.go @@ -35,7 +35,7 @@ func setupTestEnv() testEnv { ms.MountStoreWithDB(iavlCapKey, iavl.StoreConstructor, db) ms.LoadLatestVersion() - ctx := sdk.NewContext(sdk.RunTxModeDeliver, ms, &bft.Header{ChainID: "test-chain-id"}, log.NewNopLogger()) + ctx := sdk.NewContext(sdk.RunTxModeDeliver, ms, &bft.Header{ChainID: "test-chain-id"}, log.TestingLogger()) acck := authm.NewAccountKeeper(iavlCapKey, std.ProtoBaseAccount) bank := bankm.NewBankKeeper(acck) stdlibsDir := filepath.Join("..", "..", "..", "..", "gnovm", "stdlibs") diff --git a/gno.land/pkg/sdk/vm/gas.go b/gno.land/pkg/sdk/vm/gas.go new file mode 100644 index 00000000000..65cae3b2929 --- /dev/null +++ b/gno.land/pkg/sdk/vm/gas.go @@ -0,0 +1,48 @@ +package vm + +import ( + "fmt" + + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" + + "github.com/gnolang/gno/tm2/pkg/sdk" + "github.com/gnolang/overflow" +) + +const ( + + // We will use gasMemFactor and gasCpuFactor to multiply the vm memory allocation and cpu cycles to get the gas number. + // We can use these two factoctors to keep the gas for storage access, CPU and Mem in reasonable proportion. + gasFactorMem int64 = 1 // change this value based on gas profiling + gasFactorCpu int64 = 1 // change this value based on gas profiling + + logPrefixAddPkg = "gas.vm.addpkg" + logPrefixCall = "gas.vm.call" + logPrefixRun = "gas.vm.run" + logPrefixQeval = "gas.vm.qeval" + logPrefixQevalStr = "gas.vm.qevalstr" +) + +// consume gas and log vm gas usage +func consumeGas(ctx sdk.Context, m *gno.Machine, prefix string, pkgPath string, expr string) { + _, mem := m.Alloc.Status() + + gasCpu := overflow.Mul64p(m.Cycles, gasFactorCpu) + gasMem := overflow.Mul64p(mem, gasFactorMem) + + // we simplify the log here, the storage gas log included tx size and sigature verification gas. + storeLog := fmt.Sprintf("%s.storage, %s %s, %d", prefix, pkgPath, expr, ctx.GasMeter().GasConsumed()) + ctx.Logger().Info(storeLog) + + memLog := fmt.Sprintf("%s.memalloc, %s %s, %d", prefix, pkgPath, expr, gasMem) + ctx.Logger().Info(memLog) + + cpuLog := fmt.Sprintf("%s.cpucycles, %s %s, %d", prefix, pkgPath, expr, gasCpu) + ctx.Logger().Info(cpuLog) + + ctx.GasMeter().ConsumeGas(gasMem, prefix+".MemAlloc") + ctx.GasMeter().ConsumeGas(gasCpu, prefix+".CpuCycles") + + gasTotal := fmt.Sprintf("%s.total, %s %s, %d", prefix, pkgPath, expr, ctx.GasMeter().GasConsumed()) + ctx.Logger().Info(gasTotal) +} diff --git a/gno.land/pkg/sdk/vm/handler.go b/gno.land/pkg/sdk/vm/handler.go index 6c3a97696d6..e1dd31846e7 100644 --- a/gno.land/pkg/sdk/vm/handler.go +++ b/gno.land/pkg/sdk/vm/handler.go @@ -6,7 +6,6 @@ import ( abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" "github.com/gnolang/gno/tm2/pkg/sdk" - "github.com/gnolang/gno/tm2/pkg/sdk/auth" "github.com/gnolang/gno/tm2/pkg/std" ) @@ -37,15 +36,7 @@ func (vh vmHandler) Process(ctx sdk.Context, msg std.Msg) sdk.Result { // Handle MsgAddPackage. func (vh vmHandler) handleMsgAddPackage(ctx sdk.Context, msg MsgAddPackage) sdk.Result { - amount, err := std.ParseCoins("1000000ugnot") // XXX calculate - if err != nil { - return abciResult(err) - } - err = vh.vm.bank.SendCoins(ctx, msg.Creator, auth.FeeCollectorAddress(), amount) - if err != nil { - return abciResult(err) - } - err = vh.vm.AddPackage(ctx, msg) + err := vh.vm.AddPackage(ctx, msg) if err != nil { return abciResult(err) } @@ -54,16 +45,7 @@ func (vh vmHandler) handleMsgAddPackage(ctx sdk.Context, msg MsgAddPackage) sdk. // Handle MsgCall. func (vh vmHandler) handleMsgCall(ctx sdk.Context, msg MsgCall) (res sdk.Result) { - amount, err := std.ParseCoins("1000000ugnot") // XXX calculate - if err != nil { - return abciResult(err) - } - err = vh.vm.bank.SendCoins(ctx, msg.Caller, auth.FeeCollectorAddress(), amount) - if err != nil { - return abciResult(err) - } - resstr := "" - resstr, err = vh.vm.Call(ctx, msg) + resstr, err := vh.vm.Call(ctx, msg) if err != nil { return abciResult(err) } @@ -81,16 +63,7 @@ func (vh vmHandler) handleMsgCall(ctx sdk.Context, msg MsgCall) (res sdk.Result) // Handle MsgRun. func (vh vmHandler) handleMsgRun(ctx sdk.Context, msg MsgRun) (res sdk.Result) { - amount, err := std.ParseCoins("1000000ugnot") // XXX calculate - if err != nil { - return abciResult(err) - } - err = vh.vm.bank.SendCoins(ctx, msg.Caller, auth.FeeCollectorAddress(), amount) - if err != nil { - return abciResult(err) - } - resstr := "" - resstr, err = vh.vm.Run(ctx, msg) + resstr, err := vh.vm.Run(ctx, msg) if err != nil { return abciResult(err) } diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index b0ae2180c36..f4cf9841498 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -198,10 +198,18 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) error { Context: msgCtx, MaxCycles: vm.maxCycles, }) - defer m2.Release() - m2.RunMemPackage(memPkg, true) + defer func() { + if r := recover(); r != nil { + err = errors.Wrap(fmt.Errorf("%v", r), "VM addpkg panic: %v\n%s\n", + r, m2.String()) + consumeGas(ctx, m2, logPrefixAddPkg, pkgPath, "") + return + } + m2.Release() + }() - ctx.Logger().Info("CPUCYCLES", "addpkg", m2.Cycles) + m2.RunMemPackage(memPkg, true) + consumeGas(ctx, m2, logPrefixAddPkg, pkgPath, "") return nil } @@ -278,12 +286,13 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { if r := recover(); r != nil { err = errors.Wrap(fmt.Errorf("%v", r), "VM call panic: %v\n%s\n", r, m.String()) + consumeGas(ctx, m, logPrefixCall, pkgPath, fnc) return } m.Release() }() rtvs := m.Eval(xn) - ctx.Logger().Info("CPUCYCLES call: ", m.Cycles) + consumeGas(ctx, m, logPrefixCall, pkgPath, fnc) for i, rtv := range rtvs { res = res + rtv.String() if i < len(rtvs)-1 { @@ -340,9 +349,20 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { Context: msgCtx, MaxCycles: vm.maxCycles, }) - defer m.Release() + // XXX MsgRun does not have pkgPath. How do we find it on chain? + pkgPath := "" + defer func() { + if r := recover(); r != nil { + err = errors.Wrap(fmt.Errorf("%v", r), "VM run main addpkg panic: %v\n%s\n", + r, m.String()) + consumeGas(ctx, m, logPrefixRun, pkgPath, "add_main") + return + } + m.Release() + }() + _, pv := m.RunMemPackage(memPkg, false) - ctx.Logger().Info("CPUCYCLES", "addpkg", m.Cycles) + consumeGas(ctx, m, logPrefixRun, pkgPath, "add_main") m2 := gno.NewMachineWithOptions( gno.MachineOptions{ @@ -356,14 +376,15 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { m2.SetActivePackage(pv) defer func() { if r := recover(); r != nil { - err = errors.Wrap(fmt.Errorf("%v", r), "VM call panic: %v\n%s\n", + err = errors.Wrap(fmt.Errorf("%v", r), "VM run main call panic: %v\n%s\n", r, m2.String()) + consumeGas(ctx, m2, logPrefixRun, pkgPath, "main") return } m2.Release() }() m2.RunMain() - ctx.Logger().Info("CPUCYCLES call: ", m2.Cycles) + consumeGas(ctx, m2, logPrefixRun, pkgPath, "call_main") res = buf.String() return res, nil } @@ -425,6 +446,7 @@ func (vm *VMKeeper) QueryFuncs(ctx sdk.Context, pkgPath string) (fsigs FunctionS } fsigs = append(fsigs, fsig) } + ctx.Logger().Info("gas.vm.qfuncs.total,", pkgPath, ",", ctx.GasMeter().GasConsumed()) return fsigs, nil } @@ -472,11 +494,13 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res if r := recover(); r != nil { err = errors.Wrap(fmt.Errorf("%v", r), "VM query eval panic: %v\n%s\n", r, m.String()) + consumeGas(ctx, m, logPrefixQeval, pkgPath, expr) return } m.Release() }() rtvs := m.Eval(xx) + consumeGas(ctx, m, logPrefixQeval, pkgPath, expr) res = "" for i, rtv := range rtvs { res += rtv.String() @@ -532,11 +556,13 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string if r := recover(); r != nil { err = errors.Wrap(fmt.Errorf("%v", r), "VM query eval string panic: %v\n%s\n", r, m.String()) + consumeGas(ctx, m, logPrefixQevalStr, pkgPath, expr) return } m.Release() }() rtvs := m.Eval(xx) + consumeGas(ctx, m, logPrefixQevalStr, pkgPath, expr) if len(rtvs) != 1 { return "", errors.New("expected 1 string result, got %d", len(rtvs)) } else if rtvs[0].T.Kind() != gno.StringKind { diff --git a/tm2/pkg/sdk/auth/ante.go b/tm2/pkg/sdk/auth/ante.go index 6abc4380e89..5623b0364aa 100644 --- a/tm2/pkg/sdk/auth/ante.go +++ b/tm2/pkg/sdk/auth/ante.go @@ -36,6 +36,8 @@ type AnteOptions struct { // This is useful for development, and maybe production chains. // Always check your settings and inspect genesis transactions. VerifyGenesisSignatures bool + // Additional AnteHandler applied in order + AnteHandlerChain []sdk.AnteHandler } // NewAnteHandler returns an AnteHandler that checks and increments sequence @@ -161,7 +163,12 @@ func NewAnteHandler(ak AccountKeeper, bank BankKeeperI, sigGasConsumer Signature } ak.SetAccount(newCtx, signerAccs[i]) } - + for _, anteHandler := range opts.AnteHandlerChain { + newCtx, res, abort := anteHandler(newCtx, tx, simulate) + if abort { + return newCtx, res, true + } + } // TODO: tx tags (?) return newCtx, sdk.Result{GasWanted: tx.Fee.GasWanted}, false // continue... } From 1d513cead5d24043ea3b38a2b4822bf3683b9b2f Mon Sep 17 00:00:00 2001 From: piux2 <90544084+piux2@users.noreply.github.com> Date: Tue, 12 Dec 2023 00:56:36 -0800 Subject: [PATCH 02/15] fix defer() in vm keeper --- gno.land/pkg/sdk/vm/keeper.go | 118 +++++++++++++++++++++------------- 1 file changed, 74 insertions(+), 44 deletions(-) diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index f4cf9841498..d5e12b1c97c 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -141,7 +141,7 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) error { pkgPath := msg.Package.Path memPkg := msg.Package deposit := msg.Deposit - store := vm.getGnoStore(ctx) + gnostore := vm.getGnoStore(ctx) // Validate arguments. if creator.IsZero() { @@ -154,7 +154,7 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) error { if err := msg.Package.Validate(); err != nil { return ErrInvalidPkgPath(err.Error()) } - if pv := store.GetPackage(pkgPath, false); pv != nil { + if pv := gnostore.GetPackage(pkgPath, false); pv != nil { return ErrInvalidPkgPath("package already exists: " + pkgPath) } @@ -193,17 +193,22 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) error { gno.MachineOptions{ PkgPath: "", Output: os.Stdout, // XXX - Store: store, - Alloc: store.GetAllocator(), + Store: gnostore, + Alloc: gnostore.GetAllocator(), Context: msgCtx, MaxCycles: vm.maxCycles, }) defer func() { if r := recover(); r != nil { - err = errors.Wrap(fmt.Errorf("%v", r), "VM addpkg panic: %v\n%s\n", + switch r.(type) { + case store.OutOfGasException: // panic in consumeGas() + panic(r) + default: + err = errors.Wrap(fmt.Errorf("%v", r), "VM addpkg panic: %v\n%s\n", r, m2.String()) - consumeGas(ctx, m2, logPrefixAddPkg, pkgPath, "") - return + consumeGas(ctx, m2, logPrefixAddPkg, pkgPath, "") + return + } } m2.Release() }() @@ -217,12 +222,12 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) error { func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { pkgPath := msg.PkgPath // to import fnc := msg.Func - store := vm.getGnoStore(ctx) + gnostore := vm.getGnoStore(ctx) // Get the package and function type. - pv := store.GetPackage(pkgPath, false) + pv := gnostore.GetPackage(pkgPath, false) pl := gno.PackageNodeLocation(pkgPath) - pn := store.GetBlockNode(pl).(*gno.PackageNode) - ft := pn.GetStaticTypeOf(store, gno.Name(fnc)).(*gno.FuncType) + pn := gnostore.GetBlockNode(pl).(*gno.PackageNode) + ft := pn.GetStaticTypeOf(gnostore, gno.Name(fnc)).(*gno.FuncType) // Make main Package with imports. mpn := gno.NewPackageNode("main", "main", nil) mpn.Define("pkg", gno.TypedValue{T: &gno.PackageType{}, V: pv}) @@ -276,18 +281,23 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { gno.MachineOptions{ PkgPath: "", Output: os.Stdout, // XXX - Store: store, + Store: gnostore, Context: msgCtx, - Alloc: store.GetAllocator(), + Alloc: gnostore.GetAllocator(), MaxCycles: vm.maxCycles, }) m.SetActivePackage(mpv) defer func() { if r := recover(); r != nil { - err = errors.Wrap(fmt.Errorf("%v", r), "VM call panic: %v\n%s\n", - r, m.String()) - consumeGas(ctx, m, logPrefixCall, pkgPath, fnc) - return + switch r.(type) { + case store.OutOfGasException: // panic in consumeGas() + panic(r) + default: + err = errors.Wrap(fmt.Errorf("%v", r), "VM call panic: %v\n%s\n", + r, m.String()) + consumeGas(ctx, m, logPrefixCall, pkgPath, fnc) + return + } } m.Release() }() @@ -307,7 +317,7 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { caller := msg.Caller pkgAddr := caller - store := vm.getGnoStore(ctx) + gnostore := vm.getGnoStore(ctx) send := msg.Send memPkg := msg.Package @@ -344,8 +354,8 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { gno.MachineOptions{ PkgPath: "", Output: buf, - Store: store, - Alloc: store.GetAllocator(), + Store: gnostore, + Alloc: gnostore.GetAllocator(), Context: msgCtx, MaxCycles: vm.maxCycles, }) @@ -353,10 +363,15 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { pkgPath := "" defer func() { if r := recover(); r != nil { - err = errors.Wrap(fmt.Errorf("%v", r), "VM run main addpkg panic: %v\n%s\n", - r, m.String()) - consumeGas(ctx, m, logPrefixRun, pkgPath, "add_main") - return + switch r.(type) { + case store.OutOfGasException: // panic in consumeGas() + panic(r) + default: + err = errors.Wrap(fmt.Errorf("%v", r), "VM run main addpkg panic: %v\n%s\n", + r, m.String()) + consumeGas(ctx, m, logPrefixRun, pkgPath, "add_main") + return + } } m.Release() }() @@ -368,18 +383,23 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { gno.MachineOptions{ PkgPath: "", Output: buf, - Store: store, - Alloc: store.GetAllocator(), + Store: gnostore, + Alloc: gnostore.GetAllocator(), Context: msgCtx, MaxCycles: vm.maxCycles, }) m2.SetActivePackage(pv) defer func() { if r := recover(); r != nil { - err = errors.Wrap(fmt.Errorf("%v", r), "VM run main call panic: %v\n%s\n", - r, m2.String()) - consumeGas(ctx, m2, logPrefixRun, pkgPath, "main") - return + switch r.(type) { + case store.OutOfGasException: // panic in consumeGas() + panic(r) + default: + err = errors.Wrap(fmt.Errorf("%v", r), "VM run main call panic: %v\n%s\n", + r, m2.String()) + consumeGas(ctx, m2, logPrefixRun, pkgPath, "main") + return + } } m2.Release() }() @@ -455,10 +475,10 @@ func (vm *VMKeeper) QueryFuncs(ctx sdk.Context, pkgPath string) (fsigs FunctionS // TODO: then, rename to "Eval". func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res string, err error) { alloc := gno.NewAllocator(maxAllocQuery) - store := vm.getGnoStore(ctx) + gnostore := vm.getGnoStore(ctx) pkgAddr := gno.DerivePkgAddr(pkgPath) // Get Package. - pv := store.GetPackage(pkgPath, false) + pv := gnostore.GetPackage(pkgPath, false) if pv == nil { err = ErrInvalidPkgPath(fmt.Sprintf( "package not found: %s", pkgPath)) @@ -485,17 +505,22 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res gno.MachineOptions{ PkgPath: pkgPath, Output: os.Stdout, // XXX - Store: store, + Store: gnostore, Context: msgCtx, Alloc: alloc, MaxCycles: vm.maxCycles, }) defer func() { if r := recover(); r != nil { - err = errors.Wrap(fmt.Errorf("%v", r), "VM query eval panic: %v\n%s\n", - r, m.String()) - consumeGas(ctx, m, logPrefixQeval, pkgPath, expr) - return + switch r.(type) { + case store.OutOfGasException: // panic in consumeGas() + panic(r) + default: + err = errors.Wrap(fmt.Errorf("%v", r), "VM query eval panic: %v\n%s\n", + r, m.String()) + consumeGas(ctx, m, logPrefixQeval, pkgPath, expr) + return + } } m.Release() }() @@ -517,10 +542,10 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res // TODO: then, rename to "EvalString". func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string) (res string, err error) { alloc := gno.NewAllocator(maxAllocQuery) - store := vm.getGnoStore(ctx) + gnostore := vm.getGnoStore(ctx) pkgAddr := gno.DerivePkgAddr(pkgPath) // Get Package. - pv := store.GetPackage(pkgPath, false) + pv := gnostore.GetPackage(pkgPath, false) if pv == nil { err = ErrInvalidPkgPath(fmt.Sprintf( "package not found: %s", pkgPath)) @@ -547,17 +572,22 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string gno.MachineOptions{ PkgPath: pkgPath, Output: os.Stdout, // XXX - Store: store, + Store: gnostore, Context: msgCtx, Alloc: alloc, MaxCycles: vm.maxCycles, }) defer func() { if r := recover(); r != nil { - err = errors.Wrap(fmt.Errorf("%v", r), "VM query eval string panic: %v\n%s\n", - r, m.String()) - consumeGas(ctx, m, logPrefixQevalStr, pkgPath, expr) - return + switch r.(type) { + case store.OutOfGasException: // panic in consumeGas() + panic(r) + default: + err = errors.Wrap(fmt.Errorf("%v", r), "VM query eval string panic: %v\n%s\n", + r, m.String()) + consumeGas(ctx, m, logPrefixQevalStr, pkgPath, expr) + return + } } m.Release() }() From 25e4fdfdbb530f14664fe972a967c96d9b8ca5b0 Mon Sep 17 00:00:00 2001 From: piux2 <90544084+piux2@users.noreply.github.com> Date: Wed, 13 Dec 2023 10:06:36 -0800 Subject: [PATCH 03/15] Update gno.land/pkg/sdk/vm/gas.go Co-authored-by: Thomas Bruyelle --- gno.land/pkg/sdk/vm/gas.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gno.land/pkg/sdk/vm/gas.go b/gno.land/pkg/sdk/vm/gas.go index 65cae3b2929..2061c55ae5a 100644 --- a/gno.land/pkg/sdk/vm/gas.go +++ b/gno.land/pkg/sdk/vm/gas.go @@ -30,7 +30,7 @@ func consumeGas(ctx sdk.Context, m *gno.Machine, prefix string, pkgPath string, gasCpu := overflow.Mul64p(m.Cycles, gasFactorCpu) gasMem := overflow.Mul64p(mem, gasFactorMem) - // we simplify the log here, the storage gas log included tx size and sigature verification gas. + // we simplify the log here, the storage gas log included tx size and signature verification gas. storeLog := fmt.Sprintf("%s.storage, %s %s, %d", prefix, pkgPath, expr, ctx.GasMeter().GasConsumed()) ctx.Logger().Info(storeLog) From ce5c0616d8f8b2e85c48362feb154326e6267b78 Mon Sep 17 00:00:00 2001 From: piux2 <90544084+piux2@users.noreply.github.com> Date: Wed, 13 Dec 2023 10:07:31 -0800 Subject: [PATCH 04/15] Update gno.land/pkg/sdk/vm/ante.go Co-authored-by: Thomas Bruyelle --- gno.land/pkg/sdk/vm/ante.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gno.land/pkg/sdk/vm/ante.go b/gno.land/pkg/sdk/vm/ante.go index 97b216329c3..a6b0cc48bd1 100644 --- a/gno.land/pkg/sdk/vm/ante.go +++ b/gno.land/pkg/sdk/vm/ante.go @@ -31,7 +31,7 @@ func NewAnteHandler(vmKpr *VMKeeper) sdk.AnteHandler { res = vmh.Process(ctx, msg) } - // we don't abort the transaction when there is a message execution failer. the failed message should be allowed to propergate to other nodes. + // we don't abort the transaction when there is a message execution failure. The failed message should be allowed to propagate to other nodes. // We dont not want to censor the tx for VM execution failures just by one node. // XXX: Do not uncomment this. Do not remvove this either to prevent someone accidentally add this check. // if !res.IsOK() { From 2248074a0a9f3bc31429d61e1d284bccc37cb0b6 Mon Sep 17 00:00:00 2001 From: piux2 <90544084+piux2@users.noreply.github.com> Date: Wed, 10 Jan 2024 23:51:11 -0800 Subject: [PATCH 05/15] fix: check vm gas in DeliverTx instead of CheckTx --- gno.land/pkg/sdk/vm/gas_test.go | 176 ++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 gno.land/pkg/sdk/vm/gas_test.go diff --git a/gno.land/pkg/sdk/vm/gas_test.go b/gno.land/pkg/sdk/vm/gas_test.go new file mode 100644 index 00000000000..7efedb41ce8 --- /dev/null +++ b/gno.land/pkg/sdk/vm/gas_test.go @@ -0,0 +1,176 @@ +package vm + +import ( + "testing" + + bft "github.com/gnolang/gno/tm2/pkg/bft/types" + "github.com/gnolang/gno/tm2/pkg/crypto" + "github.com/gnolang/gno/tm2/pkg/sdk" + "github.com/gnolang/gno/tm2/pkg/sdk/auth" + "github.com/gnolang/gno/tm2/pkg/std" + "github.com/gnolang/gno/tm2/pkg/store" + "github.com/jaekwon/testify/assert" +) + +// Gas is consumed in both CheckTx and DeliverTx. +// VM gas is consumed only in DeliverTx. + +// Not enough gas for a successful message. + +func TestAddPkgDeliverTxNoGas(t *testing.T) { + success := true + ctx, tx, vmHandler := setupAddPkg(success) + + ctx = ctx.WithMode(sdk.RunTxModeDeliver) + simulate := false + tx.Fee.GasWanted = 3000 + gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) + + var res sdk.Result + abort := false + + defer func() { + if r := recover(); r != nil { + switch r.(type) { + case store.OutOfGasException: + res.Error = sdk.ABCIError(std.ErrOutOfGas("")) + abort = true + default: + t.Errorf("should panic on OutOfGasException only") + } + assert.True(t, abort) + assert.False(t, res.IsOK()) + gasCheck := gctx.GasMeter().GasConsumed() + assert.Equal(t, gasCheck, int64(3231)) + } else { + t.Errorf("should panic") + } + }() + msgs := tx.GetMsgs() + res = vmHandler.Process(gctx, msgs[0]) +} + +// Enough gas for a successful message. +func TestAddPkgDeliverTx(t *testing.T) { + success := true + ctx, tx, vmHandler := setupAddPkg(success) + + var simulate bool + + ctx = ctx.WithMode(sdk.RunTxModeDeliver) + simulate = false + tx.Fee.GasWanted = 500000 + gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) + msgs := tx.GetMsgs() + res := vmHandler.Process(gctx, msgs[0]) + gasDeliver := gctx.GasMeter().GasConsumed() + + assert.True(t, res.IsOK()) + assert.Equal(t, gasDeliver, int64(88305)) +} + +// Enough gas for a failed transaction. +func TestAddPkgDeliverTxFailed(t *testing.T) { + success := false + ctx, tx, vmHandler := setupAddPkg(success) + + var simulate bool + + ctx = ctx.WithMode(sdk.RunTxModeDeliver) + simulate = false + tx.Fee.GasWanted = 500000 + gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) + msgs := tx.GetMsgs() + res := vmHandler.Process(gctx, msgs[0]) + gasDeliver := gctx.GasMeter().GasConsumed() + + assert.False(t, res.IsOK()) + assert.Equal(t, gasDeliver, int64(17989)) +} + +// Not enough gas for a failed transaction. +func TestAddPkgDeliverTxFailedNoGas(t *testing.T) { + success := false + ctx, tx, vmHandler := setupAddPkg(success) + + var simulate bool + + ctx = ctx.WithMode(sdk.RunTxModeDeliver) + simulate = false + tx.Fee.GasWanted = 17988 + gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) + + var res sdk.Result + abort := false + + defer func() { + if r := recover(); r != nil { + switch r.(type) { + case store.OutOfGasException: + res.Error = sdk.ABCIError(std.ErrOutOfGas("")) + abort = true + default: + t.Errorf("should panic on OutOfGasException only") + } + assert.True(t, abort) + assert.False(t, res.IsOK()) + gasCheck := gctx.GasMeter().GasConsumed() + assert.Equal(t, gasCheck, int64(17989)) + } else { + t.Errorf("should panic") + } + }() + + msgs := tx.GetMsgs() + res = vmHandler.Process(gctx, msgs[0]) +} + +// Set up a test env for both a successful and a failed tx +func setupAddPkg(success bool) (sdk.Context, sdk.Tx, vmHandler) { + // setup + env := setupTestEnv() + ctx := env.ctx + // conduct base gas meter tests from a non-genesis block since genesis block use infinite gas meter instead. + ctx = ctx.WithBlockHeader(&bft.Header{Height: int64(1)}) + vmHandler := NewHandler(env.vmk) + // Create an account with 10M ugnot (10gnot) + addr := crypto.AddressFromPreimage([]byte("test1")) + acc := env.acck.NewAccountWithAddress(ctx, addr) + env.acck.SetAccount(ctx, acc) + env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) + // success message + var files []*std.MemFile + if success { + files = []*std.MemFile{ + { + Name: "hello.gno", + Body: `package hello + +func Echo() string { + return "hello world" +}`, + }, + } + } else { + // failed message + files = []*std.MemFile{ + { + Name: "hello.gno", + Body: `package hello + +func Echo() UnknowType { + return "hello world" +}`, + }, + } + } + + pkgPath := "gno.land/r/hello" + // create messages and a transaction + msg := NewMsgAddPackage(addr, pkgPath, files) + msgs := []std.Msg{msg} + fee := std.NewFee(500000, std.MustParseCoin("1ugnot")) + tx := std.NewTx(msgs, fee, []std.Signature{}, "") + + return ctx, tx, vmHandler +} From 7735f497f035585e9101ecca517d82a400b6d883 Mon Sep 17 00:00:00 2001 From: piux2 <90544084+piux2@users.noreply.github.com> Date: Wed, 10 Jan 2024 23:56:48 -0800 Subject: [PATCH 06/15] fix: check vm gas in DeliverTx instead of CheckTx --- gno.land/cmd/gnoland/testdata/addpkg.txtar | 41 ++-- gno.land/pkg/gnoland/app.go | 2 - gno.land/pkg/sdk/vm/ante_test.go | 211 --------------------- gno.land/pkg/sdk/vm/gas.go | 22 ++- gno.land/pkg/sdk/vm/keeper.go | 28 +-- tm2/pkg/sdk/auth/ante.go | 13 +- 6 files changed, 66 insertions(+), 251 deletions(-) delete mode 100644 gno.land/pkg/sdk/vm/ante_test.go diff --git a/gno.land/cmd/gnoland/testdata/addpkg.txtar b/gno.land/cmd/gnoland/testdata/addpkg.txtar index 7130fe54dab..b1d48fd9892 100644 --- a/gno.land/cmd/gnoland/testdata/addpkg.txtar +++ b/gno.land/cmd/gnoland/testdata/addpkg.txtar @@ -3,21 +3,34 @@ ## start a new node gnoland start -## add bar.gno package located in $WORK directory as gno.land/r/foobar/bar -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/foobar/bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +## add hello.gno package located in $WORK directory as gno.land/r/hello +gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/hello -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 -## execute Render -gnokey maketx call -pkgpath gno.land/r/foobar/bar -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +## compare AddPkg +cmp stdout stdout.addpkg.success -## compare render -stdout '("hello from foo" string)' -stdout 'OK!' -stdout 'GAS WANTED: 2000000' -stdout 'GAS USED: [0-9]+' --- bar.gno -- -package bar +## execute SayHello +gnokey maketx call -pkgpath gno.land/r/hello -func SayHello -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 -func Render(path string) string { - return "hello from foo" -} \ No newline at end of file +## compare SayHello +cmp stdout stdout.call.success + +-- hello.gno -- +package hello + +func SayHello() string { + return "hello world!" +} + + +-- stdout.addpkg.success -- + +OK! +GAS WANTED: 2000000 +GAS USED: 117850 +-- stdout.call.success -- +("hello world!" string) +OK! +GAS WANTED: 2000000 +GAS USED: 66711 diff --git a/gno.land/pkg/gnoland/app.go b/gno.land/pkg/gnoland/app.go index f34a3753d9a..54a8d3648e2 100644 --- a/gno.land/pkg/gnoland/app.go +++ b/gno.land/pkg/gnoland/app.go @@ -80,10 +80,8 @@ func NewAppWithOptions(cfg *AppOptions) (abci.Application, error) { baseApp.SetInitChainer(InitChainer(baseApp, acctKpr, bankKpr, cfg.SkipFailingGenesisTxs)) // Set AnteHandler - vmah := vm.NewAnteHandler(vmKpr) authOptions := auth.AnteOptions{ VerifyGenesisSignatures: false, // for development - AnteHandlerChain: []sdk.AnteHandler{vmah}, } authAnteHandler := auth.NewAnteHandler( acctKpr, bankKpr, auth.DefaultSigVerificationGasConsumer, authOptions) diff --git a/gno.land/pkg/sdk/vm/ante_test.go b/gno.land/pkg/sdk/vm/ante_test.go deleted file mode 100644 index d6170790693..00000000000 --- a/gno.land/pkg/sdk/vm/ante_test.go +++ /dev/null @@ -1,211 +0,0 @@ -package vm - -import ( - "testing" - - bft "github.com/gnolang/gno/tm2/pkg/bft/types" - "github.com/gnolang/gno/tm2/pkg/crypto" - "github.com/gnolang/gno/tm2/pkg/sdk" - "github.com/gnolang/gno/tm2/pkg/sdk/auth" - "github.com/gnolang/gno/tm2/pkg/std" - "github.com/gnolang/gno/tm2/pkg/store" - "github.com/jaekwon/testify/assert" -) - -// The gas consumed is counted only towards the execution of gno messages -// We only abort the tx due to the insufficient gas. - -func TestAddPkgSimulateGas(t *testing.T) { - // setup - success := true - ctx, tx, anteHandler := setup(success) - // simulation should not fail even if gas wanted is low - - ctx = ctx.WithMode(sdk.RunTxModeSimulate) - simulate := true - - tx.Fee.GasWanted = 1 - gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) - gctx, res, abort := anteHandler(gctx, tx, simulate) - gasSimulate := gctx.GasMeter().GasConsumed() - - assert.False(t, abort) - assert.True(t, res.IsOK()) - assert.Equal(t, gasSimulate, int64(94055)) -} - -// failed tx will not aborted -func TestAddPkgSimulateFailedGas(t *testing.T) { - // setup - success := false - ctx, tx, anteHandler := setup(success) - // simulation should not fail even if gas wanted is low - - ctx = ctx.WithMode(sdk.RunTxModeSimulate) - simulate := true - - tx.Fee.GasWanted = 1 - gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) - gctx, res, abort := anteHandler(gctx, tx, simulate) - gasSimulate := gctx.GasMeter().GasConsumed() - - assert.False(t, abort) - assert.True(t, res.IsOK()) - assert.Equal(t, gasSimulate, int64(18989)) -} - -func TestAddPkgCheckTxGas(t *testing.T) { - success := true - ctx, tx, anteHandler := setup(success) - // Testing case with enough gas and succcful message execution - - ctx = ctx.WithMode(sdk.RunTxModeCheck) - simulate := false - tx.Fee.GasWanted = 500000 - gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) - gctx, res, abort := anteHandler(gctx, tx, simulate) - gasCheck := gctx.GasMeter().GasConsumed() - - assert.False(t, abort) - assert.True(t, res.IsOK()) - assert.Equal(t, gasCheck, int64(94055)) -} - -// CheckTx only abort when there is no enough gas meter. -func TestAddPkgCheckTxNoGas(t *testing.T) { - success := true - ctx, tx, anteHandler := setup(success) - // Testing case with enough gas and succcful message execution - ctx = ctx.WithMode(sdk.RunTxModeCheck) - simulate := false - tx.Fee.GasWanted = 3000 - gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) - - var res sdk.Result - abort := false - - defer func() { - if r := recover(); r != nil { - switch r.(type) { - case store.OutOfGasException: - res.Error = sdk.ABCIError(std.ErrOutOfGas("")) - abort = true - default: - t.Errorf("should panic on OutOfGasException only") - } - assert.True(t, abort) - assert.False(t, res.IsOK()) - gasCheck := gctx.GasMeter().GasConsumed() - assert.Equal(t, gasCheck, int64(3231)) - } else { - t.Errorf("should panic") - } - }() - gctx, res, abort = anteHandler(gctx, tx, simulate) -} - -// failed tx execution should pass the vm.AnteHandler -func TestAddPkgCheckTxFailedGas(t *testing.T) { - success := false - ctx, tx, anteHandler := setup(success) - - ctx = ctx.WithMode(sdk.RunTxModeCheck) - simulate := false - tx.Fee.GasWanted = 500000 - gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) - gctx, res, abort := anteHandler(gctx, tx, simulate) - gasCheck := gctx.GasMeter().GasConsumed() - - assert.False(t, abort) - assert.True(t, res.IsOK()) - assert.Equal(t, gasCheck, int64(18989)) -} - -// For deliver Tx ante handler does not check gas consumption and does not consume gas -func TestAddPkgDeliverTxGas(t *testing.T) { - success := true - ctx, tx, anteHandler := setup(success) - - var simulate bool - - ctx = ctx.WithMode(sdk.RunTxModeDeliver) - simulate = false - tx.Fee.GasWanted = 1 - gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) - gasDeliver := gctx.GasMeter().GasConsumed() - gctx, res, abort := anteHandler(gctx, tx, simulate) - assert.False(t, abort) - assert.True(t, res.IsOK()) - assert.Equal(t, gasDeliver, int64(0)) -} - -// // For deliver Tx, ante handler does not check gas consumption and does not consume gas -func TestAddPkgDeliverTxFailGas(t *testing.T) { - success := true - ctx, tx, anteHandler := setup(success) - - var simulate bool - - ctx = ctx.WithMode(sdk.RunTxModeDeliver) - simulate = false - tx.Fee.GasWanted = 1 - gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) - gasDeliver := gctx.GasMeter().GasConsumed() - gctx, res, abort := anteHandler(gctx, tx, simulate) - assert.False(t, abort) - assert.True(t, res.IsOK()) - assert.Equal(t, gasDeliver, int64(0)) -} - -func setup(success bool) (sdk.Context, sdk.Tx, sdk.AnteHandler) { - // setup - env := setupTestEnv() - ctx := env.ctx - // conduct base gas meter tests from a non-genesis block since genesis block use infinite gas meter instead. - ctx = ctx.WithBlockHeader(&bft.Header{Height: int64(1)}) - anteHandler := NewAnteHandler(env.vmk) - // Createa an account with 10M gnot (10gnot) - addr := crypto.AddressFromPreimage([]byte("test1")) - acc := env.acck.NewAccountWithAddress(ctx, addr) - env.acck.SetAccount(ctx, acc) - env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) - // success message - var files []*std.MemFile - if success { - files = []*std.MemFile{ - { - Name: "hello.gno", - Body: `package hello - -import "std" - -func Echo() string { - return "hello world" -}`, - }, - } - } else { - // falied message - files = []*std.MemFile{ - { - Name: "hello.gno", - Body: `package hello - - import "std" - - func Echo() UnknowType { - return "hello world" - }`, - }, - } - } - - pkgPath := "gno.land/r/hello" - // creat messages and a transaction - msg := NewMsgAddPackage(addr, pkgPath, files) - msgs := []std.Msg{msg} - fee := std.NewFee(500000, std.MustParseCoin("1ugnot")) - tx := std.NewTx(msgs, fee, []std.Signature{}, "") - - return ctx, tx, anteHandler -} diff --git a/gno.land/pkg/sdk/vm/gas.go b/gno.land/pkg/sdk/vm/gas.go index 2061c55ae5a..21bd73b1509 100644 --- a/gno.land/pkg/sdk/vm/gas.go +++ b/gno.land/pkg/sdk/vm/gas.go @@ -4,15 +4,15 @@ import ( "fmt" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" - "github.com/gnolang/gno/tm2/pkg/sdk" + "github.com/gnolang/gno/tm2/pkg/store" "github.com/gnolang/overflow" ) const ( - // We will use gasMemFactor and gasCpuFactor to multiply the vm memory allocation and cpu cycles to get the gas number. - // We can use these two factoctors to keep the gas for storage access, CPU and Mem in reasonable proportion. + // We will use gasFactorMem and gasFactorCpu to multiply the vm memory allocation and cpu cycles to get the gas number. + // We can use these two factors to keep the gas for storage access, CPU and Mem in reasonable proportion. gasFactorMem int64 = 1 // change this value based on gas profiling gasFactorCpu int64 = 1 // change this value based on gas profiling @@ -30,8 +30,8 @@ func consumeGas(ctx sdk.Context, m *gno.Machine, prefix string, pkgPath string, gasCpu := overflow.Mul64p(m.Cycles, gasFactorCpu) gasMem := overflow.Mul64p(mem, gasFactorMem) - // we simplify the log here, the storage gas log included tx size and signature verification gas. - storeLog := fmt.Sprintf("%s.storage, %s %s, %d", prefix, pkgPath, expr, ctx.GasMeter().GasConsumed()) + // we simplify the log here, the storage gas log included tx size and signature verification gas in CheckTx() + storeLog := fmt.Sprintf("%s.txsize_sig_storage, %s %s, %d", prefix, pkgPath, expr, ctx.GasMeter().GasConsumed()) ctx.Logger().Info(storeLog) memLog := fmt.Sprintf("%s.memalloc, %s %s, %d", prefix, pkgPath, expr, gasMem) @@ -40,6 +40,18 @@ func consumeGas(ctx sdk.Context, m *gno.Machine, prefix string, pkgPath string, cpuLog := fmt.Sprintf("%s.cpucycles, %s %s, %d", prefix, pkgPath, expr, gasCpu) ctx.Logger().Info(cpuLog) + defer func() { + if r := recover(); r != nil { + m.Release() + switch r.(type) { + case store.OutOfGasException: // panic in consumeGas() + panic(r) + default: + panic("should not happen") + } + } + }() + ctx.GasMeter().ConsumeGas(gasMem, prefix+".MemAlloc") ctx.GasMeter().ConsumeGas(gasCpu, prefix+".CpuCycles") diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index d5e12b1c97c..3bda264b9ef 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -136,7 +136,7 @@ const ( ) // AddPackage adds a package with given fileset. -func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) error { +func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { creator := msg.Creator pkgPath := msg.Package.Path memPkg := msg.Package @@ -172,7 +172,7 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) error { // - check if caller is in Admins or Editors. // - check if namespace is not in pause. - err := vm.bank.SendCoins(ctx, creator, pkgAddr, deposit) + err = vm.bank.SendCoins(ctx, creator, pkgAddr, deposit) if err != nil { return err } @@ -201,13 +201,14 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) error { defer func() { if r := recover(); r != nil { switch r.(type) { - case store.OutOfGasException: // panic in consumeGas() + case store.OutOfGasException: // panic in consumeGas() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM addpkg panic: %v\n%s\n", - r, m2.String()) - consumeGas(ctx, m2, logPrefixAddPkg, pkgPath, "") - return + r, m2.String()) + consumeGas(ctx, m2, logPrefixAddPkg, pkgPath, "") + m2.Release() + return } } m2.Release() @@ -290,12 +291,13 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { defer func() { if r := recover(); r != nil { switch r.(type) { - case store.OutOfGasException: // panic in consumeGas() + case store.OutOfGasException: // panic in consumeGas() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM call panic: %v\n%s\n", r, m.String()) consumeGas(ctx, m, logPrefixCall, pkgPath, fnc) + m.Release() return } } @@ -364,12 +366,13 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { defer func() { if r := recover(); r != nil { switch r.(type) { - case store.OutOfGasException: // panic in consumeGas() + case store.OutOfGasException: // panic in consumeGas() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM run main addpkg panic: %v\n%s\n", r, m.String()) consumeGas(ctx, m, logPrefixRun, pkgPath, "add_main") + m.Release() return } } @@ -392,12 +395,13 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { defer func() { if r := recover(); r != nil { switch r.(type) { - case store.OutOfGasException: // panic in consumeGas() + case store.OutOfGasException: // panic in consumeGas() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM run main call panic: %v\n%s\n", r, m2.String()) consumeGas(ctx, m2, logPrefixRun, pkgPath, "main") + m2.Release() return } } @@ -513,12 +517,13 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res defer func() { if r := recover(); r != nil { switch r.(type) { - case store.OutOfGasException: // panic in consumeGas() + case store.OutOfGasException: // panic in consumeGas() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM query eval panic: %v\n%s\n", r, m.String()) consumeGas(ctx, m, logPrefixQeval, pkgPath, expr) + m.Release() return } } @@ -580,12 +585,13 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string defer func() { if r := recover(); r != nil { switch r.(type) { - case store.OutOfGasException: // panic in consumeGas() + case store.OutOfGasException: // panic in consumeGas() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM query eval string panic: %v\n%s\n", r, m.String()) consumeGas(ctx, m, logPrefixQevalStr, pkgPath, expr) + m.Release() return } } diff --git a/tm2/pkg/sdk/auth/ante.go b/tm2/pkg/sdk/auth/ante.go index 5623b0364aa..a0ab1cb1dd0 100644 --- a/tm2/pkg/sdk/auth/ante.go +++ b/tm2/pkg/sdk/auth/ante.go @@ -36,8 +36,6 @@ type AnteOptions struct { // This is useful for development, and maybe production chains. // Always check your settings and inspect genesis transactions. VerifyGenesisSignatures bool - // Additional AnteHandler applied in order - AnteHandlerChain []sdk.AnteHandler } // NewAnteHandler returns an AnteHandler that checks and increments sequence @@ -163,12 +161,7 @@ func NewAnteHandler(ak AccountKeeper, bank BankKeeperI, sigGasConsumer Signature } ak.SetAccount(newCtx, signerAccs[i]) } - for _, anteHandler := range opts.AnteHandlerChain { - newCtx, res, abort := anteHandler(newCtx, tx, simulate) - if abort { - return newCtx, res, true - } - } + // TODO: tx tags (?) return newCtx, sdk.Result{GasWanted: tx.Fee.GasWanted}, false // continue... } @@ -400,6 +393,10 @@ func EnsureSufficientMempoolFees(ctx sdk.Context, fee std.Fee) sdk.Result { if fgd == gpd { prod1 := big.NewInt(0).Mul(fga, gpg) // fee amount * price gas prod2 := big.NewInt(0).Mul(fgw, gpa) // fee gas * price amount + // This is equivalent to checking + // That the Fee / GasWanted ratio is greater than or equal to the minimum GasPrice per gas. + // This approach helps us avoid dealing with configurations where the value of + // the minimum gas price is set to 0.00001ugnot/gas. if prod1.Cmp(prod2) >= 0 { return sdk.Result{} } else { From 5edd98807806073cf0d24449b89ad0114e8784e0 Mon Sep 17 00:00:00 2001 From: piux2 <90544084+piux2@users.noreply.github.com> Date: Mon, 29 Jan 2024 21:26:23 -0800 Subject: [PATCH 07/15] embed gasmeter in op processing and allocators --- gno.land/cmd/gnoland/testdata/addpkg.txtar | 2 +- gno.land/pkg/sdk/vm/ante.go | 44 ---------- gno.land/pkg/sdk/vm/gas.go | 60 -------------- gno.land/pkg/sdk/vm/keeper.go | 93 ++++++++++------------ gnovm/pkg/gnolang/alloc.go | 25 ++++-- gnovm/pkg/gnolang/machine.go | 24 +++++- tm2/pkg/store/gas/store.go | 14 ++-- 7 files changed, 93 insertions(+), 169 deletions(-) delete mode 100644 gno.land/pkg/sdk/vm/ante.go delete mode 100644 gno.land/pkg/sdk/vm/gas.go diff --git a/gno.land/cmd/gnoland/testdata/addpkg.txtar b/gno.land/cmd/gnoland/testdata/addpkg.txtar index b1d48fd9892..e6419cbb0a9 100644 --- a/gno.land/cmd/gnoland/testdata/addpkg.txtar +++ b/gno.land/cmd/gnoland/testdata/addpkg.txtar @@ -33,4 +33,4 @@ GAS USED: 117850 ("hello world!" string) OK! GAS WANTED: 2000000 -GAS USED: 66711 +GAS USED: 53445 diff --git a/gno.land/pkg/sdk/vm/ante.go b/gno.land/pkg/sdk/vm/ante.go deleted file mode 100644 index a6b0cc48bd1..00000000000 --- a/gno.land/pkg/sdk/vm/ante.go +++ /dev/null @@ -1,44 +0,0 @@ -package vm - -import ( - "github.com/gnolang/gno/tm2/pkg/sdk" - "github.com/gnolang/gno/tm2/pkg/std" -) - -// It returns a AnteHandler function that can be chained togateher in app to check pre condition before put it the mempool and propergate to other nodes. -// It checks there is enough gas to execute the transaction in TxCheck and Simulation mode. -// XXX: We only abort the tx due to the insufficient gas. Should we even allow it pass ante handler to prevent censorship? In other word, should we only keep the min gas price as the check to drop a transaction? -func NewAnteHandler(vmKpr *VMKeeper) sdk.AnteHandler { - return func( - ctx sdk.Context, tx std.Tx, simulate bool, - ) (newCtx sdk.Context, res sdk.Result, abort bool) { - // skip the check for Deliver Mode Gas and Msg Executions - if ctx.Mode() == sdk.RunTxModeDeliver { - return ctx, res, false - } - // XXXX: check vm gas here for CheckTx and Simulation node. - - vmh := NewHandler(vmKpr) - msgs := tx.GetMsgs() - - for _, msg := range msgs { - // match message route - msgRoute := msg.Route() - if msgRoute == RouterKey { - // XXX: When there is no enough gas left in gas meter, it will stop the transaction in CheckTx() before passing the tx to mempool and broadcasting to other nodes. - // Same message will be processed sencond time in DeliverTx(). It should be ok for now, since CheckTx and DeliverTx execution are in different contexts that are not linked to each other. - - res = vmh.Process(ctx, msg) - } - - // we don't abort the transaction when there is a message execution failure. The failed message should be allowed to propagate to other nodes. - // We dont not want to censor the tx for VM execution failures just by one node. - // XXX: Do not uncomment this. Do not remvove this either to prevent someone accidentally add this check. - // if !res.IsOK() { - // return ctx, res, true - // } - } - - return ctx, res, false - } -} diff --git a/gno.land/pkg/sdk/vm/gas.go b/gno.land/pkg/sdk/vm/gas.go deleted file mode 100644 index 21bd73b1509..00000000000 --- a/gno.land/pkg/sdk/vm/gas.go +++ /dev/null @@ -1,60 +0,0 @@ -package vm - -import ( - "fmt" - - gno "github.com/gnolang/gno/gnovm/pkg/gnolang" - "github.com/gnolang/gno/tm2/pkg/sdk" - "github.com/gnolang/gno/tm2/pkg/store" - "github.com/gnolang/overflow" -) - -const ( - - // We will use gasFactorMem and gasFactorCpu to multiply the vm memory allocation and cpu cycles to get the gas number. - // We can use these two factors to keep the gas for storage access, CPU and Mem in reasonable proportion. - gasFactorMem int64 = 1 // change this value based on gas profiling - gasFactorCpu int64 = 1 // change this value based on gas profiling - - logPrefixAddPkg = "gas.vm.addpkg" - logPrefixCall = "gas.vm.call" - logPrefixRun = "gas.vm.run" - logPrefixQeval = "gas.vm.qeval" - logPrefixQevalStr = "gas.vm.qevalstr" -) - -// consume gas and log vm gas usage -func consumeGas(ctx sdk.Context, m *gno.Machine, prefix string, pkgPath string, expr string) { - _, mem := m.Alloc.Status() - - gasCpu := overflow.Mul64p(m.Cycles, gasFactorCpu) - gasMem := overflow.Mul64p(mem, gasFactorMem) - - // we simplify the log here, the storage gas log included tx size and signature verification gas in CheckTx() - storeLog := fmt.Sprintf("%s.txsize_sig_storage, %s %s, %d", prefix, pkgPath, expr, ctx.GasMeter().GasConsumed()) - ctx.Logger().Info(storeLog) - - memLog := fmt.Sprintf("%s.memalloc, %s %s, %d", prefix, pkgPath, expr, gasMem) - ctx.Logger().Info(memLog) - - cpuLog := fmt.Sprintf("%s.cpucycles, %s %s, %d", prefix, pkgPath, expr, gasCpu) - ctx.Logger().Info(cpuLog) - - defer func() { - if r := recover(); r != nil { - m.Release() - switch r.(type) { - case store.OutOfGasException: // panic in consumeGas() - panic(r) - default: - panic("should not happen") - } - } - }() - - ctx.GasMeter().ConsumeGas(gasMem, prefix+".MemAlloc") - ctx.GasMeter().ConsumeGas(gasCpu, prefix+".CpuCycles") - - gasTotal := fmt.Sprintf("%s.total, %s %s, %d", prefix, pkgPath, expr, ctx.GasMeter().GasConsumed()) - ctx.Logger().Info(gasTotal) -} diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index 3bda264b9ef..32ea3b4347b 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -191,12 +191,13 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { // Parse and run the files, construct *PV. m2 := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: "", - Output: os.Stdout, // XXX - Store: gnostore, - Alloc: gnostore.GetAllocator(), - Context: msgCtx, - MaxCycles: vm.maxCycles, + PkgPath: "", + Output: os.Stdout, // XXX + Store: gnostore, + Alloc: gnostore.GetAllocator(), + Context: msgCtx, + MaxCycles: vm.maxCycles, + VMGasMeter: ctx.GasMeter(), }) defer func() { if r := recover(); r != nil { @@ -206,7 +207,6 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { default: err = errors.Wrap(fmt.Errorf("%v", r), "VM addpkg panic: %v\n%s\n", r, m2.String()) - consumeGas(ctx, m2, logPrefixAddPkg, pkgPath, "") m2.Release() return } @@ -215,11 +215,10 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { }() m2.RunMemPackage(memPkg, true) - consumeGas(ctx, m2, logPrefixAddPkg, pkgPath, "") return nil } -// Calls calls a public Gno function (for delivertx). +// Call calls a public Gno function (for delivertx). func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { pkgPath := msg.PkgPath // to import fnc := msg.Func @@ -280,12 +279,13 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { // Construct machine and evaluate. m := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: "", - Output: os.Stdout, // XXX - Store: gnostore, - Context: msgCtx, - Alloc: gnostore.GetAllocator(), - MaxCycles: vm.maxCycles, + PkgPath: "", + Output: os.Stdout, // XXX + Store: gnostore, + Context: msgCtx, + Alloc: gnostore.GetAllocator(), + MaxCycles: vm.maxCycles, + VMGasMeter: ctx.GasMeter(), }) m.SetActivePackage(mpv) defer func() { @@ -296,7 +296,6 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { default: err = errors.Wrap(fmt.Errorf("%v", r), "VM call panic: %v\n%s\n", r, m.String()) - consumeGas(ctx, m, logPrefixCall, pkgPath, fnc) m.Release() return } @@ -304,7 +303,6 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { m.Release() }() rtvs := m.Eval(xn) - consumeGas(ctx, m, logPrefixCall, pkgPath, fnc) for i, rtv := range rtvs { res = res + rtv.String() if i < len(rtvs)-1 { @@ -354,15 +352,15 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { buf := new(bytes.Buffer) m := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: "", - Output: buf, - Store: gnostore, - Alloc: gnostore.GetAllocator(), - Context: msgCtx, - MaxCycles: vm.maxCycles, + PkgPath: "", + Output: buf, + Store: gnostore, + Alloc: gnostore.GetAllocator(), + Context: msgCtx, + MaxCycles: vm.maxCycles, + VMGasMeter: ctx.GasMeter(), }) // XXX MsgRun does not have pkgPath. How do we find it on chain? - pkgPath := "" defer func() { if r := recover(); r != nil { switch r.(type) { @@ -371,7 +369,6 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { default: err = errors.Wrap(fmt.Errorf("%v", r), "VM run main addpkg panic: %v\n%s\n", r, m.String()) - consumeGas(ctx, m, logPrefixRun, pkgPath, "add_main") m.Release() return } @@ -380,16 +377,16 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { }() _, pv := m.RunMemPackage(memPkg, false) - consumeGas(ctx, m, logPrefixRun, pkgPath, "add_main") m2 := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: "", - Output: buf, - Store: gnostore, - Alloc: gnostore.GetAllocator(), - Context: msgCtx, - MaxCycles: vm.maxCycles, + PkgPath: "", + Output: buf, + Store: gnostore, + Alloc: gnostore.GetAllocator(), + Context: msgCtx, + MaxCycles: vm.maxCycles, + VMGasMeter: ctx.GasMeter(), }) m2.SetActivePackage(pv) defer func() { @@ -400,7 +397,6 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { default: err = errors.Wrap(fmt.Errorf("%v", r), "VM run main call panic: %v\n%s\n", r, m2.String()) - consumeGas(ctx, m2, logPrefixRun, pkgPath, "main") m2.Release() return } @@ -408,7 +404,6 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { m2.Release() }() m2.RunMain() - consumeGas(ctx, m2, logPrefixRun, pkgPath, "call_main") res = buf.String() return res, nil } @@ -507,12 +502,13 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res } m := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: pkgPath, - Output: os.Stdout, // XXX - Store: gnostore, - Context: msgCtx, - Alloc: alloc, - MaxCycles: vm.maxCycles, + PkgPath: pkgPath, + Output: os.Stdout, // XXX + Store: gnostore, + Context: msgCtx, + Alloc: alloc, + MaxCycles: vm.maxCycles, + VMGasMeter: ctx.GasMeter(), }) defer func() { if r := recover(); r != nil { @@ -522,7 +518,6 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res default: err = errors.Wrap(fmt.Errorf("%v", r), "VM query eval panic: %v\n%s\n", r, m.String()) - consumeGas(ctx, m, logPrefixQeval, pkgPath, expr) m.Release() return } @@ -530,7 +525,6 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res m.Release() }() rtvs := m.Eval(xx) - consumeGas(ctx, m, logPrefixQeval, pkgPath, expr) res = "" for i, rtv := range rtvs { res += rtv.String() @@ -575,12 +569,13 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string } m := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: pkgPath, - Output: os.Stdout, // XXX - Store: gnostore, - Context: msgCtx, - Alloc: alloc, - MaxCycles: vm.maxCycles, + PkgPath: pkgPath, + Output: os.Stdout, // XXX + Store: gnostore, + Context: msgCtx, + Alloc: alloc, + MaxCycles: vm.maxCycles, + VMGasMeter: ctx.GasMeter(), }) defer func() { if r := recover(); r != nil { @@ -590,7 +585,6 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string default: err = errors.Wrap(fmt.Errorf("%v", r), "VM query eval string panic: %v\n%s\n", r, m.String()) - consumeGas(ctx, m, logPrefixQevalStr, pkgPath, expr) m.Release() return } @@ -598,7 +592,6 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string m.Release() }() rtvs := m.Eval(xx) - consumeGas(ctx, m, logPrefixQevalStr, pkgPath, expr) if len(rtvs) != 1 { return "", errors.New("expected 1 string result, got %d", len(rtvs)) } else if rtvs[0].T.Kind() != gno.StringKind { diff --git a/gnovm/pkg/gnolang/alloc.go b/gnovm/pkg/gnolang/alloc.go index a83f8102a2b..bff9a1c53f9 100644 --- a/gnovm/pkg/gnolang/alloc.go +++ b/gnovm/pkg/gnolang/alloc.go @@ -1,19 +1,26 @@ package gnolang -import "reflect" +import ( + "reflect" + + "github.com/gnolang/gno/tm2/pkg/store" + "github.com/gnolang/overflow" +) // Keeps track of in-memory allocations. // In the future, allocations within realm boundaries will be // (optionally?) condensed (objects to be GC'd will be discarded), // but for now, allocations strictly increment across the whole tx. type Allocator struct { - maxBytes int64 - bytes int64 + maxBytes int64 + bytes int64 + vmGasMeter *store.GasMeter } // for gonative, which doesn't consider the allocator. var nilAllocator = (*Allocator)(nil) +const GasFactorAlloc = 1 const ( // go elemental _allocBase = 24 // defensive... XXX @@ -82,6 +89,7 @@ func (alloc *Allocator) Reset() *Allocator { return nil } alloc.bytes = 0 + alloc.vmGasMeter = nil return alloc } @@ -90,8 +98,9 @@ func (alloc *Allocator) Fork() *Allocator { return nil } return &Allocator{ - maxBytes: alloc.maxBytes, - bytes: alloc.bytes, + maxBytes: alloc.maxBytes, + bytes: alloc.bytes, + vmGasMeter: alloc.vmGasMeter, } } @@ -100,6 +109,12 @@ func (alloc *Allocator) Allocate(size int64) { // this can happen for map items just prior to assignment. return } + // consume gas even if it could failed due to exceed the maxBytes + gm := alloc.vmGasMeter + if gm!=nil && *gm != nil { + gas := overflow.Mul64p(size, GasFactorAlloc) + (*gm).ConsumeGas(gas, "MemAlloc") + } alloc.bytes += size if alloc.bytes > alloc.maxBytes { panic("allocation limit exceeded") diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 94232e014d2..5f4faf259bf 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -14,6 +14,8 @@ import ( "github.com/gnolang/gno/tm2/pkg/errors" "github.com/gnolang/gno/tm2/pkg/std" + "github.com/gnolang/gno/tm2/pkg/store" + "github.com/gnolang/overflow" ) //---------------------------------------- @@ -41,9 +43,10 @@ type Machine struct { ReadOnly bool MaxCycles int64 - Output io.Writer - Store Store - Context interface{} + Output io.Writer + Store Store + Context interface{} + VMGasMeter store.GasMeter } // machine.Release() must be called on objects @@ -72,6 +75,7 @@ type MachineOptions struct { Alloc *Allocator // or see MaxAllocBytes. MaxAllocBytes int64 // or 0 for no limit. MaxCycles int64 // or 0 for no limit. + VMGasMeter store.GasMeter } // the machine constructor gets spammed @@ -91,6 +95,8 @@ func NewMachineWithOptions(opts MachineOptions) *Machine { checkTypes := opts.CheckTypes readOnly := opts.ReadOnly maxCycles := opts.MaxCycles + vmGasMeter := opts.VMGasMeter + output := opts.Output if output == nil { output = os.Stdout @@ -125,6 +131,11 @@ func NewMachineWithOptions(opts MachineOptions) *Machine { mm.Output = output mm.Store = store mm.Context = context + mm.VMGasMeter = vmGasMeter + + if mm.Alloc != nil { + mm.Alloc.vmGasMeter = &mm.VMGasMeter + } if pv != nil { mm.SetActivePackage(pv) @@ -881,10 +892,17 @@ const ( OpReturnCallDefers Op = 0xD7 // TODO rename? ) +const GasFactorCpu int64 = 1 + //---------------------------------------- // "CPU" steps. func (m *Machine) incrCPU(cycles int64) { + if m.VMGasMeter != nil { + gasCpu := overflow.Mul64p(cycles, GasFactorCpu) + m.VMGasMeter.ConsumeGas(gasCpu, "CpuCycles") + } + m.Cycles += cycles if m.MaxCycles != 0 && m.Cycles > m.MaxCycles { panic("CPU cycle overrun") diff --git a/tm2/pkg/store/gas/store.go b/tm2/pkg/store/gas/store.go index bcd0cb7ee80..4ffe46dc275 100644 --- a/tm2/pkg/store/gas/store.go +++ b/tm2/pkg/store/gas/store.go @@ -2,6 +2,7 @@ package gas import ( "github.com/gnolang/gno/tm2/pkg/store/types" + "github.com/gnolang/overflow" ) var _ types.Store = &Store{} @@ -29,8 +30,8 @@ func (gs *Store) Get(key []byte) (value []byte) { gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostFlat, types.GasReadCostFlatDesc) value = gs.parent.Get(key) - // TODO overflow-safe math? - gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostPerByte*types.Gas(len(value)), types.GasReadPerByteDesc) + gas := overflow.Mul64p(gs.gasConfig.ReadCostPerByte, types.Gas(len(value))) + gs.gasMeter.ConsumeGas(gas, types.GasReadPerByteDesc) return value } @@ -39,8 +40,9 @@ func (gs *Store) Get(key []byte) (value []byte) { func (gs *Store) Set(key []byte, value []byte) { types.AssertValidValue(value) gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostFlat, types.GasWriteCostFlatDesc) - // TODO overflow-safe math? - gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostPerByte*types.Gas(len(value)), types.GasWritePerByteDesc) + + gas := overflow.Mul64p(gs.gasConfig.WriteCostPerByte, types.Gas(len(value))) + gs.gasMeter.ConsumeGas(gas, types.GasWritePerByteDesc) gs.parent.Set(key, value) } @@ -156,7 +158,7 @@ func (gi *gasIterator) Close() { // based on the current value's length. func (gi *gasIterator) consumeSeekGas() { value := gi.Value() - - gi.gasMeter.ConsumeGas(gi.gasConfig.ReadCostPerByte*types.Gas(len(value)), types.GasValuePerByteDesc) + gas := overflow.Mul64p(gi.gasConfig.ReadCostPerByte, types.Gas(len(value))) gi.gasMeter.ConsumeGas(gi.gasConfig.IterNextCostFlat, types.GasIterNextCostFlatDesc) + gi.gasMeter.ConsumeGas(gas, types.GasValuePerByteDesc) } From d2c6269589e62bdb4f67efcf723e0c694df0dc05 Mon Sep 17 00:00:00 2001 From: piux2 <90544084+piux2@users.noreply.github.com> Date: Thu, 8 Feb 2024 01:20:11 -0800 Subject: [PATCH 08/15] remove mem alloc for gas purpose --- gno.land/cmd/gnoland/testdata/addpkg.txtar | 4 ++-- gno.land/pkg/sdk/vm/gas_test.go | 2 +- gnovm/pkg/gnolang/alloc.go | 25 ++++++---------------- gnovm/pkg/gnolang/machine.go | 4 ---- 4 files changed, 9 insertions(+), 26 deletions(-) diff --git a/gno.land/cmd/gnoland/testdata/addpkg.txtar b/gno.land/cmd/gnoland/testdata/addpkg.txtar index e6419cbb0a9..a82bd087291 100644 --- a/gno.land/cmd/gnoland/testdata/addpkg.txtar +++ b/gno.land/cmd/gnoland/testdata/addpkg.txtar @@ -28,9 +28,9 @@ func SayHello() string { OK! GAS WANTED: 2000000 -GAS USED: 117850 +GAS USED: 117354 -- stdout.call.success -- ("hello world!" string) OK! GAS WANTED: 2000000 -GAS USED: 53445 +GAS USED: 52909 diff --git a/gno.land/pkg/sdk/vm/gas_test.go b/gno.land/pkg/sdk/vm/gas_test.go index 7efedb41ce8..03af83fc689 100644 --- a/gno.land/pkg/sdk/vm/gas_test.go +++ b/gno.land/pkg/sdk/vm/gas_test.go @@ -66,7 +66,7 @@ func TestAddPkgDeliverTx(t *testing.T) { gasDeliver := gctx.GasMeter().GasConsumed() assert.True(t, res.IsOK()) - assert.Equal(t, gasDeliver, int64(88305)) + assert.Equal(t, gasDeliver, int64(87809)) } // Enough gas for a failed transaction. diff --git a/gnovm/pkg/gnolang/alloc.go b/gnovm/pkg/gnolang/alloc.go index bff9a1c53f9..ee2c3a067cd 100644 --- a/gnovm/pkg/gnolang/alloc.go +++ b/gnovm/pkg/gnolang/alloc.go @@ -1,20 +1,14 @@ package gnolang -import ( - "reflect" - - "github.com/gnolang/gno/tm2/pkg/store" - "github.com/gnolang/overflow" -) +import "reflect" // Keeps track of in-memory allocations. // In the future, allocations within realm boundaries will be // (optionally?) condensed (objects to be GC'd will be discarded), // but for now, allocations strictly increment across the whole tx. type Allocator struct { - maxBytes int64 - bytes int64 - vmGasMeter *store.GasMeter + maxBytes int64 + bytes int64 } // for gonative, which doesn't consider the allocator. @@ -89,7 +83,6 @@ func (alloc *Allocator) Reset() *Allocator { return nil } alloc.bytes = 0 - alloc.vmGasMeter = nil return alloc } @@ -98,9 +91,8 @@ func (alloc *Allocator) Fork() *Allocator { return nil } return &Allocator{ - maxBytes: alloc.maxBytes, - bytes: alloc.bytes, - vmGasMeter: alloc.vmGasMeter, + maxBytes: alloc.maxBytes, + bytes: alloc.bytes, } } @@ -109,12 +101,7 @@ func (alloc *Allocator) Allocate(size int64) { // this can happen for map items just prior to assignment. return } - // consume gas even if it could failed due to exceed the maxBytes - gm := alloc.vmGasMeter - if gm!=nil && *gm != nil { - gas := overflow.Mul64p(size, GasFactorAlloc) - (*gm).ConsumeGas(gas, "MemAlloc") - } + alloc.bytes += size if alloc.bytes > alloc.maxBytes { panic("allocation limit exceeded") diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 5f4faf259bf..4dec4c848d2 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -133,10 +133,6 @@ func NewMachineWithOptions(opts MachineOptions) *Machine { mm.Context = context mm.VMGasMeter = vmGasMeter - if mm.Alloc != nil { - mm.Alloc.vmGasMeter = &mm.VMGasMeter - } - if pv != nil { mm.SetActivePackage(pv) } From 4e8bca32948d6adf88b57052ac7eeab3b1213016 Mon Sep 17 00:00:00 2001 From: piux2 <90544084+piux2@users.noreply.github.com> Date: Mon, 26 Feb 2024 11:18:45 -0800 Subject: [PATCH 09/15] fix redundant naming and release machine before panic(r) --- gno.land/pkg/sdk/vm/keeper.go | 46 ++++++++++++++++++++--------------- gnovm/pkg/gnolang/alloc.go | 1 - gnovm/pkg/gnolang/machine.go | 12 ++++----- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index 32ea3b4347b..490d570353f 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -43,7 +43,7 @@ type VMKeeper struct { stdlibsDir string // cached, the DeliverTx persistent state. - gnoStore gno.Store + store gno.Store maxCycles int64 // max allowed cylces on VM executions } @@ -70,15 +70,15 @@ func NewVMKeeper( } func (vm *VMKeeper) Initialize(ms store.MultiStore) { - if vm.gnoStore != nil { + if vm.store != nil { panic("should not happen") } alloc := gno.NewAllocator(maxAllocTx) baseSDKStore := ms.GetStore(vm.baseKey) iavlSDKStore := ms.GetStore(vm.iavlKey) - vm.gnoStore = gno.NewStore(alloc, baseSDKStore, iavlSDKStore) - vm.initBuiltinPackagesAndTypes(vm.gnoStore) - if vm.gnoStore.NumMemPackages() > 0 { + vm.store = gno.NewStore(alloc, baseSDKStore, iavlSDKStore) + vm.initBuiltinPackagesAndTypes(vm.store) + if vm.store.NumMemPackages() > 0 { // for now, all mem packages must be re-run after reboot. // TODO remove this, and generally solve for in-mem garbage collection // and memory management across many objects/types/nodes/packages. @@ -86,7 +86,7 @@ func (vm *VMKeeper) Initialize(ms store.MultiStore) { gno.MachineOptions{ PkgPath: "", Output: os.Stdout, // XXX - Store: vm.gnoStore, + Store: vm.store, }) defer m2.Release() gno.DisableDebug() @@ -96,32 +96,32 @@ func (vm *VMKeeper) Initialize(ms store.MultiStore) { } func (vm *VMKeeper) getGnoStore(ctx sdk.Context) gno.Store { - // construct main gnoStore if nil. - if vm.gnoStore == nil { + // construct main store if nil. + if vm.store == nil { panic("VMKeeper must first be initialized") } switch ctx.Mode() { case sdk.RunTxModeDeliver: - // swap sdk store of existing gnoStore. + // swap sdk store of existing store. // this is needed due to e.g. gas wrappers. baseSDKStore := ctx.Store(vm.baseKey) iavlSDKStore := ctx.Store(vm.iavlKey) - vm.gnoStore.SwapStores(baseSDKStore, iavlSDKStore) + vm.store.SwapStores(baseSDKStore, iavlSDKStore) // clear object cache for every transaction. // NOTE: this is inefficient, but simple. // in the future, replace with more advanced caching strategy. - vm.gnoStore.ClearObjectCache() - return vm.gnoStore + vm.store.ClearObjectCache() + return vm.store case sdk.RunTxModeCheck: // For query??? XXX Why not RunTxModeQuery? - simStore := vm.gnoStore.Fork() + simStore := vm.store.Fork() baseSDKStore := ctx.Store(vm.baseKey) iavlSDKStore := ctx.Store(vm.iavlKey) simStore.SwapStores(baseSDKStore, iavlSDKStore) return simStore case sdk.RunTxModeSimulate: // always make a new store for simulate for isolation. - simStore := vm.gnoStore.Fork() + simStore := vm.store.Fork() baseSDKStore := ctx.Store(vm.baseKey) iavlSDKStore := ctx.Store(vm.iavlKey) simStore.SwapStores(baseSDKStore, iavlSDKStore) @@ -197,12 +197,13 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { Alloc: gnostore.GetAllocator(), Context: msgCtx, MaxCycles: vm.maxCycles, - VMGasMeter: ctx.GasMeter(), + GasMeter: ctx.GasMeter(), }) defer func() { if r := recover(); r != nil { switch r.(type) { case store.OutOfGasException: // panic in consumeGas() + m2.Release() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM addpkg panic: %v\n%s\n", @@ -285,13 +286,14 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { Context: msgCtx, Alloc: gnostore.GetAllocator(), MaxCycles: vm.maxCycles, - VMGasMeter: ctx.GasMeter(), + GasMeter: ctx.GasMeter(), }) m.SetActivePackage(mpv) defer func() { if r := recover(); r != nil { switch r.(type) { case store.OutOfGasException: // panic in consumeGas() + m.Release() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM call panic: %v\n%s\n", @@ -358,13 +360,14 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { Alloc: gnostore.GetAllocator(), Context: msgCtx, MaxCycles: vm.maxCycles, - VMGasMeter: ctx.GasMeter(), + GasMeter: ctx.GasMeter(), }) // XXX MsgRun does not have pkgPath. How do we find it on chain? defer func() { if r := recover(); r != nil { switch r.(type) { case store.OutOfGasException: // panic in consumeGas() + m.Release() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM run main addpkg panic: %v\n%s\n", @@ -386,13 +389,14 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { Alloc: gnostore.GetAllocator(), Context: msgCtx, MaxCycles: vm.maxCycles, - VMGasMeter: ctx.GasMeter(), + GasMeter: ctx.GasMeter(), }) m2.SetActivePackage(pv) defer func() { if r := recover(); r != nil { switch r.(type) { case store.OutOfGasException: // panic in consumeGas() + m2.Release() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM run main call panic: %v\n%s\n", @@ -508,12 +512,13 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res Context: msgCtx, Alloc: alloc, MaxCycles: vm.maxCycles, - VMGasMeter: ctx.GasMeter(), + GasMeter: ctx.GasMeter(), }) defer func() { if r := recover(); r != nil { switch r.(type) { case store.OutOfGasException: // panic in consumeGas() + m.Release() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM query eval panic: %v\n%s\n", @@ -575,12 +580,13 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string Context: msgCtx, Alloc: alloc, MaxCycles: vm.maxCycles, - VMGasMeter: ctx.GasMeter(), + GasMeter: ctx.GasMeter(), }) defer func() { if r := recover(); r != nil { switch r.(type) { case store.OutOfGasException: // panic in consumeGas() + m.Release() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM query eval string panic: %v\n%s\n", diff --git a/gnovm/pkg/gnolang/alloc.go b/gnovm/pkg/gnolang/alloc.go index ee2c3a067cd..495be0d2dc2 100644 --- a/gnovm/pkg/gnolang/alloc.go +++ b/gnovm/pkg/gnolang/alloc.go @@ -14,7 +14,6 @@ type Allocator struct { // for gonative, which doesn't consider the allocator. var nilAllocator = (*Allocator)(nil) -const GasFactorAlloc = 1 const ( // go elemental _allocBase = 24 // defensive... XXX diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 4dec4c848d2..880c761cd3f 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -46,7 +46,7 @@ type Machine struct { Output io.Writer Store Store Context interface{} - VMGasMeter store.GasMeter + GasMeter store.GasMeter } // machine.Release() must be called on objects @@ -75,7 +75,7 @@ type MachineOptions struct { Alloc *Allocator // or see MaxAllocBytes. MaxAllocBytes int64 // or 0 for no limit. MaxCycles int64 // or 0 for no limit. - VMGasMeter store.GasMeter + GasMeter store.GasMeter } // the machine constructor gets spammed @@ -95,7 +95,7 @@ func NewMachineWithOptions(opts MachineOptions) *Machine { checkTypes := opts.CheckTypes readOnly := opts.ReadOnly maxCycles := opts.MaxCycles - vmGasMeter := opts.VMGasMeter + vmGasMeter := opts.GasMeter output := opts.Output if output == nil { @@ -131,7 +131,7 @@ func NewMachineWithOptions(opts MachineOptions) *Machine { mm.Output = output mm.Store = store mm.Context = context - mm.VMGasMeter = vmGasMeter + mm.GasMeter = vmGasMeter if pv != nil { mm.SetActivePackage(pv) @@ -894,9 +894,9 @@ const GasFactorCpu int64 = 1 // "CPU" steps. func (m *Machine) incrCPU(cycles int64) { - if m.VMGasMeter != nil { + if m.GasMeter != nil { gasCpu := overflow.Mul64p(cycles, GasFactorCpu) - m.VMGasMeter.ConsumeGas(gasCpu, "CpuCycles") + m.GasMeter.ConsumeGas(gasCpu, "CpuCycles") } m.Cycles += cycles From 4aa5d13db10c726f50a866300bf0bc3ec484e7d4 Mon Sep 17 00:00:00 2001 From: piux2 <90544084+piux2@users.noreply.github.com> Date: Mon, 26 Feb 2024 13:54:02 -0800 Subject: [PATCH 10/15] clean up --- gno.land/pkg/gnoland/app.go | 1 - gno.land/pkg/sdk/vm/keeper.go | 1 - gno.land/pkg/sdk/vm/keeper_test.go | 4 ++-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/gno.land/pkg/gnoland/app.go b/gno.land/pkg/gnoland/app.go index 54a8d3648e2..df5e64ad0a5 100644 --- a/gno.land/pkg/gnoland/app.go +++ b/gno.land/pkg/gnoland/app.go @@ -132,7 +132,6 @@ func NewApp(dataRootDir string, skipFailingGenesisTxs bool, logger log.Logger, m } cfg.Logger = logger - cfg.SkipFailingGenesisTxs = skipFailingGenesisTxs return NewAppWithOptions(cfg) } diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index 490d570353f..4bf9d2f4fcf 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -469,7 +469,6 @@ func (vm *VMKeeper) QueryFuncs(ctx sdk.Context, pkgPath string) (fsigs FunctionS } fsigs = append(fsigs, fsig) } - ctx.Logger().Info("gas.vm.qfuncs.total,", pkgPath, ",", ctx.GasMeter().GasConsumed()) return fsigs, nil } diff --git a/gno.land/pkg/sdk/vm/keeper_test.go b/gno.land/pkg/sdk/vm/keeper_test.go index 294efa66fa5..aeae8835b69 100644 --- a/gno.land/pkg/sdk/vm/keeper_test.go +++ b/gno.land/pkg/sdk/vm/keeper_test.go @@ -40,12 +40,12 @@ func Echo() string { } pkgPath := "gno.land/r/test" msg1 := NewMsgAddPackage(addr, pkgPath, files) - assert.Nil(t, env.vmk.gnoStore.GetPackage(pkgPath, false)) + assert.Nil(t, env.vmk.store.GetPackage(pkgPath, false)) err := env.vmk.AddPackage(ctx, msg1) assert.NoError(t, err) - assert.NotNil(t, env.vmk.gnoStore.GetPackage(pkgPath, false)) + assert.NotNil(t, env.vmk.store.GetPackage(pkgPath, false)) err = env.vmk.AddPackage(ctx, msg1) From d95083d5f066bda0c311535a14d707cca9deabdf Mon Sep 17 00:00:00 2001 From: piux2 <90544084+piux2@users.noreply.github.com> Date: Tue, 2 Apr 2024 00:05:48 -0700 Subject: [PATCH 11/15] chores: revert variable name gnoStore and updated comments --- gno.land/pkg/gnoland/app.go | 2 +- gno.land/pkg/sdk/vm/gas_test.go | 9 ++- gno.land/pkg/sdk/vm/keeper.go | 114 ++++++++++++++--------------- gno.land/pkg/sdk/vm/keeper_test.go | 4 +- gnovm/pkg/gnolang/machine.go | 14 ++-- 5 files changed, 72 insertions(+), 71 deletions(-) diff --git a/gno.land/pkg/gnoland/app.go b/gno.land/pkg/gnoland/app.go index df5e64ad0a5..7513035dec3 100644 --- a/gno.land/pkg/gnoland/app.go +++ b/gno.land/pkg/gnoland/app.go @@ -60,7 +60,7 @@ func NewAppWithOptions(cfg *AppOptions) (abci.Application, error) { baseKey := store.NewStoreKey("base") // Create BaseApp. - // TODO: Add a flag to set min gas prices for the node, by default it does not check. + // TODO: Add a consensus based min gas prices for the node, by default it does not check baseApp := sdk.NewBaseApp("gnoland", cfg.Logger, cfg.DB, baseKey, mainKey) baseApp.SetAppVersion("dev") diff --git a/gno.land/pkg/sdk/vm/gas_test.go b/gno.land/pkg/sdk/vm/gas_test.go index 03af83fc689..dabbc2ae71c 100644 --- a/gno.land/pkg/sdk/vm/gas_test.go +++ b/gno.land/pkg/sdk/vm/gas_test.go @@ -12,12 +12,13 @@ import ( "github.com/jaekwon/testify/assert" ) -// Gas is consumed in both CheckTx and DeliverTx. -// VM gas is consumed only in DeliverTx. +// Gas for entire tx is consumed in both CheckTx and DeliverTx. +// Gas for executing VM tx (VM CPU and Store Access in bytes) is consumed in DeliverTx. +// Gas for balance checking, message size checking, and signature verification is consumed (deducted) in checkTx. -// Not enough gas for a successful message. +// Insufficient gas for a successful message. -func TestAddPkgDeliverTxNoGas(t *testing.T) { +func TestAddPkgDeliverTxInsuffGas(t *testing.T) { success := true ctx, tx, vmHandler := setupAddPkg(success) diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index 4bf9d2f4fcf..b00063b4369 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -43,7 +43,7 @@ type VMKeeper struct { stdlibsDir string // cached, the DeliverTx persistent state. - store gno.Store + gnoStore gno.Store maxCycles int64 // max allowed cylces on VM executions } @@ -70,15 +70,15 @@ func NewVMKeeper( } func (vm *VMKeeper) Initialize(ms store.MultiStore) { - if vm.store != nil { + if vm.gnoStore != nil { panic("should not happen") } alloc := gno.NewAllocator(maxAllocTx) baseSDKStore := ms.GetStore(vm.baseKey) iavlSDKStore := ms.GetStore(vm.iavlKey) - vm.store = gno.NewStore(alloc, baseSDKStore, iavlSDKStore) - vm.initBuiltinPackagesAndTypes(vm.store) - if vm.store.NumMemPackages() > 0 { + vm.gnoStore = gno.NewStore(alloc, baseSDKStore, iavlSDKStore) + vm.initBuiltinPackagesAndTypes(vm.gnoStore) + if vm.gnoStore.NumMemPackages() > 0 { // for now, all mem packages must be re-run after reboot. // TODO remove this, and generally solve for in-mem garbage collection // and memory management across many objects/types/nodes/packages. @@ -86,7 +86,7 @@ func (vm *VMKeeper) Initialize(ms store.MultiStore) { gno.MachineOptions{ PkgPath: "", Output: os.Stdout, // XXX - Store: vm.store, + Store: vm.gnoStore, }) defer m2.Release() gno.DisableDebug() @@ -97,7 +97,7 @@ func (vm *VMKeeper) Initialize(ms store.MultiStore) { func (vm *VMKeeper) getGnoStore(ctx sdk.Context) gno.Store { // construct main store if nil. - if vm.store == nil { + if vm.gnoStore == nil { panic("VMKeeper must first be initialized") } switch ctx.Mode() { @@ -106,22 +106,22 @@ func (vm *VMKeeper) getGnoStore(ctx sdk.Context) gno.Store { // this is needed due to e.g. gas wrappers. baseSDKStore := ctx.Store(vm.baseKey) iavlSDKStore := ctx.Store(vm.iavlKey) - vm.store.SwapStores(baseSDKStore, iavlSDKStore) + vm.gnoStore.SwapStores(baseSDKStore, iavlSDKStore) // clear object cache for every transaction. // NOTE: this is inefficient, but simple. // in the future, replace with more advanced caching strategy. - vm.store.ClearObjectCache() - return vm.store + vm.gnoStore.ClearObjectCache() + return vm.gnoStore case sdk.RunTxModeCheck: // For query??? XXX Why not RunTxModeQuery? - simStore := vm.store.Fork() + simStore := vm.gnoStore.Fork() baseSDKStore := ctx.Store(vm.baseKey) iavlSDKStore := ctx.Store(vm.iavlKey) simStore.SwapStores(baseSDKStore, iavlSDKStore) return simStore case sdk.RunTxModeSimulate: // always make a new store for simulate for isolation. - simStore := vm.store.Fork() + simStore := vm.gnoStore.Fork() baseSDKStore := ctx.Store(vm.baseKey) iavlSDKStore := ctx.Store(vm.iavlKey) simStore.SwapStores(baseSDKStore, iavlSDKStore) @@ -191,19 +191,19 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { // Parse and run the files, construct *PV. m2 := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: "", - Output: os.Stdout, // XXX - Store: gnostore, - Alloc: gnostore.GetAllocator(), - Context: msgCtx, - MaxCycles: vm.maxCycles, - GasMeter: ctx.GasMeter(), + PkgPath: "", + Output: os.Stdout, // XXX + Store: gnostore, + Alloc: gnostore.GetAllocator(), + Context: msgCtx, + MaxCycles: vm.maxCycles, + GasMeter: ctx.GasMeter(), }) defer func() { if r := recover(); r != nil { switch r.(type) { case store.OutOfGasException: // panic in consumeGas() - m2.Release() + m2.Release() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM addpkg panic: %v\n%s\n", @@ -280,20 +280,20 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { // Construct machine and evaluate. m := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: "", - Output: os.Stdout, // XXX - Store: gnostore, - Context: msgCtx, - Alloc: gnostore.GetAllocator(), - MaxCycles: vm.maxCycles, - GasMeter: ctx.GasMeter(), + PkgPath: "", + Output: os.Stdout, // XXX + Store: gnostore, + Context: msgCtx, + Alloc: gnostore.GetAllocator(), + MaxCycles: vm.maxCycles, + GasMeter: ctx.GasMeter(), }) m.SetActivePackage(mpv) defer func() { if r := recover(); r != nil { switch r.(type) { case store.OutOfGasException: // panic in consumeGas() - m.Release() + m.Release() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM call panic: %v\n%s\n", @@ -354,13 +354,13 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { buf := new(bytes.Buffer) m := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: "", - Output: buf, - Store: gnostore, - Alloc: gnostore.GetAllocator(), - Context: msgCtx, - MaxCycles: vm.maxCycles, - GasMeter: ctx.GasMeter(), + PkgPath: "", + Output: buf, + Store: gnostore, + Alloc: gnostore.GetAllocator(), + Context: msgCtx, + MaxCycles: vm.maxCycles, + GasMeter: ctx.GasMeter(), }) // XXX MsgRun does not have pkgPath. How do we find it on chain? defer func() { @@ -383,13 +383,13 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { m2 := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: "", - Output: buf, - Store: gnostore, - Alloc: gnostore.GetAllocator(), - Context: msgCtx, - MaxCycles: vm.maxCycles, - GasMeter: ctx.GasMeter(), + PkgPath: "", + Output: buf, + Store: gnostore, + Alloc: gnostore.GetAllocator(), + Context: msgCtx, + MaxCycles: vm.maxCycles, + GasMeter: ctx.GasMeter(), }) m2.SetActivePackage(pv) defer func() { @@ -505,13 +505,13 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res } m := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: pkgPath, - Output: os.Stdout, // XXX - Store: gnostore, - Context: msgCtx, - Alloc: alloc, - MaxCycles: vm.maxCycles, - GasMeter: ctx.GasMeter(), + PkgPath: pkgPath, + Output: os.Stdout, // XXX + Store: gnostore, + Context: msgCtx, + Alloc: alloc, + MaxCycles: vm.maxCycles, + GasMeter: ctx.GasMeter(), }) defer func() { if r := recover(); r != nil { @@ -573,19 +573,19 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string } m := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: pkgPath, - Output: os.Stdout, // XXX - Store: gnostore, - Context: msgCtx, - Alloc: alloc, - MaxCycles: vm.maxCycles, - GasMeter: ctx.GasMeter(), + PkgPath: pkgPath, + Output: os.Stdout, // XXX + Store: gnostore, + Context: msgCtx, + Alloc: alloc, + MaxCycles: vm.maxCycles, + GasMeter: ctx.GasMeter(), }) defer func() { if r := recover(); r != nil { switch r.(type) { case store.OutOfGasException: // panic in consumeGas() - m.Release() + m.Release() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM query eval string panic: %v\n%s\n", diff --git a/gno.land/pkg/sdk/vm/keeper_test.go b/gno.land/pkg/sdk/vm/keeper_test.go index aeae8835b69..294efa66fa5 100644 --- a/gno.land/pkg/sdk/vm/keeper_test.go +++ b/gno.land/pkg/sdk/vm/keeper_test.go @@ -40,12 +40,12 @@ func Echo() string { } pkgPath := "gno.land/r/test" msg1 := NewMsgAddPackage(addr, pkgPath, files) - assert.Nil(t, env.vmk.store.GetPackage(pkgPath, false)) + assert.Nil(t, env.vmk.gnoStore.GetPackage(pkgPath, false)) err := env.vmk.AddPackage(ctx, msg1) assert.NoError(t, err) - assert.NotNil(t, env.vmk.store.GetPackage(pkgPath, false)) + assert.NotNil(t, env.vmk.gnoStore.GetPackage(pkgPath, false)) err = env.vmk.AddPackage(ctx, msg1) diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 880c761cd3f..4fefc0c11a3 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -43,9 +43,9 @@ type Machine struct { ReadOnly bool MaxCycles int64 - Output io.Writer - Store Store - Context interface{} + Output io.Writer + Store Store + Context interface{} GasMeter store.GasMeter } @@ -75,7 +75,7 @@ type MachineOptions struct { Alloc *Allocator // or see MaxAllocBytes. MaxAllocBytes int64 // or 0 for no limit. MaxCycles int64 // or 0 for no limit. - GasMeter store.GasMeter + GasMeter store.GasMeter } // the machine constructor gets spammed @@ -888,15 +888,15 @@ const ( OpReturnCallDefers Op = 0xD7 // TODO rename? ) -const GasFactorCpu int64 = 1 +const GasFactorCPU int64 = 1 //---------------------------------------- // "CPU" steps. func (m *Machine) incrCPU(cycles int64) { if m.GasMeter != nil { - gasCpu := overflow.Mul64p(cycles, GasFactorCpu) - m.GasMeter.ConsumeGas(gasCpu, "CpuCycles") + gasCPU := overflow.Mul64p(cycles, GasFactorCPU) + m.GasMeter.ConsumeGas(gasCPU, "CPUCycles") } m.Cycles += cycles From dd6f0086c1a5ca6fb81c7e160110057949c09785 Mon Sep 17 00:00:00 2001 From: piux2 <90544084+piux2@users.noreply.github.com> Date: Thu, 4 Apr 2024 22:30:12 -0700 Subject: [PATCH 12/15] clean up m.Release in defer --- gno.land/pkg/sdk/vm/keeper.go | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index b00063b4369..4aacb192c9c 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -199,20 +199,18 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { MaxCycles: vm.maxCycles, GasMeter: ctx.GasMeter(), }) + defer m2.Release() defer func() { if r := recover(); r != nil { switch r.(type) { case store.OutOfGasException: // panic in consumeGas() - m2.Release() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM addpkg panic: %v\n%s\n", r, m2.String()) - m2.Release() return } } - m2.Release() }() m2.RunMemPackage(memPkg, true) @@ -288,21 +286,19 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { MaxCycles: vm.maxCycles, GasMeter: ctx.GasMeter(), }) + defer m.Release() m.SetActivePackage(mpv) defer func() { if r := recover(); r != nil { switch r.(type) { case store.OutOfGasException: // panic in consumeGas() - m.Release() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM call panic: %v\n%s\n", r, m.String()) - m.Release() return } } - m.Release() }() rtvs := m.Eval(xn) for i, rtv := range rtvs { @@ -363,20 +359,18 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { GasMeter: ctx.GasMeter(), }) // XXX MsgRun does not have pkgPath. How do we find it on chain? + defer m.Release() defer func() { if r := recover(); r != nil { switch r.(type) { case store.OutOfGasException: // panic in consumeGas() - m.Release() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM run main addpkg panic: %v\n%s\n", r, m.String()) - m.Release() return } } - m.Release() }() _, pv := m.RunMemPackage(memPkg, false) @@ -391,21 +385,19 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { MaxCycles: vm.maxCycles, GasMeter: ctx.GasMeter(), }) + defer m2.Release() m2.SetActivePackage(pv) defer func() { if r := recover(); r != nil { switch r.(type) { case store.OutOfGasException: // panic in consumeGas() - m2.Release() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM run main call panic: %v\n%s\n", r, m2.String()) - m2.Release() return } } - m2.Release() }() m2.RunMain() res = buf.String() @@ -513,20 +505,18 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res MaxCycles: vm.maxCycles, GasMeter: ctx.GasMeter(), }) + defer m.Release() defer func() { if r := recover(); r != nil { switch r.(type) { case store.OutOfGasException: // panic in consumeGas() - m.Release() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM query eval panic: %v\n%s\n", r, m.String()) - m.Release() return } } - m.Release() }() rtvs := m.Eval(xx) res = "" @@ -581,20 +571,18 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string MaxCycles: vm.maxCycles, GasMeter: ctx.GasMeter(), }) + defer m.Release() defer func() { if r := recover(); r != nil { switch r.(type) { case store.OutOfGasException: // panic in consumeGas() - m.Release() panic(r) default: err = errors.Wrap(fmt.Errorf("%v", r), "VM query eval string panic: %v\n%s\n", r, m.String()) - m.Release() return } } - m.Release() }() rtvs := m.Eval(xx) if len(rtvs) != 1 { From 28b04eafe4e8a5e8c976c8a5f15fbba0bf57ff5e Mon Sep 17 00:00:00 2001 From: piux2 <90544084+piux2@users.noreply.github.com> Date: Thu, 25 Apr 2024 14:13:46 -0600 Subject: [PATCH 13/15] chore: fix merge --- gnovm/pkg/gnolang/machine.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 82c009b222b..018fac66e64 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -55,13 +55,10 @@ type Machine struct { CheckTypes bool // not yet used ReadOnly bool MaxCycles int64 - Output io.Writer - Store Store - Context interface{} - GasMeter store.GasMeter -} - - + Output io.Writer + Store Store + Context interface{} + GasMeter store.GasMeter // PanicScope is incremented each time a panic occurs and is reset to // zero when it is recovered. PanicScope uint From 20b3f1ce7d0b9f2da35c3bb9e65072451228375f Mon Sep 17 00:00:00 2001 From: piux2 <90544084+piux2@users.noreply.github.com> Date: Thu, 25 Apr 2024 14:49:38 -0600 Subject: [PATCH 14/15] chore: fix merge --- gno.land/pkg/sdk/vm/common_test.go | 2 +- gno.land/pkg/sdk/vm/gas_test.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gno.land/pkg/sdk/vm/common_test.go b/gno.land/pkg/sdk/vm/common_test.go index d41bcb09c3a..b65757da403 100644 --- a/gno.land/pkg/sdk/vm/common_test.go +++ b/gno.land/pkg/sdk/vm/common_test.go @@ -35,7 +35,7 @@ func setupTestEnv() testEnv { ms.MountStoreWithDB(iavlCapKey, iavl.StoreConstructor, db) ms.LoadLatestVersion() - ctx := sdk.NewContext(sdk.RunTxModeDeliver, ms, &bft.Header{ChainID: "test-chain-id"}, log.TestingLogger()) + ctx := sdk.NewContext(sdk.RunTxModeDeliver, ms, &bft.Header{ChainID: "test-chain-id"}, log.NewNoopLogger()) acck := authm.NewAccountKeeper(iavlCapKey, std.ProtoBaseAccount) bank := bankm.NewBankKeeper(acck) stdlibsDir := filepath.Join("..", "..", "..", "..", "gnovm", "stdlibs") diff --git a/gno.land/pkg/sdk/vm/gas_test.go b/gno.land/pkg/sdk/vm/gas_test.go index dabbc2ae71c..75d13aa6c5d 100644 --- a/gno.land/pkg/sdk/vm/gas_test.go +++ b/gno.land/pkg/sdk/vm/gas_test.go @@ -9,7 +9,7 @@ import ( "github.com/gnolang/gno/tm2/pkg/sdk/auth" "github.com/gnolang/gno/tm2/pkg/std" "github.com/gnolang/gno/tm2/pkg/store" - "github.com/jaekwon/testify/assert" + "github.com/stretchr/testify/assert" ) // Gas for entire tx is consumed in both CheckTx and DeliverTx. @@ -42,7 +42,7 @@ func TestAddPkgDeliverTxInsuffGas(t *testing.T) { assert.True(t, abort) assert.False(t, res.IsOK()) gasCheck := gctx.GasMeter().GasConsumed() - assert.Equal(t, gasCheck, int64(3231)) + assert.Equal(t, int64(3231), gasCheck) } else { t.Errorf("should panic") } @@ -67,7 +67,7 @@ func TestAddPkgDeliverTx(t *testing.T) { gasDeliver := gctx.GasMeter().GasConsumed() assert.True(t, res.IsOK()) - assert.Equal(t, gasDeliver, int64(87809)) + assert.Equal(t, int64(87809), gasDeliver) } // Enough gas for a failed transaction. @@ -86,7 +86,7 @@ func TestAddPkgDeliverTxFailed(t *testing.T) { gasDeliver := gctx.GasMeter().GasConsumed() assert.False(t, res.IsOK()) - assert.Equal(t, gasDeliver, int64(17989)) + assert.Equal(t, int64(17989), gasDeliver) } // Not enough gas for a failed transaction. @@ -116,7 +116,7 @@ func TestAddPkgDeliverTxFailedNoGas(t *testing.T) { assert.True(t, abort) assert.False(t, res.IsOK()) gasCheck := gctx.GasMeter().GasConsumed() - assert.Equal(t, gasCheck, int64(17989)) + assert.Equal(t, int64(17989), gasCheck) } else { t.Errorf("should panic") } From 0677d5d8f2c38fd0da05c9bb1b0ae3318196f7f8 Mon Sep 17 00:00:00 2001 From: piux2 <90544084+piux2@users.noreply.github.com> Date: Thu, 25 Apr 2024 15:34:51 -0600 Subject: [PATCH 15/15] chore: fix gas output after merge --- gno.land/cmd/gnoland/testdata/addpkg.txtar | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gno.land/cmd/gnoland/testdata/addpkg.txtar b/gno.land/cmd/gnoland/testdata/addpkg.txtar index 5d6e376c6be..071096cb49d 100644 --- a/gno.land/cmd/gnoland/testdata/addpkg.txtar +++ b/gno.land/cmd/gnoland/testdata/addpkg.txtar @@ -29,9 +29,9 @@ func SayHello() string { OK! GAS WANTED: 2000000 -GAS USED: 117354 +GAS USED: 119829 -- stdout.call.success -- ("hello world!" string) OK! GAS WANTED: 2000000 -GAS USED: 52909 \ No newline at end of file +GAS USED: 52801