From a1fb5dc0d72a16fb1ff2d3629e45645b9011f37a Mon Sep 17 00:00:00 2001 From: deelawn Date: Tue, 4 Jun 2024 15:24:40 -0700 Subject: [PATCH 1/4] allow gnodev to load txs --- contribs/gnodev/cmd/gnodev/main.go | 16 ++++++++- contribs/gnodev/cmd/gnodev/setup_node.go | 12 +++++-- contribs/gnodev/cmd/gnodev/txs.go | 23 +++++++++++++ contribs/gnodev/pkg/dev/node.go | 3 ++ gno.land/cmd/gnoland/genesis_txs_add.go | 43 +----------------------- tm2/pkg/std/tx.go | 43 +++++++++++++++++++++++- 6 files changed, 94 insertions(+), 46 deletions(-) create mode 100644 contribs/gnodev/cmd/gnodev/txs.go diff --git a/contribs/gnodev/cmd/gnodev/main.go b/contribs/gnodev/cmd/gnodev/main.go index 2038dc647e7..2f35bd5c364 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -49,6 +49,7 @@ type devCfg struct { root string premineAccounts varPremineAccounts balancesFile string + txsFile string // Node Configuration minimal bool @@ -136,6 +137,13 @@ func (c *devCfg) RegisterFlags(fs *flag.FlagSet) { "load the provided balance file (refer to the documentation for format)", ) + fs.StringVar( + &c.txsFile, + "tx-file", + defaultDevOptions.txsFile, + "load the provided transactions file (refer to the documentation for format)", + ) + fs.StringVar( &c.deployKey, "deploy-key", @@ -233,10 +241,16 @@ func execDev(cfg *devCfg, args []string, io commands.IO) (err error) { } logger.Debug("balances loaded", "list", balances.List()) + // Load transactions. + txs, err := loadTxs(cfg.txsFile) + if err != nil { + return fmt.Errorf("unable to load transactions: %w", err) + } + // 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) + devNode, err := setupDevNode(ctx, nodeLogger, cfg, emitterServer, balances, pkgpaths, txs) if err != nil { return err } diff --git a/contribs/gnodev/cmd/gnodev/setup_node.go b/contribs/gnodev/cmd/gnodev/setup_node.go index c79ab9d18bf..0de237f58ee 100644 --- a/contribs/gnodev/cmd/gnodev/setup_node.go +++ b/contribs/gnodev/cmd/gnodev/setup_node.go @@ -10,6 +10,7 @@ import ( gnodev "github.com/gnolang/gno/contribs/gnodev/pkg/dev" "github.com/gnolang/gno/contribs/gnodev/pkg/emitter" "github.com/gnolang/gno/gno.land/pkg/gnoland" + "github.com/gnolang/gno/tm2/pkg/std" ) // setupDevNode initializes and returns a new DevNode. @@ -20,13 +21,19 @@ func setupDevNode( remitter emitter.Emitter, balances gnoland.Balances, pkgspath []gnodev.PackagePath, + txs []std.Tx, ) (*gnodev.Node, error) { - config := setupDevNodeConfig(cfg, balances, pkgspath) + config := setupDevNodeConfig(cfg, balances, pkgspath, txs) 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 { +func setupDevNodeConfig( + cfg *devCfg, + balances gnoland.Balances, + pkgspath []gnodev.PackagePath, + txs []std.Tx, +) *gnodev.NodeConfig { config := gnodev.DefaultNodeConfig(cfg.root) config.BalancesList = balances.List() config.PackagesPathList = pkgspath @@ -34,6 +41,7 @@ func setupDevNodeConfig(cfg *devCfg, balances gnoland.Balances, pkgspath []gnode config.NoReplay = cfg.noReplay config.MaxGasPerBlock = cfg.maxGas config.ChainID = cfg.chainId + config.Txs = txs // other listeners config.TMConfig.P2P.ListenAddress = defaultDevOptions.nodeP2PListenerAddr diff --git a/contribs/gnodev/cmd/gnodev/txs.go b/contribs/gnodev/cmd/gnodev/txs.go new file mode 100644 index 00000000000..800fdcba63c --- /dev/null +++ b/contribs/gnodev/cmd/gnodev/txs.go @@ -0,0 +1,23 @@ +package main + +import ( + "context" + "fmt" + "os" + + "github.com/gnolang/gno/tm2/pkg/std" +) + +func loadTxs(txFile string) ([]std.Tx, error) { + if txFile == "" { + return nil, nil + } + + file, loadErr := os.Open(txFile) + if loadErr != nil { + return nil, fmt.Errorf("unable to open tx file %s: %w", txFile, loadErr) + } + defer file.Close() + + return std.LoadTxs(context.Background(), file) +} diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index 30ad262b1b0..d839091d328 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -37,6 +37,7 @@ type NodeConfig struct { NoReplay bool MaxGasPerBlock int64 ChainID string + Txs []std.Tx } func DefaultNodeConfig(rootdir string) *NodeConfig { @@ -107,6 +108,8 @@ func NewDevNode(ctx context.Context, logger *slog.Logger, emitter emitter.Emitte Txs: pkgsTxs, } + 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) } diff --git a/gno.land/cmd/gnoland/genesis_txs_add.go b/gno.land/cmd/gnoland/genesis_txs_add.go index 06019f7ef59..8e979397d4d 100644 --- a/gno.land/cmd/gnoland/genesis_txs_add.go +++ b/gno.land/cmd/gnoland/genesis_txs_add.go @@ -1,15 +1,12 @@ package main import ( - "bufio" "context" "errors" "fmt" - "io" "os" "github.com/gnolang/gno/gno.land/pkg/gnoland" - "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/std" @@ -18,7 +15,6 @@ import ( var ( errInvalidTxsFile = errors.New("unable to open transactions file") errNoTxsFileSpecified = errors.New("no txs file specified") - errTxsParsingAborted = errors.New("transaction parsing aborted") ) // newTxsAddCmd creates the genesis txs add subcommand @@ -61,7 +57,7 @@ func execTxsAdd( return fmt.Errorf("%w, %w", errInvalidTxsFile, loadErr) } - txs, err := getTransactionsFromFile(ctx, file) + txs, err := std.LoadTxs(ctx, file) if err != nil { return fmt.Errorf("unable to read file, %w", err) } @@ -102,40 +98,3 @@ func execTxsAdd( return nil } - -// getTransactionsFromFile fetches the transactions from the -// specified reader -func getTransactionsFromFile(ctx context.Context, reader io.Reader) ([]std.Tx, error) { - txs := make([]std.Tx, 0) - - scanner := bufio.NewScanner(reader) - - for scanner.Scan() { - select { - case <-ctx.Done(): - return nil, errTxsParsingAborted - default: - // Parse the amino JSON - var tx std.Tx - - if err := amino.UnmarshalJSON(scanner.Bytes(), &tx); err != nil { - return nil, fmt.Errorf( - "unable to unmarshal amino JSON, %w", - err, - ) - } - - txs = append(txs, tx) - } - } - - // Check for scanning errors - if err := scanner.Err(); err != nil { - return nil, fmt.Errorf( - "error encountered while reading file, %w", - err, - ) - } - - return txs, nil -} diff --git a/tm2/pkg/std/tx.go b/tm2/pkg/std/tx.go index 3068022ae03..438eed55921 100644 --- a/tm2/pkg/std/tx.go +++ b/tm2/pkg/std/tx.go @@ -1,14 +1,22 @@ package std import ( + "bufio" + "context" "fmt" + "io" "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/crypto" "github.com/gnolang/gno/tm2/pkg/crypto/multisig" + "github.com/gnolang/gno/tm2/pkg/errors" ) -var maxGasWanted = int64((1 << 60) - 1) // something smaller than math.MaxInt64 +var ( + maxGasWanted = int64((1 << 60) - 1) // something smaller than math.MaxInt64 + + ErrTxsLoadingAborted = errors.New("transaction loading aborted") +) // Tx is a standard way to wrap a Msg with Fee and Signatures. // NOTE: the first signature is the fee payer (Signatures must not be nil). @@ -136,3 +144,36 @@ func (fee Fee) Bytes() []byte { } return bz } + +func LoadTxs(ctx context.Context, reader io.Reader) ([]Tx, error) { + var txs []Tx + scanner := bufio.NewScanner(reader) + + for scanner.Scan() { + select { + case <-ctx.Done(): + return nil, ErrTxsLoadingAborted + default: + // Parse the amino JSON + var tx Tx + if err := amino.UnmarshalJSON(scanner.Bytes(), &tx); err != nil { + return nil, fmt.Errorf( + "unable to unmarshal amino JSON, %w", + err, + ) + } + + txs = append(txs, tx) + } + } + + // Check for scanning errors + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf( + "error encountered while reading file, %w", + err, + ) + } + + return txs, nil +} From df0cebc45ab6513609a96c5c3ce5ecc8ec522bf0 Mon Sep 17 00:00:00 2001 From: deelawn Date: Thu, 6 Jun 2024 06:08:43 +0100 Subject: [PATCH 2/4] Update contribs/gnodev/cmd/gnodev/main.go Co-authored-by: Guilhem Fanton <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 2f35bd5c364..a39c5d1e4ed 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -139,7 +139,7 @@ func (c *devCfg) RegisterFlags(fs *flag.FlagSet) { fs.StringVar( &c.txsFile, - "tx-file", + "txs-file", defaultDevOptions.txsFile, "load the provided transactions file (refer to the documentation for format)", ) From 058b91173b04cb4b1f9bf3fcb7019b2c28a4d35b Mon Sep 17 00:00:00 2001 From: deelawn Date: Wed, 5 Jun 2024 22:14:15 -0700 Subject: [PATCH 3/4] addressed comments --- contribs/gnodev/cmd/gnodev/main.go | 8 +------- contribs/gnodev/cmd/gnodev/setup_node.go | 7 ++++++- contribs/gnodev/cmd/gnodev/txs.go | 4 ++-- gno.land/cmd/gnoland/genesis_txs_add.go | 2 +- tm2/pkg/std/tx.go | 2 +- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/contribs/gnodev/cmd/gnodev/main.go b/contribs/gnodev/cmd/gnodev/main.go index a39c5d1e4ed..45a47e00b5b 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -241,16 +241,10 @@ func execDev(cfg *devCfg, args []string, io commands.IO) (err error) { } logger.Debug("balances loaded", "list", balances.List()) - // Load transactions. - txs, err := loadTxs(cfg.txsFile) - if err != nil { - return fmt.Errorf("unable to load transactions: %w", err) - } - // 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, txs) + devNode, err := setupDevNode(ctx, nodeLogger, cfg, emitterServer, balances, pkgpaths) if err != nil { return err } diff --git a/contribs/gnodev/cmd/gnodev/setup_node.go b/contribs/gnodev/cmd/gnodev/setup_node.go index 0de237f58ee..55da1a596aa 100644 --- a/contribs/gnodev/cmd/gnodev/setup_node.go +++ b/contribs/gnodev/cmd/gnodev/setup_node.go @@ -21,8 +21,13 @@ func setupDevNode( remitter emitter.Emitter, balances gnoland.Balances, pkgspath []gnodev.PackagePath, - txs []std.Tx, ) (*gnodev.Node, error) { + // Load transactions. + txs, err := parseTxs(cfg.txsFile) + if err != nil { + return nil, fmt.Errorf("unable to load transactions: %w", err) + } + config := setupDevNodeConfig(cfg, balances, pkgspath, txs) return gnodev.NewDevNode(ctx, logger, remitter, config) } diff --git a/contribs/gnodev/cmd/gnodev/txs.go b/contribs/gnodev/cmd/gnodev/txs.go index 800fdcba63c..0be33b68702 100644 --- a/contribs/gnodev/cmd/gnodev/txs.go +++ b/contribs/gnodev/cmd/gnodev/txs.go @@ -8,7 +8,7 @@ import ( "github.com/gnolang/gno/tm2/pkg/std" ) -func loadTxs(txFile string) ([]std.Tx, error) { +func parseTxs(txFile string) ([]std.Tx, error) { if txFile == "" { return nil, nil } @@ -19,5 +19,5 @@ func loadTxs(txFile string) ([]std.Tx, error) { } defer file.Close() - return std.LoadTxs(context.Background(), file) + return std.ParseTxs(context.Background(), file) } diff --git a/gno.land/cmd/gnoland/genesis_txs_add.go b/gno.land/cmd/gnoland/genesis_txs_add.go index 8e979397d4d..4bb9887a7ae 100644 --- a/gno.land/cmd/gnoland/genesis_txs_add.go +++ b/gno.land/cmd/gnoland/genesis_txs_add.go @@ -57,7 +57,7 @@ func execTxsAdd( return fmt.Errorf("%w, %w", errInvalidTxsFile, loadErr) } - txs, err := std.LoadTxs(ctx, file) + txs, err := std.ParseTxs(ctx, file) if err != nil { return fmt.Errorf("unable to read file, %w", err) } diff --git a/tm2/pkg/std/tx.go b/tm2/pkg/std/tx.go index 438eed55921..4fd7af4a641 100644 --- a/tm2/pkg/std/tx.go +++ b/tm2/pkg/std/tx.go @@ -145,7 +145,7 @@ func (fee Fee) Bytes() []byte { return bz } -func LoadTxs(ctx context.Context, reader io.Reader) ([]Tx, error) { +func ParseTxs(ctx context.Context, reader io.Reader) ([]Tx, error) { var txs []Tx scanner := bufio.NewScanner(reader) From 2650a25dcec1568cc3b1925914d4b5cba42287ac Mon Sep 17 00:00:00 2001 From: deelawn Date: Wed, 5 Jun 2024 22:20:43 -0700 Subject: [PATCH 4/4] updated readme --- docs/gno-tooling/cli/gnodev.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/gno-tooling/cli/gnodev.md b/docs/gno-tooling/cli/gnodev.md index 97a4cc2e5ce..fd19922dff2 100644 --- a/docs/gno-tooling/cli/gnodev.md +++ b/docs/gno-tooling/cli/gnodev.md @@ -72,6 +72,21 @@ g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj=10000000000000ugnot # test2 # ... ``` +### Transactions file + +You can specify a transactions file using `--txs-file`. The file should contain a list of signed transactions +that will be applied when starting the in-memory node. +``` +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post1","First post","Lorem Ipsum","2022-05-20T13:17:22Z","","tag1,tag2"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post2","Second post","Lorem Ipsum","2022-05-20T13:17:23Z","","tag1,tag3"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} +``` + +#### Construction a transaction +`gnokey maketx ... >> "tx-file.json"` + +#### Signing the transaction +`gnokey sign -tx-path tx-file.json ...` + ### Deploy All realms and packages will be deployed to the in-memory node by the address passed in with the