diff --git a/gno.land/cmd/gnoland/testdata/prevrealm.txtar b/gno.land/cmd/gnoland/testdata/prevrealm.txtar new file mode 100644 index 00000000000..ac7988616a4 --- /dev/null +++ b/gno.land/cmd/gnoland/testdata/prevrealm.txtar @@ -0,0 +1,183 @@ +# This tests ensure the consistency of the std.PrevRealm function, in the +# following situations: +# +# +# | Num | Msg Type | Call from | Entry Point | Result | +# |-----|:--------:|:-------------------:|:---------------:|:------------:| +# | 1 | MsgCall | wallet direct | myrlm.A() | user address | +# | 2 | | | myrlm.B() | user address | +# | 3 | | through /r/foo | myrlm.A() | r/foo | +# | 4 | | | myrlm.B() | r/foo | +# | 5 | | through /p/demo/bar | myrlm.A() | user address | +# | 6 | | | myrlm.B() | user address | +# | 7 | MsgRun | wallet direct | myrlm.A() | user address | +# | 8 | | | myrlm.B() | user address | +# | 9 | | through /r/foo | myrlm.A() | r/foo | +# | 10 | | | myrlm.B() | r/foo | +# | 11 | | through /p/demo/bar | myrlm.A() | user address | +# | 12 | | | myrlm.B() | user address | +# | 13 | MsgCall | wallet direct | std.PrevRealm() | user address | +# | 14 | MsgRun | wallet direct | std.PrevRealm() | user address | + +# Init +## deploy myrlm +loadpkg gno.land/r/myrlm $WORK/r/myrlm +## deploy r/foo +loadpkg gno.land/r/foo $WORK/r/foo +## deploy p/demo/bar +loadpkg gno.land/p/demo/bar $WORK/p/demo/bar + +## start a new node +gnoland start + +env RFOO_ADDR=g1evezrh92xaucffmtgsaa3rvmz5s8kedffsg469 + +# Test cases +## 1. MsgCall -> myrlm.A: user address +gnokey maketx call -pkgpath gno.land/r/myrlm -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stdout ${USER_ADDR_test1} + +## 2. MsgCall -> myrealm.B -> myrlm.A: user address +gnokey maketx call -pkgpath gno.land/r/myrlm -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stdout ${USER_ADDR_test1} + +## 3. MsgCall -> r/foo.A -> myrlm.A: r/foo +gnokey maketx call -pkgpath gno.land/r/foo -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stdout ${RFOO_ADDR} + +## 4. MsgCall -> r/foo.B -> myrlm.B -> r/foo.A: r/foo +gnokey maketx call -pkgpath gno.land/r/foo -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stdout ${RFOO_ADDR} + +## 5. MsgCall -> p/demo/bar.A -> myrlm.A: user address +gnokey maketx call -pkgpath gno.land/p/demo/bar -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stdout ${USER_ADDR_test1} + +## 6. MsgCall -> p/demo/bar.B -> myrlm.B -> r/foo.A: user address +gnokey maketx call -pkgpath gno.land/p/demo/bar -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stdout ${USER_ADDR_test1} + +## 7. MsgRun -> myrlm.A: user address +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmA.gno +stdout ${USER_ADDR_test1} + +## 8. MsgRun -> myrealm.B -> myrlm.A: user address +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmB.gno +stdout ${USER_ADDR_test1} + +## 9. MsgRun -> r/foo.A -> myrlm.A: r/foo +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooA.gno +stdout ${RFOO_ADDR} + +## 10. MsgRun -> r/foo.B -> myrlm.B -> r/foo.A: r/foo +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooB.gno +stdout ${RFOO_ADDR} + +## 11. MsgRun -> p/demo/bar.A -> myrlm.A: user address +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/barA.gno +stdout ${USER_ADDR_test1} + +## 12. MsgRun -> p/demo/bar.B -> myrlm.B -> r/foo.A: user address +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/barB.gno +stdout ${USER_ADDR_test1} + +## 13. MsgCall -> std.PrevRealm(): user address +gnokey maketx call -pkgpath std -func PrevRealm -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stdout ${USER_ADDR_test1} + +## 14. MsgRun -> std.PrevRealm(): user address +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/baz.gno +stdout ${USER_ADDR_test1} + +-- r/myrlm/myrlm.gno -- +package myrlm + +import "std" + +func A() string { + return std.PrevRealm().Addr().String() +} + +func B() string { + return A() +} +-- r/foo/foo.gno -- +package foo + +import "gno.land/r/myrlm" + +func A() string { + return myrlm.A() +} + +func B() string { + return myrlm.B() +} +-- p/demo/bar/bar.gno -- +package bar + +import "gno.land/r/myrlm" + +func A() string { + return myrlm.A() +} + +func B() string { + return myrlm.B() +} +-- run/myrlmA.gno -- +package main + +import myrlm "gno.land/r/myrlm" + +func main() { + println(myrlm.A()) +} +-- run/myrlmB.gno -- +package main + +import "gno.land/r/myrlm" + +func main() { + println(myrlm.B()) +} +-- run/fooA.gno -- +package main + +import "gno.land/r/foo" + +func main() { + println(foo.A()) +} +-- run/fooB.gno -- +package main + +import "gno.land/r/foo" + +func main() { + println(foo.B()) +} +-- run/barA.gno -- +package main + +import "gno.land/p/demo/bar" + +func main() { + println(bar.A()) +} +-- run/barB.gno -- +package main + +import "gno.land/p/demo/bar" + +func main() { + println(bar.B()) +} +-- run/baz.gno -- +package main + +import "std" + +func main() { + println(std.PrevRealm().Addr().String()) +} diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index ef260bd3c42..ab7681bc3e1 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -6,7 +6,6 @@ import ( "bytes" "fmt" "os" - "regexp" "strings" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" @@ -131,8 +130,6 @@ func (vm *VMKeeper) getGnoStore(ctx sdk.Context) gno.Store { } } -var reRunPath = regexp.MustCompile(`gno\.land/r/g[a-z0-9]+/run`) - // AddPackage adds a package with given fileset. func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { creator := msg.Creator @@ -156,7 +153,7 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { return ErrInvalidPkgPath("package already exists: " + pkgPath) } - if reRunPath.MatchString(pkgPath) { + if gno.ReGnoRunPath.MatchString(pkgPath) { return ErrInvalidPkgPath("reserved package name: " + pkgPath) } diff --git a/gnovm/pkg/gnolang/realm.go b/gnovm/pkg/gnolang/realm.go index 3f615772426..17b655e6352 100644 --- a/gnovm/pkg/gnolang/realm.go +++ b/gnovm/pkg/gnolang/realm.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "reflect" + "regexp" "strings" ) @@ -1517,10 +1518,14 @@ func isUnsaved(oo Object) bool { // be realms and as such to have their state persisted. This is used by [IsRealmPath]. const realmPathPrefix = "gno.land/r/" +var ReGnoRunPath = regexp.MustCompile(`gno\.land/r/g[a-z0-9]+/run`) + // IsRealmPath determines whether the given pkgpath is for a realm, and as such // should persist the global state. func IsRealmPath(pkgPath string) bool { - return strings.HasPrefix(pkgPath, realmPathPrefix) + return strings.HasPrefix(pkgPath, realmPathPrefix) && + // MsgRun pkgPath aren't realms + !ReGnoRunPath.MatchString(pkgPath) } func prettyJSON(jstr []byte) []byte { diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 948730c4697..fda0a06f3d2 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -817,6 +817,7 @@ type PackageValue struct { fBlocksMap map[Name]*Block } +// IsRealm returns true if pv represents a realm. func (pv *PackageValue) IsRealm() bool { return IsRealmPath(pv.PkgPath) } diff --git a/gnovm/pkg/transpiler/transpiler.go b/gnovm/pkg/transpiler/transpiler.go index cc49aac4c78..e3d817700d0 100644 --- a/gnovm/pkg/transpiler/transpiler.go +++ b/gnovm/pkg/transpiler/transpiler.go @@ -231,7 +231,7 @@ func TranspileBuildPackage(fileOrPkg, goBinary string) error { return err } -var errorRe = regexp.MustCompile(`(?m)^(\S+):(\d+):(\d+): (.+)$`) +var reGoBuildError = regexp.MustCompile(`(?m)^(\S+):(\d+):(\d+): (.+)$`) // parseGoBuildErrors returns a scanner.ErrorList filled with all errors found // in out, which is supposed to be the output of the `go build` command. @@ -240,7 +240,7 @@ var errorRe = regexp.MustCompile(`(?m)^(\S+):(\d+):(\d+): (.+)$`) // See https://github.com/golang/go/issues/62067 func parseGoBuildErrors(out string) error { var errList goscanner.ErrorList - matches := errorRe.FindAllStringSubmatch(out, -1) + matches := reGoBuildError.FindAllStringSubmatch(out, -1) for _, match := range matches { filename := match[1] line, err := strconv.Atoi(match[2])