From 538b29fcfb7c6b396056bc5ad41416eecae658fe Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Wed, 24 Apr 2024 18:08:36 +0200 Subject: [PATCH 01/30] feat: initial timemachine implem Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/cmd/gnodev/main.go | 76 ++++++++++++ contribs/gnodev/pkg/dev/node.go | 27 ++++- contribs/gnodev/pkg/dev/node_state.go | 150 ++++++++++++++++++++++++ contribs/gnodev/pkg/rawterm/keypress.go | 6 + 4 files changed, 255 insertions(+), 4 deletions(-) create mode 100644 contribs/gnodev/pkg/dev/node_state.go diff --git a/contribs/gnodev/cmd/gnodev/main.go b/contribs/gnodev/cmd/gnodev/main.go index 652b4a862a3..4c52e9afb3a 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -309,6 +309,21 @@ func runEventLoop( dnode *gnodev.Node, watch *watcher.PackageWatcher, ) error { + + // XXX: move this in above, but we need to have a proper struct first + // XXX: make this configurable + exported := 0 + path, err := os.MkdirTemp("", "gnodev-export") + if err != nil { + return fmt.Errorf("unable to create `export` directory: ", err) + } + + defer func() { + if exported == 0 { + _ = os.RemoveAll(path) + } + }() + keyPressCh := listenForKeyPress(logger.WithGroup(KeyPressLogName), rt) for { var err error @@ -360,6 +375,67 @@ func runEventLoop( Error("unable to reset node state", "err", err) } + case rawterm.KeyCtrlS: // Save + logger.WithGroup(NodeLogName).Info("saving state...") + if err := dnode.SaveCurrentState(ctx); err != nil { + logger.WithGroup(NodeLogName). + Error("unable to save node state", "err", err) + } + + case rawterm.KeyCtrlE: // Export + logger.WithGroup(NodeLogName).Info("exporting state...") + doc, err := dnode.ExportStateAsGenesis(ctx) + if err != nil { + logger.WithGroup(NodeLogName). + Error("unable to export node state", "err", err) + continue + } + + docfile := filepath.Join(path, fmt.Sprintf("export_%d.jsonl", exported)) + if err := doc.SaveAs(docfile); err != nil { + logger.WithGroup(NodeLogName). + Error("unable to save genesis", "err", err) + } + exported++ + + logger.WithGroup(NodeLogName).Info("node state exported", "file", docfile) + case rawterm.KeyN: // Next tx + logger.Info("moving forward...") + if err := dnode.MoveToNextTX(ctx); err != nil { + logger.WithGroup(NodeLogName). + Error("unable to move forward", "err", err) + } + + case rawterm.KeyP: // Next tx + logger.Info("moving backward...") + if err := dnode.MoveToPreviousTX(ctx); err != nil { + logger.WithGroup(NodeLogName). + Error("unable to move backward", "err", err) + } + + // case rawterm.KeyI: // Info + // index := dnode.CurrentTXIndex() + // var s strings.Builder + // tab := tabwriter.NewWriter(&s, 5, 0, 2, ':', 0) + // fmt.Fprintf(tab, "Index\t%d", index) + // tab.Flush() + // logger.WithGroup(NodeLogName).Info("node status", "state", s.String()) + // // doc, err := dnode.ExportStateAsGenesis(ctx) + // if err != nil { + // logger.WithGroup(NodeLogName). + // Error("unable to export node state", "err", err) + // continue + // } + + // docfile := filepath.Join(path, fmt.Sprintf("export_%d.jsonl", exported)) + // if err := doc.SaveAs(docfile); err != nil { + // logger.WithGroup(NodeLogName). + // Error("unable to save genesis", "err", err) + // } + // exported++ + + // logger.WithGroup(NodeLogName).Info("", "index", docfile) + case rawterm.KeyCtrlC: // Exit return nil default: diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index 66971980b73..7068ff989e6 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -31,6 +31,7 @@ type NodeConfig struct { DefaultDeployer crypto.Address BalancesList []gnoland.Balance PackagesPathList []PackagePath + InitialTxs []std.Tx TMConfig *tmcfg.Config SkipFailingGenesisTxs bool NoReplay bool @@ -55,6 +56,7 @@ func DefaultNodeConfig(rootdir string) *NodeConfig { BalancesList: balances, ChainID: tmc.ChainID(), PackagesPathList: []PackagePath{}, + InitialTxs: []std.Tx{}, TMConfig: tmc, SkipFailingGenesisTxs: true, MaxGasPerBlock: 10_000_000_000, @@ -73,6 +75,11 @@ type Node struct { // keep track of number of loaded package to be able to skip them on restore loadedPackages int + + // state + initialState []std.Tx + previousState []std.Tx + stateIndex int } var DefaultFee = std.NewFee(50000, std.MustParseCoin("1000000ugnot")) @@ -87,13 +94,15 @@ func NewDevNode(ctx context.Context, logger *slog.Logger, emitter emitter.Emitte if err != nil { return nil, fmt.Errorf("unable to load genesis packages: %w", err) } - logger.Info("pkgs loaded", "path", cfg.PackagesPathList) + // add initials txs + txs := append(pkgsTxs, cfg.InitialTxs...) + // generate genesis state genesis := gnoland.GnoGenesisState{ Balances: cfg.BalancesList, - Txs: pkgsTxs, + Txs: txs, } devnode := &Node{ @@ -102,7 +111,9 @@ func NewDevNode(ctx context.Context, logger *slog.Logger, emitter emitter.Emitte client: client.NewLocal(), pkgs: mpkgs, logger: logger, + initialState: cfg.InitialTxs, loadedPackages: len(pkgsTxs), + stateIndex: len(cfg.InitialTxs), } if err := devnode.reset(ctx, genesis); err != nil { @@ -186,11 +197,14 @@ func (n *Node) Reset(ctx context.Context) error { } // Generate a new genesis state based on the current packages - txs, err := n.pkgs.Load(DefaultFee) + pkgsTxs, err := n.pkgs.Load(DefaultFee) if err != nil { return fmt.Errorf("unable to load pkgs: %w", err) } + // Append initialTxs + txs := append(pkgsTxs, n.initialState...) + genesis := gnoland.GnoGenesisState{ Balances: n.config.BalancesList, Txs: txs, @@ -202,6 +216,9 @@ func (n *Node) Reset(ctx context.Context) error { return fmt.Errorf("unable to initialize a new node: %w", err) } + n.loadedPackages = len(pkgsTxs) + n.stateIndex = len(n.initialState) + n.previousState = nil n.emitter.Emit(&events.Reset{}) return nil } @@ -261,7 +278,8 @@ func (n *Node) Reload(ctx context.Context) error { // Update node infos n.loadedPackages = len(pkgsTxs) - + n.stateIndex = len(state) - 1 + n.previousState = nil n.emitter.Emit(&events.Reload{}) return nil } @@ -398,6 +416,7 @@ func (n *Node) reset(ctx context.Context, genesis gnoland.GnoGenesisState) (err nodeConfig := newNodeConfig(n.config.TMConfig, n.config.ChainID, genesis) nodeConfig.GenesisTxHandler = n.genesisTxHandler nodeConfig.Genesis.ConsensusParams.Block.MaxGas = n.config.MaxGasPerBlock + nodeConfig.TMConfig.Consensus.CreateEmptyBlocks = false // recoverFromError handles panics and converts them to errors. recoverFromError := func() { diff --git a/contribs/gnodev/pkg/dev/node_state.go b/contribs/gnodev/pkg/dev/node_state.go new file mode 100644 index 00000000000..aaa9f666275 --- /dev/null +++ b/contribs/gnodev/pkg/dev/node_state.go @@ -0,0 +1,150 @@ +package dev + +import ( + "context" + "fmt" + + "github.com/gnolang/gno/contribs/gnodev/pkg/events" + "github.com/gnolang/gno/gno.land/pkg/gnoland" + bft "github.com/gnolang/gno/tm2/pkg/bft/types" + "github.com/gnolang/gno/tm2/pkg/std" +) + +func (n *Node) SaveCurrentState(ctx context.Context) error { + // Get current blockstore state + state, err := n.getBlockStoreState(ctx) + if err != nil { + return fmt.Errorf("unable to save state: %s", err.Error()) + } + + n.initialState = state + return nil +} + +func (n *Node) ExportCurrentState(ctx context.Context) ([]std.Tx, error) { + // Get current blockstore state + state, err := n.getBlockStoreState(ctx) + if err != nil { + return nil, fmt.Errorf("unable to save state: %s", err.Error()) + } + + return state, nil +} + +func (n *Node) MoveToPreviousTX(ctx context.Context) error { + state := n.previousState + if state == nil { + var err error + // Get current blockstore state + state, err = n.getBlockStoreState(ctx) + if err != nil { + return fmt.Errorf("unable to save state: %s", err.Error()) + } + n.stateIndex = len(state) + } + + newIndex := n.stateIndex - 1 + if newIndex < 0 { + return fmt.Errorf("not more previous state") + } + + // Stop the node if it's currently running. + if err := n.stopIfRunning(); err != nil { + return fmt.Errorf("unable to stop the node: %w", err) + } + + // Load genesis packages + pkgsTxs, err := n.pkgs.Load(DefaultFee) + if err != nil { + return fmt.Errorf("unable to load pkgs: %w", err) + } + + // Create genesis with loaded pkgs + previous state + newState := state[:newIndex] + genesis := gnoland.GnoGenesisState{ + Balances: n.config.BalancesList, + Txs: append(pkgsTxs, newState...), + } + + // Reset the node with the new genesis state. + err = n.reset(ctx, genesis) + n.logger.Info("reload done", "pkgs", len(pkgsTxs), "state applied", len(state)) + + n.logger.Info("moving backward", + "pkgs", len(pkgsTxs), + "tx-index", newIndex, + "state-applied", len(newState)) + + // Update node infos + n.stateIndex = newIndex + if n.previousState == nil { + n.previousState = state + } + + n.loadedPackages = len(pkgsTxs) + n.emitter.Emit(&events.Reload{}) + + return nil +} + +func (n *Node) MoveToNextTX(ctx context.Context) error { + state := n.previousState + if state == nil { + return fmt.Errorf("already at the top of txs") + } + + newIndex := n.stateIndex + 1 + if newIndex > len(state) { + return fmt.Errorf("already at the top of txs") + } + + // Stop the node if it's currently running. + if err := n.stopIfRunning(); err != nil { + return fmt.Errorf("unable to stop the node: %w", err) + } + + // Load genesis packages + pkgsTxs, err := n.pkgs.Load(DefaultFee) + if err != nil { + return fmt.Errorf("unable to load pkgs: %w", err) + } + + // Create genesis with loaded pkgs + previous state + newState := state[:newIndex] + genesis := gnoland.GnoGenesisState{ + Balances: n.config.BalancesList, + Txs: append(pkgsTxs, newState...), + } + + // Reset the node with the new genesis state. + err = n.reset(ctx, genesis) + + n.logger.Info("moving forward", + "pkgs", len(pkgsTxs), + "tx index", newIndex, + "state applied", len(newState)) + + // Update node infos + n.stateIndex = newIndex + n.loadedPackages = len(pkgsTxs) + n.emitter.Emit(&events.Reload{}) + + return nil +} + +func (n *Node) ExportStateAsGenesis(ctx context.Context) (*bft.GenesisDoc, error) { + // Get current blockstore state + state, err := n.getBlockStoreState(ctx) + if err != nil { + return nil, fmt.Errorf("unable to save state: %s", err.Error()) + } + + // Get current blockstore state + doc := *n.Node.GenesisDoc() // copy doc + doc.AppState = gnoland.GnoGenesisState{ + Balances: n.config.BalancesList, + Txs: state, + } + + return &doc, nil +} diff --git a/contribs/gnodev/pkg/rawterm/keypress.go b/contribs/gnodev/pkg/rawterm/keypress.go index 48f8367a65b..f79aceb2a1c 100644 --- a/contribs/gnodev/pkg/rawterm/keypress.go +++ b/contribs/gnodev/pkg/rawterm/keypress.go @@ -16,10 +16,14 @@ const ( KeyCtrlL KeyPress = '\x0c' // Ctrl+L KeyCtrlO KeyPress = '\x0f' // Ctrl+O KeyCtrlR KeyPress = '\x12' // Ctrl+R + KeyCtrlS KeyPress = '\x13' // Ctrl+S KeyCtrlT KeyPress = '\x14' // Ctrl+T KeyA KeyPress = 'A' KeyH KeyPress = 'H' + KeyI KeyPress = 'I' + KeyN KeyPress = 'N' + KeyP KeyPress = 'P' KeyR KeyPress = 'R' ) @@ -43,6 +47,8 @@ func (k KeyPress) String() string { return "Ctrl+O" case KeyCtrlR: return "Ctrl+R" + case KeyCtrlS: + return "Ctrl+S" case KeyCtrlT: return "Ctrl+T" default: From a38c4ae5938688999d2ea351b52ca1f6476ae204 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Wed, 5 Jun 2024 13:08:12 +0200 Subject: [PATCH 02/30] feat: add genesis load Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/cmd/gnodev/main.go | 51 ++++----- contribs/gnodev/cmd/gnodev/setup_node.go | 47 +++++--- contribs/gnodev/go.mod | 5 +- contribs/gnodev/go.sum | 12 +- contribs/gnodev/pkg/dev/node.go | 134 ++++++++++++----------- contribs/gnodev/pkg/dev/node_state.go | 132 +++++++++++----------- contribs/gnodev/pkg/rawterm/keypress.go | 1 + gnovm/cmd/gno/lint_test.go | 2 +- 8 files changed, 198 insertions(+), 186 deletions(-) diff --git a/contribs/gnodev/cmd/gnodev/main.go b/contribs/gnodev/cmd/gnodev/main.go index 64c0e54ea53..cc1465ab394 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -11,6 +11,7 @@ import ( "time" "github.com/gnolang/gno/contribs/gnodev/pkg/address" + "github.com/gnolang/gno/contribs/gnodev/pkg/dev" gnodev "github.com/gnolang/gno/contribs/gnodev/pkg/dev" "github.com/gnolang/gno/contribs/gnodev/pkg/emitter" "github.com/gnolang/gno/contribs/gnodev/pkg/rawterm" @@ -49,6 +50,7 @@ type devCfg struct { root string premineAccounts varPremineAccounts balancesFile string + genesisFile string // Node Configuration minimal bool @@ -171,6 +173,13 @@ func (c *devCfg) RegisterFlags(fs *flag.FlagSet) { "set node ChainID", ) + fs.StringVar( + &c.genesisFile, + "genesis-file", + defaultDevOptions.genesisFile, + "load the given genesis file", + ) + fs.BoolVar( &c.noWatch, "no-watch", @@ -236,7 +245,8 @@ func execDev(cfg *devCfg, args []string, io commands.IO) (err error) { // Setup Dev Node // XXX: find a good way to export or display node logs nodeLogger := logger.WithGroup(NodeLogName) - devNode, err := setupDevNode(ctx, nodeLogger, cfg, emitterServer, balances, pkgpaths) + nodeCfg := setupDevNodeConfig(cfg, logger, emitterServer, balances, pkgpaths) + devNode, err := dev.NewDevNode(ctx, nodeCfg) if err != nil { return err } @@ -292,11 +302,15 @@ func execDev(cfg *devCfg, args []string, io commands.IO) (err error) { } var helper string = ` -A Accounts - Display known accounts and balances -H Help - Display this message -R Reload - Reload all packages to take change into account. -Ctrl+R Reset - Reset application state. -Ctrl+C Exit - Exit the application +P Previous TX - Go to the previous tx +N Next TX - Go to the next tx +E Export - Export the current state as genesis doc +A Accounts - Display known accounts and balances +H Help - Display this message +R Reload - Reload all packages to take change into account. +Ctrl+S Save State - Save the current state +Ctrl+R Reset - Reset application to it's initial/save state. +Ctrl+C Exit - Exit the application ` func runEventLoop( @@ -380,7 +394,7 @@ func runEventLoop( Error("unable to save node state", "err", err) } - case rawterm.KeyCtrlE: // Export + case rawterm.KeyE: logger.WithGroup(NodeLogName).Info("exporting state...") doc, err := dnode.ExportStateAsGenesis(ctx) if err != nil { @@ -411,29 +425,6 @@ func runEventLoop( Error("unable to move backward", "err", err) } - // case rawterm.KeyI: // Info - // index := dnode.CurrentTXIndex() - // var s strings.Builder - // tab := tabwriter.NewWriter(&s, 5, 0, 2, ':', 0) - // fmt.Fprintf(tab, "Index\t%d", index) - // tab.Flush() - // logger.WithGroup(NodeLogName).Info("node status", "state", s.String()) - // // doc, err := dnode.ExportStateAsGenesis(ctx) - // if err != nil { - // logger.WithGroup(NodeLogName). - // Error("unable to export node state", "err", err) - // continue - // } - - // docfile := filepath.Join(path, fmt.Sprintf("export_%d.jsonl", exported)) - // if err := doc.SaveAs(docfile); err != nil { - // logger.WithGroup(NodeLogName). - // Error("unable to save genesis", "err", err) - // } - // exported++ - - // logger.WithGroup(NodeLogName).Info("", "index", docfile) - case rawterm.KeyCtrlC: // Exit return nil default: diff --git a/contribs/gnodev/cmd/gnodev/setup_node.go b/contribs/gnodev/cmd/gnodev/setup_node.go index c79ab9d18bf..1df744dab3e 100644 --- a/contribs/gnodev/cmd/gnodev/setup_node.go +++ b/contribs/gnodev/cmd/gnodev/setup_node.go @@ -1,33 +1,38 @@ package main import ( - "context" "fmt" "log/slog" "net" "strings" gnodev "github.com/gnolang/gno/contribs/gnodev/pkg/dev" - "github.com/gnolang/gno/contribs/gnodev/pkg/emitter" + emitter "github.com/gnolang/gno/contribs/gnodev/pkg/emitter" "github.com/gnolang/gno/gno.land/pkg/gnoland" + "github.com/gnolang/gno/tm2/pkg/bft/types" + "github.com/gnolang/gno/tm2/pkg/std" ) -// setupDevNode initializes and returns a new DevNode. -func setupDevNode( - ctx context.Context, - logger *slog.Logger, +// setupDevNodeConfig creates and returns a new dev.NodeConfig. +func setupDevNodeConfig( cfg *devCfg, - remitter emitter.Emitter, + logger *slog.Logger, + emitter emitter.Emitter, balances gnoland.Balances, pkgspath []gnodev.PackagePath, -) (*gnodev.Node, error) { - config := setupDevNodeConfig(cfg, balances, pkgspath) - return gnodev.NewDevNode(ctx, logger, remitter, config) -} - -// setupDevNodeConfig creates and returns a new dev.NodeConfig. -func setupDevNodeConfig(cfg *devCfg, balances gnoland.Balances, pkgspath []gnodev.PackagePath) *gnodev.NodeConfig { +) *gnodev.NodeConfig { config := gnodev.DefaultNodeConfig(cfg.root) + if cfg.genesisFile != "" { + var err error + if config.InitialTxs, err = extractTxsFromGenesisFile(cfg.genesisFile); err != nil { + logger.Error("unable to load genesis file", "path", cfg.genesisFile, "err", err) + } else { + logger.Info("genesis file loaded", "path", cfg.genesisFile, "txs", len(config.InitialTxs)) + } + } + + config.Logger = logger + config.Emitter = emitter config.BalancesList = balances.List() config.PackagesPathList = pkgspath config.TMConfig.RPC.ListenAddress = resolveUnixOrTCPAddr(cfg.nodeRPCListenerAddr) @@ -42,6 +47,20 @@ func setupDevNodeConfig(cfg *devCfg, balances gnoland.Balances, pkgspath []gnode return config } +func extractTxsFromGenesisFile(path string) (txs []std.Tx, err error) { + doc, err := types.GenesisDocFromFile(path) + if err != nil { + return []std.Tx{}, fmt.Errorf("unable to parse doc file: %w", err) + } + + state, ok := doc.AppState.(gnoland.GnoGenesisState) + if !ok { + return []std.Tx{}, fmt.Errorf("invalid `GnoGenesisState` app state") + } + + return state.Txs, nil +} + func resolveUnixOrTCPAddr(in string) (out string) { var err error var addr net.Addr diff --git a/contribs/gnodev/go.mod b/contribs/gnodev/go.mod index 4741a5d7326..8930d8aee9a 100644 --- a/contribs/gnodev/go.mod +++ b/contribs/gnodev/go.mod @@ -46,7 +46,7 @@ require ( github.com/peterbourgon/ff/v3 v3.4.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rivo/uniseg v0.4.3 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rs/cors v1.10.1 // indirect github.com/rs/xid v1.5.0 // indirect @@ -67,7 +67,8 @@ require ( golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/mod v0.16.0 // indirect golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.18.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.20.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.19.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect diff --git a/contribs/gnodev/go.sum b/contribs/gnodev/go.sum index a2c9f154560..5328ba9a53f 100644 --- a/contribs/gnodev/go.sum +++ b/contribs/gnodev/go.sum @@ -144,8 +144,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= -github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= @@ -203,8 +203,8 @@ golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -215,8 +215,8 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index 9e43b186d63..61f8f026812 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -29,9 +29,11 @@ import ( ) type NodeConfig struct { + Logger *slog.Logger DefaultDeployer crypto.Address BalancesList []gnoland.Balance PackagesPathList []PackagePath + Emitter emitter.Emitter InitialTxs []std.Tx TMConfig *tmcfg.Config SkipFailingGenesisTxs bool @@ -44,6 +46,7 @@ func DefaultNodeConfig(rootdir string) *NodeConfig { tmc := gnoland.NewDefaultTMConfig(rootdir) tmc.Consensus.SkipTimeoutCommit = false // avoid time drifting, see issue #1507 tmc.Consensus.WALDisabled = true + tmc.Consensus.CreateEmptyBlocks = false defaultDeployer := crypto.MustAddressFromString(integration.DefaultAccount_Address) balances := []gnoland.Balance{ @@ -54,6 +57,8 @@ func DefaultNodeConfig(rootdir string) *NodeConfig { } return &NodeConfig{ + Logger: noopLogger, + Emitter: &emitter.NoopServer{}, DefaultDeployer: defaultDeployer, BalancesList: balances, ChainID: tmc.ChainID(), @@ -80,14 +85,15 @@ type Node struct { loadedPackages int // state - initialState []std.Tx - previousState []std.Tx - stateIndex int + muState sync.RWMutex + state []std.Tx + initialState []std.Tx + currentStateIndex int } var DefaultFee = std.NewFee(50000, std.MustParseCoin("1000000ugnot")) -func NewDevNode(ctx context.Context, logger *slog.Logger, emitter emitter.Emitter, cfg *NodeConfig) (*Node, error) { +func NewDevNode(ctx context.Context, cfg *NodeConfig) (*Node, error) { mpkgs, err := NewPackagesMap(cfg.PackagesPathList) if err != nil { return nil, fmt.Errorf("unable map pkgs list: %w", err) @@ -97,24 +103,25 @@ func NewDevNode(ctx context.Context, logger *slog.Logger, emitter emitter.Emitte if err != nil { return nil, fmt.Errorf("unable to load genesis packages: %w", err) } - logger.Info("pkgs loaded", "path", cfg.PackagesPathList) + cfg.Logger.Info("pkgs loaded", "path", cfg.PackagesPathList) devnode := &Node{ - config: cfg, - client: client.NewLocal(), - emitter: emitter, - pkgs: mpkgs, - logger: logger, - initialState: cfg.InitialTxs, - loadedPackages: len(pkgsTxs), - stateIndex: len(cfg.InitialTxs), - } - - // // generate genesis state - // genesis := gnoland.GnoGenesisState{ - // Balances: cfg.BalancesList, - // Txs: txs, - // } + config: cfg, + client: client.NewLocal(), + emitter: cfg.Emitter, + pkgs: mpkgs, + logger: cfg.Logger, + loadedPackages: len(pkgsTxs), + state: cfg.InitialTxs, + initialState: cfg.InitialTxs, + currentStateIndex: len(cfg.InitialTxs), + } + + // generate genesis state + genesis := gnoland.GnoGenesisState{ + Balances: cfg.BalancesList, + Txs: append(pkgsTxs, cfg.InitialTxs...), + } if err := devnode.rebuildNode(ctx, genesis); err != nil { return nil, fmt.Errorf("unable to initialize the node: %w", err) @@ -266,7 +273,6 @@ func (n *Node) Reset(ctx context.Context) error { // Append initialTxs txs := append(pkgsTxs, n.initialState...) - genesis := gnoland.GnoGenesisState{ Balances: n.config.BalancesList, Txs: txs, @@ -279,8 +285,7 @@ func (n *Node) Reset(ctx context.Context) error { } n.loadedPackages = len(pkgsTxs) - n.stateIndex = len(n.initialState) - n.previousState = nil + n.currentStateIndex = len(n.initialState) n.emitter.Emit(&events.Reset{}) return nil } @@ -424,6 +429,40 @@ func (n *Node) rebuildNodeFromState(ctx context.Context) error { return nil } +func (n *Node) handleEventTX(evt tm2events.Event) { + switch data := evt.(type) { + case bft.EventTx: + go func() { + // Use separate routine to avoid deadlock + n.muNode.Lock() + defer n.muNode.Unlock() + + heigh := n.BlockStore().Height() + n.currentStateIndex++ + n.state = nil // invalidate state + + n.logger.Info("node state", "index", n.currentStateIndex, "height", heigh) + }() + + resEvt := events.TxResult{ + Height: data.Result.Height, + Index: data.Result.Index, + // XXX: Update this to split error for stack + Response: data.Result.Response, + } + + if err := amino.Unmarshal(data.Result.Tx, &resEvt.Tx); err != nil { + n.logger.Error("unable to unwarp tx result", + "error", err) + + } + + n.emitter.Emit(resEvt) + } +} + +var noopLogger = log.NewNoopLogger() + func (n *Node) rebuildNode(ctx context.Context, genesis gnoland.GnoGenesisState) (err error) { // Stop the node if it's currently running. if err := n.stopIfRunning(); err != nil { @@ -434,7 +473,6 @@ func (n *Node) rebuildNode(ctx context.Context, genesis gnoland.GnoGenesisState) nodeConfig := newNodeConfig(n.config.TMConfig, n.config.ChainID, genesis) nodeConfig.GenesisTxHandler = n.genesisTxHandler nodeConfig.Genesis.ConsensusParams.Block.MaxGas = n.config.MaxGasPerBlock - nodeConfig.TMConfig.Consensus.CreateEmptyBlocks = false // recoverFromError handles panics and converts them to errors. recoverFromError := func() { @@ -453,9 +491,16 @@ func (n *Node) rebuildNode(ctx context.Context, genesis gnoland.GnoGenesisState) // Execute node creation and handle any errors. defer recoverFromError() - node, nodeErr := buildNode(n.logger, n.emitter, nodeConfig) - if nodeErr != nil { // Then for any node error - return fmt.Errorf("unable to build the node: %w", nodeErr) + // XXX(TODO): Redirect the node log somewhere else + node, nodeErr := gnoland.NewInMemoryNode(noopLogger, nodeConfig) + if nodeErr != nil { + return fmt.Errorf("unable to create a new node: %w", err) + } + + node.EventSwitch().AddListener("dev-emitter", n.handleEventTX) + + if startErr := node.Start(); startErr != nil { + return fmt.Errorf("unable to start the node: %w", startErr) } // Wait for the node to be ready @@ -502,41 +547,6 @@ func (n *Node) genesisTxHandler(ctx sdk.Context, tx std.Tx, res sdk.Result) { return } -var noopLogger = log.NewNoopLogger() - -func buildNode(logger *slog.Logger, emitter emitter.Emitter, cfg *gnoland.InMemoryNodeConfig) (*node.Node, error) { - // XXX(TODO): Redirect the node log somewhere else - node, err := gnoland.NewInMemoryNode(noopLogger, cfg) - if err != nil { - return nil, fmt.Errorf("unable to create a new node: %w", err) - } - - node.EventSwitch().AddListener("dev-emitter", func(evt tm2events.Event) { - switch data := evt.(type) { - case bft.EventTx: - resEvt := events.TxResult{ - Height: data.Result.Height, - Index: data.Result.Index, - // XXX: Update this to split error for stack - Response: data.Result.Response, - } - - if err := amino.Unmarshal(data.Result.Tx, &resEvt.Tx); err != nil { - logger.Error("unable to unwarp tx result", - "error", err) - } - - emitter.Emit(resEvt) - } - }) - - if startErr := node.Start(); startErr != nil { - return nil, fmt.Errorf("unable to start the node: %w", startErr) - } - - return node, nil -} - func newNodeConfig(tmc *tmcfg.Config, chainid string, appstate gnoland.GnoGenesisState) *gnoland.InMemoryNodeConfig { // Create Mocked Identity pv := gnoland.NewMockedPrivValidator() diff --git a/contribs/gnodev/pkg/dev/node_state.go b/contribs/gnodev/pkg/dev/node_state.go index aaa9f666275..b005e7f3c0c 100644 --- a/contribs/gnodev/pkg/dev/node_state.go +++ b/contribs/gnodev/pkg/dev/node_state.go @@ -10,97 +10,75 @@ import ( "github.com/gnolang/gno/tm2/pkg/std" ) +// Save the current state as initialState func (n *Node) SaveCurrentState(ctx context.Context) error { + n.muNode.RLock() + defer n.muNode.RUnlock() + // Get current blockstore state - state, err := n.getBlockStoreState(ctx) + state, err := n.getState(ctx) if err != nil { return fmt.Errorf("unable to save state: %s", err.Error()) } - n.initialState = state + n.initialState = state[:n.currentStateIndex] return nil } +// Export the current state as list of txs func (n *Node) ExportCurrentState(ctx context.Context) ([]std.Tx, error) { + n.muNode.RLock() + defer n.muNode.RUnlock() + // Get current blockstore state - state, err := n.getBlockStoreState(ctx) + state, err := n.getState(ctx) if err != nil { return nil, fmt.Errorf("unable to save state: %s", err.Error()) } - return state, nil + return state[:n.currentStateIndex], nil } -func (n *Node) MoveToPreviousTX(ctx context.Context) error { - state := n.previousState - if state == nil { +func (n *Node) getState(ctx context.Context) ([]std.Tx, error) { + if n.state == nil { var err error - // Get current blockstore state - state, err = n.getBlockStoreState(ctx) + n.state, err = n.getBlockStoreState(ctx) if err != nil { - return fmt.Errorf("unable to save state: %s", err.Error()) + return nil, fmt.Errorf("unable to save state: %s", err.Error()) } - n.stateIndex = len(state) } - newIndex := n.stateIndex - 1 - if newIndex < 0 { - return fmt.Errorf("not more previous state") - } + return n.state, nil +} - // Stop the node if it's currently running. - if err := n.stopIfRunning(); err != nil { - return fmt.Errorf("unable to stop the node: %w", err) - } +// MoveFrom adjusts the current state of the node by `x` transactions. +// `x` can be negative to move backward or positive to move forward, however, index boundaries are respected +// with a lower limit of 0 and upper limit equaling the total number of states. +// If a move is successful, node is reload. +func (n *Node) MoveFrom(ctx context.Context, x int) error { + n.muNode.Lock() + defer n.muNode.Unlock() - // Load genesis packages - pkgsTxs, err := n.pkgs.Load(DefaultFee) + newIndex := n.currentStateIndex + x + state, err := n.getState(ctx) if err != nil { - return fmt.Errorf("unable to load pkgs: %w", err) + return fmt.Errorf("unable to get current state: %w", err) } - // Create genesis with loaded pkgs + previous state - newState := state[:newIndex] - genesis := gnoland.GnoGenesisState{ - Balances: n.config.BalancesList, - Txs: append(pkgsTxs, newState...), + maxState := len(state) + switch { + case maxState == 0: // no state + return fmt.Errorf("empty state") + case newIndex < 0: + newIndex = 0 + n.logger.Info("minimum state reached", "tx-index", fmt.Sprintf("%d/%d", newIndex, maxState)) + case newIndex > maxState: + newIndex = maxState + n.logger.Info("maximum state reached", "tx-index", fmt.Sprintf("%d/%d", newIndex, maxState)) } - // Reset the node with the new genesis state. - err = n.reset(ctx, genesis) - n.logger.Info("reload done", "pkgs", len(pkgsTxs), "state applied", len(state)) - - n.logger.Info("moving backward", - "pkgs", len(pkgsTxs), - "tx-index", newIndex, - "state-applied", len(newState)) - - // Update node infos - n.stateIndex = newIndex - if n.previousState == nil { - n.previousState = state - } - - n.loadedPackages = len(pkgsTxs) - n.emitter.Emit(&events.Reload{}) - - return nil -} - -func (n *Node) MoveToNextTX(ctx context.Context) error { - state := n.previousState - if state == nil { - return fmt.Errorf("already at the top of txs") - } - - newIndex := n.stateIndex + 1 - if newIndex > len(state) { - return fmt.Errorf("already at the top of txs") - } - - // Stop the node if it's currently running. - if err := n.stopIfRunning(); err != nil { - return fmt.Errorf("unable to stop the node: %w", err) + if newIndex == n.currentStateIndex { + return nil } // Load genesis packages @@ -109,32 +87,44 @@ func (n *Node) MoveToNextTX(ctx context.Context) error { return fmt.Errorf("unable to load pkgs: %w", err) } + newState := n.state[:newIndex] + // Create genesis with loaded pkgs + previous state - newState := state[:newIndex] genesis := gnoland.GnoGenesisState{ Balances: n.config.BalancesList, Txs: append(pkgsTxs, newState...), } // Reset the node with the new genesis state. - err = n.reset(ctx, genesis) + err = n.rebuildNode(ctx, genesis) + if err != nil { + return fmt.Errorf("uanble to rebuild node: %w", err) + } - n.logger.Info("moving forward", - "pkgs", len(pkgsTxs), - "tx index", newIndex, - "state applied", len(newState)) + n.logger.Info("moving to", "tx-index", fmt.Sprintf("%d/%d", newIndex, maxState)) // Update node infos - n.stateIndex = newIndex - n.loadedPackages = len(pkgsTxs) + n.currentStateIndex = newIndex n.emitter.Emit(&events.Reload{}) return nil } +func (n *Node) MoveToPreviousTX(ctx context.Context) error { + return n.MoveFrom(ctx, -1) +} + +func (n *Node) MoveToNextTX(ctx context.Context) error { + return n.MoveFrom(ctx, 1) +} + +// Export the current state as genesis doc func (n *Node) ExportStateAsGenesis(ctx context.Context) (*bft.GenesisDoc, error) { + n.muNode.RLock() + defer n.muNode.RUnlock() + // Get current blockstore state - state, err := n.getBlockStoreState(ctx) + state, err := n.getState(ctx) if err != nil { return nil, fmt.Errorf("unable to save state: %s", err.Error()) } diff --git a/contribs/gnodev/pkg/rawterm/keypress.go b/contribs/gnodev/pkg/rawterm/keypress.go index f79aceb2a1c..45c64c999dd 100644 --- a/contribs/gnodev/pkg/rawterm/keypress.go +++ b/contribs/gnodev/pkg/rawterm/keypress.go @@ -20,6 +20,7 @@ const ( KeyCtrlT KeyPress = '\x14' // Ctrl+T KeyA KeyPress = 'A' + KeyE KeyPress = 'E' KeyH KeyPress = 'H' KeyI KeyPress = 'I' KeyN KeyPress = 'N' diff --git a/gnovm/cmd/gno/lint_test.go b/gnovm/cmd/gno/lint_test.go index fff05726e53..cc6dea1297b 100644 --- a/gnovm/cmd/gno/lint_test.go +++ b/gnovm/cmd/gno/lint_test.go @@ -8,7 +8,7 @@ func TestLintApp(t *testing.T) { args: []string{"lint"}, errShouldBe: "flag: help requested", }, { - args: []string{"lint", "--set-exit-status=0", "../../tests/integ/run_main/"}, + args: []string{"lint", "../../tests/integ/run_main/"}, stderrShouldContain: "./../../tests/integ/run_main: missing 'gno.mod' file (code=1).", }, { args: []string{"lint", "--set-exit-status=0", "../../tests/integ/undefined_variable_test/undefined_variables_test.gno"}, From 51e02dddb6c5d443dd5573818a233fcca25ebe45 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Wed, 5 Jun 2024 13:28:21 +0200 Subject: [PATCH 03/30] chore: lint Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/cmd/gnodev/main.go | 6 ++---- contribs/gnodev/pkg/dev/node.go | 7 ++----- contribs/gnodev/pkg/dev/node_test.go | 11 +++++++---- gnovm/cmd/gno/lint_test.go | 2 +- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/contribs/gnodev/cmd/gnodev/main.go b/contribs/gnodev/cmd/gnodev/main.go index cc1465ab394..aa2809097f2 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -11,7 +11,6 @@ import ( "time" "github.com/gnolang/gno/contribs/gnodev/pkg/address" - "github.com/gnolang/gno/contribs/gnodev/pkg/dev" gnodev "github.com/gnolang/gno/contribs/gnodev/pkg/dev" "github.com/gnolang/gno/contribs/gnodev/pkg/emitter" "github.com/gnolang/gno/contribs/gnodev/pkg/rawterm" @@ -246,7 +245,7 @@ func execDev(cfg *devCfg, args []string, io commands.IO) (err error) { // XXX: find a good way to export or display node logs nodeLogger := logger.WithGroup(NodeLogName) nodeCfg := setupDevNodeConfig(cfg, logger, emitterServer, balances, pkgpaths) - devNode, err := dev.NewDevNode(ctx, nodeCfg) + devNode, err := gnodev.NewDevNode(ctx, nodeCfg) if err != nil { return err } @@ -321,13 +320,12 @@ func runEventLoop( dnode *gnodev.Node, watch *watcher.PackageWatcher, ) error { - // XXX: move this in above, but we need to have a proper struct first // XXX: make this configurable exported := 0 path, err := os.MkdirTemp("", "gnodev-export") if err != nil { - return fmt.Errorf("unable to create `export` directory: ", err) + return fmt.Errorf("unable to create `export` directory: %w", err) } defer func() { diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index 61f8f026812..a6379db723d 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -85,10 +85,8 @@ type Node struct { loadedPackages int // state - muState sync.RWMutex - state []std.Tx - initialState []std.Tx - currentStateIndex int + initialState, state []std.Tx + currentStateIndex int } var DefaultFee = std.NewFee(50000, std.MustParseCoin("1000000ugnot")) @@ -454,7 +452,6 @@ func (n *Node) handleEventTX(evt tm2events.Event) { if err := amino.Unmarshal(data.Result.Tx, &resEvt.Tx); err != nil { n.logger.Error("unable to unwarp tx result", "error", err) - } n.emitter.Emit(resEvt) diff --git a/contribs/gnodev/pkg/dev/node_test.go b/contribs/gnodev/pkg/dev/node_test.go index d4868a5766f..557913b4020 100644 --- a/contribs/gnodev/pkg/dev/node_test.go +++ b/contribs/gnodev/pkg/dev/node_test.go @@ -8,7 +8,6 @@ import ( mock "github.com/gnolang/gno/contribs/gnodev/internal/mock" - "github.com/gnolang/gno/contribs/gnodev/pkg/emitter" "github.com/gnolang/gno/contribs/gnodev/pkg/events" "github.com/gnolang/gno/gno.land/pkg/gnoclient" "github.com/gnolang/gno/gno.land/pkg/integration" @@ -34,7 +33,8 @@ func TestNewNode_NoPackages(t *testing.T) { // Call NewDevNode with no package should work cfg := DefaultNodeConfig(gnoenv.RootDir()) - node, err := NewDevNode(ctx, logger, &emitter.NoopServer{}, cfg) + cfg.Logger = logger + node, err := NewDevNode(ctx, cfg) require.NoError(t, err) assert.Len(t, node.ListPkgs(), 0) @@ -62,7 +62,8 @@ func Render(_ string) string { return "foo" } // Call NewDevNode with no package should work cfg := DefaultNodeConfig(gnoenv.RootDir()) cfg.PackagesPathList = []PackagePath{pkgpath} - node, err := NewDevNode(ctx, logger, &emitter.NoopServer{}, cfg) + cfg.Logger = logger + node, err := NewDevNode(ctx, cfg) require.NoError(t, err) assert.Len(t, node.ListPkgs(), 1) @@ -286,7 +287,9 @@ func newTestingDevNode(t *testing.T, pkgslist ...PackagePath) (*Node, *mock.Serv // Call NewDevNode with no package should work cfg := DefaultNodeConfig(gnoenv.RootDir()) cfg.PackagesPathList = pkgslist - node, err := NewDevNode(ctx, logger, emitter, cfg) + cfg.Emitter = emitter + cfg.Logger = logger + node, err := NewDevNode(ctx, cfg) require.NoError(t, err) assert.Len(t, node.ListPkgs(), len(pkgslist)) diff --git a/gnovm/cmd/gno/lint_test.go b/gnovm/cmd/gno/lint_test.go index cc6dea1297b..fff05726e53 100644 --- a/gnovm/cmd/gno/lint_test.go +++ b/gnovm/cmd/gno/lint_test.go @@ -8,7 +8,7 @@ func TestLintApp(t *testing.T) { args: []string{"lint"}, errShouldBe: "flag: help requested", }, { - args: []string{"lint", "../../tests/integ/run_main/"}, + args: []string{"lint", "--set-exit-status=0", "../../tests/integ/run_main/"}, stderrShouldContain: "./../../tests/integ/run_main: missing 'gno.mod' file (code=1).", }, { args: []string{"lint", "--set-exit-status=0", "../../tests/integ/undefined_variable_test/undefined_variables_test.gno"}, From 079f82edc15f52dbe20270aadccfee76a9f1c22d Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Wed, 5 Jun 2024 19:00:02 +0200 Subject: [PATCH 04/30] chore: update gnodev doc Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- docs/gno-tooling/cli/gnodev.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/gno-tooling/cli/gnodev.md b/docs/gno-tooling/cli/gnodev.md index 97a4cc2e5ce..ff86faff697 100644 --- a/docs/gno-tooling/cli/gnodev.md +++ b/docs/gno-tooling/cli/gnodev.md @@ -21,6 +21,8 @@ local instance of `gnoweb`, allowing you to see the rendering of your Gno code i file changes, reloading and automatically restarting the node as needed. - **State Maintenance**: Gnodev replays all transactions in between reloads, ensuring the previous node state is preserved. +- **Transaction Manipulation**: Gnodev adds the capability to cancel and redo transactions interactively. +- **State Export:** Export the current state at any time in a genesis doc format. ## Installation @@ -100,6 +102,11 @@ While `gnodev` is running, the following shortcuts are available: - To see help, press `H`. - To display accounts balances, press `A`. - To reload manually, press `R`. +- To cancel the last action, press `P`. +- To redo the last cancelled action, press `N`. +- To save the current state, press `Ctrl+S`. +- To restore the saved state, press `Ctrl+R`. +- To export the current state to a genesis file, press `E`. - To reset the state of the node, press `CMD+R`. - To stop `gnodev`, press `CMD+C`. @@ -121,3 +128,4 @@ While `gnodev` is running, the following shortcuts are available: | --server-mode | disable interaction, and adjust logging for server use. | | --verbose | enable verbose output for development | | --web-listener | web server listening address | +| --genesis-file | Load and extract transactions from a genesis file | From c589e5d4d24bd6ec64cd14eaa95c4b24c6527202 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Wed, 5 Jun 2024 20:41:31 +0200 Subject: [PATCH 05/30] fix: add events unknown for mock emitter Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/internal/mock/server_emitter.go | 2 ++ contribs/gnodev/pkg/events/events.go | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/contribs/gnodev/internal/mock/server_emitter.go b/contribs/gnodev/internal/mock/server_emitter.go index d093d8855fe..be5ecc2bd21 100644 --- a/contribs/gnodev/internal/mock/server_emitter.go +++ b/contribs/gnodev/internal/mock/server_emitter.go @@ -23,6 +23,8 @@ func (m *ServerEmitter) Emit(evt events.Event) { } func (m *ServerEmitter) NextEvent() (evt events.Event) { + evt = &events.Unknown{} + m.muEvents.Lock() defer m.muEvents.Unlock() diff --git a/contribs/gnodev/pkg/events/events.go b/contribs/gnodev/pkg/events/events.go index c387c331eed..bb16c1f99d2 100644 --- a/contribs/gnodev/pkg/events/events.go +++ b/contribs/gnodev/pkg/events/events.go @@ -8,6 +8,7 @@ import ( type Type string const ( + EvtUnknown Type = "UNKNOWN" EvtReload Type = "NODE_RELOAD" EvtReset Type = "NODE_RESET" EvtPackagesUpdate Type = "PACKAGES_UPDATE" @@ -22,6 +23,13 @@ type Event interface { // Reload Event +type Unknown struct{} + +func (Unknown) Type() Type { return EvtUnknown } +func (Unknown) assertEvent() {} + +// Reload Event + type Reload struct{} func (Reload) Type() Type { return EvtReload } From 9af80cb240ca53309643fdf6408a0135742df1d6 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Wed, 5 Jun 2024 20:41:59 +0200 Subject: [PATCH 06/30] fix: add node state test Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node_state_test.go | 189 +++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 contribs/gnodev/pkg/dev/node_state_test.go diff --git a/contribs/gnodev/pkg/dev/node_state_test.go b/contribs/gnodev/pkg/dev/node_state_test.go new file mode 100644 index 00000000000..b22c03f8871 --- /dev/null +++ b/contribs/gnodev/pkg/dev/node_state_test.go @@ -0,0 +1,189 @@ +package dev + +import ( + "context" + "strconv" + "testing" + + emitter "github.com/gnolang/gno/contribs/gnodev/internal/mock" + "github.com/gnolang/gno/contribs/gnodev/pkg/events" + "github.com/gnolang/gno/gno.land/pkg/gnoclient" + "github.com/gnolang/gno/gno.land/pkg/gnoland" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNodeMovePreviousTX(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + const callInc = 5 + + node, emitter := testingCounterRealm(t, callInc) + + t.Run("Prev TX", func(t *testing.T) { + err := node.MoveToPreviousTX(ctx) + require.NoError(t, err) + assert.Equal(t, events.EvtReload, emitter.NextEvent().Type()) + + // Check for correct render update + render, err := testingRenderRealm(t, node, "gno.land/r/dev/counter") + require.NoError(t, err) + require.Equal(t, render, "4") + }) + + t.Run("Next TX", func(t *testing.T) { + err := node.MoveToNextTX(ctx) + require.NoError(t, err) + assert.Equal(t, events.EvtReload, emitter.NextEvent().Type()) + + // Check for correct render update + render, err := testingRenderRealm(t, node, "gno.land/r/dev/counter") + require.NoError(t, err) + require.Equal(t, render, "5") + }) + + t.Run("Multi Move TX", func(t *testing.T) { + moves := []struct { + Move int + ExpectedResult string + }{ + {-2, "3"}, + {2, "5"}, + {-5, "0"}, + {5, "5"}, + {-100, "0"}, + {100, "5"}, + {0, "5"}, + } + + t.Logf("initial state %d", callInc) + for _, tc := range moves { + t.Logf("moving from `%d`", tc.Move) + err := node.MoveFrom(ctx, tc.Move) + require.NoError(t, err) + if tc.Move != 0 { + assert.Equal(t, events.EvtReload, emitter.NextEvent().Type()) + } + + // Check for correct render update + render, err := testingRenderRealm(t, node, "gno.land/r/dev/counter") + require.NoError(t, err) + require.Equal(t, render, tc.ExpectedResult) + } + }) +} + +func TestSaveCurrentState(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + node, emitter := testingCounterRealm(t, 2) + + // Save current state + err := node.SaveCurrentState(ctx) + require.NoError(t, err) + + // Send a new tx + msg := gnoclient.MsgCall{ + PkgPath: "gno.land/r/dev/counter", + FuncName: "Inc", + Args: []string{"10"}, + } + + res, err := testingCallRealm(t, node, msg) + require.NoError(t, err) + require.NoError(t, res.CheckTx.Error) + require.NoError(t, res.DeliverTx.Error) + assert.Equal(t, events.EvtTxResult, emitter.NextEvent().Type()) + + // Test render + render, err := testingRenderRealm(t, node, "gno.land/r/dev/counter") + require.NoError(t, err) + require.Equal(t, render, "12") // 2 + 10 + + // Reset state + err = node.Reset(ctx) + require.NoError(t, err) + assert.Equal(t, events.EvtReset, emitter.NextEvent().Type()) + + render, err = testingRenderRealm(t, node, "gno.land/r/dev/counter") + require.NoError(t, err) + require.Equal(t, render, "2") // Back to the original state +} + +func TestExportState(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + node, _ := testingCounterRealm(t, 3) + + t.Run("export state", func(t *testing.T) { + state, err := node.ExportCurrentState(ctx) + require.NoError(t, err) + assert.Equal(t, 3, len(state)) + }) + + t.Run("export genesis doc", func(t *testing.T) { + doc, err := node.ExportStateAsGenesis(ctx) + require.NoError(t, err) + require.NotNil(t, doc.AppState) + + state, ok := doc.AppState.(gnoland.GnoGenesisState) + require.True(t, ok) + assert.Equal(t, 3, len(state.Txs)) + }) +} + +func testingCounterRealm(t *testing.T, inc int) (*Node, *emitter.ServerEmitter) { + t.Helper() + + const ( + // foo package + counterGnoMod = "module gno.land/r/dev/counter\n" + counterFile = `package counter +import "strconv" + +var value int = 0 +func Inc(v int) { value += v } // method to increment value +func Render(_ string) string { return strconv.Itoa(value) } +` + ) + + // Generate package counter + counterPkg := generateTestingPackage(t, + "gno.mod", counterGnoMod, + "foo.gno", counterFile) + + // Call NewDevNode with no package should work + node, emitter := newTestingDevNode(t, counterPkg) + assert.Len(t, node.ListPkgs(), 1) + + // Test rendering + render, err := testingRenderRealm(t, node, "gno.land/r/dev/counter") + require.NoError(t, err) + require.Equal(t, render, "0") + + // Increment the counter 10 times + for i := 0; i < inc; i++ { + t.Logf("call %d", i) + // Craft `Inc` msg + msg := gnoclient.MsgCall{ + PkgPath: "gno.land/r/dev/counter", + FuncName: "Inc", + Args: []string{"1"}, + } + + res, err := testingCallRealm(t, node, msg) + require.NoError(t, err) + require.NoError(t, res.CheckTx.Error) + require.NoError(t, res.DeliverTx.Error) + assert.Equal(t, events.EvtTxResult, emitter.NextEvent().Type()) + } + + render, err = testingRenderRealm(t, node, "gno.land/r/dev/counter") + require.NoError(t, err) + require.Equal(t, render, strconv.Itoa(inc)) + + return node, emitter +} From 69f8c507b0816cf880d8820e332adad824933a4a Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Wed, 5 Jun 2024 20:45:17 +0200 Subject: [PATCH 07/30] fix: unknown event emitter Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/gnodev/pkg/dev/node_test.go b/contribs/gnodev/pkg/dev/node_test.go index 557913b4020..55cfe904a2c 100644 --- a/contribs/gnodev/pkg/dev/node_test.go +++ b/contribs/gnodev/pkg/dev/node_test.go @@ -216,7 +216,7 @@ func Render(_ string) string { return str } require.NoError(t, err) require.Equal(t, render, "foo") - assert.Nil(t, emitter.NextEvent()) + assert.Equal(t, emitter.NextEvent(), events.EvtUnknown) } func testingRenderRealm(t *testing.T, node *Node, rlmpath string) (string, error) { From 8f5d77bdaba34614cc6d30449edc1fc6c2ee7210 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Wed, 5 Jun 2024 21:00:44 +0200 Subject: [PATCH 08/30] fix: use mocked null event for test Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/internal/mock/server_emitter.go | 8 +++++++- contribs/gnodev/pkg/dev/node_test.go | 6 +++--- contribs/gnodev/pkg/events/events.go | 8 -------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/contribs/gnodev/internal/mock/server_emitter.go b/contribs/gnodev/internal/mock/server_emitter.go index be5ecc2bd21..eaf8d07210b 100644 --- a/contribs/gnodev/internal/mock/server_emitter.go +++ b/contribs/gnodev/internal/mock/server_emitter.go @@ -7,6 +7,12 @@ import ( "github.com/gnolang/gno/contribs/gnodev/pkg/events" ) +// Define empty event for NextEvent empty queue +var ( + eventNull = events.Custom("NULL") + EvtNull = eventNull.Type() +) + // ServerEmitter is an `emitter.Emitter` var _ emitter.Emitter = (*ServerEmitter)(nil) @@ -23,7 +29,7 @@ func (m *ServerEmitter) Emit(evt events.Event) { } func (m *ServerEmitter) NextEvent() (evt events.Event) { - evt = &events.Unknown{} + evt = eventNull m.muEvents.Lock() defer m.muEvents.Unlock() diff --git a/contribs/gnodev/pkg/dev/node_test.go b/contribs/gnodev/pkg/dev/node_test.go index 55cfe904a2c..48204b4ce8d 100644 --- a/contribs/gnodev/pkg/dev/node_test.go +++ b/contribs/gnodev/pkg/dev/node_test.go @@ -155,14 +155,14 @@ func Render(_ string) string { return "bar" } require.NoError(t, err) // Check reload event - assert.Equal(t, emitter.NextEvent().Type(), events.EvtReload) + assert.Equal(t, events.EvtReload, emitter.NextEvent().Type()) // After a reload, render should succeed render, err = testingRenderRealm(t, node, "gno.land/r/dev/foobar") require.NoError(t, err) require.Equal(t, render, "bar") - assert.Nil(t, emitter.NextEvent()) + assert.Equal(t, mock.EvtNull, emitter.NextEvent().Type()) } func TestNodeReset(t *testing.T) { @@ -216,7 +216,7 @@ func Render(_ string) string { return str } require.NoError(t, err) require.Equal(t, render, "foo") - assert.Equal(t, emitter.NextEvent(), events.EvtUnknown) + assert.Equal(t, mock.EvtNull, emitter.NextEvent().Type()) } func testingRenderRealm(t *testing.T, node *Node, rlmpath string) (string, error) { diff --git a/contribs/gnodev/pkg/events/events.go b/contribs/gnodev/pkg/events/events.go index bb16c1f99d2..c387c331eed 100644 --- a/contribs/gnodev/pkg/events/events.go +++ b/contribs/gnodev/pkg/events/events.go @@ -8,7 +8,6 @@ import ( type Type string const ( - EvtUnknown Type = "UNKNOWN" EvtReload Type = "NODE_RELOAD" EvtReset Type = "NODE_RESET" EvtPackagesUpdate Type = "PACKAGES_UPDATE" @@ -23,13 +22,6 @@ type Event interface { // Reload Event -type Unknown struct{} - -func (Unknown) Type() Type { return EvtUnknown } -func (Unknown) assertEvent() {} - -// Reload Event - type Reload struct{} func (Reload) Type() Type { return EvtReload } From 977507199b46f42a30f797cf7b4259abd57f57fb Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Fri, 7 Jun 2024 14:00:25 +0200 Subject: [PATCH 09/30] fix: typo Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/cmd/gnodev/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/gnodev/cmd/gnodev/main.go b/contribs/gnodev/cmd/gnodev/main.go index d7d1aacfe01..33a35c7c2d1 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -67,7 +67,7 @@ type devCfg struct { func (cfg *devCfg) validateConfigFlags() error { if (cfg.balancesFile != "" || cfg.txsFile != "") && cfg.genesisFile != "" { - return errors.New("cannot specify `balances-file` or `txs-file` along `genesis-file`") + return errors.New("cannot specify `balances-file` or `txs-file` along with `genesis-file`") } return nil From e9b83b0960b0285d7d58d9a2e3acf22532772f46 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Fri, 7 Jun 2024 14:09:29 +0200 Subject: [PATCH 10/30] chore: lint Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/cmd/gnodev/main.go | 16 ++++++++-------- contribs/gnodev/cmd/gnodev/setup_node.go | 1 - 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/contribs/gnodev/cmd/gnodev/main.go b/contribs/gnodev/cmd/gnodev/main.go index 33a35c7c2d1..d2bd3a00004 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -65,14 +65,6 @@ type devCfg struct { serverMode bool } -func (cfg *devCfg) validateConfigFlags() error { - if (cfg.balancesFile != "" || cfg.txsFile != "") && cfg.genesisFile != "" { - return errors.New("cannot specify `balances-file` or `txs-file` along with `genesis-file`") - } - - return nil -} - var defaultDevOptions = &devCfg{ chainId: "dev", maxGas: 10_000_000_000, @@ -220,6 +212,14 @@ func (c *devCfg) RegisterFlags(fs *flag.FlagSet) { ) } +func (c *devCfg) validateConfigFlags() error { + if (c.balancesFile != "" || c.txsFile != "") && c.genesisFile != "" { + return errors.New("cannot specify `balances-file` or `txs-file` along with `genesis-file`") + } + + return nil +} + func execDev(cfg *devCfg, args []string, io commands.IO) (err error) { ctx, cancel := context.WithCancelCause(context.Background()) defer cancel(nil) diff --git a/contribs/gnodev/cmd/gnodev/setup_node.go b/contribs/gnodev/cmd/gnodev/setup_node.go index bedbdc38fd5..6e698d451c0 100644 --- a/contribs/gnodev/cmd/gnodev/setup_node.go +++ b/contribs/gnodev/cmd/gnodev/setup_node.go @@ -27,7 +27,6 @@ func setupDevNode( if err != nil { return nil, fmt.Errorf("unable to load transactions: %w", err) } - } else if devCfg.genesisFile != "" { // Load genesis file state, err := extractAppStateFromGenesisFile(devCfg.genesisFile) if err != nil { From a35e7a7f631f6f73a26423806a999948349b026a Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Fri, 7 Jun 2024 14:10:38 +0200 Subject: [PATCH 11/30] chore: remove useless field Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index afe6b0947a3..a6379db723d 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -40,7 +40,6 @@ type NodeConfig struct { NoReplay bool MaxGasPerBlock int64 ChainID string - Txs []std.Tx } func DefaultNodeConfig(rootdir string) *NodeConfig { @@ -122,8 +121,6 @@ func NewDevNode(ctx context.Context, cfg *NodeConfig) (*Node, error) { Txs: append(pkgsTxs, cfg.InitialTxs...), } - genesis.Txs = append(genesis.Txs, cfg.Txs...) - if err := devnode.rebuildNode(ctx, genesis); err != nil { return nil, fmt.Errorf("unable to initialize the node: %w", err) } From 727bf2aac758d9e36961f6f8c192b5bce40e4d9a Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Tue, 11 Jun 2024 00:15:27 +0200 Subject: [PATCH 12/30] fix: bade rebase Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/cmd/gnodev/setup_node.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/gnodev/cmd/gnodev/setup_node.go b/contribs/gnodev/cmd/gnodev/setup_node.go index 6e698d451c0..578cf525751 100644 --- a/contribs/gnodev/cmd/gnodev/setup_node.go +++ b/contribs/gnodev/cmd/gnodev/setup_node.go @@ -13,7 +13,7 @@ import ( "github.com/gnolang/gno/tm2/pkg/bft/types" ) -// setupDevNodeConfig creates and returns a new dev.NodeConfig. +// setupDevNode initializes and returns a new DevNode. func setupDevNode( ctx context.Context, devCfg *devCfg, From bc9416c424e8b156c1e2e8a776b82d6c99585d38 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Tue, 11 Jun 2024 00:16:58 +0200 Subject: [PATCH 13/30] fix: remove useless config init Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index a6379db723d..d8fd86994b2 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -32,9 +32,7 @@ type NodeConfig struct { Logger *slog.Logger DefaultDeployer crypto.Address BalancesList []gnoland.Balance - PackagesPathList []PackagePath Emitter emitter.Emitter - InitialTxs []std.Tx TMConfig *tmcfg.Config SkipFailingGenesisTxs bool NoReplay bool From 19a4e8535434e5e4b99024a2bd645fd90ec98fa0 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Tue, 11 Jun 2024 00:19:01 +0200 Subject: [PATCH 14/30] fix: typo Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index d8fd86994b2..b2cbbf08ebc 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -448,7 +448,7 @@ func (n *Node) handleEventTX(evt tm2events.Event) { } if err := amino.Unmarshal(data.Result.Tx, &resEvt.Tx); err != nil { - n.logger.Error("unable to unwarp tx result", + n.logger.Error("unable to unwrap tx result", "error", err) } From 7316ebd1a54fc5dbe509fbd2a7b4db89f7bf6a7a Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Tue, 11 Jun 2024 00:20:11 +0200 Subject: [PATCH 15/30] fix: use uint for exported var counter Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/cmd/gnodev/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/gnodev/cmd/gnodev/main.go b/contribs/gnodev/cmd/gnodev/main.go index d2bd3a00004..3ed441cba56 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -345,7 +345,7 @@ func runEventLoop( ) error { // XXX: move this in above, but we need to have a proper struct first // XXX: make this configurable - exported := 0 + var exported uint path, err := os.MkdirTemp("", "gnodev-export") if err != nil { return fmt.Errorf("unable to create `export` directory: %w", err) From fee8837018224267219e20473344ff684be3465d Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Tue, 11 Jun 2024 00:35:54 +0200 Subject: [PATCH 16/30] chore: improve comment Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index b2cbbf08ebc..fbf1e6d308e 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -429,7 +429,9 @@ func (n *Node) handleEventTX(evt tm2events.Event) { switch data := evt.(type) { case bft.EventTx: go func() { - // Use separate routine to avoid deadlock + // Use a separate goroutine in order to avoid a deadlock situation. + // This is needed because this callback may get called during node rebuilding while + // lock is held. n.muNode.Lock() defer n.muNode.Unlock() From 7133f20f5f062cce471422161c7d803761d11dc7 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Tue, 11 Jun 2024 00:36:06 +0200 Subject: [PATCH 17/30] fix: wrong deleted fields Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index fbf1e6d308e..fa71b9cebd8 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -32,7 +32,9 @@ type NodeConfig struct { Logger *slog.Logger DefaultDeployer crypto.Address BalancesList []gnoland.Balance + PackagesPathList []PackagePath Emitter emitter.Emitter + InitialTxs []std.Tx TMConfig *tmcfg.Config SkipFailingGenesisTxs bool NoReplay bool @@ -60,8 +62,6 @@ func DefaultNodeConfig(rootdir string) *NodeConfig { DefaultDeployer: defaultDeployer, BalancesList: balances, ChainID: tmc.ChainID(), - PackagesPathList: []PackagePath{}, - InitialTxs: []std.Tx{}, TMConfig: tmc, SkipFailingGenesisTxs: true, MaxGasPerBlock: 10_000_000_000, From c0ee7d1770b528516489d67e01bc098b8e0fbc43 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Mon, 24 Jun 2024 14:40:57 +0200 Subject: [PATCH 18/30] chore: update genesis-file name to genesis for constancy Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/cmd/gnodev/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/gnodev/cmd/gnodev/main.go b/contribs/gnodev/cmd/gnodev/main.go index b0e21460c94..9ae85f115aa 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -160,7 +160,7 @@ func (c *devCfg) RegisterFlags(fs *flag.FlagSet) { fs.StringVar( &c.genesisFile, - "genesis-file", + "genesis", defaultDevOptions.genesisFile, "load the given genesis file", ) From a39d826ba5b397cba2d896da3c436fc25090aeec Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Mon, 24 Jun 2024 14:43:00 +0200 Subject: [PATCH 19/30] chore: global error flags Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/cmd/gnodev/main.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contribs/gnodev/cmd/gnodev/main.go b/contribs/gnodev/cmd/gnodev/main.go index 9ae85f115aa..e29d8acf6d0 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -31,6 +31,8 @@ const ( AccountsLogName = "Accounts" ) +var ErrConflictingFileArgs = errors.New("cannot specify `balances-file` or `txs-file` along with `genesis-file`") + var ( DefaultDeployerName = integration.DefaultAccount_Name DefaultDeployerAddress = crypto.MustAddressFromString(integration.DefaultAccount_Address) @@ -224,7 +226,7 @@ func (c *devCfg) RegisterFlags(fs *flag.FlagSet) { func (c *devCfg) validateConfigFlags() error { if (c.balancesFile != "" || c.txsFile != "") && c.genesisFile != "" { - return errors.New("cannot specify `balances-file` or `txs-file` along with `genesis-file`") + return ErrConflictingFileArgs } return nil From 79f2e2fec796409989324bdce39da9c01ab6f383 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Mon, 24 Jun 2024 14:44:03 +0200 Subject: [PATCH 20/30] chore: lint case space Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/cmd/gnodev/main.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contribs/gnodev/cmd/gnodev/main.go b/contribs/gnodev/cmd/gnodev/main.go index e29d8acf6d0..3a8920b5e13 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -404,8 +404,10 @@ func runEventLoop( switch key.Upper() { case rawterm.KeyH: // Helper logger.Info("Gno Dev Helper", "helper", helper) + case rawterm.KeyA: // Accounts logAccounts(logger.WithGroup(AccountsLogName), bk, dnode) + case rawterm.KeyR: // Reload logger.WithGroup(NodeLogName).Info("reloading...") if err = dnode.ReloadAll(ctx); err != nil { @@ -444,6 +446,7 @@ func runEventLoop( exported++ logger.WithGroup(NodeLogName).Info("node state exported", "file", docfile) + case rawterm.KeyN: // Next tx logger.Info("moving forward...") if err := dnode.MoveToNextTX(ctx); err != nil { @@ -460,6 +463,7 @@ func runEventLoop( case rawterm.KeyCtrlC: // Exit return nil + default: } From 852eeeaa9ec081f47bd5ac545a18d3250ba1d51b Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Mon, 24 Jun 2024 14:45:32 +0200 Subject: [PATCH 21/30] chore: remove global noop logger Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index 2527c44d8d8..6189f694b4a 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -458,9 +458,9 @@ func (n *Node) handleEventTX(evt tm2events.Event) { } } -var noopLogger = log.NewNoopLogger() - func (n *Node) rebuildNode(ctx context.Context, genesis gnoland.GnoGenesisState) (err error) { + var noopLogger = log.NewNoopLogger() + // Stop the node if it's currently running. if err := n.stopIfRunning(); err != nil { return fmt.Errorf("unable to stop the node: %w", err) From c026fb72050e6fa814bff2bdb21a0f2d957a97c5 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Mon, 24 Jun 2024 14:46:30 +0200 Subject: [PATCH 22/30] chore: todo Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index 6189f694b4a..fb9165d6f38 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -488,7 +488,7 @@ func (n *Node) rebuildNode(ctx context.Context, genesis gnoland.GnoGenesisState) // Execute node creation and handle any errors. defer recoverFromError() - // XXX(TODO): Redirect the node log somewhere else + // XXX: Redirect the node log somewhere else node, nodeErr := gnoland.NewInMemoryNode(noopLogger, nodeConfig) if nodeErr != nil { return fmt.Errorf("unable to create a new node: %w", err) From 29afbc93066d491de01e37fe0be947d883d91143 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Mon, 24 Jun 2024 15:52:35 +0200 Subject: [PATCH 23/30] fix: noop logger Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index fb9165d6f38..6968d7ce385 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -57,7 +57,7 @@ func DefaultNodeConfig(rootdir string) *NodeConfig { } return &NodeConfig{ - Logger: noopLogger, + Logger: log.NewNoopLogger(), Emitter: &emitter.NoopServer{}, DefaultDeployer: defaultDeployer, BalancesList: balances, From c721a9850e7450a4575304a43e39a834a3340ae2 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Mon, 24 Jun 2024 15:53:00 +0200 Subject: [PATCH 24/30] fix: add empty state error Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node_state.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contribs/gnodev/pkg/dev/node_state.go b/contribs/gnodev/pkg/dev/node_state.go index b005e7f3c0c..afc7e456291 100644 --- a/contribs/gnodev/pkg/dev/node_state.go +++ b/contribs/gnodev/pkg/dev/node_state.go @@ -10,6 +10,8 @@ import ( "github.com/gnolang/gno/tm2/pkg/std" ) +var ErrEmptyState = errors.New("empty state") + // Save the current state as initialState func (n *Node) SaveCurrentState(ctx context.Context) error { n.muNode.RLock() @@ -68,7 +70,7 @@ func (n *Node) MoveFrom(ctx context.Context, x int) error { maxState := len(state) switch { case maxState == 0: // no state - return fmt.Errorf("empty state") + return ErrEmptyState case newIndex < 0: newIndex = 0 n.logger.Info("minimum state reached", "tx-index", fmt.Sprintf("%d/%d", newIndex, maxState)) From a6049d6ca21316189a09bf5c41595f6465b62997 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Mon, 24 Jun 2024 15:53:13 +0200 Subject: [PATCH 25/30] feat: rename moveFrom to moveBy Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node_state.go | 11 ++++++----- contribs/gnodev/pkg/dev/node_state_test.go | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/contribs/gnodev/pkg/dev/node_state.go b/contribs/gnodev/pkg/dev/node_state.go index afc7e456291..3c056d9e578 100644 --- a/contribs/gnodev/pkg/dev/node_state.go +++ b/contribs/gnodev/pkg/dev/node_state.go @@ -2,6 +2,7 @@ package dev import ( "context" + "errors" "fmt" "github.com/gnolang/gno/contribs/gnodev/pkg/events" @@ -53,11 +54,11 @@ func (n *Node) getState(ctx context.Context) ([]std.Tx, error) { return n.state, nil } -// MoveFrom adjusts the current state of the node by `x` transactions. +// MoveBy adjusts the current state of the node by `x` transactions. // `x` can be negative to move backward or positive to move forward, however, index boundaries are respected // with a lower limit of 0 and upper limit equaling the total number of states. -// If a move is successful, node is reload. -func (n *Node) MoveFrom(ctx context.Context, x int) error { +// If a move is successful, node is reloaded. +func (n *Node) MoveBy(ctx context.Context, x int) error { n.muNode.Lock() defer n.muNode.Unlock() @@ -113,11 +114,11 @@ func (n *Node) MoveFrom(ctx context.Context, x int) error { } func (n *Node) MoveToPreviousTX(ctx context.Context) error { - return n.MoveFrom(ctx, -1) + return n.MoveBy(ctx, -1) } func (n *Node) MoveToNextTX(ctx context.Context) error { - return n.MoveFrom(ctx, 1) + return n.MoveBy(ctx, 1) } // Export the current state as genesis doc diff --git a/contribs/gnodev/pkg/dev/node_state_test.go b/contribs/gnodev/pkg/dev/node_state_test.go index b22c03f8871..2252f1f9bd2 100644 --- a/contribs/gnodev/pkg/dev/node_state_test.go +++ b/contribs/gnodev/pkg/dev/node_state_test.go @@ -60,7 +60,7 @@ func TestNodeMovePreviousTX(t *testing.T) { t.Logf("initial state %d", callInc) for _, tc := range moves { t.Logf("moving from `%d`", tc.Move) - err := node.MoveFrom(ctx, tc.Move) + err := node.MoveBy(ctx, tc.Move) require.NoError(t, err) if tc.Move != 0 { assert.Equal(t, events.EvtReload, emitter.NextEvent().Type()) From efc8d31c12321e9ca6a5df1145597663ae35fa92 Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:39:28 +0200 Subject: [PATCH 26/30] chore: wrap context generation in test Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node_state_test.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/contribs/gnodev/pkg/dev/node_state_test.go b/contribs/gnodev/pkg/dev/node_state_test.go index 2252f1f9bd2..78e687fa598 100644 --- a/contribs/gnodev/pkg/dev/node_state_test.go +++ b/contribs/gnodev/pkg/dev/node_state_test.go @@ -4,6 +4,7 @@ import ( "context" "strconv" "testing" + "time" emitter "github.com/gnolang/gno/contribs/gnodev/internal/mock" "github.com/gnolang/gno/contribs/gnodev/pkg/events" @@ -14,14 +15,12 @@ import ( ) func TestNodeMovePreviousTX(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - const callInc = 5 node, emitter := testingCounterRealm(t, callInc) t.Run("Prev TX", func(t *testing.T) { + ctx := testingContext(t) err := node.MoveToPreviousTX(ctx) require.NoError(t, err) assert.Equal(t, events.EvtReload, emitter.NextEvent().Type()) @@ -33,6 +32,7 @@ func TestNodeMovePreviousTX(t *testing.T) { }) t.Run("Next TX", func(t *testing.T) { + ctx := testingContext(t) err := node.MoveToNextTX(ctx) require.NoError(t, err) assert.Equal(t, events.EvtReload, emitter.NextEvent().Type()) @@ -44,6 +44,7 @@ func TestNodeMovePreviousTX(t *testing.T) { }) t.Run("Multi Move TX", func(t *testing.T) { + ctx := testingContext(t) moves := []struct { Move int ExpectedResult string @@ -75,8 +76,7 @@ func TestNodeMovePreviousTX(t *testing.T) { } func TestSaveCurrentState(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := testingContext(t) node, emitter := testingCounterRealm(t, 2) @@ -113,18 +113,17 @@ func TestSaveCurrentState(t *testing.T) { } func TestExportState(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - node, _ := testingCounterRealm(t, 3) t.Run("export state", func(t *testing.T) { + ctx := testingContext(t) state, err := node.ExportCurrentState(ctx) require.NoError(t, err) assert.Equal(t, 3, len(state)) }) t.Run("export genesis doc", func(t *testing.T) { + ctx := testingContext(t) doc, err := node.ExportStateAsGenesis(ctx) require.NoError(t, err) require.NotNil(t, doc.AppState) @@ -187,3 +186,9 @@ func Render(_ string) string { return strconv.Itoa(value) } return node, emitter } + +func testingContext(t *testing.T) context.Context { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*7) + t.Cleanup(cancel) + return ctx +} From fd5dba2750bf29225be5e01765b540377134c81f Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:41:26 +0200 Subject: [PATCH 27/30] chore: inline node rebuild error Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node_state.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contribs/gnodev/pkg/dev/node_state.go b/contribs/gnodev/pkg/dev/node_state.go index 3c056d9e578..846c4857784 100644 --- a/contribs/gnodev/pkg/dev/node_state.go +++ b/contribs/gnodev/pkg/dev/node_state.go @@ -99,8 +99,7 @@ func (n *Node) MoveBy(ctx context.Context, x int) error { } // Reset the node with the new genesis state. - err = n.rebuildNode(ctx, genesis) - if err != nil { + if err = n.rebuildNode(ctx, genesis); err != nil { return fmt.Errorf("uanble to rebuild node: %w", err) } From e4175dbae91aa287f8452865d9cd82608d8ce1ba Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:41:56 +0200 Subject: [PATCH 28/30] chore: wrap realm name into a const Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node_state_test.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/contribs/gnodev/pkg/dev/node_state_test.go b/contribs/gnodev/pkg/dev/node_state_test.go index 78e687fa598..a4adfd20999 100644 --- a/contribs/gnodev/pkg/dev/node_state_test.go +++ b/contribs/gnodev/pkg/dev/node_state_test.go @@ -14,6 +14,8 @@ import ( "github.com/stretchr/testify/require" ) +const testCounterRealm = "gno.land/r/dev/counter" + func TestNodeMovePreviousTX(t *testing.T) { const callInc = 5 @@ -26,7 +28,7 @@ func TestNodeMovePreviousTX(t *testing.T) { assert.Equal(t, events.EvtReload, emitter.NextEvent().Type()) // Check for correct render update - render, err := testingRenderRealm(t, node, "gno.land/r/dev/counter") + render, err := testingRenderRealm(t, node, testCounterRealm) require.NoError(t, err) require.Equal(t, render, "4") }) @@ -38,7 +40,7 @@ func TestNodeMovePreviousTX(t *testing.T) { assert.Equal(t, events.EvtReload, emitter.NextEvent().Type()) // Check for correct render update - render, err := testingRenderRealm(t, node, "gno.land/r/dev/counter") + render, err := testingRenderRealm(t, node, testCounterRealm) require.NoError(t, err) require.Equal(t, render, "5") }) @@ -68,7 +70,7 @@ func TestNodeMovePreviousTX(t *testing.T) { } // Check for correct render update - render, err := testingRenderRealm(t, node, "gno.land/r/dev/counter") + render, err := testingRenderRealm(t, node, testCounterRealm) require.NoError(t, err) require.Equal(t, render, tc.ExpectedResult) } @@ -86,7 +88,7 @@ func TestSaveCurrentState(t *testing.T) { // Send a new tx msg := gnoclient.MsgCall{ - PkgPath: "gno.land/r/dev/counter", + PkgPath: testCounterRealm, FuncName: "Inc", Args: []string{"10"}, } @@ -98,7 +100,7 @@ func TestSaveCurrentState(t *testing.T) { assert.Equal(t, events.EvtTxResult, emitter.NextEvent().Type()) // Test render - render, err := testingRenderRealm(t, node, "gno.land/r/dev/counter") + render, err := testingRenderRealm(t, node, testCounterRealm) require.NoError(t, err) require.Equal(t, render, "12") // 2 + 10 @@ -107,7 +109,7 @@ func TestSaveCurrentState(t *testing.T) { require.NoError(t, err) assert.Equal(t, events.EvtReset, emitter.NextEvent().Type()) - render, err = testingRenderRealm(t, node, "gno.land/r/dev/counter") + render, err = testingRenderRealm(t, node, testCounterRealm) require.NoError(t, err) require.Equal(t, render, "2") // Back to the original state } @@ -159,7 +161,7 @@ func Render(_ string) string { return strconv.Itoa(value) } assert.Len(t, node.ListPkgs(), 1) // Test rendering - render, err := testingRenderRealm(t, node, "gno.land/r/dev/counter") + render, err := testingRenderRealm(t, node, testCounterRealm) require.NoError(t, err) require.Equal(t, render, "0") @@ -168,7 +170,7 @@ func Render(_ string) string { return strconv.Itoa(value) } t.Logf("call %d", i) // Craft `Inc` msg msg := gnoclient.MsgCall{ - PkgPath: "gno.land/r/dev/counter", + PkgPath: testCounterRealm, FuncName: "Inc", Args: []string{"1"}, } @@ -180,7 +182,7 @@ func Render(_ string) string { return strconv.Itoa(value) } assert.Equal(t, events.EvtTxResult, emitter.NextEvent().Type()) } - render, err = testingRenderRealm(t, node, "gno.land/r/dev/counter") + render, err = testingRenderRealm(t, node, testCounterRealm) require.NoError(t, err) require.Equal(t, render, strconv.Itoa(inc)) From e165f62b1ce7d3e846900755a1c7394c8772f5ff Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:48:39 +0200 Subject: [PATCH 29/30] chore: lint Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/pkg/dev/node.go | 2 +- contribs/gnodev/pkg/dev/node_state_test.go | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index 6968d7ce385..846b5f3493d 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -459,7 +459,7 @@ func (n *Node) handleEventTX(evt tm2events.Event) { } func (n *Node) rebuildNode(ctx context.Context, genesis gnoland.GnoGenesisState) (err error) { - var noopLogger = log.NewNoopLogger() + noopLogger := log.NewNoopLogger() // Stop the node if it's currently running. if err := n.stopIfRunning(); err != nil { diff --git a/contribs/gnodev/pkg/dev/node_state_test.go b/contribs/gnodev/pkg/dev/node_state_test.go index a4adfd20999..17f96367512 100644 --- a/contribs/gnodev/pkg/dev/node_state_test.go +++ b/contribs/gnodev/pkg/dev/node_state_test.go @@ -190,6 +190,8 @@ func Render(_ string) string { return strconv.Itoa(value) } } func testingContext(t *testing.T) context.Context { + t.Helper() + ctx, cancel := context.WithTimeout(context.Background(), time.Second*7) t.Cleanup(cancel) return ctx From c6f8da22123149d2c4e9325313d771d85f32fb5b Mon Sep 17 00:00:00 2001 From: gfanton <8671905+gfanton@users.noreply.github.com> Date: Mon, 8 Jul 2024 15:19:56 +0200 Subject: [PATCH 30/30] fix: untabify helper Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com> --- contribs/gnodev/cmd/gnodev/main.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/contribs/gnodev/cmd/gnodev/main.go b/contribs/gnodev/cmd/gnodev/main.go index 19fc2503870..2c694b608bb 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -363,15 +363,15 @@ func execDev(cfg *devCfg, args []string, io commands.IO) (err error) { var helper string = `For more in-depth documentation, visit the GNO Tooling CLI documentation: https://docs.gno.land/gno-tooling/cli/gno-tooling-gnodev -P Previous TX - Go to the previous tx -N Next TX - Go to the next tx -E Export - Export the current state as genesis doc -A Accounts - Display known accounts and balances -H Help - Display this message -R Reload - Reload all packages to take change into account. -Ctrl+S Save State - Save the current state -Ctrl+R Reset - Reset application to it's initial/save state. -Ctrl+C Exit - Exit the application +P Previous TX - Go to the previous tx +N Next TX - Go to the next tx +E Export - Export the current state as genesis doc +A Accounts - Display known accounts and balances +H Help - Display this message +R Reload - Reload all packages to take change into account. +Ctrl+S Save State - Save the current state +Ctrl+R Reset - Reset application to it's initial/save state. +Ctrl+C Exit - Exit the application ` func runEventLoop(