Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 15 additions & 0 deletions gnovm/pkg/gnolang/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -2136,6 +2136,21 @@ func (m *Machine) NumFrames() int {
return len(m.Frames)
}

// NumNonClosureFrames returns the number of call frames whose function
// is not a closure (func literal). Closures are internal implementation
// details of the enclosing function and should not count as separate
// "method" calls for origin-call purposes.
func (m *Machine) NumNonClosureFrames() int {
count := 0
for i := range m.Frames {
fr := &m.Frames[i]
if fr.Func != nil && !fr.Func.IsClosure {
count++
}
}
return count
}

// Returns the current frame.
func (m *Machine) LastFrame() *Frame {
return &m.Frames[len(m.Frames)-1]
Expand Down
6 changes: 5 additions & 1 deletion gnovm/stdlibs/chain/runtime/native.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ func isOriginCall(m *gno.Machine) bool {
}
firstPkg := m.Frames[0].LastPackage
isMsgCall := firstPkg != nil && firstPkg.PkgPath == ""
return n <= 2 && isMsgCall
if !isMsgCall {
return false
}
// count only non-closure frames.
return m.NumNonClosureFrames() <= 2
}

func ChainID(m *gno.Machine) string {
Expand Down
18 changes: 18 additions & 0 deletions gnovm/tests/files/std13.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package main

import "chain/runtime"

func Register() {
runtime.AssertOriginCall()
}

func main() {
fn := func() {
Register()
}
fn()
println("ok")
}

// Output:
// ok
33 changes: 33 additions & 0 deletions gnovm/tests/files/std14.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package main

import "chain/runtime"

func Register(username string) {
runtime.AssertOriginCall()
}

func notPanics(f func()) (panicked bool) {
defer func() {
if r := recover(); r != nil {
panicked = true
}
}()
f()
return false
}

func main() {
panicked := notPanics(func() {
Register("alice")
})
println("anon call panicked:", panicked)

panicked = notPanics(func() {
Register("bob")
})
println("direct call panicked:", panicked)
}

// Output:
// anon call panicked: true
// direct call panicked: true
15 changes: 10 additions & 5 deletions gnovm/tests/stdlibs/chain/runtime/testing_runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,25 +40,30 @@ func typedString(s gno.StringValue) gno.TypedValue {

func isOriginCall(m *gno.Machine) bool {
tname := m.Frames[0].Func.Name
// Count only non-closure frames. This allows anonymous
// function wrappers (e.g. for testing) to be transparent.
nonClosureFrames := m.NumNonClosureFrames()
switch tname {
case "main": // test is a _filetest
// Non-closure frames expected:
// 0. main
// 1. $RealmFuncName
// 2. td.IsOriginCall
return len(m.Frames) == 3
// 2. runtime.AssertOriginCall
return nonClosureFrames == 3
case "RunTest": // test is a _test
// Non-closure frames expected:
// 0. testing.RunTest
// 1. tRunner
// 2. $TestFuncName
// 3. $RealmFuncName
// 4. std.IsOriginCall
return len(m.Frames) == 5
// 4. runtime.AssertOriginCall
return nonClosureFrames == 5
}
// support init() in _filetest
// XXX do we need to distinguish from 'runtest'/_test?
// XXX pretty hacky even if not.
if strings.HasPrefix(string(tname), "init.") {
return len(m.Frames) == 3
return nonClosureFrames == 3
}
panic("unable to determine if test is a _test or a _filetest")
}
Expand Down
Loading