Skip to content

Commit

Permalink
feat(gnovm): forbid importing realms in packages (#3042)
Browse files Browse the repository at this point in the history
Closes #3040 
50% of the work comes from @harry-hov's PR #1393 (let's repay to Caesar
what belongs to Caesar) 🚀

Notable additions:
- handle different domains (e.g github.com/p/demo/...)
- skip non ``.gno`` files (LICENSE, README, ...) or empty files


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

- [x] Added new tests, or not needed, or not feasible
- [x] Provided an example (e.g. screenshot) to aid review or the PR is
self-explanatory
- [x] 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
</details>

---------

Co-authored-by: n0izn0iz <[email protected]>
Co-authored-by: Morgan <[email protected]>
Co-authored-by: Morgan <[email protected]>
  • Loading branch information
4 people authored Nov 26, 2024
1 parent 18e4eb9 commit 4004ba1
Show file tree
Hide file tree
Showing 11 changed files with 60 additions and 77 deletions.
5 changes: 1 addition & 4 deletions examples/gno.land/p/demo/groups/gno.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
module gno.land/p/demo/groups

require (
gno.land/p/demo/rat v0.0.0-latest
gno.land/r/demo/boards v0.0.0-latest
)
require gno.land/p/demo/rat v0.0.0-latest
8 changes: 0 additions & 8 deletions examples/gno.land/p/demo/groups/groups.gno

This file was deleted.

1 change: 0 additions & 1 deletion examples/gno.land/p/demo/tests/gno.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ module gno.land/p/demo/tests
require (
gno.land/p/demo/tests/subtests v0.0.0-latest
gno.land/p/demo/uassert v0.0.0-latest
gno.land/r/demo/tests v0.0.0-latest
)
13 changes: 0 additions & 13 deletions examples/gno.land/p/demo/tests/tests.gno
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,10 @@ import (
"std"

psubtests "gno.land/p/demo/tests/subtests"
"gno.land/r/demo/tests"
rtests "gno.land/r/demo/tests"
)

const World = "world"

// IncCounter demonstrates that it's possible to call a realm function from
// a package. So a package can potentially write into the store, by calling
// an other realm.
func IncCounter() {
tests.IncCounter()
}

func CurrentRealmPath() string {
return std.CurrentRealm().PkgPath()
}
Expand Down Expand Up @@ -64,10 +55,6 @@ func GetPSubtestsPrevRealm() std.Realm {
return psubtests.GetPrevRealm()
}

func GetRTestsGetPrevRealm() std.Realm {
return rtests.GetPrevRealm()
}

// Warning: unsafe pattern.
func Exec(fn func()) {
fn()
Expand Down
16 changes: 0 additions & 16 deletions examples/gno.land/p/demo/tests/z0_filetest.gno

This file was deleted.

29 changes: 15 additions & 14 deletions gno.land/cmd/gnoland/testdata/assertorigincall.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@
# | 4 | | through /r/foo | myrealm.A() | PANIC |
# | 5 | | | myrealm.B() | pass |
# | 6 | | | myrealm.C() | PANIC |
# | 7 | | through /p/demo/bar | myrealm.A() | PANIC |
# | 8 | | | myrealm.B() | pass |
# | 9 | | | myrealm.C() | PANIC |
# | 7 | | through /p/demo/bar | bar.A() | PANIC |
# | 8 | | | bar.B() | pass |
# | 9 | | | bar.C() | PANIC |
# | 10 | MsgRun | wallet direct | myrealm.A() | PANIC |
# | 11 | | | myrealm.B() | pass |
# | 12 | | | myrealm.C() | PANIC |
# | 13 | | through /r/foo | myrealm.A() | PANIC |
# | 14 | | | myrealm.B() | pass |
# | 15 | | | myrealm.C() | PANIC |
# | 16 | | through /p/demo/bar | myrealm.A() | PANIC |
# | 17 | | | myrealm.B() | pass |
# | 18 | | | myrealm.C() | PANIC |
# | 16 | | through /p/demo/bar | bar.A() | PANIC |
# | 17 | | | bar.B() | pass |
# | 18 | | | bar.C() | PANIC |
# | 19 | MsgCall | wallet direct | std.AssertOriginCall() | pass |
# | 20 | MsgRun | wallet direct | std.AssertOriginCall() | PANIC |

Expand Down Expand Up @@ -57,15 +57,15 @@ stdout 'OK!'
stderr 'invalid non-origin call'

## remove due to update to maketx call can only call realm (case 7,8,9)
## 7. MsgCall -> p/demo/bar.A -> myrlm.A: PANIC
## 7. MsgCall -> p/demo/bar.A: PANIC
## ! gnokey maketx call -pkgpath gno.land/p/demo/bar -func A -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1
## stderr 'invalid non-origin call'

## 8. MsgCall -> p/demo/bar.B -> myrlm.B: PASS
## 8. MsgCall -> p/demo/bar.B: PASS
## gnokey maketx call -pkgpath gno.land/p/demo/bar -func B -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1
## stdout 'OK!'

## 9. MsgCall -> p/demo/bar.C -> myrlm.C: PANIC
## 9. MsgCall -> p/demo/bar.C: PANIC
## ! gnokey maketx call -pkgpath gno.land/p/demo/bar -func C -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1
## stderr 'invalid non-origin call'

Expand Down Expand Up @@ -152,18 +152,19 @@ func C() {
-- p/demo/bar/bar.gno --
package bar

import "gno.land/r/myrlm"
import "std"

func A() {
myrlm.A()
C()
}

func B() {
myrlm.B()
if false {
C()
}
}

func C() {
myrlm.C()
std.AssertOriginCall()
}
-- run/myrlmA.gno --
package main
Expand Down
22 changes: 11 additions & 11 deletions gno.land/cmd/gnoland/testdata/prevrealm.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
# | 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 |
# | 5 | | through /p/demo/bar | bar.A() | user address |
# | 6 | | | bar.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 |
# | 11 | | through /p/demo/bar | bar.A() | user address |
# | 12 | | | bar.B() | user address |
# | 13 | MsgCall | wallet direct | std.PrevRealm() | user address |
# | 14 | MsgRun | wallet direct | std.PrevRealm() | user address |

Expand Down Expand Up @@ -50,11 +50,11 @@ gnokey maketx call -pkgpath gno.land/r/foo -func B -gas-fee 100000ugnot -gas-wan
stdout ${RFOO_ADDR}

## remove due to update to maketx call can only call realm (case 5, 6, 13)
## 5. MsgCall -> p/demo/bar.A -> myrlm.A: user address
## 5. MsgCall -> p/demo/bar.A: user address
## gnokey maketx call -pkgpath gno.land/p/demo/bar -func A -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1
## stdout ${USER_ADDR_test1}

## 6. MsgCall -> p/demo/bar.B -> myrlm.B -> r/foo.A: user address
## 6. MsgCall -> p/demo/bar.B: user address
## gnokey maketx call -pkgpath gno.land/p/demo/bar -func B -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1
## stdout ${USER_ADDR_test1}

Expand All @@ -74,11 +74,11 @@ stdout ${RFOO_ADDR}
gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooB.gno
stdout ${RFOO_ADDR}

## 11. MsgRun -> p/demo/bar.A -> myrlm.A: user address
## 11. MsgRun -> p/demo/bar.A: user address
gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -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
## 12. MsgRun -> p/demo/bar.B: user address
gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/barB.gno
stdout ${USER_ADDR_test1}

Expand Down Expand Up @@ -117,14 +117,14 @@ func B() string {
-- p/demo/bar/bar.gno --
package bar

import "gno.land/r/myrlm"
import "std"

func A() string {
return myrlm.A()
return std.PrevRealm().Addr().String()
}

func B() string {
return myrlm.B()
return A()
}
-- run/myrlmA.gno --
package main
Expand Down
12 changes: 11 additions & 1 deletion gnovm/pkg/gnolang/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import (

// RealmPathPrefix is the prefix used to identify pkgpaths which are meant to
// be realms and as such to have their state persisted. This is used by [IsRealmPath].
const RealmPathPrefix = "gno.land/r/"
const (
RealmPathPrefix = "gno.land/r/"
PackagePathPrefix = "gno.land/p/"
)

// ReGnoRunPath is the path used for realms executed in maketx run.
// These are not considered realms, as an exception to the RealmPathPrefix rule.
Expand All @@ -26,6 +29,13 @@ func IsRealmPath(pkgPath string) bool {
!ReGnoRunPath.MatchString(pkgPath)
}

// IsPurePackagePath determines whether the given pkgpath is for a published Gno package.
// It only considers "pure" those starting with gno.land/p/, so it returns false for
// stdlib packages and MsgRun paths.
func IsPurePackagePath(pkgPath string) bool {
return strings.HasPrefix(pkgPath, PackagePathPrefix)
}

// IsStdlib determines whether s is a pkgpath for a standard library.
func IsStdlib(s string) bool {
// NOTE(morgan): this is likely to change in the future as we add support for
Expand Down
7 changes: 7 additions & 0 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,13 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) {
case *ImportDecl:
nx := &n.NameExpr
nn := nx.Name
loc := last.GetLocation()
// NOTE: imports from "pure packages" are actually sometimes
// allowed, most notably in MsgRun and filetests; IsPurePackagePath
// returns false in these cases.
if IsPurePackagePath(loc.PkgPath) && IsRealmPath(n.PkgPath) {
panic(fmt.Sprintf("pure package path %q cannot import realm path %q", loc.PkgPath, n.PkgPath))
}
if nn == "." {
panic("dot imports not allowed in gno")
}
Expand Down
13 changes: 13 additions & 0 deletions gnovm/tests/files/import11.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// PKGPATH: gno.land/p/demo/bar
package bar

import (
"gno.land/r/demo/tests"
)

func main() {
println(tests.Counter())
}

// Error:
// gno.land/p/demo/bar/files/import11.gno:5:2: pure package path "gno.land/p/demo/bar" cannot import realm path "gno.land/r/demo/tests"
11 changes: 2 additions & 9 deletions gnovm/tests/files/zrealm_crossrealm11.gno
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
package crossrealm_test

import (
"std"

ptests "gno.land/p/demo/tests"
"gno.land/p/demo/ufmt"
rtests "gno.land/r/demo/tests"
"std"
)

func getPrevRealm() std.Realm {
Expand Down Expand Up @@ -64,10 +65,6 @@ func main() {
callStackAdd: " -> r/demo/tests -> r/demo/tests/subtests",
callerFn: rtests.GetRSubtestsPrevRealm,
},
{
callStackAdd: " -> p/demo/tests -> r/demo/tests",
callerFn: ptests.GetRTestsGetPrevRealm,
},
}

println("---") // needed to have space prefixes
Expand Down Expand Up @@ -140,7 +137,3 @@ func printColumns(left, right string) {
// user1.gno -> r/crossrealm_test.main -> r/crossrealm_test.Exec -> r/demo/tests -> r/demo/tests/subtests = gno.land/r/demo/tests
// user1.gno -> r/crossrealm_test.main -> r/demo/tests.Exec -> r/demo/tests -> r/demo/tests/subtests = gno.land/r/demo/tests
// user1.gno -> r/crossrealm_test.main -> p/demo/tests.Exec -> r/demo/tests -> r/demo/tests/subtests = gno.land/r/demo/tests
// user1.gno -> r/crossrealm_test.main -> p/demo/tests -> r/demo/tests = gno.land/r/crossrealm_test
// user1.gno -> r/crossrealm_test.main -> r/crossrealm_test.Exec -> p/demo/tests -> r/demo/tests = gno.land/r/crossrealm_test
// user1.gno -> r/crossrealm_test.main -> r/demo/tests.Exec -> p/demo/tests -> r/demo/tests = gno.land/r/crossrealm_test
// user1.gno -> r/crossrealm_test.main -> p/demo/tests.Exec -> p/demo/tests -> r/demo/tests = gno.land/r/crossrealm_test

0 comments on commit 4004ba1

Please sign in to comment.