state: allow to encode AppExecResult with recursive items

1. Encode them to a special type, decode to `nil`.
2. `Interop` can be encoded in JSON, this info should also be preserved.
This commit is contained in:
Evgenii Stratonikov 2020-12-18 12:28:01 +03:00
parent c13d6ecc55
commit 8c22d27acc
6 changed files with 164 additions and 52 deletions

View file

@ -57,7 +57,11 @@ func (aer *AppExecResult) EncodeBinary(w *io.BinWriter) {
w.WriteB(byte(aer.Trigger))
w.WriteB(byte(aer.VMState))
w.WriteU64LE(uint64(aer.GasConsumed))
stackitem.EncodeBinaryStackItem(stackitem.NewArray(aer.Stack), w)
// Stack items are expected to be marshaled one by one.
w.WriteVarUint(uint64(len(aer.Stack)))
for _, it := range aer.Stack {
stackitem.EncodeBinaryStackItemAppExec(it, w)
}
w.WriteArray(aer.Events)
w.WriteVarBytes([]byte(aer.FaultException))
}
@ -68,15 +72,21 @@ func (aer *AppExecResult) DecodeBinary(r *io.BinReader) {
aer.Trigger = trigger.Type(r.ReadB())
aer.VMState = vm.State(r.ReadB())
aer.GasConsumed = int64(r.ReadU64LE())
item := stackitem.DecodeBinaryStackItem(r)
if r.Err == nil {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
r.Err = errors.New("array expected")
sz := r.ReadVarUint()
if stackitem.MaxArraySize < sz && r.Err == nil {
r.Err = errors.New("invalid format")
}
if r.Err != nil {
return
}
arr := make([]stackitem.Item, sz)
for i := 0; i < int(sz); i++ {
arr[i] = stackitem.DecodeBinaryStackItemAppExec(r)
if r.Err != nil {
return
}
aer.Stack = arr
}
aer.Stack = arr
r.ReadArray(&aer.Events)
aer.FaultException = r.ReadString()
}
@ -182,23 +192,22 @@ type executionAux struct {
// MarshalJSON implements implements json.Marshaler interface.
func (e Execution) MarshalJSON() ([]byte, error) {
var st json.RawMessage
var errRecursive = []byte(`"error: recursive reference"`)
arr := make([]json.RawMessage, len(e.Stack))
for i := range arr {
if e.Stack[i] == nil {
arr[i] = errRecursive
continue
}
data, err := stackitem.ToJSONWithTypes(e.Stack[i])
if err != nil {
st = []byte(`"error: recursive reference"`)
break
data = errRecursive
}
arr[i] = data
}
var err error
if st == nil {
st, err = json.Marshal(arr)
if err != nil {
return nil, err
}
st, err := json.Marshal(arr)
if err != nil {
return nil, err
}
return json.Marshal(&executionAux{
Trigger: e.Trigger.String(),
@ -222,7 +231,11 @@ func (e *Execution) UnmarshalJSON(data []byte) error {
for i := range arr {
st[i], err = stackitem.FromJSONWithTypes(arr[i])
if err != nil {
break
var s string
if json.Unmarshal(arr[i], &s) != nil {
break
}
err = nil
}
}
if err == nil {