Skip to content

Commit

Permalink
feat(std): PrevRealm ignores user realms in MsgRun (#1719)
Browse files Browse the repository at this point in the history
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.

BREAKING CHANGE: `std.PrevRealm` is not returning the user realm any
more when invoked under a transaction broadcasted by `MsgRun`.

To run the txtar test:
```
$ go test ./gno.land/cmd/gnoland/ -v -run TestTestdata/prevrealm
```

<!-- please provide a detailed description of the changes made in this
pull request. -->

<details><summary>Contributors' checklist...</summary>

- [x] Added new tests, or not needed, or not feasible
- [ ] Provided an example (e.g. screenshot) to aid review or the PR is
self-explanatory
- [ ] Updated the official documentation or not needed
- [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message
was included in the description
- [x] Added references to related issues and PRs
- [x] Provided any useful hints for running manual tests
- [ ] Added new benchmarks to [generated
graphs](https://gnoland.github.io/benchmarks), if any. More info
[here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
</details>
  • Loading branch information
tbruyelle authored May 23, 2024
1 parent e1586a5 commit f165df7
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 7 deletions.
183 changes: 183 additions & 0 deletions gno.land/cmd/gnoland/testdata/prevrealm.txtar
Original file line number Diff line number Diff line change
@@ -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())
}
5 changes: 1 addition & 4 deletions gno.land/pkg/sdk/vm/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"bytes"
"fmt"
"os"
"regexp"
"strings"

gno "github.com/gnolang/gno/gnovm/pkg/gnolang"
Expand Down Expand Up @@ -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
Expand All @@ -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)
}

Expand Down
7 changes: 6 additions & 1 deletion gnovm/pkg/gnolang/realm.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"reflect"
"regexp"
"strings"
)

Expand Down Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions gnovm/pkg/gnolang/values.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
4 changes: 2 additions & 2 deletions gnovm/pkg/transpiler/transpiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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])
Expand Down

0 comments on commit f165df7

Please sign in to comment.