diff --git a/pkg/core/state/notification_event.go b/pkg/core/state/notification_event.go index 48027137d5..6fa365e598 100644 --- a/pkg/core/state/notification_event.go +++ b/pkg/core/state/notification_event.go @@ -1,7 +1,9 @@ package state import ( + "encoding/json" "errors" + "fmt" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" @@ -13,9 +15,9 @@ import ( // NotificationEvent is a tuple of scripthash that emitted the Item as a // notification and that item itself. type NotificationEvent struct { - ScriptHash util.Uint160 - Name string - Item *stackitem.Array + ScriptHash util.Uint160 `json:"contract"` + Name string `json:"eventname"` + Item *stackitem.Array `json:"state"` } // AppExecResult represent the result of the script execution, gathering together @@ -79,3 +81,40 @@ func (aer *AppExecResult) DecodeBinary(r *io.BinReader) { } r.ReadArray(&aer.Events) } + +// notificationEventAux is an auxiliary struct for NotificationEvent JSON marshalling +type notificationEventAux struct { + ScriptHash util.Uint160 `json:"contract"` + Name string `json:"eventname"` + Item json.RawMessage `json:"state"` +} + +func (ne *NotificationEvent) MarshalJSON() ([]byte, error) { + item, err := stackitem.ToJSONWithTypes(ne.Item) + if err != nil { + return nil, err + } + return json.Marshal(¬ificationEventAux{ + ScriptHash: ne.ScriptHash, + Name: ne.Name, + Item: item, + }) +} + +func (ne *NotificationEvent) UnmarshalJSON(data []byte) error { + aux := new(notificationEventAux) + if err := json.Unmarshal(data, aux); err != nil { + return err + } + item, err := stackitem.FromJSONWithTypes(aux.Item) + if err != nil { + return err + } + if t := item.Type(); t != stackitem.ArrayT { + return fmt.Errorf("failed to convert notification event state of type %s to array", t.String()) + } + ne.Item = item.(*stackitem.Array) + ne.Name = aux.Name + ne.ScriptHash = aux.ScriptHash + return nil +} diff --git a/pkg/rpc/client/rpc_test.go b/pkg/rpc/client/rpc_test.go index da1667e2d8..f2233d9737 100644 --- a/pkg/rpc/client/rpc_test.go +++ b/pkg/rpc/client/rpc_test.go @@ -119,7 +119,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ VMState: "HALT", GasConsumed: 1, Stack: []stackitem.Item{stackitem.NewBigInteger(big.NewInt(1))}, - Events: []result.NotificationEvent{}, + Events: []state.NotificationEvent{}, } }, }, diff --git a/pkg/rpc/client/wsclient.go b/pkg/rpc/client/wsclient.go index f434ff51aa..70ede7790b 100644 --- a/pkg/rpc/client/wsclient.go +++ b/pkg/rpc/client/wsclient.go @@ -8,6 +8,7 @@ import ( "github.com/gorilla/websocket" "github.com/nspcc-dev/neo-go/pkg/core/block" + "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/rpc/request" "github.com/nspcc-dev/neo-go/pkg/rpc/response" @@ -141,7 +142,7 @@ readloop: case response.TransactionEventID: val = &transaction.Transaction{Network: c.opts.Network} case response.NotificationEventID: - val = new(result.NotificationEvent) + val = new(state.NotificationEvent) case response.ExecutionEventID: val = new(result.ApplicationLog) case response.MissedEventID: diff --git a/pkg/rpc/response/result/application_log.go b/pkg/rpc/response/result/application_log.go index 455f1d4319..dbd2be0441 100644 --- a/pkg/rpc/response/result/application_log.go +++ b/pkg/rpc/response/result/application_log.go @@ -4,7 +4,6 @@ import ( "encoding/json" "github.com/nspcc-dev/neo-go/pkg/core/state" - "github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) @@ -17,23 +16,16 @@ type ApplicationLog struct { VMState string GasConsumed int64 Stack []stackitem.Item - Events []NotificationEvent -} - -//NotificationEvent response wrapper -type NotificationEvent struct { - Contract util.Uint160 `json:"contract"` - Name string `json:"eventname"` - Item smartcontract.Parameter `json:"state"` + Events []state.NotificationEvent } type applicationLogAux struct { - TxHash util.Uint256 `json:"txid"` - Trigger string `json:"trigger"` - VMState string `json:"vmstate"` - GasConsumed int64 `json:"gasconsumed,string"` - Stack []json.RawMessage `json:"stack"` - Events []NotificationEvent `json:"notifications"` + TxHash util.Uint256 `json:"txid"` + Trigger string `json:"trigger"` + VMState string `json:"vmstate"` + GasConsumed int64 `json:"gasconsumed,string"` + Stack []json.RawMessage `json:"stack"` + Events []state.NotificationEvent `json:"notifications"` } // MarshalJSON implements json.Marshaler. @@ -80,30 +72,14 @@ func (l *ApplicationLog) UnmarshalJSON(data []byte) error { return nil } -// StateEventToResultNotification converts state.NotificationEvent to -// result.NotificationEvent. -func StateEventToResultNotification(event state.NotificationEvent) NotificationEvent { - seen := make(map[stackitem.Item]bool) - item := smartcontract.ParameterFromStackItem(event.Item, seen) - return NotificationEvent{ - Contract: event.ScriptHash, - Name: event.Name, - Item: item, - } -} - // NewApplicationLog creates a new ApplicationLog wrapper. func NewApplicationLog(appExecRes *state.AppExecResult) ApplicationLog { - events := make([]NotificationEvent, 0, len(appExecRes.Events)) - for _, e := range appExecRes.Events { - events = append(events, StateEventToResultNotification(e)) - } return ApplicationLog{ TxHash: appExecRes.TxHash, Trigger: appExecRes.Trigger.String(), VMState: appExecRes.VMState.String(), GasConsumed: appExecRes.GasConsumed, Stack: appExecRes.Stack, - Events: events, + Events: appExecRes.Events, } } diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index f89bf00acc..f69c4962ea 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -1162,7 +1162,7 @@ chloop: resp.Payload[0] = result.NewApplicationLog(execution) case notification := <-s.notificationCh: resp.Event = response.NotificationEventID - resp.Payload[0] = result.StateEventToResultNotification(*notification) + resp.Payload[0] = *notification case tx := <-s.transactionCh: resp.Event = response.TransactionEventID resp.Payload[0] = tx diff --git a/pkg/rpc/server/subscription.go b/pkg/rpc/server/subscription.go index 3b2b728b52..fb8b7eec08 100644 --- a/pkg/rpc/server/subscription.go +++ b/pkg/rpc/server/subscription.go @@ -3,6 +3,7 @@ package server import ( "github.com/gorilla/websocket" "github.com/nspcc-dev/neo-go/pkg/core/block" + "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/rpc/request" "github.com/nspcc-dev/neo-go/pkg/rpc/response" @@ -72,8 +73,8 @@ func (f *feed) Matches(r *response.Notification) bool { return senderOK && signerOK case response.NotificationEventID: filt := f.filter.(request.NotificationFilter) - notification := r.Payload[0].(result.NotificationEvent) - hashOk := filt.Contract == nil || notification.Contract.Equals(*filt.Contract) + notification := r.Payload[0].(state.NotificationEvent) + hashOk := filt.Contract == nil || notification.ScriptHash.Equals(*filt.Contract) nameOk := filt.Name == nil || notification.Name == *filt.Name return hashOk && nameOk case response.ExecutionEventID: