diff --git a/cli/testdata/verify.yml b/cli/testdata/verify.yml index 8d3cb83ad..421e5d254 100644 --- a/cli/testdata/verify.yml +++ b/cli/testdata/verify.yml @@ -1,5 +1,5 @@ name: Test verify -Events: +events: - name: OnNEP11Payment parameters: - name: from diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index c2cf96533..5fd993f01 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -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) diff --git a/pkg/compiler/compiler_test.go b/pkg/compiler/compiler_test.go index cfe300e8d..d77a26012 100644 --- a/pkg/compiler/compiler_test.go +++ b/pkg/compiler/compiler_test.go @@ -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) + }) +} diff --git a/pkg/compiler/inline.go b/pkg/compiler/inline.go index d3653941b..6c5b676ce 100644 --- a/pkg/compiler/inline.go +++ b/pkg/compiler/inline.go @@ -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) + } +} diff --git a/pkg/compiler/syscall_test.go b/pkg/compiler/syscall_test.go index 86adb3306..048362af2 100644 --- a/pkg/compiler/syscall_test.go +++ b/pkg/compiler/syscall_test.go @@ -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) {