vm: implement Map item serialization

This commit is contained in:
Evgenii Stratonikov 2019-11-05 11:57:55 +03:00
parent cd690803cf
commit e1d019e087
2 changed files with 39 additions and 5 deletions

View file

@ -21,14 +21,20 @@ const (
func serializeItem(item StackItem) ([]byte, error) { func serializeItem(item StackItem) ([]byte, error) {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
serializeItemTo(item, w.BinWriter) serializeItemTo(item, w.BinWriter, make(map[StackItem]bool))
if w.Err != nil { if w.Err != nil {
return nil, w.Err return nil, w.Err
} }
return w.Bytes(), nil return w.Bytes(), nil
} }
func serializeItemTo(item StackItem, w *io.BinWriter) { func serializeItemTo(item StackItem, w *io.BinWriter, seen map[StackItem]bool) {
if seen[item] {
w.Err = errors.New("recursive structures are not supported")
return
}
seen[item] = true
switch t := item.(type) { switch t := item.(type) {
case *ByteArrayItem: case *ByteArrayItem:
w.WriteLE(byte(byteArrayT)) w.WriteLE(byte(byteArrayT))
@ -46,7 +52,12 @@ func serializeItemTo(item StackItem, w *io.BinWriter) {
case *StructItem: case *StructItem:
w.Err = errors.New("not implemented") w.Err = errors.New("not implemented")
case *MapItem: case *MapItem:
w.Err = errors.New("not implemented") w.WriteLE(byte(mapT))
w.WriteVarUint(uint64(len(t.value)))
for k, v := range t.value {
serializeItemTo(v, w, seen)
serializeItemTo(makeStackItem(k), w, seen)
}
} }
} }
@ -87,8 +98,17 @@ func deserializeItemFrom(r *io.BinReader) StackItem {
r.Err = errors.New("not implemented") r.Err = errors.New("not implemented")
return nil return nil
case mapT: case mapT:
r.Err = errors.New("not implemented") size := int(r.ReadVarUint())
return nil m := NewMapItem()
for i := 0; i < size; i++ {
value := deserializeItemFrom(r)
key := deserializeItemFrom(r)
if r.Err != nil {
break
}
m.Add(key, value)
}
return m
default: default:
r.Err = errors.New("unknown type") r.Err = errors.New("unknown type")
return nil return nil

View file

@ -256,6 +256,20 @@ func TestSerializeInteger(t *testing.T) {
require.Equal(t, value, vm.estack.Top().BigInt().Int64()) require.Equal(t, value, vm.estack.Top().BigInt().Int64())
} }
func TestSerializeMap(t *testing.T) {
vm := load(getSerializeProg())
item := NewMapItem()
item.Add(makeStackItem(true), makeStackItem([]byte{1, 2, 3}))
item.Add(makeStackItem([]byte{0}), makeStackItem(false))
vm.estack.Push(&Element{value: item})
testSerialize(t, vm)
require.IsType(t, (*MapItem)(nil), vm.estack.Top().value)
require.Equal(t, item.value, vm.estack.Top().value.(*MapItem).value)
}
func callNTimes(n uint16) []byte { func callNTimes(n uint16) []byte {
return makeProgram( return makeProgram(
PUSHBYTES2, Instruction(n), Instruction(n>>8), // little-endian PUSHBYTES2, Instruction(n), Instruction(n>>8), // little-endian