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: support custom VM domain #2911

Draft
wants to merge 23 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
25 changes: 17 additions & 8 deletions contribs/gnodev/cmd/gnodev/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,20 @@ type devCfg struct {
webRemoteHelperAddr string

// Node Configuration
minimal bool
verbose bool
noWatch bool
noReplay bool
maxGas int64
chainId string
serverMode bool
unsafeAPI bool
minimal bool
verbose bool
noWatch bool
noReplay bool
maxGas int64
chainId string
chainDomain string
serverMode bool
unsafeAPI bool
}

var defaultDevOptions = &devCfg{
chainId: "dev",
chainDomain: "gno.land",
maxGas: 10_000_000_000,
webListenerAddr: "127.0.0.1:8888",
nodeRPCListenerAddr: "127.0.0.1:26657",
Expand Down Expand Up @@ -203,6 +205,13 @@ func (c *devCfg) RegisterFlags(fs *flag.FlagSet) {
"set node ChainID",
)

fs.StringVar(
&c.chainDomain,
"chain-domain",
defaultDevOptions.chainDomain,
"set node ChainDomain",
)

fs.BoolVar(
&c.noWatch,
"no-watch",
Expand Down
2 changes: 1 addition & 1 deletion contribs/gnodev/cmd/gnodev/setup_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func setupDevNodeConfig(
balances gnoland.Balances,
pkgspath []gnodev.PackagePath,
) *gnodev.NodeConfig {
config := gnodev.DefaultNodeConfig(cfg.root)
config := gnodev.DefaultNodeConfig(cfg.root, cfg.chainDomain)

config.Logger = logger
config.Emitter = emitter
Expand Down
12 changes: 8 additions & 4 deletions contribs/gnodev/pkg/dev/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ type NodeConfig struct {
NoReplay bool
MaxGasPerBlock int64
ChainID string
ChainDomain string
}

func DefaultNodeConfig(rootdir string) *NodeConfig {
func DefaultNodeConfig(rootdir, domain string) *NodeConfig {
tmc := gnoland.NewDefaultTMConfig(rootdir)
tmc.Consensus.SkipTimeoutCommit = false // avoid time drifting, see issue #1507
tmc.Consensus.WALDisabled = true
Expand All @@ -63,6 +64,7 @@ func DefaultNodeConfig(rootdir string) *NodeConfig {
DefaultDeployer: defaultDeployer,
BalancesList: balances,
ChainID: tmc.ChainID(),
ChainDomain: domain,
TMConfig: tmc,
SkipFailingGenesisTxs: true,
MaxGasPerBlock: 10_000_000_000,
Expand Down Expand Up @@ -468,7 +470,7 @@ func (n *Node) rebuildNode(ctx context.Context, genesis gnoland.GnoGenesisState)
}

// Setup node config
nodeConfig := newNodeConfig(n.config.TMConfig, n.config.ChainID, genesis)
nodeConfig := newNodeConfig(n.config.TMConfig, n.config.ChainID, n.config.ChainDomain, genesis)
nodeConfig.GenesisTxResultHandler = n.genesisTxResultHandler
// Speed up stdlib loading after first start (saves about 2-3 seconds on each reload).
nodeConfig.CacheStdlibLoad = true
Expand Down Expand Up @@ -547,7 +549,7 @@ func (n *Node) genesisTxResultHandler(ctx sdk.Context, tx std.Tx, res sdk.Result
return
}

func newNodeConfig(tmc *tmcfg.Config, chainid string, appstate gnoland.GnoGenesisState) *gnoland.InMemoryNodeConfig {
func newNodeConfig(tmc *tmcfg.Config, chainid, chaindomain string, appstate gnoland.GnoGenesisState) *gnoland.InMemoryNodeConfig {
// Create Mocked Identity
pv := gnoland.NewMockedPrivValidator()
genesis := gnoland.NewDefaultGenesisConfig(chainid)
Expand All @@ -564,9 +566,11 @@ func newNodeConfig(tmc *tmcfg.Config, chainid string, appstate gnoland.GnoGenesi
},
}

return &gnoland.InMemoryNodeConfig{
cfg := &gnoland.InMemoryNodeConfig{
PrivValidator: pv,
TMConfig: tmc,
Genesis: genesis,
}
cfg.InitChainerConfig.ChainDomain = chaindomain
return cfg
}
6 changes: 3 additions & 3 deletions contribs/gnodev/pkg/dev/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func TestNewNode_NoPackages(t *testing.T) {
logger := log.NewTestingLogger(t)

// Call NewDevNode with no package should work
cfg := DefaultNodeConfig(gnoenv.RootDir())
cfg := DefaultNodeConfig(gnoenv.RootDir(), "gno.land")
cfg.Logger = logger
node, err := NewDevNode(ctx, cfg)
require.NoError(t, err)
Expand Down Expand Up @@ -62,7 +62,7 @@ func Render(_ string) string { return "foo" }
logger := log.NewTestingLogger(t)

// Call NewDevNode with no package should work
cfg := DefaultNodeConfig(gnoenv.RootDir())
cfg := DefaultNodeConfig(gnoenv.RootDir(), "gno.land")
cfg.PackagesPathList = []PackagePath{pkgpath}
cfg.Logger = logger
node, err := NewDevNode(ctx, cfg)
Expand Down Expand Up @@ -295,7 +295,7 @@ func newTestingDevNode(t *testing.T, pkgslist ...PackagePath) (*Node, *mock.Serv
emitter := &mock.ServerEmitter{}

// Call NewDevNode with no package should work
cfg := DefaultNodeConfig(gnoenv.RootDir())
cfg := DefaultNodeConfig(gnoenv.RootDir(), "gno.land")
cfg.PackagesPathList = pkgslist
cfg.Emitter = emitter
cfg.Logger = logger
Expand Down
8 changes: 8 additions & 0 deletions gno.land/cmd/gnoland/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type startCfg struct {
genesisRemote string // TODO: remove as part of https://github.com/gnolang/gno/issues/1952
genesisFile string
chainID string
chainDomain string
dataDir string
lazyInit bool

Expand Down Expand Up @@ -114,6 +115,13 @@ func (c *startCfg) RegisterFlags(fs *flag.FlagSet) {
"the ID of the chain",
)

fs.StringVar(
&c.chainDomain,
"chaindomain",
"gno.land",
"the domain of the chain for packages",
)

fs.StringVar(
&c.gnoRootDir,
"gnoroot-dir",
Expand Down
15 changes: 15 additions & 0 deletions gno.land/cmd/gnoland/testdata/addpkg_domain.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
gnoland start

# addpkg with anotherdomain.land
! gnokey maketx addpkg -pkgdir $WORK -pkgpath anotherdomain.land/r/foobar/bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
stdout 'TX HASH:'
stderr 'invalid package path'
stderr 'invalid domain: anotherdomain.land/r/foobar/bar'

# addpkg with gno.land
gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/foobar/bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
stdout 'OK!'

-- bar.gno --
package bar
func Render(path string) string { return "hello" }
6 changes: 5 additions & 1 deletion gno.land/pkg/gnoland/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func TestAppOptions(db dbm.DB) *AppOptions {
GenesisTxResultHandler: PanicOnFailingTxResultHandler,
StdlibDir: filepath.Join(gnoenv.RootDir(), "gnovm", "stdlibs"),
CacheStdlibLoad: true,
ChainDomain: "gno.land",
},
}
}
Expand Down Expand Up @@ -87,7 +88,7 @@ func NewAppWithOptions(cfg *AppOptions) (abci.Application, error) {
// Construct keepers.
acctKpr := auth.NewAccountKeeper(mainKey, ProtoGnoAccount)
bankKpr := bank.NewBankKeeper(acctKpr)
vmk := vm.NewVMKeeper(baseKey, mainKey, acctKpr, bankKpr)
vmk := vm.NewVMKeeper(baseKey, mainKey, acctKpr, bankKpr, cfg.ChainDomain)

// Set InitChainer
icc := cfg.InitChainerConfig
Expand Down Expand Up @@ -222,6 +223,9 @@ type InitChainerConfig struct {
// called several times.
CacheStdlibLoad bool

// ChainDomain is the primary domain name for the chain and its packages.
ChainDomain string
Comment on lines +226 to +227
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why add this here instead of in genesis?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that I prefer your idea. I'm waiting for more feedback before making the change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree it should be in genesis. Allows us more easily to find problems when there's a mismatch between two nodes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

switching the PR to draft until I finish and merge #3003.


// These fields are passed directly by NewAppWithOptions, and should not be
// configurable by end-users.
baseApp *sdk.BaseApp
Expand Down
1 change: 1 addition & 0 deletions gno.land/pkg/integration/testing_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ func TestingMinimalNodeConfig(t TestingTS, gnoroot string) *gnoland.InMemoryNode
InitChainerConfig: gnoland.InitChainerConfig{
GenesisTxResultHandler: gnoland.PanicOnFailingTxResultHandler,
CacheStdlibLoad: true,
ChainDomain: "gno.land",
},
}
}
Expand Down
3 changes: 2 additions & 1 deletion gno.land/pkg/sdk/vm/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ func _setupTestEnv(cacheStdlibs bool) testEnv {
ctx := sdk.NewContext(sdk.RunTxModeDeliver, ms, &bft.Header{ChainID: "test-chain-id"}, log.NewNoopLogger())
acck := authm.NewAccountKeeper(iavlCapKey, std.ProtoBaseAccount)
bank := bankm.NewBankKeeper(acck)
vmk := NewVMKeeper(baseCapKey, iavlCapKey, acck, bank)
chainDomain := "gno.land"
vmk := NewVMKeeper(baseCapKey, iavlCapKey, acck, bank, chainDomain)

mcw := ms.MultiCacheWrap()
vmk.Initialize(log.NewNoopLogger(), mcw)
Expand Down
25 changes: 19 additions & 6 deletions gno.land/pkg/sdk/vm/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@

// cached, the DeliverTx persistent state.
gnoStore gno.Store

domain string // chain domain

// internal
reNamespace *regexp.Regexp
}

// NewVMKeeper returns a new VMKeeper.
Expand All @@ -70,14 +75,19 @@
iavlKey store.StoreKey,
acck auth.AccountKeeper,
bank bank.BankKeeper,
chainDomain string,
) *VMKeeper {
// TODO: create an Options struct to avoid too many constructor parameters
vmk := &VMKeeper{
baseKey: baseKey,
iavlKey: iavlKey,
acck: acck,
bank: bank,
domain: chainDomain,
}

// Namespace can be either a user or crypto address.
vmk.reNamespace = regexp.MustCompile(`^` + regexp.QuoteMeta(chainDomain) + `/(?:r|p)/([\.~_a-zA-Z0-9]+)`)
return vmk
}

Expand Down Expand Up @@ -185,6 +195,7 @@
}

m := gno.NewMachineWithOptions(gno.MachineOptions{
// XXX: gno.land, vm.domain, other?
PkgPath: "gno.land/r/stdlibs/" + pkgPath,
// PkgPath: pkgPath, XXX why?
Output: os.Stdout,
Expand Down Expand Up @@ -219,16 +230,13 @@
return txStore
}

// Namespace can be either a user or crypto address.
var reNamespace = regexp.MustCompile(`^gno.land/(?:r|p)/([\.~_a-zA-Z0-9]+)`)

// checkNamespacePermission check if the user as given has correct permssion to on the given pkg path
func (vm *VMKeeper) checkNamespacePermission(ctx sdk.Context, creator crypto.Address, pkgPath string) error {
const sysUsersPkg = "gno.land/r/sys/users"
sysUsersPkg := vm.domain + "/r/sys/users" // configurable through sys/params

store := vm.getGnoTransactionStore(ctx)

match := reNamespace.FindStringSubmatch(pkgPath)
match := vm.reNamespace.FindStringSubmatch(pkgPath)
switch len(match) {
case 0:
return ErrInvalidPkgPath(pkgPath) // no match
Expand All @@ -251,6 +259,7 @@
pkgAddr := gno.DerivePkgAddr(pkgPath)
msgCtx := stdlibs.ExecContext{
ChainID: ctx.ChainID(),
ChainDomain: vm.domain,

Check warning on line 262 in gno.land/pkg/sdk/vm/keeper.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/keeper.go#L262

Added line #L262 was not covered by tests
Height: ctx.BlockHeight(),
Timestamp: ctx.BlockTime().Unix(),
OrigCaller: creator.Bech32(),
Expand Down Expand Up @@ -319,6 +328,9 @@
if err := msg.Package.Validate(); err != nil {
return ErrInvalidPkgPath(err.Error())
}
if !strings.HasPrefix(pkgPath, vm.domain+"/") {
return ErrInvalidPkgPath("invalid domain: " + pkgPath)
}
if pv := gnostore.GetPackage(pkgPath, false); pv != nil {
return ErrPkgAlreadyExists("package already exists: " + pkgPath)
}
Expand Down Expand Up @@ -522,7 +534,7 @@
// coerce path to right one.
// the path in the message must be "" or the following path.
// this is already checked in MsgRun.ValidateBasic
memPkg.Path = "gno.land/r/" + msg.Caller.String() + "/run"
memPkg.Path = vm.domain + "/r/" + msg.Caller.String() + "/run"

// Validate arguments.
callerAcc := vm.acck.GetAccount(ctx, caller)
Expand All @@ -548,6 +560,7 @@
// Parse and run the files, construct *PV.
msgCtx := stdlibs.ExecContext{
ChainID: ctx.ChainID(),
ChainDomain: vm.domain,
Height: ctx.BlockHeight(),
Timestamp: ctx.BlockTime().Unix(),
Msg: msg,
Expand Down
39 changes: 38 additions & 1 deletion gno.land/pkg/sdk/vm/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"github.com/gnolang/gno/tm2/pkg/store/types"
)

var coinsString = ugnot.ValueString(10000000)
var coinsString = ugnot.ValueString(10_000_000)

func TestVMKeeperAddPackage(t *testing.T) {
env := setupTestEnv()
Expand Down Expand Up @@ -67,6 +67,43 @@ func Echo() string { return "hello world" }
assert.Equal(t, expected, memFile.Body)
}

func TestVMKeeperAddPackage_InvalidDomain(t *testing.T) {
env := setupTestEnv()
ctx := env.vmk.MakeGnoTransactionStore(env.ctx)

// Give "addr1" some gnots.
addr := crypto.AddressFromPreimage([]byte("addr1"))
acc := env.acck.NewAccountWithAddress(ctx, addr)
env.acck.SetAccount(ctx, acc)
env.bank.SetCoins(ctx, addr, std.MustParseCoins(coinsString))
assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString)))

// Create test package.
files := []*std.MemFile{
{
Name: "test.gno",
Body: `package test
func Echo() string {return "hello world"}`,
},
}
pkgPath := "anotherdomain.land/r/test"
msg1 := NewMsgAddPackage(addr, pkgPath, files)
assert.Nil(t, env.vmk.getGnoTransactionStore(ctx).GetPackage(pkgPath, false))

err := env.vmk.AddPackage(ctx, msg1)

assert.Error(t, err, ErrInvalidPkgPath("invalid domain: anotherdomain.land/r/test"))
assert.Nil(t, env.vmk.getGnoTransactionStore(ctx).GetPackage(pkgPath, false))

err = env.vmk.AddPackage(ctx, msg1)
assert.Error(t, err, ErrInvalidPkgPath("invalid domain: anotherdomain.land/r/test"))

// added package is formatted
store := env.vmk.getGnoTransactionStore(ctx)
memFile := store.GetMemFile("gno.land/r/test", "test.gno")
assert.Nil(t, memFile)
}

// Sending total send amount succeeds.
func TestVMKeeperOrigSend1(t *testing.T) {
env := setupTestEnv()
Expand Down
4 changes: 2 additions & 2 deletions gno.land/pkg/sdk/vm/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,8 @@ func (msg MsgRun) ValidateBasic() error {
}

// Force memPkg path to the reserved run path.
wantPath := "gno.land/r/" + msg.Caller.String() + "/run"
if path := msg.Package.Path; path != "" && path != wantPath {
wantSuffix := "/r/" + msg.Caller.String() + "/run"
if path := msg.Package.Path; path != "" && !strings.HasSuffix(path, wantSuffix) {
return ErrInvalidPkgPath(fmt.Sprintf("invalid pkgpath for MsgRun: %q", path))
}

Expand Down
2 changes: 1 addition & 1 deletion gnovm/cmd/gno/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ func gnoTestPkg(
if gnoPkgPath == "" {
// unable to read pkgPath from gno.mod, generate a random realm path
io.ErrPrintfln("--- WARNING: unable to read package path from gno.mod or gno root directory; try creating a gno.mod file")
gnoPkgPath = gno.RealmPathPrefix + random.RandStr(8)
gnoPkgPath = "gno.land/r/" + random.RandStr(8) // XXX: "gno.land" hardcoded for convenience
}
}
memPkg := gno.ReadMemPackage(pkgPath, gnoPkgPath)
Expand Down
Loading
Loading