forked from TrueCloudLab/neoneo-go
Merge pull request #1989 from nspcc-dev/compiler-notify-name
compiler: check event name length in `runtime.Notify`
This commit is contained in:
commit
ebff8be20a
5 changed files with 87 additions and 15 deletions
2
cli/testdata/verify.yml
vendored
2
cli/testdata/verify.yml
vendored
|
@ -1,5 +1,5 @@
|
|||
name: Test verify
|
||||
Events:
|
||||
events:
|
||||
- name: OnNEP11Payment
|
||||
parameters:
|
||||
- name: from
|
||||
|
|
|
@ -959,20 +959,6 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
ast.Walk(c, n.Fun)
|
||||
emit.Opcodes(c.prog.BinWriter, opcode.CALLA)
|
||||
case isSyscall(f):
|
||||
if f.pkg.Name() == "runtime" && f.name == "Notify" {
|
||||
tv := c.typeAndValueOf(n.Args[0])
|
||||
params := make([]string, 0, len(n.Args[1:]))
|
||||
for _, p := range n.Args[1:] {
|
||||
st, _ := c.scAndVMTypeFromExpr(p)
|
||||
params = append(params, st.String())
|
||||
}
|
||||
// Sometimes event name is stored in a var.
|
||||
// Skip in this case.
|
||||
if tv.Value != nil {
|
||||
name := constant.StringVal(tv.Value)
|
||||
c.emittedEvents[name] = append(c.emittedEvents[name], params)
|
||||
}
|
||||
}
|
||||
c.convertSyscall(f, n)
|
||||
default:
|
||||
emit.Call(c.prog.BinWriter, opcode.CALLL, f.label)
|
||||
|
|
|
@ -9,6 +9,8 @@ import (
|
|||
|
||||
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -130,3 +132,46 @@ func TestOnPayableChecks(t *testing.T) {
|
|||
require.Error(t, compileAndCheck(t, src))
|
||||
})
|
||||
}
|
||||
|
||||
func TestEventWarnings(t *testing.T) {
|
||||
src := `package payable
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||
func Main() { runtime.Notify("Event", 1) }`
|
||||
|
||||
_, di, err := compiler.CompileWithDebugInfo("eventTest", strings.NewReader(src))
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("event it missing from config", func(t *testing.T) {
|
||||
_, err = compiler.CreateManifest(di, &compiler.Options{})
|
||||
require.Error(t, err)
|
||||
|
||||
t.Run("suppress", func(t *testing.T) {
|
||||
_, err = compiler.CreateManifest(di, &compiler.Options{NoEventsCheck: true})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
})
|
||||
t.Run("wrong parameter number", func(t *testing.T) {
|
||||
_, err = compiler.CreateManifest(di, &compiler.Options{
|
||||
ContractEvents: []manifest.Event{{Name: "Event"}},
|
||||
})
|
||||
require.Error(t, err)
|
||||
})
|
||||
t.Run("wrong parameter type", func(t *testing.T) {
|
||||
_, err = compiler.CreateManifest(di, &compiler.Options{
|
||||
ContractEvents: []manifest.Event{{
|
||||
Name: "Event",
|
||||
Parameters: []manifest.Parameter{manifest.NewParameter("number", smartcontract.StringType)},
|
||||
}},
|
||||
})
|
||||
require.Error(t, err)
|
||||
})
|
||||
t.Run("good", func(t *testing.T) {
|
||||
_, err = compiler.CreateManifest(di, &compiler.Options{
|
||||
ContractEvents: []manifest.Event{{
|
||||
Name: "Event",
|
||||
Parameters: []manifest.Parameter{manifest.NewParameter("number", smartcontract.IntegerType)},
|
||||
}},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package compiler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/constant"
|
||||
"go/types"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
)
|
||||
|
@ -27,6 +30,8 @@ func (c *codegen) inlineCall(f *funcScope, n *ast.CallExpr) {
|
|||
pkg := c.buildInfo.program.Package(f.pkg.Path())
|
||||
sig := c.typeOf(n.Fun).(*types.Signature)
|
||||
|
||||
c.processNotify(f, n.Args)
|
||||
|
||||
// When inlined call is used during global initialization
|
||||
// there is no func scope, thus this if.
|
||||
if c.scope == nil {
|
||||
|
@ -114,3 +119,28 @@ func (c *codegen) inlineCall(f *funcScope, n *ast.CallExpr) {
|
|||
c.importMap = oldMap
|
||||
c.pkgInfoInline = c.pkgInfoInline[:len(c.pkgInfoInline)-1]
|
||||
}
|
||||
|
||||
func (c *codegen) processNotify(f *funcScope, args []ast.Expr) {
|
||||
if f != nil && f.pkg.Path() == interopPrefix+"/runtime" && f.name == "Notify" {
|
||||
// Sometimes event name is stored in a var.
|
||||
// Skip in this case.
|
||||
tv := c.typeAndValueOf(args[0])
|
||||
if tv.Value == nil {
|
||||
return
|
||||
}
|
||||
|
||||
params := make([]string, 0, len(args[1:]))
|
||||
for _, p := range args[1:] {
|
||||
st, _ := c.scAndVMTypeFromExpr(p)
|
||||
params = append(params, st.String())
|
||||
}
|
||||
|
||||
name := constant.StringVal(tv.Value)
|
||||
if len(name) > runtime.MaxEventNameLen {
|
||||
c.prog.Err = fmt.Errorf("event name '%s' should be less than %d",
|
||||
name, runtime.MaxEventNameLen)
|
||||
return
|
||||
}
|
||||
c.emittedEvents[name] = append(c.emittedEvents[name], params)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -188,6 +188,17 @@ func TestNotify(t *testing.T) {
|
|||
assert.Equal(t, exp0, s.events[0].Item.Value())
|
||||
assert.Equal(t, "single", s.events[1].Name)
|
||||
assert.Equal(t, []stackitem.Item{}, s.events[1].Item.Value())
|
||||
|
||||
t.Run("long event name", func(t *testing.T) {
|
||||
src := `package foo
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||
func Main(arg int) {
|
||||
runtime.Notify("long event12345678901234567890123")
|
||||
}`
|
||||
|
||||
_, _, err := compiler.CompileWithDebugInfo("foo.go", strings.NewReader(src))
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSyscallInGlobalInit(t *testing.T) {
|
||||
|
|
Loading…
Reference in a new issue