rpc: use state.AppExecResult for ApplicationLog marshalling

Closes #1371
This commit is contained in:
Anna Shaleva 2020-09-03 19:58:50 +03:00
parent 34df5d5949
commit acacac1b24
11 changed files with 276 additions and 136 deletions

View file

@ -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,119 @@ 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"`
}
// MarshalJSON implements implements json.Marshaler interface.
func (ne *NotificationEvent) MarshalJSON() ([]byte, error) {
item, err := stackitem.ToJSONWithTypes(ne.Item)
if err != nil {
item = []byte(`"error: recursive reference"`)
}
return json.Marshal(&notificationEventAux{
ScriptHash: ne.ScriptHash,
Name: ne.Name,
Item: item,
})
}
// UnmarshalJSON implements json.Unmarshaler interface.
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
}
// appExecResultAux is an auxiliary struct for JSON marshalling
type appExecResultAux 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"`
}
// MarshalJSON implements implements json.Marshaler interface.
func (aer *AppExecResult) MarshalJSON() ([]byte, error) {
var st json.RawMessage
arr := make([]json.RawMessage, len(aer.Stack))
for i := range arr {
data, err := stackitem.ToJSONWithTypes(aer.Stack[i])
if err != nil {
st = []byte(`"error: recursive reference"`)
break
}
arr[i] = data
}
var err error
if st == nil {
st, err = json.Marshal(arr)
if err != nil {
return nil, err
}
}
return json.Marshal(&appExecResultAux{
TxHash: aer.TxHash,
Trigger: aer.Trigger.String(),
VMState: aer.VMState.String(),
GasConsumed: aer.GasConsumed,
Stack: st,
Events: aer.Events,
})
}
// UnmarshalJSON implements implements json.Unmarshaler interface.
func (aer *AppExecResult) UnmarshalJSON(data []byte) error {
aux := new(appExecResultAux)
if err := json.Unmarshal(data, aux); err != nil {
return err
}
var arr []json.RawMessage
if err := json.Unmarshal(aux.Stack, &arr); err == nil {
st := make([]stackitem.Item, len(arr))
for i := range arr {
st[i], err = stackitem.FromJSONWithTypes(arr[i])
if err != nil {
break
}
}
if err == nil {
aer.Stack = st
}
}
trigger, err := trigger.FromString(aux.Trigger)
if err != nil {
return err
}
aer.Trigger = trigger
aer.TxHash = aux.TxHash
state, err := vm.StateFromString(aux.VMState)
if err != nil {
return err
}
aer.VMState = state
aer.Events = aux.Events
aer.GasConsumed = aux.GasConsumed
return nil
}