github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/smartcontract/manifest/parameter.go (about)

     1  package manifest
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"sort"
     7  
     8  	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
     9  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    10  )
    11  
    12  // Parameter represents smartcontract's parameter's definition.
    13  type Parameter struct {
    14  	Name string                  `json:"name"`
    15  	Type smartcontract.ParamType `json:"type"`
    16  }
    17  
    18  // Parameters is just an array of Parameter.
    19  type Parameters []Parameter
    20  
    21  // NewParameter returns a new parameter of the specified name and type.
    22  func NewParameter(name string, typ smartcontract.ParamType) Parameter {
    23  	return Parameter{
    24  		Name: name,
    25  		Type: typ,
    26  	}
    27  }
    28  
    29  // IsValid checks Parameter consistency and correctness.
    30  func (p *Parameter) IsValid() error {
    31  	if p.Name == "" {
    32  		return errors.New("empty or absent name")
    33  	}
    34  	if p.Type == smartcontract.VoidType {
    35  		return errors.New("void parameter")
    36  	}
    37  	_, err := smartcontract.ConvertToParamType(int(p.Type))
    38  	return err
    39  }
    40  
    41  // ToStackItem converts Parameter to stackitem.Item.
    42  func (p *Parameter) ToStackItem() stackitem.Item {
    43  	return stackitem.NewStruct([]stackitem.Item{
    44  		stackitem.Make(p.Name),
    45  		stackitem.Make(int(p.Type)),
    46  	})
    47  }
    48  
    49  // FromStackItem converts stackitem.Item to Parameter.
    50  func (p *Parameter) FromStackItem(item stackitem.Item) error {
    51  	var err error
    52  	if item.Type() != stackitem.StructT {
    53  		return errors.New("invalid Parameter stackitem type")
    54  	}
    55  	param := item.Value().([]stackitem.Item)
    56  	if len(param) != 2 {
    57  		return errors.New("invalid Parameter stackitem length")
    58  	}
    59  	p.Name, err = stackitem.ToString(param[0])
    60  	if err != nil {
    61  		return err
    62  	}
    63  	typ, err := param[1].TryInteger()
    64  	if err != nil {
    65  		return err
    66  	}
    67  	p.Type, err = smartcontract.ConvertToParamType(int(typ.Int64()))
    68  	if err != nil {
    69  		return err
    70  	}
    71  	return nil
    72  }
    73  
    74  // AreValid checks all parameters for validity and consistency.
    75  func (p Parameters) AreValid() error {
    76  	for i := range p {
    77  		err := p[i].IsValid()
    78  		if err != nil {
    79  			return fmt.Errorf("parameter #%d/%q: %w", i, p[i].Name, err)
    80  		}
    81  	}
    82  	if len(p) < 2 {
    83  		return nil
    84  	}
    85  	names := make([]string, len(p))
    86  	for i := range p {
    87  		names[i] = p[i].Name
    88  	}
    89  	if stringsHaveDups(names) {
    90  		return errors.New("duplicate parameter name")
    91  	}
    92  	return nil
    93  }
    94  
    95  // stringsHaveDups checks the given set of strings for duplicates. It modifies the slice given!
    96  func stringsHaveDups(strings []string) bool {
    97  	sort.Strings(strings)
    98  	for i := range strings {
    99  		if i == 0 {
   100  			continue
   101  		}
   102  		if strings[i] == strings[i-1] {
   103  			return true
   104  		}
   105  	}
   106  	return false
   107  }
   108  
   109  // permissionDescsHaveDups checks the given set of strings for duplicates. It modifies the slice given!
   110  func permissionDescsHaveDups(descs []PermissionDesc) bool {
   111  	sort.Slice(descs, func(i, j int) bool {
   112  		return descs[i].Less(descs[j])
   113  	})
   114  	for i := range descs {
   115  		if i == 0 {
   116  			continue
   117  		}
   118  		j := i - 1
   119  		if descs[i].Type != descs[j].Type {
   120  			continue
   121  		}
   122  		switch descs[i].Type {
   123  		case PermissionWildcard:
   124  			return true
   125  		case PermissionHash:
   126  			if descs[i].Hash() == descs[j].Hash() {
   127  				return true
   128  			}
   129  		case PermissionGroup:
   130  			if descs[i].Group().Cmp(descs[j].Group()) == 0 {
   131  				return true
   132  			}
   133  		}
   134  	}
   135  	return false
   136  }