Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
894d729
fix(examples): meta2
moul Apr 29, 2025
909374b
chore: bootstrap the _drafts folder
moul Apr 29, 2025
cf5635c
chore: fixup
moul Apr 29, 2025
f9918c2
chore: fixup
moul Apr 29, 2025
ef8a7c5
chore: fixup
moul Apr 29, 2025
8ae7795
chore: fixup
moul Apr 29, 2025
80dedd9
chore: fixup
moul Apr 29, 2025
b67944f
chore: fixup
moul Apr 29, 2025
b77d543
chore: fixup
moul Apr 29, 2025
0d3222a
chore: fixup
moul Apr 29, 2025
3a710e5
RunFunc and RunMain don't cross; no need to, 'frame -1' handles crossing
jaekwon Apr 29, 2025
2ba6723
Merge branch 'master' into fix/crossrealm/examples-integrations2
n2p5 Apr 29, 2025
94933d3
fixed makefile for _drafts
jaekwon Apr 30, 2025
af61e4f
TestStart_Lazy returns sooner and shows error
jaekwon Apr 30, 2025
9493656
chore: fixup
moul Apr 30, 2025
4651908
chore: fixup
moul Apr 30, 2025
7f1b8e5
chore: fixup
moul Apr 30, 2025
a187a67
fix(txtar): increase initial balance for add user
gfanton Apr 30, 2025
e89fed6
wip(example): r/demo/wugnot + p/demo/grc/grc20
gfanton Apr 30, 2025
9fa9c58
chore: fixup
moul Apr 30, 2025
f0b71db
Merge branch 'master' into fix/crossrealm/examples-integrations2
moul Apr 30, 2025
5e45efc
chore: fixup
moul Apr 30, 2025
ac2b9a5
chore: fixup
moul Apr 30, 2025
7fc8941
chore: fixup
moul Apr 30, 2025
493ba2c
chore: fixup
moul Apr 30, 2025
28e5760
fix(examples): r/sys/users
gfanton Apr 30, 2025
57f9ec1
chore: r/docs/minisocial/...
moul Apr 30, 2025
c78fc62
chore: r/docs/minisocial/...
moul Apr 30, 2025
b07c658
chore: r/demo/tests (incomplete)
moul Apr 30, 2025
f9ae459
chore: fixup
moul Apr 30, 2025
174c77c
chore: move disperse back from _drafts to gno.land
aeddi Apr 30, 2025
834e432
fix: r/demo/grc20factory
aeddi Apr 30, 2025
fdefa08
fix: r/demo/disperse z_3 and z_4
aeddi Apr 30, 2025
2178e48
fix: r/demo/disperse z_0, z_1 and z_2
aeddi Apr 30, 2025
3fb6b7d
govdao test fixes WIP
ajnavarro Apr 30, 2025
2ff14f1
Add govdao integration tests
ajnavarro Apr 28, 2025
65e902f
chore: p/demo/grc/grc20
moul Apr 30, 2025
d155fae
fix: update loci testing and core behavior to work with cross realms …
n2p5 Apr 30, 2025
b2a960a
Merge branch 'master' into fix/crossrealm/examples-integrations2
n2p5 Apr 30, 2025
a80b9b7
fixup gno.land/r/morgan/chess
thehowl Apr 30, 2025
435d0e9
Merge branch 'fix/crossrealm/examples-integrations2' of github.com:gn…
thehowl Apr 30, 2025
4510975
fix gno.land/r/morgan/guestbook
thehowl Apr 30, 2025
a0f3114
fix(examples): r/sys/names + ownable drop/transfert
gfanton Apr 30, 2025
0a761bf
Merge branch 'master' into fix/crossrealm/examples-integrations2
n2p5 Apr 30, 2025
2aa29d1
move examples/_draft to examples_draft; improve error message from gn…
jaekwon Apr 30, 2025
988c2b9
update: atomicswap_test
masonmcbride Apr 30, 2025
1ec399c
Revert "update: atomicswap_test"
jaekwon May 1, 2025
6f9d11a
fix wugnot test
jaekwon May 1, 2025
2c92d47
fix owneable again
jaekwon May 1, 2025
2c70c87
fix examples/gno.land/r/gov/dao test failure
piux2 May 1, 2025
642ca15
fix frame not found, xxx override; fix gnoland/home
ltzmaxwell May 1, 2025
896be15
Merge commit 'refs/pull/4228/head' of github.com:gnolang/gno into pr-…
ltzmaxwell May 1, 2025
7f69a44
Revert "fix frame not found, xxx override; fix gnoland/home"
jaekwon May 1, 2025
076790e
improve panic output; fix panic string in crossing()
jaekwon May 1, 2025
df98ae2
in the middle of fixing r/gov/dao; improved readonly error; TODO need…
jaekwon May 2, 2025
b12310b
Remove PreprocessingMode in favor of StagePre; Actually use it for ov…
jaekwon May 2, 2025
a616966
fix tamagochi
jaekwon May 2, 2025
de26632
fix manfred_upgrade_patterns
jaekwon May 2, 2025
c755558
added uassert.[Not][Typed]Nil(); gotypecheck uses .gnobuiltins.go for…
jaekwon May 2, 2025
b17cba2
fix last frame line number
jaekwon May 2, 2025
91c9ecc
intermediate: fixing r/gov/dao and gnoland/users
jaekwon May 2, 2025
085c687
fix r/gnoland/users tests
jaekwon May 2, 2025
a0b6cca
update gnovm tests with new Realm string
jaekwon May 2, 2025
6b309e9
fix r/gnoland and r/gov/dao tests; authorizable supports assertions o…
jaekwon May 3, 2025
c598542
fix authorizable tests
jaekwon May 3, 2025
45d36a2
tv.IsTypedNil() and stacktrace fix
jaekwon May 3, 2025
7e6f15e
finalize upon every explicit and implicit realm crossing
jaekwon May 3, 2025
2813919
realm finalize also upon withcross; otherwise zrealm_crossrealm30d.gn…
jaekwon May 3, 2025
4ea65fd
panic aborts the transaction when crossing a realm boundary
jaekwon May 3, 2025
2060d3a
chore: use revive
moul May 3, 2025
7476d73
chore: fixup
moul May 3, 2025
aa228e1
revive()
jaekwon May 3, 2025
5a1cf02
chore: atomicswap error
moul May 3, 2025
d1738f1
chore: revive related changes
moul May 3, 2025
2262b04
fix revive() and uassert tests
jaekwon May 3, 2025
4ff490f
add 'revive' to interrealm spec
jaekwon May 3, 2025
df66418
chore: restore Panics
moul May 3, 2025
61270a4
fix: downloadDeps
moul May 3, 2025
279478b
chore: fixup
moul May 3, 2025
52c0274
chore: wording
moul May 3, 2025
ab20dd9
chore: morgan/chess
moul May 3, 2025
b4c3972
chore: fixup
moul May 3, 2025
808c7e4
fix atomicswap
ltzmaxwell May 3, 2025
0ae9d4d
fix foo20
ltzmaxwell May 3, 2025
705e0df
chore: revert uassert Panics->Aborts in tests by default
moul May 3, 2025
33bf4df
chore: uassert, update tests
moul May 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
82 changes: 69 additions & 13 deletions docs/resources/gno-interrealm.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Interrealm Specification

## Introduction

XXX short intro on realms.
XXX comparison to kernel syscalls, but cross-user.
XXX simple code example.

## Realm Finalization

A realm boundary is defined as a change in realm in the call frame stack
from one realm to another, whether explicitly crossed with `cross(fn)()`
or implictly borrow-crossed into a different receiver's storage realm.
A realm may cross into itself with an explicit cross-call.

When returning from a realm boundary, all new reachable objects are assigned
object IDs and stored in the current realm, ref-count-zero objects deleted
(full "disk-persistent cycle GC" will come after launch) and any modified
ref-count and Merkle hash root computed. This is called realm finalization.

## `cross(fn)()` and `crossing()`

Gno extends Go's type system with interrealm rules. These rules can be
checked during the static type-checking phase (but at the moment they are
partially dependent on runtime checks).
Expand Down Expand Up @@ -30,7 +50,8 @@ A crossing function declared in a realm different than the last explicitly
crossed realm *must* be called like `cross(fn)(...)`. That is, functions of
calls that result in explicit realm crossings must be wrapped with `cross()`.

`std.CurrentRealm()` returns the current realm last explicitly crossed to.
`std.CurrentRealm()` returns the current realm that was last explicitly crossed
to.

`std.PreviousRealm()` returns the realm explicitly crossed to before that.

Expand Down Expand Up @@ -59,7 +80,7 @@ receiver (and in general anything reachable is readable).
New unreal objects reachable from the borrowed realm (or current realm if there
was no method call that borrowed) become persisted in the borrowed realm (or
current realm) upon finalization of the foreign object's method (or function).
(When you put an unlabeled photo in someone else's scrap book the photo now
(When you put an unlabeled photo in someone else's scrapbook the photo now
belongs to the other person). In the future we will introduce an `attach()`
function to prevent a new unreal object from being taken.

Expand All @@ -72,7 +93,7 @@ A realm package's initialization (including `init()` calls) execute with current
realm of itself, and it `std.PreviousRealm()` will panic unless the call stack
includes a crossing function called like `cross(fn)(...)`.

### Justifications
### `cross` and `crossing` Design Goals

P package code should behave the same even when copied verbatim in a realm
package.
Expand Down Expand Up @@ -107,7 +128,42 @@ be upgraded.
Both `crossing()` and `cross(fn)(...)` statements may become special syntax in
future Gno versions.

### Usage
## `attach()`

## `panic()` and `revive(fn)`

`panic()` behaves the same within the same realm boundary, but when a panic
crosses a realm boundary (as defined in [Realm
Finalization](#realm-finalization)) the Machine aborts the program. This is
because in a multi-user environment it isn't safe to let the caller recover
from realm panics that often leave the state in an invalid state.

This would be sufficient, but we also want to write our tests to be able
to detect such aborts and make assertions. For this reason Gno provides
the `revive(fn)` builtin.

```go
abort := revive(func() {
cross(func() {
crossing()
panic("cross-realm panic")
})
})
abort == "cross-realm panic"
```

`revive(fn)` will execute 'fn' and return the exception that crossed
a realm finalization boundary.

This is only enabled in testing mode (for now), behavior is only partially
implemented. In the future `revive(fn)` will be available for non-testing code,
and the behavior will change such that `fn()` is run in transactional
(cache-wrapped) memory context and any mutations discarded if and only if there
was an abort.

TL;DR: `revive(fn)` is Gno's builtin for STM (software transactional memory).

## Application

P package code cannot contain crossing functions, nor use `crossing()`. P
package code also cannot import R realm packages. But code can call named
Expand All @@ -126,8 +182,8 @@ 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;
object is like a quasi-realm in itself, that could possibly reside and migrate
to other realms. 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
Expand All @@ -143,10 +199,10 @@ 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

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

```go
Expand Down Expand Up @@ -180,7 +236,7 @@ func AnotherPublic() {
}
```

#### MsgRun
### MsgRun

```go
// PKGPATH: gno.land/r/g1user/run
Expand Down Expand Up @@ -259,12 +315,12 @@ 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
### MsgAddPackage

During MsgAddPackage `std.PreviousRealm()` refers to the package deployer both
in global 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.
deployer in the initialization phase if needed.

```go
// PKGPATH: gno.land/r/test/test
Expand Down Expand Up @@ -314,7 +370,7 @@ 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
### Testing overrides with stdlibs/testing

The `gnovm/tests/stdlibs/testing/context_testing.gno` file provides functions
for overriding frame details from Gno test code.
Expand Down Expand Up @@ -419,7 +475,7 @@ func main() {
// XXX
```

#### Future Work
## Future Work

`std.SetOriginCaller()` should maybe be deprecated in favor of
`std.SetRealm(std.NewUserRealm(user))` renamed to
Expand Down
2 changes: 1 addition & 1 deletion examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ build:

.PHONY: test
test:
go run ../gnovm/cmd/gno test -v ./...
go run ../gnovm/cmd/gno test -v ./gno.land/...

.PHONY: test.fast
test.fast:
Expand Down
1 change: 1 addition & 0 deletions examples/gno.land/p/agherasie/forms/submit_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func TestAnswerForm(t *testing.T) {
urequire.True(t, len(db.Answers) == 1, "Expected 1 answer, got", string(len(db.Answers)))
urequire.True(t, db.Answers[0].FormID == formID, "Expected form ID", formID, "got", db.Answers[0].FormID)
urequire.True(t, db.Answers[0].Answers == answers, "Expected answers", answers, "got", db.Answers[0].Answers)
urequire.True(t, err == nil, "Submit should not return an error")
}

func TestAnswerFormDates(t *testing.T) {
Expand Down
2 changes: 0 additions & 2 deletions examples/gno.land/p/demo/avl/z_0_filetest.gno
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ func main() {
// Output:
// false 2



// Realm:
// finalizerealm["gno.land/r/test"]
// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]=
Expand Down
2 changes: 0 additions & 2 deletions examples/gno.land/p/demo/avl/z_1_filetest.gno
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ func main() {
// Output:
// false 3



// Realm:
// finalizerealm["gno.land/r/test"]
// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]=
Expand Down
2 changes: 0 additions & 2 deletions examples/gno.land/p/demo/avl/z_2_filetest.gno
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ func main() {
// Output:
// false 3



// Realm:
// finalizerealm["gno.land/r/test"]
// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]=
Expand Down
2 changes: 1 addition & 1 deletion examples/gno.land/p/demo/grc/grc20/tellers.gno
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func (tok *Token) CallerTeller() Teller {

return &fnTeller{
accountFn: func() std.Address {
caller := std.CurrentRealm().Address()
caller := std.PreviousRealm().Address()
return caller
},
Token: tok,
Expand Down
11 changes: 8 additions & 3 deletions examples/gno.land/p/demo/grc/grc20/tellers_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,21 @@ func TestCallerTeller(t *testing.T) {
checkBalances(1000, 0, 0)
checkAllowances(0, 0, 0, 0, 0, 0)

tellerThrough := func(action func()) {
testing.SetRealm(std.NewCodeRealm("gno.land/r/realm_exposing_the_teller"))
action()
}

testing.SetRealm(std.NewUserRealm(alice))
urequire.NoError(t, teller.Approve(bob, 600))
tellerThrough(func() { urequire.NoError(t, teller.Approve(bob, 600)) })
checkBalances(1000, 0, 0)
checkAllowances(600, 0, 0, 0, 0, 0)

testing.SetRealm(std.NewUserRealm(bob))
urequire.Error(t, teller.TransferFrom(alice, carl, 700))
tellerThrough(func() { urequire.Error(t, teller.TransferFrom(alice, carl, 700)) })
checkBalances(1000, 0, 0)
checkAllowances(600, 0, 0, 0, 0, 0)
urequire.NoError(t, teller.TransferFrom(alice, carl, 400))
tellerThrough(func() { urequire.NoError(t, teller.TransferFrom(alice, carl, 400)) })
checkBalances(600, 0, 400)
checkAllowances(200, 0, 0, 0, 0, 0)
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,17 @@ func (a *Authorizable) AddToAuthList(addr std.Address) error {
if !a.OwnedByCurrent() {
return ErrNotSuperuser
}
return a.addToAuthList(addr)
}

func (a *Authorizable) AddToAuthListByPrevious(addr std.Address) error {
if !a.OwnedByPrevious() {
return ErrNotSuperuser
}
return a.addToAuthList(addr)
}

func (a *Authorizable) addToAuthList(addr std.Address) error {
if _, exists := a.authorized.Get(addr.String()); exists {
return ErrAlreadyInList
}
Expand All @@ -69,7 +79,17 @@ func (a *Authorizable) DeleteFromAuthList(addr std.Address) error {
if !a.OwnedByCurrent() {
return ErrNotSuperuser
}
return a.deleteFromAuthList(addr)
}

func (a *Authorizable) DeleteFromAuthListByPrevious(addr std.Address) error {
if !a.OwnedByPrevious() {
return ErrNotSuperuser
}
return a.deleteFromAuthList(addr)
}

func (a *Authorizable) deleteFromAuthList(addr std.Address) error {
if !a.authorized.Has(addr.String()) {
return ErrNotInAuthList
}
Expand All @@ -82,20 +102,33 @@ func (a *Authorizable) DeleteFromAuthList(addr std.Address) error {
return nil
}

func (a Authorizable) CallerOnAuthList() error {
caller := std.CurrentRealm().Address()
func (a *Authorizable) OnAuthList() error {
current := std.CurrentRealm().Address()
return a.onAuthList(current)
}

func (a *Authorizable) PreviousOnAuthList() error {
previous := std.PreviousRealm().Address()
return a.onAuthList(previous)
}

func (a *Authorizable) onAuthList(caller std.Address) error {
if !a.authorized.Has(caller.String()) {
return ErrNotInAuthList
}

return nil
}

func (a Authorizable) AssertOnAuthList() {
caller := std.CurrentRealm().Address()
err := a.OnAuthList()
if err != nil {
panic(err)
}
}

if !a.authorized.Has(caller.String()) {
panic(ErrNotInAuthList)
func (a Authorizable) AssertPreviousOnAuthList() {
err := a.PreviousOnAuthList()
if err != nil {
panic(err)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,20 @@ func TestNewAuthorizableWithAddress(t *testing.T) {
}
}

func TestCallerOnAuthList(t *testing.T) {
func TestOnAuthList(t *testing.T) {
a := NewAuthorizableWithAddress(alice)
testing.SetRealm(std.NewUserRealm(alice))

if err := a.CallerOnAuthList(); err == ErrNotInAuthList {
if err := a.OnAuthList(); err == ErrNotInAuthList {
t.Fatalf("expected alice to be on the list")
}
}

func TestNotCallerOnAuthList(t *testing.T) {
func TestNotOnAuthList(t *testing.T) {
a := NewAuthorizableWithAddress(alice)
testing.SetRealm(std.NewUserRealm(bob))

if err := a.CallerOnAuthList(); err == nil {
if err := a.OnAuthList(); err == nil {
t.Fatalf("expected bob to not be on the list")
}
}
Expand Down
Loading
Loading