diff --git a/examples/gno.land/r/demo/tests/subtests/subtests.gno b/examples/gno.land/r/demo/tests/subtests/subtests.gno index e8796a73081..6bf43cba5eb 100644 --- a/examples/gno.land/r/demo/tests/subtests/subtests.gno +++ b/examples/gno.land/r/demo/tests/subtests/subtests.gno @@ -15,3 +15,11 @@ func GetPrevRealm() std.Realm { func Exec(fn func()) { fn() } + +func CallAssertOriginCall() { + std.AssertOriginCall() +} + +func CallIsOriginCall() bool { + return std.IsOriginCall() +} diff --git a/examples/gno.land/r/demo/tests/tests.gno b/examples/gno.land/r/demo/tests/tests.gno index 14adad7355c..773412c3db9 100644 --- a/examples/gno.land/r/demo/tests/tests.gno +++ b/examples/gno.land/r/demo/tests/tests.gno @@ -26,14 +26,22 @@ func InitOrigCaller() std.Address { return initOrigCaller } -func AssertOriginCall() { +func CallAssertOriginCall() { std.AssertOriginCall() } -func IsOriginCall() bool { +func CallIsOriginCall() bool { return std.IsOriginCall() } +func CallSubtestsAssertOriginCall() { + rsubtests.CallAssertOriginCall() +} + +func CallSubtestsIsOriginCall() bool { + return rsubtests.CallIsOriginCall() +} + //---------------------------------------- // Test structure to ensure cross-realm modification is prevented. diff --git a/examples/gno.land/r/demo/tests/tests_test.gno b/examples/gno.land/r/demo/tests/tests_test.gno index 3dcbeecf18c..41d89526a4b 100644 --- a/examples/gno.land/r/demo/tests/tests_test.gno +++ b/examples/gno.land/r/demo/tests/tests_test.gno @@ -8,28 +8,40 @@ import ( ) func TestAssertOriginCall(t *testing.T) { - // No-panic case - AssertOriginCall() - if !IsOriginCall() { + // CallAssertOriginCall(): no panic + CallAssertOriginCall() + if !CallIsOriginCall() { t.Errorf("expected IsOriginCall=true but got false") } - // Panic case + // CallAssertOriginCall() from a block: panic expectedReason := "invalid non-origin call" + func() { + defer func() { + r := recover() + if r == nil || r.(string) != expectedReason { + t.Errorf("expected panic with '%v', got '%v'", expectedReason, r) + } + }() + // if called inside a function literal, this is no longer an origin call + // because there's one additional frame (the function literal block). + if CallIsOriginCall() { + t.Errorf("expected IsOriginCall=false but got true") + } + CallAssertOriginCall() + }() + + // CallSubtestsAssertOriginCall(): panic defer func() { r := recover() if r == nil || r.(string) != expectedReason { t.Errorf("expected panic with '%v', got '%v'", expectedReason, r) } }() - func() { - // if called inside a function literal, this is no longer an origin call - // because there's one additional frame (the function literal). - if IsOriginCall() { - t.Errorf("expected IsOriginCall=false but got true") - } - AssertOriginCall() - }() + if CallSubtestsIsOriginCall() { + t.Errorf("expected IsOriginCall=false but got true") + } + CallSubtestsAssertOriginCall() } func TestPrevRealm(t *testing.T) { diff --git a/examples/gno.land/r/demo/tests/z0_filetest.gno b/examples/gno.land/r/demo/tests/z0_filetest.gno index c4beb8e2005..ff625d4906f 100644 --- a/examples/gno.land/r/demo/tests/z0_filetest.gno +++ b/examples/gno.land/r/demo/tests/z0_filetest.gno @@ -5,24 +5,24 @@ import ( ) func main() { - println("IsOriginCall:", tests.IsOriginCall()) - tests.AssertOriginCall() - println("AssertOriginCall doesn't panic when called directly") + println("tests.CallIsOriginCall:", tests.CallIsOriginCall()) + tests.CallAssertOriginCall() + println("tests.CallAssertOriginCall doesn't panic when called directly") - func() { - // if called inside a function literal, this is no longer an origin call - // because there's one additional frame (the function literal). - println("IsOriginCall:", tests.IsOriginCall()) + { + // if called inside a block, this is no longer an origin call because + // there's one additional frame (the block). + println("tests.CallIsOriginCall:", tests.CallIsOriginCall()) defer func() { r := recover() - println("AssertOriginCall panics if when called inside a function literal:", r) + println("tests.AssertOriginCall panics if when called inside a function literal:", r) }() - tests.AssertOriginCall() - }() + tests.CallAssertOriginCall() + } } // Output: -// IsOriginCall: true -// AssertOriginCall doesn't panic when called directly -// IsOriginCall: false -// AssertOriginCall panics if when called inside a function literal: invalid non-origin call +// tests.CallIsOriginCall: true +// tests.CallAssertOriginCall doesn't panic when called directly +// tests.CallIsOriginCall: true +// tests.AssertOriginCall panics if when called inside a function literal: undefined diff --git a/gno.land/cmd/gnoland/testdata/assertorigincall.txtar b/gno.land/cmd/gnoland/testdata/assertorigincall.txtar new file mode 100644 index 00000000000..fdbfebeef4a --- /dev/null +++ b/gno.land/cmd/gnoland/testdata/assertorigincall.txtar @@ -0,0 +1,245 @@ +# This test ensures the consistency of the std.AssertOriginCall function, in +# the following situations: +# +# | Num | Msg Type | Call from | Entry Point | Result | +# |-----|:--------:|:-------------------:|:----------------------:|:------:| +# | 1 | MsgCall | wallet direct | myrealm.A() | PANIC | +# | 2 | | | myrealm.B() | pass | +# | 3 | | | myrealm.C() | pass | +# | 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 | +# | 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 | +# | 19 | MsgCall | wallet direct | std.AssertOriginCall() | pass | +# | 20 | MsgRun | wallet direct | std.AssertOriginCall() | PANIC | + +# Init +## set up and start a new node +loadpkg gno.land/r/myrlm $WORK/r/myrlm +loadpkg gno.land/r/foo $WORK/r/foo +loadpkg gno.land/p/demo/bar $WORK/p/demo/bar +gnoland start + +# Test cases +## 1. MsgCall -> myrlm.A: PANIC +! gnokey maketx call -pkgpath gno.land/r/myrlm -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stderr 'invalid non-origin call' + +## 2. MsgCall -> myrlm.B: PASS +gnokey maketx call -pkgpath gno.land/r/myrlm -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stdout 'OK!' + +## 3. MsgCall -> myrlm.C: PASS +gnokey maketx call -pkgpath gno.land/r/myrlm -func C -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stdout 'OK!' + +## 4. MsgCall -> r/foo.A -> myrlm.A: PANIC +! gnokey maketx call -pkgpath gno.land/r/foo -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stderr 'invalid non-origin call' + +## 5. MsgCall -> r/foo.B -> myrlm.B: PASS +gnokey maketx call -pkgpath gno.land/r/foo -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stdout 'OK!' + +## 6. MsgCall -> r/foo.C -> myrlm.C: PANIC +! gnokey maketx call -pkgpath gno.land/r/foo -func C -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stderr 'invalid non-origin call' + +## 7. MsgCall -> p/demo/bar.A -> myrlm.A: PANIC +! gnokey maketx call -pkgpath gno.land/p/demo/bar -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stderr 'invalid non-origin call' + +## 8. MsgCall -> p/demo/bar.B -> myrlm.B: PASS +gnokey maketx call -pkgpath gno.land/p/demo/bar -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stdout 'OK!' + +## 9. MsgCall -> p/demo/bar.C -> myrlm.C: PANIC +! gnokey maketx call -pkgpath gno.land/p/demo/bar -func C -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stderr 'invalid non-origin call' + +## 10. MsgRun -> run.main -> myrlm.A: PANIC +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmA.gno +stderr 'invalid non-origin call' + +## 11. MsgRun -> run.main -> myrlm.B: PASS +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmB.gno +stdout 'OK!' + +## 12. MsgRun -> run.main -> myrlm.C: PANIC +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmC.gno +stderr 'invalid non-origin call' + +## 13. MsgRun -> run.main -> foo.A: PANIC +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooA.gno +stderr 'invalid non-origin call' + +## 14. MsgRun -> run.main -> foo.B: PASS +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooB.gno +stdout 'OK!' + +## 15. MsgRun -> run.main -> foo.C: PANIC +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooC.gno +stderr 'invalid non-origin call' + +## 16. MsgRun -> run.main -> bar.A: PANIC +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/barA.gno +stderr 'invalid non-origin call' + +## 17. MsgRun -> run.main -> bar.B: PASS +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/barB.gno +stdout 'OK!' + +## 18. MsgRun -> run.main -> bar.C: PANIC +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/barC.gno +stderr 'invalid non-origin call' + +## 19. MsgCall -> std.AssertOriginCall: pass +gnokey maketx call -pkgpath std -func AssertOriginCall -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +stdout 'OK!' + +## 20. MsgRun -> std.AssertOriginCall: PANIC +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/baz.gno +stderr 'invalid non-origin call' + + +-- r/myrlm/rlm.gno -- +package myrlm + +import "std" + +func A() { + C() +} + +func B() { + if false { + C() + } +} + +func C() { + std.AssertOriginCall() +} +-- r/foo/foo.gno -- +package foo + +import "gno.land/r/myrlm" + +func A() { + myrlm.A() +} + +func B() { + myrlm.B() +} + +func C() { + myrlm.C() +} +-- p/demo/bar/bar.gno -- +package bar + +import "gno.land/r/myrlm" + +func A() { + myrlm.A() +} + +func B() { + myrlm.B() +} + +func C() { + myrlm.C() +} +-- run/myrlmA.gno -- +package main + +import myrlm "gno.land/r/myrlm" + +func main() { + myrlm.A() +} +-- run/myrlmB.gno -- +package main + +import "gno.land/r/myrlm" + +func main() { + myrlm.B() +} +-- run/myrlmC.gno -- +package main + +import "gno.land/r/myrlm" + +func main() { + myrlm.C() +} +-- run/fooA.gno -- +package main + +import "gno.land/r/foo" + +func main() { + foo.A() +} +-- run/fooB.gno -- +package main + +import "gno.land/r/foo" + +func main() { + foo.B() +} +-- run/fooC.gno -- +package main + +import "gno.land/r/foo" + +func main() { + foo.C() +} +-- run/barA.gno -- +package main + +import "gno.land/p/demo/bar" + +func main() { + bar.A() +} +-- run/barB.gno -- +package main + +import "gno.land/p/demo/bar" + +func main() { + bar.B() +} +-- run/barC.gno -- +package main + +import "gno.land/p/demo/bar" + +func main() { + bar.C() +} +-- run/baz.gno -- +package main + +import "std" + +func main() { + std.AssertOriginCall() +} diff --git a/gnovm/stdlibs/std/native.gno b/gnovm/stdlibs/std/native.gno index ef2601eeca3..22a16fc18d1 100644 --- a/gnovm/stdlibs/std/native.gno +++ b/gnovm/stdlibs/std/native.gno @@ -1,7 +1,15 @@ package std -func AssertOriginCall() // injected +// AssertOriginCall panics if [IsOriginCall] returns false. +func AssertOriginCall() // injected + +// IsOriginCall returns true only if the calling method is invoked via a direct +// MsgCall. It returns false for all other cases, like if the calling method +// is invoked by another method (even from the same realm or package). +// It also returns false every time when the transaction is broadcasted via +// MsgRun. func IsOriginCall() bool // injected + func GetChainID() string // injected func GetHeight() int64 // injected diff --git a/gnovm/stdlibs/std/native.go b/gnovm/stdlibs/std/native.go index 7148a4ba4f4..7581334a952 100644 --- a/gnovm/stdlibs/std/native.go +++ b/gnovm/stdlibs/std/native.go @@ -14,7 +14,13 @@ func AssertOriginCall(m *gno.Machine) { } func IsOriginCall(m *gno.Machine) bool { - return len(m.Frames) == 2 + n := m.NumFrames() + if n == 0 { + return false + } + firstPkg := m.Frames[0].LastPackage + isMsgCall := firstPkg != nil && firstPkg.PkgPath == "main" + return n <= 2 && isMsgCall } func GetChainID(m *gno.Machine) string { diff --git a/gnovm/stdlibs/std/native_test.go b/gnovm/stdlibs/std/native_test.go new file mode 100644 index 00000000000..9af87174bda --- /dev/null +++ b/gnovm/stdlibs/std/native_test.go @@ -0,0 +1,194 @@ +package std + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" + "github.com/gnolang/gno/tm2/pkg/crypto" +) + +func TestPrevRealmIsOrigin(t *testing.T) { + var ( + user = gno.DerivePkgAddr("user1.gno").Bech32() + ctx = ExecContext{ + OrigCaller: user, + } + msgCallFrame = &gno.Frame{LastPackage: &gno.PackageValue{PkgPath: "main"}} + msgRunFrame = &gno.Frame{LastPackage: &gno.PackageValue{PkgPath: "gno.land/r/user-realm"}} + ) + tests := []struct { + name string + machine *gno.Machine + expectedAddr crypto.Bech32Address + expectedPkgPath string + expectedIsOriginCall bool + }{ + { + name: "no frames", + machine: &gno.Machine{ + Context: ctx, + Frames: []*gno.Frame{}, + }, + expectedAddr: user, + expectedPkgPath: "", + expectedIsOriginCall: false, + }, + { + name: "one frame w/o LastPackage", + machine: &gno.Machine{ + Context: ctx, + Frames: []*gno.Frame{ + {LastPackage: nil}, + }, + }, + expectedAddr: user, + expectedPkgPath: "", + expectedIsOriginCall: false, + }, + { + name: "one package frame", + machine: &gno.Machine{ + Context: ctx, + Frames: []*gno.Frame{ + {LastPackage: &gno.PackageValue{PkgPath: "gno.land/p/xxx"}}, + }, + }, + expectedAddr: user, + expectedPkgPath: "", + expectedIsOriginCall: false, + }, + { + name: "one realm frame", + machine: &gno.Machine{ + Context: ctx, + Frames: []*gno.Frame{ + {LastPackage: &gno.PackageValue{PkgPath: "gno.land/r/xxx"}}, + }, + }, + expectedAddr: user, + expectedPkgPath: "", + expectedIsOriginCall: false, + }, + { + name: "one msgCall frame", + machine: &gno.Machine{ + Context: ctx, + Frames: []*gno.Frame{ + msgCallFrame, + }, + }, + expectedAddr: user, + expectedPkgPath: "", + expectedIsOriginCall: true, + }, + { + name: "one msgRun frame", + machine: &gno.Machine{ + Context: ctx, + Frames: []*gno.Frame{ + msgRunFrame, + }, + }, + expectedAddr: user, + expectedPkgPath: "", + expectedIsOriginCall: false, + }, + { + name: "one package frame and one msgCall frame", + machine: &gno.Machine{ + Context: ctx, + Frames: []*gno.Frame{ + msgCallFrame, + {LastPackage: &gno.PackageValue{PkgPath: "gno.land/p/xxx"}}, + }, + }, + expectedAddr: user, + expectedPkgPath: "", + expectedIsOriginCall: true, + }, + { + name: "one realm frame and one msgCall frame", + machine: &gno.Machine{ + Context: ctx, + Frames: []*gno.Frame{ + msgCallFrame, + {LastPackage: &gno.PackageValue{PkgPath: "gno.land/r/xxx"}}, + }, + }, + expectedAddr: user, + expectedPkgPath: "", + expectedIsOriginCall: true, + }, + { + name: "one package frame and one msgRun frame", + machine: &gno.Machine{ + Context: ctx, + Frames: []*gno.Frame{ + msgRunFrame, + {LastPackage: &gno.PackageValue{PkgPath: "gno.land/p/xxx"}}, + }, + }, + expectedAddr: user, + expectedPkgPath: "", + expectedIsOriginCall: false, + }, + { + name: "one realm frame and one msgRun frame", + machine: &gno.Machine{ + Context: ctx, + Frames: []*gno.Frame{ + msgRunFrame, + {LastPackage: &gno.PackageValue{PkgPath: "gno.land/r/xxx"}}, + }, + }, + expectedAddr: user, + expectedPkgPath: "", + expectedIsOriginCall: false, + }, + { + name: "multiple frames with one realm", + machine: &gno.Machine{ + Context: ctx, + Frames: []*gno.Frame{ + {LastPackage: &gno.PackageValue{PkgPath: "gno.land/p/xxx"}}, + {LastPackage: &gno.PackageValue{PkgPath: "gno.land/p/xxx"}}, + {LastPackage: &gno.PackageValue{PkgPath: "gno.land/r/xxx"}}, + }, + }, + expectedAddr: user, + expectedPkgPath: "", + expectedIsOriginCall: false, + }, + { + name: "multiple frames with multiple realms", + machine: &gno.Machine{ + Context: ctx, + Frames: []*gno.Frame{ + {LastPackage: &gno.PackageValue{PkgPath: "gno.land/r/zzz"}}, + {LastPackage: &gno.PackageValue{PkgPath: "gno.land/r/zzz"}}, + {LastPackage: &gno.PackageValue{PkgPath: "gno.land/r/yyy"}}, + {LastPackage: &gno.PackageValue{PkgPath: "gno.land/p/yyy"}}, + {LastPackage: &gno.PackageValue{PkgPath: "gno.land/p/xxx"}}, + {LastPackage: &gno.PackageValue{PkgPath: "gno.land/r/xxx"}}, + }, + }, + expectedAddr: gno.DerivePkgAddr("gno.land/r/yyy").Bech32(), + expectedPkgPath: "gno.land/r/yyy", + expectedIsOriginCall: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert := assert.New(t) + + addr, pkgPath := X_getRealm(tt.machine, 1) + isOrigin := IsOriginCall(tt.machine) + + assert.Equal(string(tt.expectedAddr), addr) + assert.Equal(tt.expectedPkgPath, pkgPath) + assert.Equal(tt.expectedIsOriginCall, isOrigin) + }) + } +} diff --git a/gnovm/tests/files/zrealm_natbind0.gno b/gnovm/tests/files/zrealm_natbind0.gno index 3808905928b..dedc5b565c3 100644 --- a/gnovm/tests/files/zrealm_natbind0.gno +++ b/gnovm/tests/files/zrealm_natbind0.gno @@ -154,7 +154,7 @@ func main() { // "BlockNode": null, // "Location": { // "File": "native.gno", -// "Line": "5", +// "Line": "13", // "Nonce": "0", // "PkgPath": "std" // } diff --git a/gnovm/tests/files/zrealm_tests0.gno b/gnovm/tests/files/zrealm_tests0.gno index 79a930b5ecc..9542b5e8d1a 100644 --- a/gnovm/tests/files/zrealm_tests0.gno +++ b/gnovm/tests/files/zrealm_tests0.gno @@ -247,7 +247,7 @@ func main() { // "BlockNode": null, // "Location": { // "File": "tests.gno", -// "Line": "48", +// "Line": "56", // "Nonce": "0", // "PkgPath": "gno.land/r/demo/tests" // } @@ -670,7 +670,7 @@ func main() { // }, // "FileName": "tests.gno", // "IsMethod": false, -// "Name": "AssertOriginCall", +// "Name": "CallAssertOriginCall", // "NativeName": "", // "NativePkg": "", // "PkgPath": "gno.land/r/demo/tests", @@ -716,7 +716,7 @@ func main() { // }, // "FileName": "tests.gno", // "IsMethod": false, -// "Name": "IsOriginCall", +// "Name": "CallIsOriginCall", // "NativeName": "", // "NativePkg": "", // "PkgPath": "gno.land/r/demo/tests", @@ -750,6 +750,98 @@ func main() { // { // "T": { // "@type": "/gno.FuncType", +// "Params": [], +// "Results": [] +// }, +// "V": { +// "@type": "/gno.FuncValue", +// "Closure": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:4" +// }, +// "FileName": "tests.gno", +// "IsMethod": false, +// "Name": "CallSubtestsAssertOriginCall", +// "NativeName": "", +// "NativePkg": "", +// "PkgPath": "gno.land/r/demo/tests", +// "Source": { +// "@type": "/gno.RefNode", +// "BlockNode": null, +// "Location": { +// "File": "tests.gno", +// "Line": "37", +// "Nonce": "0", +// "PkgPath": "gno.land/r/demo/tests" +// } +// }, +// "Type": { +// "@type": "/gno.FuncType", +// "Params": [], +// "Results": [] +// } +// } +// }, +// { +// "T": { +// "@type": "/gno.FuncType", +// "Params": [], +// "Results": [ +// { +// "Embedded": false, +// "Name": "", +// "Tag": "", +// "Type": { +// "@type": "/gno.PrimitiveType", +// "value": "4" +// } +// } +// ] +// }, +// "V": { +// "@type": "/gno.FuncValue", +// "Closure": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:4" +// }, +// "FileName": "tests.gno", +// "IsMethod": false, +// "Name": "CallSubtestsIsOriginCall", +// "NativeName": "", +// "NativePkg": "", +// "PkgPath": "gno.land/r/demo/tests", +// "Source": { +// "@type": "/gno.RefNode", +// "BlockNode": null, +// "Location": { +// "File": "tests.gno", +// "Line": "41", +// "Nonce": "0", +// "PkgPath": "gno.land/r/demo/tests" +// } +// }, +// "Type": { +// "@type": "/gno.FuncType", +// "Params": [], +// "Results": [ +// { +// "Embedded": false, +// "Name": "", +// "Tag": "", +// "Type": { +// "@type": "/gno.PrimitiveType", +// "value": "4" +// } +// } +// ] +// } +// } +// }, +// { +// "T": { +// "@type": "/gno.FuncType", // "Params": [ // { // "Embedded": false, @@ -784,7 +876,7 @@ func main() { // "BlockNode": null, // "Location": { // "File": "tests.gno", -// "Line": "44", +// "Line": "52", // "Nonce": "0", // "PkgPath": "gno.land/r/demo/tests" // } @@ -833,7 +925,7 @@ func main() { // "BlockNode": null, // "Location": { // "File": "tests.gno", -// "Line": "66", +// "Line": "74", // "Nonce": "0", // "PkgPath": "gno.land/r/demo/tests" // } @@ -869,7 +961,7 @@ func main() { // "BlockNode": null, // "Location": { // "File": "tests.gno", -// "Line": "71", +// "Line": "79", // "Nonce": "0", // "PkgPath": "gno.land/r/demo/tests" // } @@ -905,7 +997,7 @@ func main() { // "BlockNode": null, // "Location": { // "File": "tests.gno", -// "Line": "79", +// "Line": "87", // "Nonce": "0", // "PkgPath": "gno.land/r/demo/tests" // } @@ -951,7 +1043,7 @@ func main() { // "BlockNode": null, // "Location": { // "File": "tests.gno", -// "Line": "83", +// "Line": "91", // "Nonce": "0", // "PkgPath": "gno.land/r/demo/tests" // } @@ -1007,7 +1099,7 @@ func main() { // "BlockNode": null, // "Location": { // "File": "tests.gno", -// "Line": "87", +// "Line": "95", // "Nonce": "0", // "PkgPath": "gno.land/r/demo/tests" // } @@ -1064,7 +1156,7 @@ func main() { // "BlockNode": null, // "Location": { // "File": "tests.gno", -// "Line": "91", +// "Line": "99", // "Nonce": "0", // "PkgPath": "gno.land/r/demo/tests" // }