Merge pull request #1941 from nspcc-dev/storage-find-prefix

interop: strip full prefix in `System.Storage.Find`
This commit is contained in:
Roman Khimov 2021-04-29 17:55:00 +03:00 committed by GitHub
commit 62810bb510
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 34 additions and 24 deletions

View file

@ -18,17 +18,19 @@ const (
// Iterator is an iterator state representation.
type Iterator struct {
m []stackitem.MapElement
opts int64
index int
m []stackitem.MapElement
opts int64
index int
prefixSize int
}
// NewIterator creates a new Iterator with given options for a given map.
func NewIterator(m *stackitem.Map, opts int64) *Iterator {
func NewIterator(m *stackitem.Map, prefix int, opts int64) *Iterator {
return &Iterator{
m: m.Value().([]stackitem.MapElement),
opts: opts,
index: -1,
m: m.Value().([]stackitem.MapElement),
opts: opts,
index: -1,
prefixSize: prefix,
}
}
@ -46,7 +48,7 @@ func (s *Iterator) Next() bool {
func (s *Iterator) Value() stackitem.Item {
key := s.m[s.index].Key.Value().([]byte)
if s.opts&FindRemovePrefix != 0 {
key = key[1:]
key = key[s.prefixSize:]
}
if s.opts&FindKeysOnly != 0 {
return stackitem.NewByteArray(key)

View file

@ -59,7 +59,7 @@ func storageFind(ic *interop.Context) error {
filteredMap.Value().([]stackitem.MapElement)[j].Key.Value().([]byte)) == -1
})
item := storage.NewIterator(filteredMap, opts)
item := storage.NewIterator(filteredMap, len(prefix), opts)
ic.VM.Estack().PushVal(stackitem.NewInterop(item))
return nil

View file

@ -49,7 +49,9 @@ func TestStorageFind(t *testing.T) {
require.NoError(t, err)
skeys := [][]byte{{0x01, 0x02}, {0x02, 0x01}, {0x01, 0x01},
{0x04, 0x00}, {0x05, 0x00}, {0x06}, {0x07}, {0x08}}
{0x04, 0x00}, {0x05, 0x00}, {0x06}, {0x07}, {0x08},
{0x09, 0x12, 0x34}, {0x09, 0x12, 0x56},
}
items := []state.StorageItem{
[]byte{0x01, 0x02, 0x03, 0x04},
[]byte{0x04, 0x03, 0x02, 0x01},
@ -59,6 +61,8 @@ func TestStorageFind(t *testing.T) {
rawArr,
rawArr0,
rawArr1,
[]byte{111},
[]byte{222},
}
require.NoError(t, chain.contracts.Management.PutContractState(chain.dao, contractState))
@ -70,9 +74,9 @@ func TestStorageFind(t *testing.T) {
require.NoError(t, err)
}
testFind := func(t *testing.T, prefix byte, opts int64, expected []stackitem.Item) {
testFind := func(t *testing.T, prefix []byte, opts int64, expected []stackitem.Item) {
v.Estack().PushVal(opts)
v.Estack().PushVal([]byte{prefix})
v.Estack().PushVal(prefix)
v.Estack().PushVal(stackitem.NewInterop(&StorageContext{ID: id}))
err := storageFind(context)
@ -101,7 +105,7 @@ func TestStorageFind(t *testing.T) {
}
t.Run("normal invocation", func(t *testing.T) {
testFind(t, 0x01, istorage.FindDefault, []stackitem.Item{
testFind(t, []byte{0x01}, istorage.FindDefault, []stackitem.Item{
stackitem.NewStruct([]stackitem.Item{
stackitem.NewByteArray(skeys[2]),
stackitem.NewByteArray(items[2]),
@ -114,25 +118,29 @@ func TestStorageFind(t *testing.T) {
})
t.Run("keys only", func(t *testing.T) {
testFind(t, 0x01, istorage.FindKeysOnly, []stackitem.Item{
testFind(t, []byte{0x01}, istorage.FindKeysOnly, []stackitem.Item{
stackitem.NewByteArray(skeys[2]),
stackitem.NewByteArray(skeys[0]),
})
})
t.Run("remove prefix", func(t *testing.T) {
testFind(t, 0x01, istorage.FindKeysOnly|istorage.FindRemovePrefix, []stackitem.Item{
testFind(t, []byte{0x01}, istorage.FindKeysOnly|istorage.FindRemovePrefix, []stackitem.Item{
stackitem.NewByteArray(skeys[2][1:]),
stackitem.NewByteArray(skeys[0][1:]),
})
testFind(t, []byte{0x09, 0x12}, istorage.FindKeysOnly|istorage.FindRemovePrefix, []stackitem.Item{
stackitem.NewByteArray(skeys[8][2:]),
stackitem.NewByteArray(skeys[9][2:]),
})
})
t.Run("values only", func(t *testing.T) {
testFind(t, 0x01, istorage.FindValuesOnly, []stackitem.Item{
testFind(t, []byte{0x01}, istorage.FindValuesOnly, []stackitem.Item{
stackitem.NewByteArray(items[2]),
stackitem.NewByteArray(items[0]),
})
})
t.Run("deserialize values", func(t *testing.T) {
testFind(t, 0x04, istorage.FindValuesOnly|istorage.FindDeserialize, []stackitem.Item{
testFind(t, []byte{0x04}, istorage.FindValuesOnly|istorage.FindDeserialize, []stackitem.Item{
stackitem.NewByteArray(items[3][2:]),
})
t.Run("invalid", func(t *testing.T) {
@ -153,21 +161,21 @@ func TestStorageFind(t *testing.T) {
})
})
t.Run("PickN", func(t *testing.T) {
testFind(t, 0x06, istorage.FindPick0|istorage.FindValuesOnly|istorage.FindDeserialize, arr[:1])
testFind(t, 0x06, istorage.FindPick1|istorage.FindValuesOnly|istorage.FindDeserialize, arr[1:2])
testFind(t, []byte{0x06}, istorage.FindPick0|istorage.FindValuesOnly|istorage.FindDeserialize, arr[:1])
testFind(t, []byte{0x06}, istorage.FindPick1|istorage.FindValuesOnly|istorage.FindDeserialize, arr[1:2])
// Array with 0 elements.
testFind(t, 0x07, istorage.FindPick0|istorage.FindValuesOnly|istorage.FindDeserialize,
testFind(t, []byte{0x07}, istorage.FindPick0|istorage.FindValuesOnly|istorage.FindDeserialize,
[]stackitem.Item{nil})
// Array with 1 element.
testFind(t, 0x08, istorage.FindPick1|istorage.FindValuesOnly|istorage.FindDeserialize,
testFind(t, []byte{0x08}, istorage.FindPick1|istorage.FindValuesOnly|istorage.FindDeserialize,
[]stackitem.Item{nil})
// Not an array, but serialized ByteArray.
testFind(t, 0x04, istorage.FindPick1|istorage.FindValuesOnly|istorage.FindDeserialize,
testFind(t, []byte{0x04}, istorage.FindPick1|istorage.FindValuesOnly|istorage.FindDeserialize,
[]stackitem.Item{nil})
})
t.Run("normal invocation, empty result", func(t *testing.T) {
testFind(t, 0x03, istorage.FindDefault, nil)
testFind(t, []byte{0x03}, istorage.FindDefault, nil)
})
t.Run("invalid options", func(t *testing.T) {

View file

@ -229,7 +229,7 @@ func (n *nonfungible) tokens(ic *interop.Context, args []stackitem.Item) stackit
return bytes.Compare(filteredMap.Value().([]stackitem.MapElement)[i].Key.Value().([]byte),
filteredMap.Value().([]stackitem.MapElement)[j].Key.Value().([]byte)) == -1
})
iter := istorage.NewIterator(filteredMap, istorage.FindValuesOnly|istorage.FindDeserialize|istorage.FindPick1)
iter := istorage.NewIterator(filteredMap, 1, istorage.FindValuesOnly|istorage.FindDeserialize|istorage.FindPick1)
return stackitem.NewInterop(iter)
}