Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: add p/sys/boot + codegen system for contracts #2488

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions contribs/gnodev/cmd/gnodev/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,12 @@ func resolvePackagesPathFromArgs(cfg *devCfg, bk *address.Book, args []string) (
Creator: defaultKey,
Deposit: nil,
})
} else {
paths = append(paths, gnodev.PackagePath{
Path: filepath.Join(cfg.root, "examples", "gno.land", "p", "sys", "boot"),
Creator: defaultKey,
Deposit: nil,
})
}

return paths, nil
Expand Down
36 changes: 36 additions & 0 deletions contribs/gnodev/pkg/dev/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,42 @@ func Render(_ string) string { return "foo" }
require.NoError(t, node.Close())
}

func TestNewNode_tplData(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

const (
// foobar package
testGnoMod = "module gno.land/r/dev/foobar\n"
docFile = `package foobar`
testFile = `package foobar
func Render(_ string) string { return "{{.}}" }
`
)

// Generate package
pkgpath := generateTestingPackage(t,
"gno.mod", testGnoMod,
"foobar.gno.tpl", testFile,
"doc.gno", docFile,
)
logger := log.NewTestingLogger(t)

// Call NewDevNode with no package should work
cfg := DefaultNodeConfig(gnoenv.RootDir())
cfg.PackagesPathList = []PackagePath{pkgpath}
node, err := NewDevNode(ctx, logger, &emitter.NoopServer{}, cfg)
require.NoError(t, err)
assert.Len(t, node.ListPkgs(), 1)

// Test rendering
render, err := testingRenderRealm(t, node, "gno.land/r/dev/foobar")
require.NoError(t, err)
assert.Equal(t, render, "foo")

require.NoError(t, node.Close())
}

func TestNodeAddPackage(t *testing.T) {
// Setup a Node instance
const (
Expand Down
32 changes: 18 additions & 14 deletions contribs/gnodev/pkg/dev/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (
"path/filepath"

"github.com/gnolang/gno/contribs/gnodev/pkg/address"
vmm "github.com/gnolang/gno/gno.land/pkg/sdk/vm"
"github.com/gnolang/gno/gno.land/pkg/gnoland"
"github.com/gnolang/gno/gno.land/pkg/sdk/vm"
gno "github.com/gnolang/gno/gnovm/pkg/gnolang"
"github.com/gnolang/gno/gnovm/pkg/gnomod"
"github.com/gnolang/gno/tm2/pkg/amino"
"github.com/gnolang/gno/tm2/pkg/crypto"
"github.com/gnolang/gno/tm2/pkg/std"
)
Expand Down Expand Up @@ -128,6 +130,9 @@ func (pm PackagesMap) Load(fee std.Fee) ([]std.Tx, error) {

nonDraft := sorted.GetNonDraftPkgs()
txs := []std.Tx{}

tplData := gnoland.GenesisTplData{}

for _, modPkg := range nonDraft {
pkg := pm[modPkg.Dir]
if pkg.Creator.IsZero() {
Expand All @@ -136,23 +141,22 @@ func (pm PackagesMap) Load(fee std.Fee) ([]std.Tx, error) {

// Open files in directory as MemPackage.
memPkg := gno.ReadMemPackage(modPkg.Dir, modPkg.Name)
if err := memPkg.Validate(); err != nil {
return nil, fmt.Errorf("invalid package: %w", err)
for _, file := range memPkg.Files {
fmt.Printf("BBB: %q, %s\n", file.Name, file.Body)
}

tx, err := gnoland.LoadPackage(memPkg, pkg.Creator, fee, pkg.Deposit, tplData)
if err != nil {
return nil, err
}

// Create transaction
tx := std.Tx{
Fee: fee,
Msgs: []std.Msg{
vmm.MsgAddPackage{
Creator: pkg.Creator,
Deposit: pkg.Deposit,
Package: memPkg,
},
},
var msg vm.MsgAddPackage
bz := tx.Msgs[0].GetSignBytes()
amino.MustUnmarshalJSON(bz, &msg)
for _, file := range msg.Package.Files {
fmt.Printf("AAA: %q, %s\n", file.Name, file.Body)
}

tx.Signatures = make([]std.Signature, len(tx.GetSigners()))
txs = append(txs, tx)
}

Expand Down
14 changes: 14 additions & 0 deletions examples/gno.land/p/sys/boot/doc.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// the boot package is similar to linux' /boot/cmdline.
//
// it contains values that were used to initialize the chain. as a pure-package,
// its content is immutable, which makes this package having a high potential of
// quickly becoming outdated. however, it can be used safely by initial
// contracts' init() functions.
//
// per-context expected usages:
// - gnodev:
// - register current node's on poa
// - dynamically load local gnokey's information
//
// - gnoland: static file manually patched by the chain architects.
package boot
5 changes: 5 additions & 0 deletions examples/gno.land/p/sys/boot/gen.gno.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package boot

/*
{{.}}
*/
1 change: 1 addition & 0 deletions examples/gno.land/p/sys/boot/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module gno.land/p/sys/boot
3 changes: 2 additions & 1 deletion gno.land/cmd/gnoland/genesis_txs_add_packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ func execTxsAddPackages(
}

parsedTxs := make([]std.Tx, 0)
tplData := gnoland.GenesisTplData{}
for _, path := range args {
// Generate transactions from the packages (recursively)
txs, err := gnoland.LoadPackagesFromDir(path, genesisDeployAddress, genesisDeployFee)
txs, err := gnoland.LoadPackagesFromDir(path, genesisDeployAddress, genesisDeployFee, tplData)
if err != nil {
return fmt.Errorf("unable to load txs from directory, %w", err)
}
Expand Down
3 changes: 2 additions & 1 deletion gno.land/cmd/gnoland/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,8 @@ func generateGenesisFile(genesisFile string, pk crypto.PubKey, c *startCfg) erro

// Load examples folder
examplesDir := filepath.Join(c.gnoRootDir, "examples")
pkgsTxs, err := gnoland.LoadPackagesFromDir(examplesDir, genesisDeployAddress, genesisDeployFee)
tplData := gnoland.GenesisTplData{}
pkgsTxs, err := gnoland.LoadPackagesFromDir(examplesDir, genesisDeployAddress, genesisDeployFee, tplData)
if err != nil {
return fmt.Errorf("unable to load examples folder: %w", err)
}
Expand Down
36 changes: 31 additions & 5 deletions gno.land/pkg/gnoland/genesis.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package gnoland

import (
"bytes"
"errors"
"fmt"
"strings"
"text/template"

vmm "github.com/gnolang/gno/gno.land/pkg/sdk/vm"
gno "github.com/gnolang/gno/gnovm/pkg/gnolang"
"github.com/gnolang/gno/gnovm/pkg/gnomod"
"github.com/gnolang/gno/tm2/pkg/amino"
"github.com/gnolang/gno/tm2/pkg/bft/types"

Check failure on line 14 in gno.land/pkg/gnoland/genesis.go

View workflow job for this annotation

GitHub Actions / Run Main / Go Linter / lint

ST1019: package "github.com/gnolang/gno/tm2/pkg/bft/types" is being imported more than once (stylecheck)
bft "github.com/gnolang/gno/tm2/pkg/bft/types"

Check failure on line 15 in gno.land/pkg/gnoland/genesis.go

View workflow job for this annotation

GitHub Actions / Run Main / Go Linter / lint

ST1019(related information): other import of "github.com/gnolang/gno/tm2/pkg/bft/types" (stylecheck)
"github.com/gnolang/gno/tm2/pkg/crypto"
osm "github.com/gnolang/gno/tm2/pkg/os"
"github.com/gnolang/gno/tm2/pkg/std"
Expand Down Expand Up @@ -86,9 +89,9 @@

// LoadPackagesFromDir loads gno packages from a directory.
// It creates and returns a list of transactions based on these packages.
func LoadPackagesFromDir(dir string, creator bft.Address, fee std.Fee) ([]std.Tx, error) {
func LoadPackagesFromDir(dir string, creator bft.Address, fee std.Fee, genData GenesisTplData) ([]std.Tx, error) {

Check warning on line 92 in gno.land/pkg/gnoland/genesis.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/gnoland/genesis.go#L92

Added line #L92 was not covered by tests
// list all packages from target path
pkgs, err := gnomod.ListPkgs(dir)
pkgs, err := gnomod.ListPkgs(dir) // XXX: gnomod isn't maanaging packages but modules

Check warning on line 94 in gno.land/pkg/gnoland/genesis.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/gnoland/genesis.go#L94

Added line #L94 was not covered by tests
if err != nil {
return nil, fmt.Errorf("listing gno packages: %w", err)
}
Expand All @@ -103,7 +106,8 @@
nonDraftPkgs := sortedPkgs.GetNonDraftPkgs()
txs := []std.Tx{}
for _, pkg := range nonDraftPkgs {
tx, err := LoadPackage(pkg, creator, fee, nil)
memPkg := gno.ReadMemPackage(pkg.Dir, pkg.Name, genData)
tx, err := LoadPackage(memPkg, creator, fee, nil, genData)

Check warning on line 110 in gno.land/pkg/gnoland/genesis.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/gnoland/genesis.go#L109-L110

Added lines #L109 - L110 were not covered by tests
if err != nil {
return nil, fmt.Errorf("unable to load package %q: %w", pkg.Dir, err)
}
Expand All @@ -115,16 +119,31 @@
}

// LoadPackage loads a single package into a `std.Tx`
func LoadPackage(pkg gnomod.Pkg, creator bft.Address, fee std.Fee, deposit std.Coins) (std.Tx, error) {
func LoadPackage(memPkg *std.MemPackage, creator bft.Address, fee std.Fee, deposit std.Coins, genData GenesisTplData) (std.Tx, error) {
var tx std.Tx

// Open files in directory as MemPackage.
memPkg := gno.ReadMemPackage(pkg.Dir, pkg.Name)
err := memPkg.Validate()
if err != nil {
return tx, fmt.Errorf("invalid package: %w", err)
}

// Codegen (.tpl)
for _, file := range memPkg.Files {
if strings.HasSuffix(file.Name, ".tpl") {
file.Name = strings.TrimSuffix(file.Name, ".tpl")
var tpl = template.Must(template.New(file.Name).Parse(file.Body))

Check failure on line 135 in gno.land/pkg/gnoland/genesis.go

View workflow job for this annotation

GitHub Actions / Run Main / Go Linter / lint

File is not `gofumpt`-ed (gofumpt)
var buf bytes.Buffer
if err := tpl.Execute(&buf, genData); err != nil {
return std.Tx{}, err

Check warning on line 138 in gno.land/pkg/gnoland/genesis.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/gnoland/genesis.go#L138

Added line #L138 was not covered by tests
}
file.Body = buf.String()
if strings.HasSuffix(file.Name, ".gno") {
file.Body = "// Code generated by gnoland; DO NOT EDIT.\n" + file.Body
}
}
}

// Create transaction
tx.Fee = fee
tx.Msgs = []std.Msg{
Expand All @@ -138,3 +157,10 @@

return tx, nil
}

type GenesisTplData struct {
Genesis types.GenesisDoc
// LocalGnokey
// BuildTags
// -X
}
47 changes: 47 additions & 0 deletions gno.land/pkg/gnoland/genesis_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package gnoland

import (
"testing"

"github.com/gnolang/gno/gno.land/pkg/sdk/vm"
"github.com/gnolang/gno/tm2/pkg/amino"
bft "github.com/gnolang/gno/tm2/pkg/bft/types"
"github.com/gnolang/gno/tm2/pkg/std"
"github.com/stretchr/testify/assert"
)

func TestLoadPackagesFromDir(t *testing.T) {
var (
memPkg = &std.MemPackage{
Name: "foo",
Path: "gno.land/r/demo/foo",
Files: []*std.MemFile{
{Name: "empty.gno", Body: "package foo"},
{Name: "generated.gno.tpl", Body: `package foo

var ChainID = {{.Genesis.ChainID | printf "%q"}}
`},
},
}
creator = bft.Address{}
fee = std.Fee{}
deposit = std.Coins{}
)
tplData := GenesisTplData{}
tplData.Genesis.ChainID = "test"
tx, err := LoadPackage(memPkg, creator, fee, deposit, tplData)
assert.NoError(t, err)
var msg vm.MsgAddPackage
bz := tx.Msgs[0].GetSignBytes()
amino.MustUnmarshalJSON(bz, &msg)
for _, file := range msg.Package.Files {
assert.NotEqual(t, "generated.gno.tpl", file.Name, "*.tpl files should be removed")
if file.Name == "generated.gno.tpl" {
expected := `package foo

var ChainID = "test"
`
assert.Equal(t, expected, file.Body)
}
}
}
6 changes: 5 additions & 1 deletion gno.land/pkg/integration/testing_integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/gnolang/gno/gno.land/pkg/keyscli"
"github.com/gnolang/gno/gno.land/pkg/log"
"github.com/gnolang/gno/gnovm/pkg/gnoenv"
gno "github.com/gnolang/gno/gnovm/pkg/gnolang"
"github.com/gnolang/gno/gnovm/pkg/gnomod"
"github.com/gnolang/gno/tm2/pkg/bft/node"
bft "github.com/gnolang/gno/tm2/pkg/bft/types"
Expand Down Expand Up @@ -595,8 +596,11 @@ func (pl *pkgsLoader) LoadPackages(creator bft.Address, fee std.Fee, deposit std
}

txs := make([]std.Tx, len(pkgslist))
tplData := gnoland.GenesisTplData{}
for i, pkg := range pkgslist {
tx, err := gnoland.LoadPackage(pkg, creator, fee, deposit)
genData := gnoland.GenesisTplData{}
memPkg := gno.ReadMemPackage(pkg.Dir, pkg.Name, genData)
tx, err := gnoland.LoadPackage(memPkg, creator, fee, deposit, tplData)
if err != nil {
return nil, fmt.Errorf("unable to load pkg %q: %w", pkg.Name, err)
}
Expand Down
12 changes: 9 additions & 3 deletions gno.land/pkg/integration/testing_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@
creator := crypto.MustAddressFromString(DefaultAccount_Address) // test1

balances := LoadDefaultGenesisBalanceFile(t, gnoroot)
tplData := DefaultGenesisTplData()

Check warning on line 51 in gno.land/pkg/integration/testing_node.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/integration/testing_node.go#L51

Added line #L51 was not covered by tests
txs := []std.Tx{}
txs = append(txs, LoadDefaultPackages(t, creator, gnoroot)...)
txs = append(txs, LoadDefaultPackages(t, creator, gnoroot, tplData)...)

Check warning on line 53 in gno.land/pkg/integration/testing_node.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/integration/testing_node.go#L53

Added line #L53 was not covered by tests
txs = append(txs, LoadDefaultGenesisTXsFile(t, cfg.Genesis.ChainID, gnoroot)...)

cfg.Genesis.AppState = gnoland.GnoGenesisState{
Expand All @@ -60,6 +61,11 @@
return cfg, creator
}

func DefaultGenesisTplData() gnoland.GenesisTplData {
tplData := gnoland.GenesisTplData{}
return tplData

Check warning on line 66 in gno.land/pkg/integration/testing_node.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/integration/testing_node.go#L64-L66

Added lines #L64 - L66 were not covered by tests
}

// TestingMinimalNodeConfig constructs the default minimal in-memory node configuration for testing.
func TestingMinimalNodeConfig(t TestingTS, gnoroot string) *gnoland.InMemoryNodeConfig {
tmconfig := DefaultTestingTMConfig(gnoroot)
Expand Down Expand Up @@ -111,11 +117,11 @@
}

// LoadDefaultPackages loads the default packages for testing using a given creator address and gnoroot directory.
func LoadDefaultPackages(t TestingTS, creator bft.Address, gnoroot string) []std.Tx {
func LoadDefaultPackages(t TestingTS, creator bft.Address, gnoroot string, tplData gnoland.GenesisTplData) []std.Tx {

Check warning on line 120 in gno.land/pkg/integration/testing_node.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/integration/testing_node.go#L120

Added line #L120 was not covered by tests
examplesDir := filepath.Join(gnoroot, "examples")

defaultFee := std.NewFee(50000, std.MustParseCoin("1000000ugnot"))
txs, err := gnoland.LoadPackagesFromDir(examplesDir, creator, defaultFee)
txs, err := gnoland.LoadPackagesFromDir(examplesDir, creator, defaultFee, tplData)

Check warning on line 124 in gno.land/pkg/integration/testing_node.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/integration/testing_node.go#L124

Added line #L124 was not covered by tests
require.NoError(t, err)

return txs
Expand Down
3 changes: 2 additions & 1 deletion gno.land/pkg/keyscli/addpkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ func execMakeAddPkg(cfg *MakeAddPkgCfg, args []string, io commands.IO) error {
}

// open files in directory as MemPackage.
memPkg := gno.ReadMemPackage(cfg.PkgDir, cfg.PkgPath)
var genData interface{} = nil
memPkg := gno.ReadMemPackage(cfg.PkgDir, cfg.PkgPath, genData)
if memPkg.IsEmpty() {
panic(fmt.Sprintf("found an empty package %q", cfg.PkgPath))
}
Expand Down
3 changes: 2 additions & 1 deletion gno.land/pkg/keyscli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@
return fmt.Errorf("could not read source path: %q, %w", sourcePath, err)
}
if info.IsDir() {
memPkg = gno.ReadMemPackage(sourcePath, "")
var genData interface{} = nil
memPkg = gno.ReadMemPackage(sourcePath, "", genData)

Check warning on line 95 in gno.land/pkg/keyscli/run.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/keyscli/run.go#L94-L95

Added lines #L94 - L95 were not covered by tests
} else { // is file
b, err := os.ReadFile(sourcePath)
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion gno.land/pkg/sdk/vm/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ func (vm *VMKeeper) getPackage(pkgPath string, store gno.Store) (pn *gno.Package
// does not exist.
return nil, nil
}
memPkg := gno.ReadMemPackage(stdlibPath, pkgPath)
var genData interface{} = nil
memPkg := gno.ReadMemPackage(stdlibPath, pkgPath, genData)
if memPkg.IsEmpty() {
// no gno files are present, skip this package
return nil, nil
Expand Down
Loading
Loading