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

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
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,10 +566,12 @@ func newNodeConfig(tmc *tmcfg.Config, chainid string, appstate gnoland.GnoGenesi
},
}

return &gnoland.InMemoryNodeConfig{
cfg := &gnoland.InMemoryNodeConfig{
PrivValidator: pv,
TMConfig: tmc,
Genesis: genesis,
GenesisMaxVMCycles: 100_000_000,
}
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
16 changes: 8 additions & 8 deletions gno.land/cmd/gnoland/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ 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
genesisMaxVMCycles int64
config string
lazyInit bool

Expand Down Expand Up @@ -116,6 +116,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 All @@ -137,13 +144,6 @@ func (c *startCfg) RegisterFlags(fs *flag.FlagSet) {
"replacement for '%%REMOTE%%' in genesis",
)

fs.Int64Var(
moul marked this conversation as resolved.
Show resolved Hide resolved
&c.genesisMaxVMCycles,
"genesis-max-vm-cycles",
100_000_000,
"set maximum allowed vm cycles per operation. Zero means no limit.",
)

fs.StringVar(
&c.config,
flagConfigFlag,
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 @@ -49,6 +49,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 @@ -88,7 +89,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, cfg.MaxCycles)
vmk := vm.NewVMKeeper(baseKey, mainKey, acctKpr, bankKpr, cfg.ChainDomain, cfg.MaxCycles)

// Set InitChainer
icc := cfg.InitChainerConfig
Expand Down Expand Up @@ -223,6 +224,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 +227 to +228
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.


// 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, 100_000_000)
chainDomain := "gno.land"
vmk := NewVMKeeper(baseCapKey, iavlCapKey, acck, bank, chainDomain, 100_000_000)

mcw := ms.MultiCacheWrap()
vmk.Initialize(log.NewNoopLogger(), mcw)
Expand Down
26 changes: 19 additions & 7 deletions gno.land/pkg/sdk/vm/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@
// cached, the DeliverTx persistent state.
gnoStore gno.Store

maxCycles int64 // max allowed cylces on VM executions
domain string // chain domain
maxCycles int64 // max allowed cylces on VM executions

// internal
reNamespace *regexp.Regexp
}

// NewVMKeeper returns a new VMKeeper.
Expand All @@ -72,6 +76,7 @@
iavlKey store.StoreKey,
acck auth.AccountKeeper,
bank bank.BankKeeper,
chainDomain string,
maxCycles int64,
) *VMKeeper {
// TODO: create an Options struct to avoid too many constructor parameters
Expand All @@ -80,8 +85,12 @@
iavlKey: iavlKey,
acck: acck,
bank: bank,
domain: chainDomain,
maxCycles: maxCycles,
}

// 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 @@ -189,6 +198,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 @@ -223,16 +233,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 @@ -255,6 +262,7 @@
pkgAddr := gno.DerivePkgAddr(pkgPath)
msgCtx := stdlibs.ExecContext{
ChainID: ctx.ChainID(),
ChainDomain: vm.domain,

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

View check run for this annotation

Codecov / codecov/patch

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

Added line #L265 was not covered by tests
Height: ctx.BlockHeight(),
Timestamp: ctx.BlockTime().Unix(),
OrigCaller: creator.Bech32(),
Expand Down Expand Up @@ -324,6 +332,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 @@ -529,7 +540,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 @@ -555,6 +566,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