forked from TrueCloudLab/neoneo-go
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.KeysOnly, istorage.FindKeysOnly)
|
||||||
require.EqualValues(t, storage.RemovePrefix, istorage.FindRemovePrefix)
|
require.EqualValues(t, storage.RemovePrefix, istorage.FindRemovePrefix)
|
||||||
require.EqualValues(t, storage.ValuesOnly, istorage.FindValuesOnly)
|
require.EqualValues(t, storage.ValuesOnly, istorage.FindValuesOnly)
|
||||||
|
require.EqualValues(t, storage.DeserializeValues, istorage.FindDeserialize)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStoragePutGet(t *testing.T) {
|
func TestStoragePutGet(t *testing.T) {
|
||||||
|
|
|
@ -8,8 +8,10 @@ const (
|
||||||
FindKeysOnly = 1 << 0
|
FindKeysOnly = 1 << 0
|
||||||
FindRemovePrefix = 1 << 1
|
FindRemovePrefix = 1 << 1
|
||||||
FindValuesOnly = 1 << 2
|
FindValuesOnly = 1 << 2
|
||||||
|
FindDeserialize = 1 << 3
|
||||||
|
|
||||||
FindAll = FindDefault | FindKeysOnly | FindRemovePrefix | FindValuesOnly
|
FindAll = FindDefault | FindKeysOnly | FindRemovePrefix | FindValuesOnly |
|
||||||
|
FindDeserialize
|
||||||
)
|
)
|
||||||
|
|
||||||
type Iterator struct {
|
type Iterator struct {
|
||||||
|
@ -41,11 +43,20 @@ func (s *Iterator) Value() stackitem.Item {
|
||||||
if s.opts&FindKeysOnly != 0 {
|
if s.opts&FindKeysOnly != 0 {
|
||||||
return stackitem.NewByteArray(key)
|
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 {
|
if s.opts&FindValuesOnly != 0 {
|
||||||
return s.m[s.index].Value
|
return value
|
||||||
}
|
}
|
||||||
return stackitem.NewStruct([]stackitem.Item{
|
return stackitem.NewStruct([]stackitem.Item{
|
||||||
stackitem.NewByteArray(key),
|
stackitem.NewByteArray(key),
|
||||||
s.m[s.index].Value,
|
value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,9 @@ func storageFind(ic *interop.Context) error {
|
||||||
if opts&^storage.FindAll != 0 {
|
if opts&^storage.FindAll != 0 {
|
||||||
return fmt.Errorf("%w: unknown flag", errFindInvalidOptions)
|
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 &&
|
if opts&storage.FindValuesOnly != 0 &&
|
||||||
opts&(storage.FindKeysOnly|storage.FindRemovePrefix) != 0 {
|
opts&(storage.FindKeysOnly|storage.FindRemovePrefix) != 0 {
|
||||||
return fmt.Errorf("%w: KeysOnly conflicts with ValuesOnly", errFindInvalidOptions)
|
return fmt.Errorf("%w: KeysOnly conflicts with ValuesOnly", errFindInvalidOptions)
|
||||||
|
|
|
@ -37,7 +37,8 @@ func TestStorageFind(t *testing.T) {
|
||||||
v, contractState, context, chain := createVMAndContractState(t)
|
v, contractState, context, chain := createVMAndContractState(t)
|
||||||
defer chain.Close()
|
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{
|
items := []*state.StorageItem{
|
||||||
{
|
{
|
||||||
Value: []byte{0x01, 0x02, 0x03, 0x04},
|
Value: []byte{0x01, 0x02, 0x03, 0x04},
|
||||||
|
@ -48,6 +49,12 @@ func TestStorageFind(t *testing.T) {
|
||||||
{
|
{
|
||||||
Value: []byte{0x03, 0x04, 0x05, 0x06},
|
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))
|
require.NoError(t, chain.contracts.Management.PutContractState(chain.dao, contractState))
|
||||||
|
@ -116,6 +123,27 @@ func TestStorageFind(t *testing.T) {
|
||||||
stackitem.NewByteArray(items[0].Value),
|
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) {
|
t.Run("normal invocation, empty result", func(t *testing.T) {
|
||||||
testFind(t, 0x03, istorage.FindDefault, nil)
|
testFind(t, 0x03, istorage.FindDefault, nil)
|
||||||
|
@ -125,6 +153,7 @@ func TestStorageFind(t *testing.T) {
|
||||||
invalid := []int64{
|
invalid := []int64{
|
||||||
istorage.FindKeysOnly | istorage.FindValuesOnly,
|
istorage.FindKeysOnly | istorage.FindValuesOnly,
|
||||||
^istorage.FindAll,
|
^istorage.FindAll,
|
||||||
|
istorage.FindKeysOnly | istorage.FindDeserialize,
|
||||||
}
|
}
|
||||||
for _, opts := range invalid {
|
for _, opts := range invalid {
|
||||||
v.Estack().PushVal(opts)
|
v.Estack().PushVal(opts)
|
||||||
|
|
|
@ -26,6 +26,9 @@ const (
|
||||||
RemovePrefix FindFlags = 1 << 1
|
RemovePrefix FindFlags = 1 << 1
|
||||||
// ValuesOnly is used for iterating over values.
|
// ValuesOnly is used for iterating over values.
|
||||||
ValuesOnly FindFlags = 1 << 2
|
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
|
// ConvertContextToReadOnly returns new context from the given one, but with
|
||||||
|
|
Loading…
Reference in a new issue