Skip to content

Commit

Permalink
feat: add the ability to add packages to genesis transactions (#2327)
Browse files Browse the repository at this point in the history
## Description

This PR introduces the ability to specify a package directory that will
recursively be added (deployed) to the `genesis.json`, utilizing the
existing `gnoland genesis txs add` command.

It also separates out the logic from `gnoland genesis txs add` into:
- `gnoland genesis txs add sheets` for individual tx sheet files (ex.
from tx-archive output)
- `gnoland genesis txs add packages` for recursively adding packages
(ex. `examples`)


![sample](https://github.com/gnolang/gno/assets/16712663/e88b363f-2911-454e-8002-46ee4cbecde6)

Related:
- #1952 
- #1988

<details><summary>Contributors' checklist...</summary>

- [x] Added new tests, or not needed, or not feasible
- [x] Provided an example (e.g. screenshot) to aid review or the PR is
self-explanatory
- [x] Updated the official documentation or not needed
- [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message
was included in the description
- [x] Added references to related issues and PRs
- [ ] Provided any useful hints for running manual tests
- [ ] Added new benchmarks to [generated
graphs](https://gnoland.github.io/benchmarks), if any. More info
[here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
</details>

---------

Co-authored-by: Guilhem Fanton <8671905+gfanton@users.noreply.github.com>
  • Loading branch information
zivkovicmilos and gfanton authored Jun 11, 2024
1 parent 5541e35 commit e2e0611
Show file tree
Hide file tree
Showing 11 changed files with 362 additions and 95 deletions.
1 change: 0 additions & 1 deletion examples/gno.land/p/demo/blog/blog.gno
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ func (b Blog) RenderPost(res *mux.ResponseWriter, req *mux.Request) {

res.Write("</details>\n")
res.Write("</main>")

}

func (b Blog) RenderTag(res *mux.ResponseWriter, req *mux.Request) {
Expand Down
6 changes: 4 additions & 2 deletions examples/gno.land/r/gnoland/events/events.gno
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ func upcomingEvents() ui.Element {
<div class="column">
</div><!-- end column-->
</div><!-- end columns-3-->`)}
</div><!-- end columns-3-->`),
}
}

func pastEvents() ui.Element {
Expand Down Expand Up @@ -211,5 +212,6 @@ func pastEvents() ui.Element {
[Watch the talk](https://www.youtube.com/watch?v=hCLErPgnavI)
</div><!-- end column-->
</div><!-- end columns-3-->`)}
</div><!-- end columns-3-->`),
}
}
36 changes: 36 additions & 0 deletions gno.land/cmd/gnoland/genesis_txs.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
package main

import (
"errors"
"flag"

"github.com/gnolang/gno/gno.land/pkg/gnoland"
"github.com/gnolang/gno/tm2/pkg/bft/types"
"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/std"
)

type txsCfg struct {
commonCfg
}

var errInvalidGenesisStateType = errors.New("invalid genesis state type")

// newTxsCmd creates the genesis txs subcommand
func newTxsCmd(io commands.IO) *commands.Command {
cfg := &txsCfg{}
Expand Down Expand Up @@ -37,3 +43,33 @@ func newTxsCmd(io commands.IO) *commands.Command {
func (c *txsCfg) RegisterFlags(fs *flag.FlagSet) {
c.commonCfg.RegisterFlags(fs)
}

// appendGenesisTxs saves the given transactions to the genesis doc
func appendGenesisTxs(genesis *types.GenesisDoc, txs []std.Tx) error {
// Initialize the app state if it's not present
if genesis.AppState == nil {
genesis.AppState = gnoland.GnoGenesisState{}
}

// Make sure the app state is the Gno genesis state
state, ok := genesis.AppState.(gnoland.GnoGenesisState)
if !ok {
return errInvalidGenesisStateType
}

// Left merge the transactions
fileTxStore := txStore(txs)
genesisTxStore := txStore(state.Txs)

// The genesis transactions have preference with the order
// in the genesis.json
if err := genesisTxStore.leftMerge(fileTxStore); err != nil {
return err
}

// Save the state
state.Txs = genesisTxStore
genesis.AppState = state

return nil
}
92 changes: 9 additions & 83 deletions gno.land/cmd/gnoland/genesis_txs_add.go
Original file line number Diff line number Diff line change
@@ -1,100 +1,26 @@
package main

import (
"context"
"errors"
"fmt"
"os"

"github.com/gnolang/gno/gno.land/pkg/gnoland"
"github.com/gnolang/gno/tm2/pkg/bft/types"
"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/std"
)

var (
errInvalidTxsFile = errors.New("unable to open transactions file")
errNoTxsFileSpecified = errors.New("no txs file specified")
)

// newTxsAddCmd creates the genesis txs add subcommand
func newTxsAddCmd(txsCfg *txsCfg, io commands.IO) *commands.Command {
return commands.NewCommand(
cmd := commands.NewCommand(
commands.Metadata{
Name: "add",
ShortUsage: "txs add <tx-file ...>",
ShortHelp: "imports transactions into the genesis.json",
LongHelp: "Imports the transactions from a tx-archive backup to the genesis.json",
ShortUsage: "txs add <subcommand> [flags] [<arg>...]",
ShortHelp: "adds transactions into the genesis.json",
LongHelp: "Adds initial transactions to the genesis.json",
},
commands.NewEmptyConfig(),
func(ctx context.Context, args []string) error {
return execTxsAdd(ctx, txsCfg, io, args)
},
commands.HelpExec,
)
}

func execTxsAdd(
ctx context.Context,
cfg *txsCfg,
io commands.IO,
args []string,
) error {
// Load the genesis
genesis, loadErr := types.GenesisDocFromFile(cfg.genesisPath)
if loadErr != nil {
return fmt.Errorf("unable to load genesis, %w", loadErr)
}

// Open the transactions files
if len(args) == 0 {
return errNoTxsFileSpecified
}

parsedTxs := make([]std.Tx, 0)
for _, file := range args {
file, loadErr := os.Open(file)
if loadErr != nil {
return fmt.Errorf("%w, %w", errInvalidTxsFile, loadErr)
}

txs, err := std.ParseTxs(ctx, file)
if err != nil {
return fmt.Errorf("unable to read file, %w", err)
}

parsedTxs = append(parsedTxs, txs...)
}

// Initialize the app state if it's not present
if genesis.AppState == nil {
genesis.AppState = gnoland.GnoGenesisState{}
}

state := genesis.AppState.(gnoland.GnoGenesisState)

// Left merge the transactions
fileTxStore := txStore(parsedTxs)
genesisTxStore := txStore(state.Txs)

// The genesis transactions have preference with the order
// in the genesis.json
if err := genesisTxStore.leftMerge(fileTxStore); err != nil {
return err
}

// Save the state
state.Txs = genesisTxStore
genesis.AppState = state

// Save the updated genesis
if err := genesis.SaveAs(cfg.genesisPath); err != nil {
return fmt.Errorf("unable to save genesis.json, %w", err)
}

io.Printfln(
"Saved %d transactions to genesis.json",
len(parsedTxs),
cmd.AddSubCommands(
newTxsAddSheetCmd(txsCfg, io),
newTxsAddPackagesCmd(txsCfg, io),
)

return nil
return cmd
}
81 changes: 81 additions & 0 deletions gno.land/cmd/gnoland/genesis_txs_add_packages.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package main

import (
"context"
"errors"
"fmt"

"github.com/gnolang/gno/gno.land/pkg/gnoland"
"github.com/gnolang/gno/tm2/pkg/bft/types"
"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/crypto"
"github.com/gnolang/gno/tm2/pkg/std"
)

var errInvalidPackageDir = errors.New("invalid package directory")

var (
genesisDeployAddress = crypto.MustAddressFromString("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") // test1
genesisDeployFee = std.NewFee(50000, std.MustParseCoin("1000000ugnot"))
)

// newTxsAddPackagesCmd creates the genesis txs add packages subcommand
func newTxsAddPackagesCmd(txsCfg *txsCfg, io commands.IO) *commands.Command {
return commands.NewCommand(
commands.Metadata{
Name: "packages",
ShortUsage: "txs add packages <package-path ...>",
ShortHelp: "imports transactions from the given packages into the genesis.json",
LongHelp: "Imports the transactions from a given package directory recursively to the genesis.json",
},
commands.NewEmptyConfig(),
func(_ context.Context, args []string) error {
return execTxsAddPackages(txsCfg, io, args)
},
)
}

func execTxsAddPackages(
cfg *txsCfg,
io commands.IO,
args []string,
) error {
// Load the genesis
genesis, loadErr := types.GenesisDocFromFile(cfg.genesisPath)
if loadErr != nil {
return fmt.Errorf("unable to load genesis, %w", loadErr)
}

// Make sure the package dir is set
if len(args) == 0 {
return errInvalidPackageDir
}

parsedTxs := make([]std.Tx, 0)
for _, path := range args {
// Generate transactions from the packages (recursively)
txs, err := gnoland.LoadPackagesFromDir(path, genesisDeployAddress, genesisDeployFee)
if err != nil {
return fmt.Errorf("unable to load txs from directory, %w", err)
}

parsedTxs = append(parsedTxs, txs...)
}

// Save the txs to the genesis.json
if err := appendGenesisTxs(genesis, parsedTxs); err != nil {
return fmt.Errorf("unable to append genesis transactions, %w", err)
}

// Save the updated genesis
if err := genesis.SaveAs(cfg.genesisPath); err != nil {
return fmt.Errorf("unable to save genesis.json, %w", err)
}

io.Printfln(
"Saved %d transactions to genesis.json",
len(parsedTxs),
)

return nil
}
Loading

0 comments on commit e2e0611

Please sign in to comment.