From f4e487bf3a48120c6578744a8e70b665fee8cbd8 Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Fri, 1 Mar 2024 16:54:36 +0100 Subject: [PATCH 1/4] feat: PrevRealm ignores user realms Fix #1664 As commented in the IsRealm() method, a better format of user realms should emerge in the form of `gno.land/u/user_address`, which would remove the confusion between standard realms and the realm forged under the MsgRun transaction. --- gno.land/cmd/gnoland/testdata/prevrealm.txtar | 188 ++++++++++++++++++ gnovm/pkg/gnolang/values.go | 9 +- 2 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 gno.land/cmd/gnoland/testdata/prevrealm.txtar diff --git a/gno.land/cmd/gnoland/testdata/prevrealm.txtar b/gno.land/cmd/gnoland/testdata/prevrealm.txtar new file mode 100644 index 00000000000..f583dc9fa09 --- /dev/null +++ b/gno.land/cmd/gnoland/testdata/prevrealm.txtar @@ -0,0 +1,188 @@ +# 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 +## start a new node +gnoland start + +## deploy myrlm +gnokey maketx addpkg -pkgdir $WORK/r/myrlm -pkgpath gno.land/r/myrlm -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +stdout 'OK!' + +## deploy r/foo +gnokey maketx addpkg -pkgdir $WORK/r/foo -pkgpath gno.land/r/foo -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +stdout 'OK!' + +## deploy p/demo/bar +gnokey maketx addpkg -pkgdir $WORK/p/demo/bar -pkgpath gno.land/p/demo/bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +stdout 'OK!' + +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/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 85e6562eca6..5234b4a0470 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -816,8 +816,15 @@ type PackageValue struct { fBlocksMap map[Name]*Block } +// IsRealm returns true if pv represents a realm. +// A user realm, forged by the MsgRun transaction, isn't considered as a realm. +// XXX The user realm format is: +// PkgPath="gno.land/r/user_address" PkgName="main" +// A less confusing format could emerge in the future, with the form of +// PkgPath="gno.land/u/user_address" func (pv *PackageValue) IsRealm() bool { - return IsRealmPath(pv.PkgPath) + return IsRealmPath(pv.PkgPath) && + pv.PkgName != "main" // Discard user realms forged by MsgRun } func (pv *PackageValue) getFBlocksMap() map[Name]*Block { From f103d97a2a13f927c759de69412cecb409b09a2c Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Thu, 7 Mar 2024 09:44:20 +0100 Subject: [PATCH 2/4] use regexp defined in vmkeeper to distinguish MsgRun path --- gno.land/pkg/sdk/vm/keeper.go | 5 +---- gnovm/pkg/gnolang/precompile.go | 4 ++-- gnovm/pkg/gnolang/realm.go | 11 ++++++----- gnovm/pkg/gnolang/values.go | 8 +------- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index 54f424ee058..f39343831be 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) error { creator := msg.Creator @@ -156,7 +153,7 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) 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/precompile.go b/gnovm/pkg/gnolang/precompile.go index af51e962416..b1e57094c32 100644 --- a/gnovm/pkg/gnolang/precompile.go +++ b/gnovm/pkg/gnolang/precompile.go @@ -265,7 +265,7 @@ func PrecompileBuildPackage(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. @@ -275,7 +275,7 @@ var errorRe = regexp.MustCompile(`(?m)^(\S+):(\d+):(\d+): (.+)$`) // (see [Precompile] for that header). 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]) diff --git a/gnovm/pkg/gnolang/realm.go b/gnovm/pkg/gnolang/realm.go index 519b183ad3a..8846ad864bf 100644 --- a/gnovm/pkg/gnolang/realm.go +++ b/gnovm/pkg/gnolang/realm.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "reflect" + "regexp" "strings" ) @@ -1511,13 +1512,13 @@ func isUnsaved(oo Object) bool { return oo.GetIsNewReal() || oo.GetIsDirty() } +var ReGnoRunPath = regexp.MustCompile(`gno\.land/r/g[a-z0-9]+/run`) + func IsRealmPath(pkgPath string) bool { // TODO: make it more distinct to distinguish from normal paths. - if strings.HasPrefix(pkgPath, GnoRealmPkgsPrefixBefore) { - return true - } else { - return false - } + return strings.HasPrefix(pkgPath, GnoRealmPkgsPrefixBefore) && + // 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 5234b4a0470..e999c6e69f3 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -817,14 +817,8 @@ type PackageValue struct { } // IsRealm returns true if pv represents a realm. -// A user realm, forged by the MsgRun transaction, isn't considered as a realm. -// XXX The user realm format is: -// PkgPath="gno.land/r/user_address" PkgName="main" -// A less confusing format could emerge in the future, with the form of -// PkgPath="gno.land/u/user_address" func (pv *PackageValue) IsRealm() bool { - return IsRealmPath(pv.PkgPath) && - pv.PkgName != "main" // Discard user realms forged by MsgRun + return IsRealmPath(pv.PkgPath) } func (pv *PackageValue) getFBlocksMap() map[Name]*Block { From f70b104dddcfe7cfda87634d8f2f36ece5629040 Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Wed, 15 May 2024 15:15:21 +0200 Subject: [PATCH 3/4] test: fix gas-wanted --- gno.land/cmd/gnoland/testdata/prevrealm.txtar | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gno.land/cmd/gnoland/testdata/prevrealm.txtar b/gno.land/cmd/gnoland/testdata/prevrealm.txtar index f583dc9fa09..cc1f63dd0e9 100644 --- a/gno.land/cmd/gnoland/testdata/prevrealm.txtar +++ b/gno.land/cmd/gnoland/testdata/prevrealm.txtar @@ -24,7 +24,7 @@ gnoland start ## deploy myrlm -gnokey maketx addpkg -pkgdir $WORK/r/myrlm -pkgpath gno.land/r/myrlm -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK/r/myrlm -pkgpath gno.land/r/myrlm -gas-fee 1000000ugnot -gas-wanted 2100000 -broadcast -chainid=tendermint_test test1 stdout 'OK!' ## deploy r/foo From 89f6938acbf9daac1c9614f5c1e627c772649cfd Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Thu, 23 May 2024 09:55:21 +0200 Subject: [PATCH 4/4] test: use loadpkg testscript cmd --- gno.land/cmd/gnoland/testdata/prevrealm.txtar | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/gno.land/cmd/gnoland/testdata/prevrealm.txtar b/gno.land/cmd/gnoland/testdata/prevrealm.txtar index cc1f63dd0e9..ac7988616a4 100644 --- a/gno.land/cmd/gnoland/testdata/prevrealm.txtar +++ b/gno.land/cmd/gnoland/testdata/prevrealm.txtar @@ -20,20 +20,15 @@ # | 14 | MsgRun | wallet direct | std.PrevRealm() | user address | # Init -## start a new node -gnoland start - ## deploy myrlm -gnokey maketx addpkg -pkgdir $WORK/r/myrlm -pkgpath gno.land/r/myrlm -gas-fee 1000000ugnot -gas-wanted 2100000 -broadcast -chainid=tendermint_test test1 -stdout 'OK!' - +loadpkg gno.land/r/myrlm $WORK/r/myrlm ## deploy r/foo -gnokey maketx addpkg -pkgdir $WORK/r/foo -pkgpath gno.land/r/foo -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 -stdout 'OK!' - +loadpkg gno.land/r/foo $WORK/r/foo ## deploy p/demo/bar -gnokey maketx addpkg -pkgdir $WORK/p/demo/bar -pkgpath gno.land/p/demo/bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 -stdout 'OK!' +loadpkg gno.land/p/demo/bar $WORK/p/demo/bar + +## start a new node +gnoland start env RFOO_ADDR=g1evezrh92xaucffmtgsaa3rvmz5s8kedffsg469