From a3abdbd7f0e3107e439acc388714780d5bd111bf Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 8 Feb 2021 23:53:22 +0300 Subject: [PATCH] manifest: add duplicate events/methods checks to ABI Refs. #1699. --- pkg/smartcontract/manifest/abi.go | 38 ++++++++++++++++++++++++ pkg/smartcontract/manifest/abi_test.go | 41 ++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 pkg/smartcontract/manifest/abi_test.go diff --git a/pkg/smartcontract/manifest/abi.go b/pkg/smartcontract/manifest/abi.go index cffb4a21f..8d8f97c76 100644 --- a/pkg/smartcontract/manifest/abi.go +++ b/pkg/smartcontract/manifest/abi.go @@ -2,6 +2,7 @@ package manifest import ( "errors" + "sort" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) @@ -60,12 +61,49 @@ func (a *ABI) IsValid() error { return err } } + if len(a.Methods) > 1 { + methods := make([]struct { + name string + params int + }, len(a.Methods)) + for i := range methods { + methods[i].name = a.Methods[i].Name + methods[i].params = len(a.Methods[i].Parameters) + } + sort.Slice(methods, func(i, j int) bool { + if methods[i].name < methods[j].name { + return true + } + if methods[i].name == methods[j].name { + return methods[i].params < methods[j].params + } + return false + }) + for i := range methods { + if i == 0 { + continue + } + if methods[i].name == methods[i-1].name && + methods[i].params == methods[i-1].params { + return errors.New("duplicate method specifications") + } + } + } for i := range a.Events { err := a.Events[i].IsValid() if err != nil { return err } } + if len(a.Events) > 1 { + names := make([]string, len(a.Events)) + for i := range a.Events { + names[i] = a.Events[i].Name + } + if stringsHaveDups(names) { + return errors.New("duplicate event names") + } + } return nil } diff --git a/pkg/smartcontract/manifest/abi_test.go b/pkg/smartcontract/manifest/abi_test.go new file mode 100644 index 000000000..2b9a54f0e --- /dev/null +++ b/pkg/smartcontract/manifest/abi_test.go @@ -0,0 +1,41 @@ +package manifest + +import ( + "testing" + + "github.com/nspcc-dev/neo-go/pkg/smartcontract" + "github.com/stretchr/testify/require" +) + +func TestABIIsValid(t *testing.T) { + a := &ABI{} + require.Error(t, a.IsValid()) // No methods. + + a.Methods = append(a.Methods, Method{Name: "qwe"}) + require.NoError(t, a.IsValid()) + + a.Methods = append(a.Methods, Method{Name: "qaz"}) + require.NoError(t, a.IsValid()) + + a.Methods = append(a.Methods, Method{Name: "qaz", Offset: -42}) + require.Error(t, a.IsValid()) + + a.Methods = append(a.Methods[:len(a.Methods)-1], Method{Name: "qwe", Parameters: []Parameter{NewParameter("param", smartcontract.BoolType)}}) + require.NoError(t, a.IsValid()) + + a.Methods = append(a.Methods, Method{Name: "qwe"}) + require.Error(t, a.IsValid()) + a.Methods = a.Methods[:len(a.Methods)-1] + + a.Events = append(a.Events, Event{Name: "wsx"}) + require.NoError(t, a.IsValid()) + + a.Events = append(a.Events, Event{}) + require.Error(t, a.IsValid()) + + a.Events = append(a.Events[:len(a.Events)-1], Event{Name: "edc"}) + require.NoError(t, a.IsValid()) + + a.Events = append(a.Events, Event{Name: "wsx"}) + require.Error(t, a.IsValid()) +}