Skip to content

Commit

Permalink
rpc: use stackitem for NotificationEvent.State
Browse files Browse the repository at this point in the history
Closes #1371
  • Loading branch information
AnnaShaleva committed Sep 4, 2020
1 parent d40a730 commit 602a91c
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 40 deletions.
45 changes: 42 additions & 3 deletions pkg/core/state/notification_event.go
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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
Expand Down Expand Up @@ -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(&notificationEventAux{
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
}
2 changes: 1 addition & 1 deletion pkg/rpc/client/rpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{},
}
},
},
Expand Down
3 changes: 2 additions & 1 deletion pkg/rpc/client/wsclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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:
Expand Down
40 changes: 8 additions & 32 deletions pkg/rpc/response/result/application_log.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -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.
Expand Down Expand Up @@ -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,
}
}
2 changes: 1 addition & 1 deletion pkg/rpc/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions pkg/rpc/server/subscription.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit 602a91c

Please sign in to comment.