manifest: deduplicate duplicate-checking code

Signed-off-by: Roman Khimov <roman@nspcc.ru>
This commit is contained in:
Roman Khimov 2024-08-26 20:08:58 +03:00
parent db820cb0dc
commit 49438798b5
5 changed files with 35 additions and 78 deletions

View file

@ -4,7 +4,6 @@ import (
"cmp"
"errors"
"fmt"
"slices"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
@ -63,23 +62,14 @@ func (a *ABI) IsValid() error {
return fmt.Errorf("method %q/%d: %w", a.Methods[i].Name, len(a.Methods[i].Parameters), err)
}
}
if len(a.Methods) > 1 {
var methods = slices.Clone(a.Methods)
slices.SortFunc(methods, func(a, b Method) int {
return cmp.Or(
cmp.Compare(a.Name, b.Name),
cmp.Compare(len(a.Parameters), len(b.Parameters)),
)
})
for i := range methods {
if i == 0 {
continue
}
if methods[i].Name == methods[i-1].Name &&
len(methods[i].Parameters) == len(methods[i-1].Parameters) {
return errors.New("duplicate method specifications")
}
if sliceHasDups(a.Methods, func(a, b Method) int {
res := cmp.Compare(a.Name, b.Name)
if res != 0 {
return res
}
return cmp.Compare(len(a.Parameters), len(b.Parameters))
}) {
return errors.New("duplicate method specifications")
}
for i := range a.Events {
err := a.Events[i].IsValid()
@ -87,14 +77,10 @@ func (a *ABI) IsValid() error {
return fmt.Errorf("event %q/%d: %w", a.Events[i].Name, len(a.Events[i].Parameters), 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")
}
if sliceHasDups(a.Events, func(a, b Event) int {
return cmp.Compare(a.Name, b.Name)
}) {
return errors.New("duplicate event names")
}
return nil
}

View file

@ -6,7 +6,6 @@ import (
"encoding/json"
"errors"
"slices"
"sort"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
@ -59,7 +58,7 @@ func (g Groups) AreValid(h util.Uint160) error {
for i := range g {
pkeys[i] = g[i].PublicKey
}
sort.Sort(pkeys)
slices.SortFunc(pkeys, (*keys.PublicKey).Cmp)
for i := range pkeys {
if i == 0 {
continue

View file

@ -95,11 +95,8 @@ func (m *Manifest) IsValid(hash util.Uint160, checkSize bool) error {
if slices.Contains(m.SupportedStandards, "") {
return errors.New("invalid nameless supported standard")
}
if len(m.SupportedStandards) > 1 {
names := slices.Clone(m.SupportedStandards)
if stringsHaveDups(names) {
return errors.New("duplicate supported standards")
}
if sliceHasDups(m.SupportedStandards, strings.Compare) {
return errors.New("duplicate supported standards")
}
err = m.ABI.IsValid()
if err != nil {
@ -122,11 +119,8 @@ func (m *Manifest) IsValid(hash util.Uint160, checkSize bool) error {
if m.Trusts.Value == nil && !m.Trusts.Wildcard {
return errors.New("invalid (null?) trusts")
}
if len(m.Trusts.Value) > 1 {
hashes := slices.Clone(m.Trusts.Value)
if permissionDescsHaveDups(hashes) {
return errors.New("duplicate trusted contracts")
}
if sliceHasDups(m.Trusts.Value, PermissionDesc.Compare) {
return errors.New("duplicate trusted contracts")
}
err = Permissions(m.Permissions).AreValid()
if err != nil {

View file

@ -1,6 +1,7 @@
package manifest
import (
"cmp"
"errors"
"fmt"
"slices"
@ -79,42 +80,28 @@ func (p Parameters) AreValid() error {
return fmt.Errorf("parameter #%d/%q: %w", i, p[i].Name, err)
}
}
if len(p) < 2 {
return nil
}
names := make([]string, len(p))
for i := range p {
names[i] = p[i].Name
}
if stringsHaveDups(names) {
if sliceHasDups(p, func(a, b Parameter) int {
return cmp.Compare(a.Name, b.Name)
}) {
return errors.New("duplicate parameter name")
}
return nil
}
// stringsHaveDups checks the given set of strings for duplicates. It modifies the slice given!
func stringsHaveDups(strings []string) bool {
slices.Sort(strings)
for i := range strings {
// sliceHasDups checks the slice for duplicate elements.
func sliceHasDups[S ~[]E, E any](x S, cmp func(a, b E) int) bool {
if len(x) < 2 {
return false
}
if len(x) > 2 {
x = slices.Clone(x)
slices.SortFunc(x, cmp)
}
for i := range x {
if i == 0 {
continue
}
if strings[i] == strings[i-1] {
return true
}
}
return false
}
// permissionDescsHaveDups checks the given set of strings for duplicates. It modifies the slice given!
func permissionDescsHaveDups(descs []PermissionDesc) bool {
slices.SortFunc(descs, PermissionDesc.Compare)
for i := range descs {
if i == 0 {
continue
}
j := i - 1
if descs[i].Compare(descs[j]) == 0 {
if cmp(x[i-1], x[i]) == 0 {
return true
}
}

View file

@ -119,11 +119,7 @@ func (p *Permission) IsValid() error {
if slices.Contains(p.Methods.Value, "") {
return errors.New("empty method name")
}
if len(p.Methods.Value) < 2 {
return nil
}
names := slices.Clone(p.Methods.Value)
if stringsHaveDups(names) {
if sliceHasDups(p.Methods.Value, cmp.Compare) {
return errors.New("duplicate method names")
}
return nil
@ -137,14 +133,9 @@ func (ps Permissions) AreValid() error {
return err
}
}
if len(ps) < 2 {
return nil
}
contracts := make([]PermissionDesc, 0, len(ps))
for i := range ps {
contracts = append(contracts, ps[i].Contract)
}
if permissionDescsHaveDups(contracts) {
if sliceHasDups(ps, func(a, b Permission) int {
return a.Contract.Compare(b.Contract)
}) {
return errors.New("contracts have duplicates")
}
return nil