Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
3196a9e
fix(txtar): use previous realm, rework prev realm
gfanton Apr 22, 2025
b971800
fix(txtar): update Render msgcall to use qeval
gfanton Apr 22, 2025
3f1b72b
fix(txtar): assert origin call
gfanton Apr 22, 2025
5832c33
fix(txtar): loadpkg_work
gfanton Apr 22, 2025
239e7b7
fix(txtar): realm call
gfanton Apr 22, 2025
0a44fc9
fix(txtar): issue 1543, issue 1786, issue 2266
gfanton Apr 22, 2025
f663354
fix(txtar): sysparams
gfanton Apr 22, 2025
d0698ec
fix(txtar): realm_banker_issued_coin_denom
gfanton Apr 22, 2025
1a0eeb9
chore: fixup
moul Apr 23, 2025
7471870
chore: fixup
moul Apr 23, 2025
1560def
chore: fixup
moul Apr 23, 2025
1b75cfd
types declared in funcs have DeclaredType.Loc set for disambiugation
jaekwon Apr 24, 2025
2df0713
fix(examples): gno.land/r/x/jeronimo_render_proxy
jeronimoalbi Apr 24, 2025
bb88a73
fix(examples): restored expected behavior for Ownable (#4207)
n2p5 Apr 24, 2025
55484b3
added INMEMORY_TS=true message
jaekwon Apr 24, 2025
fe91728
init() in realm functions crossed from deployer in frame -1
jaekwon Apr 25, 2025
a65358d
minor error string fix
jaekwon Apr 25, 2025
a7131a6
fix gnoland/home; fix ownable
ltzmaxwell Apr 25, 2025
a8a5630
fix grc20; subscription; memland;authorizable
ltzmaxwell Apr 25, 2025
7b0bf47
ownable.NewWithOrigin(); reverted original error messages; remove tra…
jaekwon Apr 26, 2025
f1ac3c7
fix grc20 tests
jaekwon Apr 26, 2025
f80ab6f
fix memeland tests
jaekwon Apr 26, 2025
91942b4
complete ownable tests fix
jaekwon Apr 26, 2025
6f57a7f
fix again memeland tests
jaekwon Apr 26, 2025
be46ffe
fix subscription tests
jaekwon Apr 26, 2025
ce2bea9
testing.SetRealm(std.NewUserRealm(addr)) == testing.SetOriginCaller(a…
jaekwon Apr 26, 2025
6a2eb64
PreviousRealm -> CurrentRealm
jaekwon Apr 26, 2025
6777cca
frame not found: cannot seek beyond origin caller override
jaekwon Apr 26, 2025
aa5c0e6
fix moul/debug
jaekwon Apr 26, 2025
5258356
fix loci/mgroup
jaekwon Apr 26, 2025
4937369
fix moul/* tests
jaekwon Apr 26, 2025
e2bfb01
fix gno.land/p/oxtekgrinder/ownable2step
jaekwon Apr 26, 2025
e6ecfed
fix gno.land/p/wyhaines/rand tests
jaekwon Apr 26, 2025
6f29d98
fix demo/atomicswap
jaekwon Apr 26, 2025
0005e86
fix non render boards filetests
jeronimoalbi Apr 27, 2025
48b10f5
Add files via upload
piux2 Apr 27, 2025
dd896bd
Create gno.mod
piux2 Apr 27, 2025
85f4f08
verify previous realm
piux2 Apr 27, 2025
56785a7
verify previous realm
piux2 Apr 27, 2025
4ccc2f0
fix test realm name
piux2 Apr 27, 2025
97908a2
consistent message output
piux2 Apr 28, 2025
5717b0a
fix fun29.gno; fixes https://github.com/gnolang/gno/pull/4211#issueco…
jaekwon Apr 28, 2025
a6de0ee
add test cases for prior
jaekwon Apr 28, 2025
c57e5a7
added current realm cross tests
piux2 Apr 28, 2025
5514d2e
Merge branch 'fix/crossrealm/examples-integrations' of https://github…
piux2 Apr 28, 2025
bb03b95
added current realm cross tests
piux2 Apr 28, 2025
e90ebfe
fix render related board filetests
jeronimoalbi Apr 28, 2025
a8f2ca5
fx(example): r/demo/profile/profile crossing
gfanton Apr 28, 2025
27fe126
Update examples/gno.land/r/stefann/fomo3d/fomo3d.gno
moul Apr 28, 2025
2ad7064
Update examples/gno.land/r/demo/banktest/banktest.gno
moul Apr 28, 2025
6fa99a4
add gno-interrealm usage
jaekwon Apr 28, 2025
8fec35f
update gno-interrealm with more usage guide
jaekwon Apr 28, 2025
3a48feb
MsgCall from gno.land to crossing functions returns std.PreviousRealm…
jaekwon Apr 28, 2025
1782f4c
fix(examples): grc20factory
gfanton Apr 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
321 changes: 321 additions & 0 deletions docs/resources/gno-interrealm.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,324 @@ be upgraded.

Both `crossing()` and `cross(fn)(...)` statements may become special syntax in
future Gno versions.

### Usage

P package code cannot containing crossing functions, nor use crossing(). P
package code also cannot import R realm packages. But code can call named
crossing functions e.g. those passed in as parameters.

You must declare a public realm function to be crossing() if it is intended to
be called by end users, because users cannot MsgCall non-crossing functions
(for safety/consistency) or p package functions (there's no point).

Utility functions that are a common sequence of non-crossing logic can be
offered in realm packages as non-crossing functions. These can also import and
use other realm utility non-crossing functions; whereas p packages cannot
import realm packages at all. And convenience/utility functions that are being
staged before publishing as permanent p code should also reside in upgreadeable
realms.

Generally you want your methods to be non-crossing. Because they should work
for everyone. They are functions that are pre-bound to an object, and that
object is like a quasi-realm in itself, that could reside and migrate to other
realms possibly. This is consistent with any p code copied over to r realms;
none of those methods would be crossing, and behavior would be the same; stored
in any realm, mostly non-crossing methods that anyone can call. Why is a
quasi-realm self-encapsulated Object in need to modify the realm in which it is
declared, by crossing? That's intrusive, but sometimes desired.

You can always cross-call a method from a non-crossing method if you need it.

Implementation for `std.CurrentRealm()` and `std.PreviousRealm()` are defined
in `stdlibs/std/native.gno/go` and related files in the directory, while
overrides for testing are defined in `testing/stdlibs/std/std.gno/go`. All
stdlibs functions are available unless overridden by the latter.

`std.CurrentRealm()` shifts to `std.PreviousRealm()` if and only if a function
is called like cross(fn)(...).

#### MsgCall

MsgCall may only call crossing functions. This is to prevent potential
confusion of non-sophisticated users. Non-crossing calls of non-crossing
functions of other realms is still possible with MsgRun.

```go
// PKGPATH: gno.land/r/test/test

func Public() {
crossing()

// Returns (
// addr:<origin_caller>,
// pkgpath:""
// ) == std.NewUserRealm(origin_caller)
std.PreviousRealm()

// Returns (
// addr:<derived_from "gno.land/r/test/test">,
// pkgpath:"gno.land/r/test/test"
// ) == std.NewCodeRealm("gno.land/r/test/test")
std.CurrentRealm()

// Already in gno.land/r/test/test realm,
// no need to cross unless the intent
// is to call AnotherPublic() as a consumer
// in which case cross(AnotherPublic)() needed.
AnotherPublic()
}

func AnotherPublic() {
crossing()
...
}
```

#### MsgRun

```go
// PKGPATH: gno.land/r/g1user/run

import "gno.land/r/realmA"

func main() {
// There is assumed to be in "frame -1"
// a crossing from UserRealm(g1user) to
// CodeRealm(gno.land/r/g1user/run) before
// main() is called, so crossing() here
// is redundant.
// crossing()

// Returns (
// addr:g1user,
// pkgpath:""
// ) == std.NewUserRealm(g1user)
std.PreviousRealm()

// Returns (
// addr:g1user,
// pkgpath:"gno.land/r/g1user/run"
// ) == std.NewCodeRealm("gno.land/r/g1user/run")
std.CurrentRealm()

realmA.PublicNoncrossing()
cross(realmA.PublicCrossing)()
}
```

Notice in gnovm/pkg/gnolang/misc.go, the following:

```go
// For keeping record of package & realm coins.
// If you need the bech32 address it is faster to call DerivePkgBech32Addr().
func DerivePkgCryptoAddr(pkgPath string) crypto.Address {
b32addr, ok := IsGnoRunPath(pkgPath)
if ok {
addr, err := crypto.AddressFromBech32(b32addr)
if err != nil {
panic("invalid bech32 address in run path: " + pkgPath)
}
return addr
}
// NOTE: must not collide with pubkey addrs.
return crypto.AddressFromPreimage([]byte("pkgPath:" + pkgPath))
}

func DerivePkgBech32Addr(pkgPath string) crypto.Bech32Address {
b32addr, ok := IsGnoRunPath(pkgPath)
if ok {
return crypto.Bech32Address(b32addr)
}
// NOTE: must not collide with pubkey addrs.
return crypto.AddressFromPreimage([]byte("pkgPath:" + pkgPath)).Bech32()
}
```

These function names are distinct from what is available in Gno
from stdlibs/std/crypto.gno:

```go
// Returns a crypto hash derived pkgPath, unless pkgPath is a MsgRun run path,
// in which case the address is extracted from the path.
func DerivePkgAddr(pkgPath string) Address {
addr := derivePkgAddr(pkgPath) <-- calls gno.DerivePkgBech32Addr()
return Address(addr)
}
```

1. `std.DerivePkgAddr("gno.land/r/name123/realm")` - bech32 from hash(path)
2. `std.DerivePkgAddr("gno.land/r/g1user/run")` - bech32 substring "g1user"

Therefore in the MsgRun file's init() function the previous realm and current
realm have different pkgpaths (the origin caller always has empty pkgpath) but
the address is the same.

#### MsgAddPackage

During MsgAddPackage `std.PreviousRealm()` refers to the package deployer both
in gloval var decls as well as inside `init()` functions. After that the
package deployer is no longer provided, so packages need to remember the
deployer in the initialization if needed.

```go
// PKGPATH: gno.land/r/test/test

func init() {
// Returns (
// addr:<origin_deployer>,
// pkgpath:""
// ) == std.NewUserRealm(origin_deployer)
// Inside init() and global var decls
// are the only time std.PreviousRealm()
// returns the deployer of the package.
// Save it here or lose it forever.
std.PreviousRealm()

// Returns (
// addr:<origin_deployer>,
// pkgpath:"gno.land/r/test/test"
// ) == std.NewCodeRealm("gno.land/r/test/test")
std.CurrentRealm()
}

// Same as in init().
var _ = std.PreviousRealm()
```

```go
// PKGPATH: gno.land/r/g1user/run

func init() {
// Returns (
// addr:g1user,
// pkgpath:""
// ) == std.NewUserRealm(g1user)
std.PreviousRealm()

// Returns (
// addr:g1user,
// pkgpath:"gno.land/r/g1user/run"
// ) == std.NewCodeRealm("gno.land/r/g1user/run")
std.CurrentRealm()
}
```

The same applies for p package initialization. Initialization and tests are the
only times that `std.CurrentRealm()` will return a p package path that starts
with "/p/" instead of "/r/". The package is technically still mutable during
initialization.

#### Testing overrides with stdlibs/testing

The `gnovm/tests/stdlibs/testing/context_testing.gno` file provides functions
for overriding frame details from Gno test code.

`testing.SetRealm(std.NewUserRealm("g1user"))` is identical to
`testing.SetOriginCaller("g1user"). Both will override the Gno frame to make it
appear as if the current frame is the end user signing with a hardware signer.
Both will also set ExecContext.OriginCaller to that user. One of these will
become deprecated.

#### Gno test cases with `_test.gno` like `TestFoo(t *testing.T)`

```go
// PKGPATH: gno.land/r/user/myrealm
package myrealm

import (
"std"
"stdlibs/testing"
)

func TestFoo(t *testing.T) {
// At first OriginCaller is not set.

// Override the OriginCaller.
testing.SetRealm(std.NewUserRealm("g1user"))

// Identical behavior:
testing.SetOriginCaller("g1user")

// This panics now: seeking beyond the overridden origin frame:
// std.PreviousRealm()

// Simulate g1user cross-calling Public().
// Produce a new frame to override
func() {
testing.SetRealm(std.SetCodeRealm("gno.land/r/user/myrealm"))

std.PreviousRealm() // "g1user", ""
std.CurrentRealm() // bech32(hash("gno.land/r/user/myrealm")), "gno.land/r/user/myrealm"

Public(...) // already in "gno.land/r/user/myrealm"
}()

// The following is identical to the above,
// but not possible in p packages which
// cannot import realms.
cross(Public)(...)
}
```

#### Gno filetest cases with `_filetest.gno`

```go
// PKGPATH: gno.land/r/test/test
package test

import (
"std"
"stdlibs/testing"

"gno.land/r/user/myrealm"
)

func init() {
// XXX Frame not found, there is no deployer for filetests.
std.PreviousRealm()

// Returns (
// addr:std.DerivePkgAddr("gno.land/r/test/test")
// pkgpath:"gno.land/r/test/test"
// ) == std.NewCodeRealm("gno.land/r/test/test")
std.CurrentRealm()
}

func main() {
// There is assumed to be in "frame -1"
// a crossing from UserRealm(g1user) to
// CodeRealm(gno.land/r/test/test) before
// main() is called, so crossing() here
// is redundant.
// crossing()

// Returns (
// addr:g1user,
// pkgpath:""
// ) == std.NewUserRealm(g1user)
std.PreviousRealm()

// Returns (
// addr:g1user,
// pkgpath:"gno.land/r/test/test"
// ) == std.NewCodeRealm("gno.land/r/test/test")
std.CurrentRealm()

// gno.land/r/test/test cross-calling
// gno.land/r/user/myrealm:
cross(myrealm.Public)(...)
}

// Output:
// XXX
```

#### Future Work

std.SetOriginCaller() should maybe be deprecated in favor of
std.SetRealm(std.NewUserRealm(user)) renamed to
std.SetRealm(std.NewOriginRealm(user)).

std.SetRealm(std.NewCodeRealm(path)) renamed to
std.SetRealm(std.NewPackageRealm(path)).
2 changes: 1 addition & 1 deletion examples/gno.land/p/agherasie/forms/create.gno
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (db *FormDB) CreateForm(title string, description string, openAt string, cl
// Creating the form
form := Form{
ID: id,
Owner: std.PreviousRealm().Address(),
Owner: std.CurrentRealm().Address(),
Title: title,
Description: description,
CreatedAt: time.Now(),
Expand Down
5 changes: 3 additions & 2 deletions examples/gno.land/p/agherasie/forms/create_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import (
func TestCreateForm(t *testing.T) {
alice := testutils.TestAddress("alice")
testing.SetOriginCaller(alice)
testing.SetRealm(std.NewUserRealm("g1user"))
testing.SetRealm(std.NewUserRealm(alice))

db := NewDB()
title := "Simple Form"
description := "This is a form"
Expand Down Expand Up @@ -58,7 +59,7 @@ func TestCreateForm(t *testing.T) {
}

urequire.True(t, form.ID == id, "Form ID is not correct")
urequire.True(t, form.Owner == alice, "Owner is not correct")
urequire.Equal(t, form.Owner, alice, "Owner is not correct")
urequire.True(t, form.Title == title, "Title is not correct")
urequire.True(t, form.Description == description, "Description is not correct")
urequire.True(t, len(form.Fields) == 5, "Not enough fields were provided")
Expand Down
4 changes: 2 additions & 2 deletions examples/gno.land/p/agherasie/forms/submit.gno
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func (db *FormDB) SubmitForm(formID string, answers string) {
}

// Check if form was already submitted by this user
previousAnswer, err := db.GetAnswer(formID, std.PreviousRealm().Address())
previousAnswer, err := db.GetAnswer(formID, std.CurrentRealm().Address())
if previousAnswer != nil {
panic(errAlreadySubmitted)
}
Expand All @@ -33,7 +33,7 @@ func (db *FormDB) SubmitForm(formID string, answers string) {
answer := Submission{
FormID: formID,
Answers: answers,
Author: std.PreviousRealm().Address(),
Author: std.CurrentRealm().Address(),
SubmittedAt: time.Now(),
}
db.Answers = append(db.Answers, &answer)
Expand Down
Loading
Loading