diff --git a/pkg/vm/serialization.go b/pkg/vm/serialization.go index 6c54c658f..6fd71b5cf 100644 --- a/pkg/vm/serialization.go +++ b/pkg/vm/serialization.go @@ -47,10 +47,19 @@ func serializeItemTo(item StackItem, w *io.BinWriter, seen map[StackItem]bool) { w.WriteBytes(t.Bytes()) case *InteropItem: w.Err = errors.New("not supported") - case *ArrayItem: - w.Err = errors.New("not implemented") - case *StructItem: - w.Err = errors.New("not implemented") + case *ArrayItem, *StructItem: + _, isArray := t.(*ArrayItem) + if isArray { + w.WriteLE(byte(arrayT)) + } else { + w.WriteLE(byte(structT)) + } + + arr := t.Value().([]StackItem) + w.WriteVarUint(uint64(len(arr))) + for i := range arr { + serializeItemTo(arr[i], w, seen) + } case *MapItem: w.WriteLE(byte(mapT)) w.WriteVarUint(uint64(len(t.value))) @@ -91,12 +100,17 @@ func deserializeItemFrom(r *io.BinReader) StackItem { return &BigIntegerItem{ value: num, } - case arrayT: - r.Err = errors.New("not implemented") - return nil - case structT: - r.Err = errors.New("not implemented") - return nil + case arrayT, structT: + size := int(r.ReadVarUint()) + arr := make([]StackItem, size) + for i := 0; i < size; i++ { + arr[i] = deserializeItemFrom(r) + } + + if stackItemType(t) == arrayT { + return &ArrayItem{value: arr} + } + return &StructItem{value: arr} case mapT: size := int(r.ReadVarUint()) m := NewMapItem() diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index 589bc0521..0af1144a0 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -256,6 +256,50 @@ func TestSerializeInteger(t *testing.T) { require.Equal(t, value, vm.estack.Top().BigInt().Int64()) } +func TestSerializeArray(t *testing.T) { + vm := load(getSerializeProg()) + item := NewArrayItem([]StackItem{ + makeStackItem(true), + makeStackItem(123), + NewMapItem(), + }) + + vm.estack.Push(&Element{value: item}) + + testSerialize(t, vm) + + require.IsType(t, (*ArrayItem)(nil), vm.estack.Top().value) + require.Equal(t, item.value, vm.estack.Top().Array()) +} + +func TestSerializeArrayBad(t *testing.T) { + vm := load(getSerializeProg()) + item := NewArrayItem(makeArrayOfFalses(2)) + item.value[1] = item + + vm.estack.Push(&Element{value: item}) + + err := vm.Step() + require.Error(t, err) + require.True(t, vm.HasFailed()) +} + +func TestSerializeStruct(t *testing.T) { + vm := load(getSerializeProg()) + item := NewStructItem([]StackItem{ + makeStackItem(true), + makeStackItem(123), + NewMapItem(), + }) + + vm.estack.Push(&Element{value: item}) + + testSerialize(t, vm) + + require.IsType(t, (*StructItem)(nil), vm.estack.Top().value) + require.Equal(t, item.value, vm.estack.Top().Array()) +} + func TestSerializeMap(t *testing.T) { vm := load(getSerializeProg()) item := NewMapItem()