manifest: add method validity check

Refs. #1699.
This commit is contained in:
Roman Khimov 2021-02-08 18:37:39 +03:00
parent f3c761e4c2
commit f0c3066ef6
5 changed files with 67 additions and 17 deletions

View file

@ -54,6 +54,12 @@ func (a *ABI) IsValid() error {
if len(a.Methods) == 0 { if len(a.Methods) == 0 {
return errors.New("ABI contains no methods") return errors.New("ABI contains no methods")
} }
for i := range a.Methods {
err := a.Methods[i].IsValid()
if err != nil {
return err
}
}
for i := range a.Events { for i := range a.Events {
err := a.Events[i].IsValid() err := a.Events[i].IsValid()
if err != nil { if err != nil {

View file

@ -2,7 +2,6 @@ package manifest
import ( import (
"errors" "errors"
"sort"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
) )
@ -18,22 +17,7 @@ func (e *Event) IsValid() error {
if e.Name == "" { if e.Name == "" {
return errors.New("empty or absent name") return errors.New("empty or absent name")
} }
if len(e.Parameters) > 1 { return Parameters(e.Parameters).AreValid()
paramNames := make([]string, len(e.Parameters))
for i := range e.Parameters {
paramNames[i] = e.Parameters[i].Name
}
sort.Strings(paramNames)
for i := range paramNames {
if i == 0 {
continue
}
if paramNames[i] == paramNames[i-1] {
return errors.New("duplicate parameter name")
}
}
}
return nil
} }
// ToStackItem converts Event to stackitem.Item. // ToStackItem converts Event to stackitem.Item.

View file

@ -16,6 +16,21 @@ type Method struct {
Safe bool `json:"safe"` Safe bool `json:"safe"`
} }
// IsValid checks Method consistency and correctness.
func (m *Method) IsValid() error {
if m.Name == "" {
return errors.New("empty or absent name")
}
if m.Offset < 0 {
return errors.New("negative offset")
}
_, err := smartcontract.ConvertToParamType(int(m.ReturnType))
if err != nil {
return err
}
return Parameters(m.Parameters).AreValid()
}
// ToStackItem converts Method to stackitem.Item. // ToStackItem converts Method to stackitem.Item.
func (m *Method) ToStackItem() stackitem.Item { func (m *Method) ToStackItem() stackitem.Item {
params := make([]stackitem.Item, len(m.Parameters)) params := make([]stackitem.Item, len(m.Parameters))

View file

@ -10,6 +10,27 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestMethodIsValid(t *testing.T) {
m := &Method{}
require.Error(t, m.IsValid()) // No name.
m.Name = "qwerty"
require.NoError(t, m.IsValid())
m.Offset = -100
require.Error(t, m.IsValid())
m.Offset = 100
m.ReturnType = 0x42 // Invalid type.
require.Error(t, m.IsValid())
m.ReturnType = smartcontract.BoolType
require.NoError(t, m.IsValid())
m.Parameters = append(m.Parameters, NewParameter("param", smartcontract.BoolType), NewParameter("param", smartcontract.BoolType))
require.Error(t, m.IsValid())
}
func TestMethod_ToStackItemFromStackItem(t *testing.T) { func TestMethod_ToStackItemFromStackItem(t *testing.T) {
m := &Method{ m := &Method{
Name: "mur", Name: "mur",

View file

@ -14,6 +14,9 @@ type Parameter struct {
Type smartcontract.ParamType `json:"type"` Type smartcontract.ParamType `json:"type"`
} }
// Parameters is just an array of Parameter.
type Parameters []Parameter
// NewParameter returns new parameter of specified name and type. // NewParameter returns new parameter of specified name and type.
func NewParameter(name string, typ smartcontract.ParamType) Parameter { func NewParameter(name string, typ smartcontract.ParamType) Parameter {
return Parameter{ return Parameter{
@ -54,3 +57,24 @@ func (p *Parameter) FromStackItem(item stackitem.Item) error {
} }
return nil return nil
} }
// AreValid checks all parameters for validity and consistency.
func (p Parameters) AreValid() error {
if len(p) < 2 {
return nil
}
names := make([]string, len(p))
for i := range p {
names[i] = p[i].Name
}
sort.Strings(names)
for i := range names {
if i == 0 {
continue
}
if names[i] == names[i-1] {
return errors.New("duplicate parameter name")
}
}
return nil
}