rpc: allow to marshal Iterators for invoke* results
This commit is contained in:
parent
4e55b1a9ed
commit
9eeebf481c
5 changed files with 108 additions and 21 deletions
|
@ -2,20 +2,35 @@ package result
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
// Invoke represents code invocation result and is used by several RPC calls
|
||||
// that invoke functions, scripts and generic bytecode.
|
||||
type Invoke struct {
|
||||
State string
|
||||
GasConsumed int64
|
||||
Script []byte
|
||||
Stack []stackitem.Item
|
||||
FaultException string
|
||||
Transaction *transaction.Transaction
|
||||
State string
|
||||
GasConsumed int64
|
||||
Script []byte
|
||||
Stack []stackitem.Item
|
||||
FaultException string
|
||||
Transaction *transaction.Transaction
|
||||
maxIteratorResultItems int
|
||||
}
|
||||
|
||||
// NewInvoke returns new Invoke structure with the given fields set.
|
||||
func NewInvoke(vm *vm.VM, script []byte, faultException string, maxIteratorResultItems int) *Invoke {
|
||||
return &Invoke{
|
||||
State: vm.State().String(),
|
||||
GasConsumed: vm.GasConsumed(),
|
||||
Script: script,
|
||||
Stack: vm.Estack().ToArray(),
|
||||
FaultException: faultException,
|
||||
maxIteratorResultItems: maxIteratorResultItems,
|
||||
}
|
||||
}
|
||||
|
||||
type invokeAux struct {
|
||||
|
@ -27,15 +42,51 @@ type invokeAux struct {
|
|||
Transaction []byte `json:"tx,omitempty"`
|
||||
}
|
||||
|
||||
type iteratorAux struct {
|
||||
Type string `json:"type"`
|
||||
Value []json.RawMessage `json:"iterator"`
|
||||
Truncated bool `json:"truncated"`
|
||||
}
|
||||
|
||||
// Iterator represents deserialized VM iterator values with truncated flag.
|
||||
type Iterator struct {
|
||||
Values []stackitem.Item
|
||||
Truncated bool
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
func (r Invoke) MarshalJSON() ([]byte, error) {
|
||||
var st json.RawMessage
|
||||
arr := make([]json.RawMessage, len(r.Stack))
|
||||
for i := range arr {
|
||||
data, err := stackitem.ToJSONWithTypes(r.Stack[i])
|
||||
if err != nil {
|
||||
st = []byte(`"error: recursive reference"`)
|
||||
break
|
||||
var (
|
||||
data []byte
|
||||
err error
|
||||
)
|
||||
if (r.Stack[i].Type() == stackitem.InteropT) && vm.IsIterator(r.Stack[i]) {
|
||||
iteratorValues, truncated := vm.IteratorValues(r.Stack[i], r.maxIteratorResultItems)
|
||||
value := make([]json.RawMessage, len(iteratorValues))
|
||||
for j := range iteratorValues {
|
||||
value[j], err = stackitem.ToJSONWithTypes(iteratorValues[j])
|
||||
if err != nil {
|
||||
st = []byte(`"error: recursive reference"`)
|
||||
break
|
||||
}
|
||||
}
|
||||
data, err = json.Marshal(iteratorAux{
|
||||
Type: stackitem.InteropT.String(),
|
||||
Value: value,
|
||||
Truncated: truncated,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal iterator: %w", err)
|
||||
}
|
||||
} else {
|
||||
data, err = stackitem.ToJSONWithTypes(r.Stack[i])
|
||||
if err != nil {
|
||||
st = []byte(`"error: recursive reference"`)
|
||||
break
|
||||
}
|
||||
}
|
||||
arr[i] = data
|
||||
}
|
||||
|
@ -76,6 +127,26 @@ func (r *Invoke) UnmarshalJSON(data []byte) error {
|
|||
if err != nil {
|
||||
break
|
||||
}
|
||||
if st[i].Type() == stackitem.InteropT {
|
||||
iteratorAux := new(iteratorAux)
|
||||
if json.Unmarshal(arr[i], iteratorAux) == nil {
|
||||
iteratorValues := make([]stackitem.Item, len(iteratorAux.Value))
|
||||
for j := range iteratorValues {
|
||||
iteratorValues[j], err = stackitem.FromJSONWithTypes(iteratorAux.Value[j])
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to unmarshal iterator values: %w", err)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// it's impossible to restore initial iterator type; also iterator is almost
|
||||
// useless outside of the VM, thus let's replace it with a special structure.
|
||||
st[i] = stackitem.NewInterop(Iterator{
|
||||
Values: iteratorValues,
|
||||
Truncated: iteratorAux.Truncated,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
r.Stack = st
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue