diff --git a/pkg/smartcontract/manifest/event.go b/pkg/smartcontract/manifest/event.go new file mode 100644 index 000000000..a80b13902 --- /dev/null +++ b/pkg/smartcontract/manifest/event.go @@ -0,0 +1,54 @@ +package manifest + +import ( + "errors" + + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" +) + +// Event is a description of a single event. +type Event struct { + Name string `json:"name"` + Parameters []Parameter `json:"parameters"` +} + +// ToStackItem converts Event to stackitem.Item. +func (e *Event) ToStackItem() stackitem.Item { + params := make([]stackitem.Item, len(e.Parameters)) + for i := range e.Parameters { + params[i] = e.Parameters[i].ToStackItem() + } + return stackitem.NewStruct([]stackitem.Item{ + stackitem.Make(e.Name), + stackitem.Make(params), + }) +} + +// FromStackItem converts stackitem.Item to Event. +func (e *Event) FromStackItem(item stackitem.Item) error { + var err error + if item.Type() != stackitem.StructT { + return errors.New("invalid Event stackitem type") + } + event := item.Value().([]stackitem.Item) + if len(event) != 2 { + return errors.New("invalid Event stackitem length") + } + e.Name, err = stackitem.ToString(event[0]) + if err != nil { + return err + } + if event[1].Type() != stackitem.ArrayT { + return errors.New("invalid Params stackitem type") + } + params := event[1].Value().([]stackitem.Item) + e.Parameters = make([]Parameter, len(params)) + for i := range params { + p := new(Parameter) + if err := p.FromStackItem(params[i]); err != nil { + return err + } + e.Parameters[i] = *p + } + return nil +} diff --git a/pkg/smartcontract/manifest/event_test.go b/pkg/smartcontract/manifest/event_test.go new file mode 100644 index 000000000..81c63c755 --- /dev/null +++ b/pkg/smartcontract/manifest/event_test.go @@ -0,0 +1,43 @@ +package manifest + +import ( + "math/big" + "testing" + + "github.com/nspcc-dev/neo-go/pkg/smartcontract" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" + "github.com/stretchr/testify/require" +) + +func TestEvent_ToStackItemFromStackItem(t *testing.T) { + m := &Event{ + Name: "mur", + Parameters: []Parameter{{Name: "p1", Type: smartcontract.BoolType}}, + } + expected := stackitem.NewStruct([]stackitem.Item{ + stackitem.NewByteArray([]byte(m.Name)), + stackitem.NewArray([]stackitem.Item{ + stackitem.NewStruct([]stackitem.Item{ + stackitem.NewByteArray([]byte(m.Parameters[0].Name)), + stackitem.NewBigInteger(big.NewInt(int64(m.Parameters[0].Type))), + }), + }), + }) + CheckToFromStackItem(t, m, expected) +} + +func TestEvent_FromStackItemErrors(t *testing.T) { + errCases := map[string]stackitem.Item{ + "not a struct": stackitem.NewArray([]stackitem.Item{}), + "invalid length": stackitem.NewStruct([]stackitem.Item{}), + "invalid name type": stackitem.NewStruct([]stackitem.Item{stackitem.NewInterop(nil), stackitem.Null{}}), + "invalid parameters type": stackitem.NewStruct([]stackitem.Item{stackitem.NewByteArray([]byte{}), stackitem.Null{}}), + "invalid parameter": stackitem.NewStruct([]stackitem.Item{stackitem.NewByteArray([]byte{}), stackitem.NewArray([]stackitem.Item{stackitem.NewStruct([]stackitem.Item{})})}), + } + for name, errCase := range errCases { + t.Run(name, func(t *testing.T) { + p := new(Event) + require.Error(t, p.FromStackItem(errCase)) + }) + } +} diff --git a/pkg/smartcontract/manifest/method.go b/pkg/smartcontract/manifest/method.go index f6e99175f..af271bacc 100644 --- a/pkg/smartcontract/manifest/method.go +++ b/pkg/smartcontract/manifest/method.go @@ -13,12 +13,6 @@ type Parameter struct { Type smartcontract.ParamType `json:"type"` } -// Event is a description of a single event. -type Event struct { - Name string `json:"name"` - Parameters []Parameter `json:"parameters"` -} - // Method represents method's metadata. type Method struct { Name string `json:"name"` @@ -130,44 +124,3 @@ func (p *Parameter) FromStackItem(item stackitem.Item) error { } return nil } - -// ToStackItem converts Event to stackitem.Item. -func (e *Event) ToStackItem() stackitem.Item { - params := make([]stackitem.Item, len(e.Parameters)) - for i := range e.Parameters { - params[i] = e.Parameters[i].ToStackItem() - } - return stackitem.NewStruct([]stackitem.Item{ - stackitem.Make(e.Name), - stackitem.Make(params), - }) -} - -// FromStackItem converts stackitem.Item to Event. -func (e *Event) FromStackItem(item stackitem.Item) error { - var err error - if item.Type() != stackitem.StructT { - return errors.New("invalid Event stackitem type") - } - event := item.Value().([]stackitem.Item) - if len(event) != 2 { - return errors.New("invalid Event stackitem length") - } - e.Name, err = stackitem.ToString(event[0]) - if err != nil { - return err - } - if event[1].Type() != stackitem.ArrayT { - return errors.New("invalid Params stackitem type") - } - params := event[1].Value().([]stackitem.Item) - e.Parameters = make([]Parameter, len(params)) - for i := range params { - p := new(Parameter) - if err := p.FromStackItem(params[i]); err != nil { - return err - } - e.Parameters[i] = *p - } - return nil -} diff --git a/pkg/smartcontract/manifest/method_test.go b/pkg/smartcontract/manifest/method_test.go index c05e517f8..063b873cd 100644 --- a/pkg/smartcontract/manifest/method_test.go +++ b/pkg/smartcontract/manifest/method_test.go @@ -80,39 +80,6 @@ func TestParameter_FromStackItemErrors(t *testing.T) { } } -func TestEvent_ToStackItemFromStackItem(t *testing.T) { - m := &Event{ - Name: "mur", - Parameters: []Parameter{{Name: "p1", Type: smartcontract.BoolType}}, - } - expected := stackitem.NewStruct([]stackitem.Item{ - stackitem.NewByteArray([]byte(m.Name)), - stackitem.NewArray([]stackitem.Item{ - stackitem.NewStruct([]stackitem.Item{ - stackitem.NewByteArray([]byte(m.Parameters[0].Name)), - stackitem.NewBigInteger(big.NewInt(int64(m.Parameters[0].Type))), - }), - }), - }) - CheckToFromStackItem(t, m, expected) -} - -func TestEvent_FromStackItemErrors(t *testing.T) { - errCases := map[string]stackitem.Item{ - "not a struct": stackitem.NewArray([]stackitem.Item{}), - "invalid length": stackitem.NewStruct([]stackitem.Item{}), - "invalid name type": stackitem.NewStruct([]stackitem.Item{stackitem.NewInterop(nil), stackitem.Null{}}), - "invalid parameters type": stackitem.NewStruct([]stackitem.Item{stackitem.NewByteArray([]byte{}), stackitem.Null{}}), - "invalid parameter": stackitem.NewStruct([]stackitem.Item{stackitem.NewByteArray([]byte{}), stackitem.NewArray([]stackitem.Item{stackitem.NewStruct([]stackitem.Item{})})}), - } - for name, errCase := range errCases { - t.Run(name, func(t *testing.T) { - p := new(Event) - require.Error(t, p.FromStackItem(errCase)) - }) - } -} - func TestGroup_ToStackItemFromStackItem(t *testing.T) { pk, _ := keys.NewPrivateKey() g := &Group{