mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-22 19:29:39 +00:00
core: add Deserialize flag to Storage.Find
Allow to deserialize values being iterated over.
This commit is contained in:
parent
7fc0c04dba
commit
44af99fd07
5 changed files with 51 additions and 4 deletions
|
@ -30,6 +30,7 @@ func TestFindFlags(t *testing.T) {
|
|||
require.EqualValues(t, storage.KeysOnly, istorage.FindKeysOnly)
|
||||
require.EqualValues(t, storage.RemovePrefix, istorage.FindRemovePrefix)
|
||||
require.EqualValues(t, storage.ValuesOnly, istorage.FindValuesOnly)
|
||||
require.EqualValues(t, storage.DeserializeValues, istorage.FindDeserialize)
|
||||
}
|
||||
|
||||
func TestStoragePutGet(t *testing.T) {
|
||||
|
|
|
@ -8,8 +8,10 @@ const (
|
|||
FindKeysOnly = 1 << 0
|
||||
FindRemovePrefix = 1 << 1
|
||||
FindValuesOnly = 1 << 2
|
||||
FindDeserialize = 1 << 3
|
||||
|
||||
FindAll = FindDefault | FindKeysOnly | FindRemovePrefix | FindValuesOnly
|
||||
FindAll = FindDefault | FindKeysOnly | FindRemovePrefix | FindValuesOnly |
|
||||
FindDeserialize
|
||||
)
|
||||
|
||||
type Iterator struct {
|
||||
|
@ -41,11 +43,20 @@ func (s *Iterator) Value() stackitem.Item {
|
|||
if s.opts&FindKeysOnly != 0 {
|
||||
return stackitem.NewByteArray(key)
|
||||
}
|
||||
value := s.m[s.index].Value
|
||||
if s.opts&FindDeserialize != 0 {
|
||||
bs := s.m[s.index].Value.Value().([]byte)
|
||||
var err error
|
||||
value, err = stackitem.DeserializeItem(bs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
if s.opts&FindValuesOnly != 0 {
|
||||
return s.m[s.index].Value
|
||||
return value
|
||||
}
|
||||
return stackitem.NewStruct([]stackitem.Item{
|
||||
stackitem.NewByteArray(key),
|
||||
s.m[s.index].Value,
|
||||
value,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -28,6 +28,9 @@ func storageFind(ic *interop.Context) error {
|
|||
if opts&^storage.FindAll != 0 {
|
||||
return fmt.Errorf("%w: unknown flag", errFindInvalidOptions)
|
||||
}
|
||||
if opts&storage.FindKeysOnly != 0 && opts&storage.FindDeserialize != 0 {
|
||||
return fmt.Errorf("%w KeysOnly conflicts with other options", errFindInvalidOptions)
|
||||
}
|
||||
if opts&storage.FindValuesOnly != 0 &&
|
||||
opts&(storage.FindKeysOnly|storage.FindRemovePrefix) != 0 {
|
||||
return fmt.Errorf("%w: KeysOnly conflicts with ValuesOnly", errFindInvalidOptions)
|
||||
|
|
|
@ -37,7 +37,8 @@ func TestStorageFind(t *testing.T) {
|
|||
v, contractState, context, chain := createVMAndContractState(t)
|
||||
defer chain.Close()
|
||||
|
||||
skeys := [][]byte{{0x01, 0x02}, {0x02, 0x01}, {0x01, 0x01}}
|
||||
skeys := [][]byte{{0x01, 0x02}, {0x02, 0x01}, {0x01, 0x01},
|
||||
{0x04, 0x00}, {0x05, 0x00}}
|
||||
items := []*state.StorageItem{
|
||||
{
|
||||
Value: []byte{0x01, 0x02, 0x03, 0x04},
|
||||
|
@ -48,6 +49,12 @@ func TestStorageFind(t *testing.T) {
|
|||
{
|
||||
Value: []byte{0x03, 0x04, 0x05, 0x06},
|
||||
},
|
||||
{
|
||||
Value: []byte{byte(stackitem.ByteArrayT), 2, 0xCA, 0xFE},
|
||||
},
|
||||
{
|
||||
Value: []byte{0xFF, 0xFF},
|
||||
},
|
||||
}
|
||||
|
||||
require.NoError(t, chain.contracts.Management.PutContractState(chain.dao, contractState))
|
||||
|
@ -116,6 +123,27 @@ func TestStorageFind(t *testing.T) {
|
|||
stackitem.NewByteArray(items[0].Value),
|
||||
})
|
||||
})
|
||||
t.Run("deserialize values", func(t *testing.T) {
|
||||
testFind(t, 0x04, istorage.FindValuesOnly|istorage.FindDeserialize, []stackitem.Item{
|
||||
stackitem.NewByteArray(items[3].Value[2:]),
|
||||
})
|
||||
t.Run("invalid", func(t *testing.T) {
|
||||
v.Estack().PushVal(istorage.FindDeserialize)
|
||||
v.Estack().PushVal([]byte{0x05})
|
||||
v.Estack().PushVal(stackitem.NewInterop(&StorageContext{ID: id}))
|
||||
err := storageFind(context)
|
||||
require.NoError(t, err)
|
||||
|
||||
var iter *stackitem.Interop
|
||||
require.NotPanics(t, func() { iter = v.Estack().Pop().Interop() })
|
||||
|
||||
v.Estack().PushVal(iter)
|
||||
require.NoError(t, iterator.Next(context))
|
||||
|
||||
v.Estack().PushVal(iter)
|
||||
require.Panics(t, func() { _ = iterator.Value(context) })
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("normal invocation, empty result", func(t *testing.T) {
|
||||
testFind(t, 0x03, istorage.FindDefault, nil)
|
||||
|
@ -125,6 +153,7 @@ func TestStorageFind(t *testing.T) {
|
|||
invalid := []int64{
|
||||
istorage.FindKeysOnly | istorage.FindValuesOnly,
|
||||
^istorage.FindAll,
|
||||
istorage.FindKeysOnly | istorage.FindDeserialize,
|
||||
}
|
||||
for _, opts := range invalid {
|
||||
v.Estack().PushVal(opts)
|
||||
|
|
|
@ -26,6 +26,9 @@ const (
|
|||
RemovePrefix FindFlags = 1 << 1
|
||||
// ValuesOnly is used for iterating over values.
|
||||
ValuesOnly FindFlags = 1 << 2
|
||||
// DeserializeValues is used for deserializing values on-the-fly.
|
||||
// It can be combined with other options.
|
||||
DeserializeValues FindFlags = 1 << 3
|
||||
)
|
||||
|
||||
// ConvertContextToReadOnly returns new context from the given one, but with
|
||||
|
|
Loading…
Reference in a new issue