Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

out of gas error is unclear (VM call panic: {ReadPerByte}) #1205

Closed
irreverentsimplicity opened this issue Oct 8, 2023 · 5 comments
Closed
Assignees

Comments

@irreverentsimplicity
Copy link
Contributor

VM call panic: {ReadPerByte}

Description

VM halts with a panic on calling this code. I'm not sure which part of it generates it, but I suspect it may be related to how we read marshalled JSONs.

call:

gnokey maketx call -broadcast -pkgpath gno.land/r/demo/flippando -gas-wanted 100000 -gas-fee 1000000ugnot -func StartGame -args someGameId -args someGameType -args 16 test

Stack trace:

--= Error =--
Data: {ReadPerByte}
Msg Traces:
    0  /Users/dragosroua/gno/tm2/pkg/crypto/keys/client/addpkg.go:214 - deliver transaction failed: log:msg:0,success:false,log:--= Error =--
Data: &errors.errorString{s:"{ReadPerByte}"}
Msg Traces:
    0  /Users/dragosroua/gno/gno.land/pkg/sdk/vm/keeper.go:266 - VM call panic: {ReadPerByte}
Machine:
    CheckTypes: false
        Op: [OpHalt OpBody OpReturn OpPrecall OpEval OpEval OpEval OpSelector]
        Values: (len: 1)
          #0 (StartGame func(gameId string,tileType string,boardSize int)( string))
        Exprs:
          #4 flippandoserver<VPBlock(2,2)>.CreateGameBoard
          #3 gameId<VPBlock(1,0)>
          #2 tileType<VPBlock(1,1)>
          #1 boardSize<VPBlock(1,2)>
          #0 flippandoserver<VPBlock(2,2)>.CreateGameBoard(gameId<VPBlock(1,0)>, tileType<VPBlock(1,1)>, boardSize<VPBlock(1,2)>)
        Stmts:
          #0 bodyStmt[0/0/1]=(end)
        Blocks:
          @(1) Block(ID:0000000000000000000000000000000000000000:0,Addr:0x1400b602b40,Source:func StartGame(gameId (const-typ...,Parent:0x1400b6021e0)
            gameId: ("someGameId" string)
            tileType: ("someGameType" string)
            boardSize: (16 int)
            .res_0: ( string)
 (s vals) @(1) Block(ID:0000000000000000000000000000000000000000:0,Addr:0x14004b19820,Source:func StartGame(gameId (const-typ...,Parent:0x14002217620)
            gameId: ( string)
            tileType: ( string)
            boardSize: (0 int)
            .res_0: ( string)
 (s typs) @(1) [string string int string]
          @(2) Block(ID:1b4fe769c2b0acba527e54f1eca22a38499de5b4:3,Addr:0x1400b6021e0,Source:ref(gno.land/r/demo/flippando/fl...,Parent:%!!(MISSING)!(MISSING)p(gnolang.RefValue={{{[27 79 231 105 194 176 172 186 82 126 84 241 236 162 42 56 73 157 229 180]} 2} true  {[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]}}))
            (RefNode names not shown)
 (s vals) @(2) Block(ID:0000000000000000000000000000000000000000:0,Addr:0x14002217620,Source:file{ package flippando; import ...,Parent:0x14009c538e0)
            bytes: (package(bytes bytes) package{})
            errors: (package(errors errors) package{})
            flippandoserver: (package(flippandoserver gno.land/p/demo/flippandoserver) package{})
 (s typs) @(2) [package{} package{} package{}]
            (block ref 1b4fe769c2b0acba527e54f1eca22a38499de5b4:2)
        Blocks (other):

        Frames:
          #0 [FRAME FUNC:StartGame RECV:(undefined) (3 args) 1/0/0/0/1 LASTPKG:main LASTRLM:Realm(nil)]
        Realm:
          gno.land/r/demo/flippando
        Exceptions:
          []
          

Stack Trace:
    0  /Users/dragosroua/gno/tm2/pkg/errors/errors.go:20
    1  /Users/dragosroua/gno/gno.land/pkg/sdk/vm/keeper.go:266
    2  /usr/local/go/src/runtime/panic.go:884
    3  /Users/dragosroua/gno/tm2/pkg/store/types/gas.go:97
    4  /Users/dragosroua/gno/tm2/pkg/store/gas/store.go:33
    5  /Users/dragosroua/gno/gnovm/pkg/gnolang/store.go:274
    6  /Users/dragosroua/gno/gnovm/pkg/gnolang/store.go:258
    7  /Users/dragosroua/gno/gnovm/pkg/gnolang/store.go:244
    8  /Users/dragosroua/gno/gnovm/pkg/gnolang/values.go:822
    9  /Users/dragosroua/gno/gnovm/pkg/gnolang/store.go:129
   10  /Users/dragosroua/gno/gnovm/pkg/gnolang/values.go:2476
   11  /Users/dragosroua/gno/gnovm/pkg/gnolang/values.go:2288
   12  /Users/dragosroua/gno/gnovm/pkg/gnolang/values.go:2322
   13  /Users/dragosroua/gno/gnovm/pkg/gnolang/op_eval.go:34
   14  /Users/dragosroua/gno/gnovm/pkg/gnolang/machine.go:1179
   15  /Users/dragosroua/gno/gnovm/pkg/gnolang/machine.go:642
   16  /Users/dragosroua/gno/gno.land/pkg/sdk/vm/keeper.go:272
   17  /Users/dragosroua/gno/gno.land/pkg/sdk/vm/handler.go:64
   18  /Users/dragosroua/gno/gno.land/pkg/sdk/vm/handler.go:29
   19  /Users/dragosroua/gno/tm2/pkg/sdk/baseapp.go:644
   20  /Users/dragosroua/gno/tm2/pkg/sdk/baseapp.go:823
   21  /Users/dragosroua/gno/tm2/pkg/sdk/baseapp.go:580
   22  /Users/dragosroua/gno/tm2/pkg/bft/abci/client/local_client.go:82
   23  /Users/dragosroua/gno/tm2/pkg/bft/proxy/app_conn.go:73
   24  /Users/dragosroua/gno/tm2/pkg/bft/state/execution.go:253
   25  /Users/dragosroua/gno/tm2/pkg/bft/state/execution.go:102
   26  /Users/dragosroua/gno/tm2/pkg/bft/consensus/state.go:1347
   27  /Users/dragosroua/gno/tm2/pkg/bft/consensus/state.go:1275
   28  /Users/dragosroua/gno/tm2/pkg/bft/consensus/state.go:1221
   29  /Users/dragosroua/gno/tm2/pkg/bft/consensus/state.go:1252
   30  /Users/dragosroua/gno/tm2/pkg/bft/consensus/state.go:1637
   31  /Users/dragosroua/gno/tm2/pkg/bft/consensus/state.go:1483
--= /Error =--
,events:[]
--= /Error =--

realm function call (flippando.gno):

func StartGame(gameId string, tileType string, boardSize int) string {
	return flippandoserver.CreateGameBoard(gameId, tileType, boardSize)
}

package related functions (flippandoserver.gno):

import (
	"std"
	"time"
	"bytes"
	"strconv"

	"gno.land/p/demo/ufmt"
)

type Game struct {
	GameId    string `json:"id"`
	Board     []int  `json:"board"`
	TileType  string `json:"tileType"`
	GameTiles []int  `json:"gameTiles"`
	BoardSize int    `json:"-"`
	Status    string `json:"status"`
}

[...]


func CreateGameBoard(gameId string, tileType string, boardSize int) (string) {
	// Initialize the board and gameTiles slices based on boardSize
	board := make([]int, boardSize)

	// Initialize the gameTiles slice with a length that is the square root of boardSize
	gameTilesLength := int(sqrt(float64(boardSize)))
	gameTiles := make([]int, gameTilesLength)

	// Create a new game instance
	newGame := &Game{
		GameId:    gameId,
		Board:     board,
		TileType:  tileType,
		GameTiles: gameTiles,
		BoardSize: boardSize,
		Status:    "initiated",
	}

	// Convert game to JSON
	gameJSON, err := newGame.MarshalJSON()
	if err != nil {
		return "error";
	}

	return string(gameJSON)
}

func (g Game) MarshalJSON() ([]byte, error) {
	var b bytes.Buffer

	b.WriteByte('{')
	
	b.WriteString(`"GameId":"`)
	b.WriteString(g.GameId)
	b.WriteString(`",`)

	b.WriteString(`"TileType":"`)
	b.WriteString(g.TileType)
	b.WriteString(`",`)

	b.WriteString(`"Status":"`)
	b.WriteString(g.Status)
	b.WriteString(`",`)

	b.WriteString(`"BoardSize":`)
	b.WriteString(strconv.Itoa(g.BoardSize)) // converting int to string
	b.WriteString(`,`)

	b.WriteString(`"Board":[`)
	writeIntSlice(&b, g.Board)
	b.WriteString(`],`)

	b.WriteString(`"GameTiles":[`)
	writeIntSlice(&b, g.GameTiles)
	b.WriteString(`]`)

	b.WriteByte('}')

	return b.Bytes(), nil
}

func writeIntSlice(b *bytes.Buffer, slice []int) {
	for i, v := range slice {
		if i > 0 {
			b.WriteString(",")
		}
		b.WriteString(strconv.Itoa(v)) // converting int to string
	}
}

client calls (gno-js-client):

flip.js

async function createNewGame(gameLevel, typeOfGame) {
    const actions = await Actions.getInstance();
    try {
      actions.startGame("someGameId", "someGameType", "16").then((response) => {
        console.log("response in Flip", response);
      });
    } catch (err) {
      console.log("error in calling startGame", err);
    }
  }

actions.ts

public async callMethod(
    method: string,
    args: string[] | null,
    gasWanted: Long = defaultGasWanted
  ): Promise<BroadcastTxCommitResult> {
    const gkLog = this.gkLog();
    try {
      if (gkLog) {
        const gkArgs = args?.map((arg) => '-args ' + arg).join(' ') ?? '';
        console.log(
          `$ gnokey maketx call -broadcast ` +
            `-pkgpath ${flippandoRealm} -gas-wanted ${gasWanted} -gas-fee ${defaultTxFee} ` +
            `-func ${method} ${gkArgs} test`
        );
      }
            
      const resp = (await this.wallet?.callMethod(
        flippandoRealm,
        method,
        args,
        TransactionEndpoint.BROADCAST_TX_COMMIT,
        undefined,
        {
          gasFee: defaultTxFee,
          gasWanted: gasWanted
        }
      )) as BroadcastTxCommitResult;
      if (gkLog) {
        console.info('response:', JSON.stringify(resp));
        const respData = resp.deliver_tx.ResponseBase.Data;
        if (respData !== null) {
          console.info('response (parsed):', parsedJSONOrRaw(respData));
        }
      }
      return resp;
    } 
    catch (err) {
      if(err !== undefined){
        let error: TM2Error;
      const ex = err as { log?: string; message?: string } | undefined;
      if (
        typeof ex?.log !== 'undefined' &&
        typeof ex?.message !== 'undefined' &&
        ex.message.includes('abci.StringError')
      ) {
        error = ErrorTransform(err as TM2Error);
      }
      if (gkLog) {
        console.log('error:', error);
      }
      throw error;
    }
    }
  }

Your environment

  • MacOS Venture 13.4.1
  • latest version
  • main

Steps to reproduce

The repo containing all the above code is here: https://github.com/irreverentsimplicity/gno, feel free to pull and try generating a call using some of the approaches above.

Expected behaviour

The call should returned a formatted JSON.

Actual behaviour

The call generates a VM panic

Proposed solution

No proposed solution.

@thehowl
Copy link
Member

thehowl commented Oct 8, 2023

It's actually an 'out of gas' error. Solution: increase gas wanted.

The hint is in the stacktrace: the line after panic.go is gas.go.

I'd still say to keep this issue open until we make the error clear.

@irreverentsimplicity
Copy link
Contributor Author

irreverentsimplicity commented Oct 8, 2023

Damn! It worked at -gas-wanted 400000 -gas-fee 8000000ugnot. Thanks, I feel a bit stupid for not trying this. Keeping the issue open until a more explanatory error message is added looks like a good idea, others may stumble upon this as well.

@thehowl thehowl changed the title VM call panic {ReadPerByte} out of gas error is unclear (VM call panic: {ReadPerByte}) Nov 14, 2023
@ltzmaxwell ltzmaxwell self-assigned this Nov 16, 2023
@ltzmaxwell
Copy link
Contributor

ltzmaxwell commented Nov 17, 2023

have a base solution to make the error clear, more digging needed to beautify the entangled logs:
master...ltzmaxwell:gno:ltzmaxwell/fix/out_of_gas_error

--= Error =--
Data: out of gas in location: ReadPerByte;
Msg Traces:
    0  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/crypto/keys/client/addpkg.go:215 - deliver transaction failed: errMsg: msg:0,success:false,events:[],log start:------>
    --= Error =--
    Data: &errors.errorString{s:"out of gas in location: ReadPerByte;"}
    Msg Traces:
        0  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gno.land/pkg/sdk/vm/keeper.go:272 - VM call panic: out of gas in location: ReadPerByte;
    Machine:
        CheckTypes: false
    	Op: [OpHalt OpExec OpBody OpDefine OpPrecall OpEval]
    	Values: (len: 2)
              #1 (&0x14007462708.(*gno.land/p/demo/avl.Tree) *gno.land/p/demo/avl.Tree)
              #0 (Register func(inviter std.Address,name string,profile string)())
    	Exprs:
              #1 name<VPBlock(1,1)>
              #0 &(name2User<VPBlock(3,13)>).Get(name<VPBlock(1,1)>)
    	Stmts:
              #1 bodyStmt[0/0/7]=if ok<VPBlock(2,6)> { panic((const ("name already registered" <untyped> string))) }*
              #0 return
    	Blocks:
              @(1) Block(ID:0000000000000000000000000000000000000000:0,Addr:0x14000facf00,Source:func Register(inviter std<VPBloc...,Parent:0x14000fac3c0)
                inviter: ("" std.Address)
                name: ("1maxwell" string)
                profile: ("Profile description" string)
                caller: ("g1dsd4mgqadm0rpqp99ghkdmffktuhdnplxeqfm6" std.Address)
                sentCoins: (slice[(struct{("ugnot" string),(200000000 int64)} std.Coin)] std.Coins)
                minCoin: (struct{("ugnot" string),(200000000 int64)} std.Coin)
                ok: (undefined)
                invites: (undefined)
                user: (undefined)
     (s vals) @(1) Block(ID:0000000000000000000000000000000000000000:0,Addr:0x14007ebf020,Source:func Register(inviter std<VPBloc...,Parent:0x14007f1e5a0)
                inviter: ( std.Address)
                name: ( string)
                profile: ( string)
                caller: ( std.Address)
                sentCoins: (nil std.Coins)
                minCoin: (nil std.Coin)
                ok: (false bool)
                invites: (0 int)
                user: (nil *gno.land/r/demo/users.User)
     (s typs) @(1) [std.Address string string std.Address std.Coins std.Coin bool int *gno.land/r/demo/users.User]
              @(2) Block(ID:e1fe0949cd51eca16aaf71ea6a02cd81c7431576:3,Addr:0x14000fac3c0,Source:ref(gno.land/r/demo/users/users....,Parent:0x14000fac000)
                (RefNode names not shown)
     (s vals) @(2) Block(ID:0000000000000000000000000000000000000000:0,Addr:0x14007f1e5a0,Source:file{ package users; import rege...,Parent:0x14007f4b620)
                regexp: (package(regexp regexp) package{})
                std: (package(std std) package{})
                strconv: (package(strconv strconv) package{})
                strings: (package(strings strings) package{})
                avl: (package(avl gno.land/p/demo/avl) package{})
     (s typs) @(2) [package{} package{} package{} package{} package{}]
              @(3) gno.land/r/demo/users
    	Blocks (other):

    	Frames:
              #0 [FRAME FUNC:Register RECV:(undefined) (3 args) 1/0/0/0/1 LASTPKG:main LASTRLM:Realm(nil)]
    	Realm:
    	  gno.land/r/demo/users
    	Exceptions:
    	  []

    Stack Trace:
        0  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/errors/errors.go:20
        1  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gno.land/pkg/sdk/vm/keeper.go:272
        2  /usr/local/go/src/runtime/panic.go:884
        3  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/store/types/gas.go:104
        4  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/store/gas/store.go:33
        5  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gnovm/pkg/gnolang/store.go:272
        6  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gnovm/pkg/gnolang/store.go:256
        7  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gnovm/pkg/gnolang/store.go:242
        8  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gnovm/pkg/gnolang/values.go:830
        9  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gnovm/pkg/gnolang/store.go:127
       10  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gnovm/pkg/gnolang/values.go:590
       11  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gnovm/pkg/gnolang/values.go:603
       12  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gnovm/pkg/gnolang/types.go:1573
       13  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gnovm/pkg/gnolang/values.go:1750
       14  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gnovm/pkg/gnolang/op_expressions.go:81
       15  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gnovm/pkg/gnolang/machine.go:1185
       16  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gnovm/pkg/gnolang/machine.go:636
       17  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gno.land/pkg/sdk/vm/keeper.go:282
       18  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gno.land/pkg/sdk/vm/handler.go:64
       19  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/gno.land/pkg/sdk/vm/handler.go:29
       20  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/sdk/baseapp.go:644
       21  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/sdk/baseapp.go:833
       22  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/sdk/baseapp.go:580
       23  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/bft/abci/client/local_client.go:82
       24  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/bft/proxy/app_conn.go:73
       25  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/bft/state/execution.go:253
       26  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/bft/state/execution.go:102
       27  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/bft/consensus/state.go:1347
       28  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/bft/consensus/state.go:1275
       29  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/bft/consensus/state.go:1221
       30  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/bft/consensus/state.go:1252
       31  /Users/maxwell/workbench/blockchain/gno/gno_forks/gno/tm2/pkg/bft/consensus/state.go:1637
    --= /Error =--
    <------end log
--= /Error =--

@thehowl
Copy link
Member

thehowl commented Nov 20, 2023

@ltzmaxwell

have a base solution to make the error clear, more digging needed to beautify the entangled logs:

I think you can already make a PR with this.

The logs should be improved in general, and it's part of the greater effort in #999 and probably needs to be discussed further :)

@thehowl
Copy link
Member

thehowl commented May 26, 2024

This issue should be fixed, the errors should now be saner:

$ gnokey maketx addpkg  -gas-wanted 100_000 -pkgpath gno.land/r/demo/tt2 -pkgdir . -gas-fee 100ugnot -chainid dev -broadcast -remote 127.0.0.1:36657 gentest
Enter password.
--= Error =--
Data: out of gas error
Msg Traces:
    0  /home/howl/oc/gno/tm2/pkg/crypto/keys/client/maketx.go:213 - deliver transaction failed: log:out of gas, gasWanted: 100000, gasUsed: 105103 location: WritePerByte
--= /Error =--

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: 🚀 Needed for Launch
Development

No branches or pull requests

3 participants