core: implement Neo.Storage.Find interop

This commit is contained in:
Evgenii Stratonikov 2019-12-26 14:34:38 +03:00
parent 7b5c47e7f5
commit 48cf4f4a84
4 changed files with 76 additions and 5 deletions

View file

@ -4,6 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"math" "math"
"strings"
"github.com/CityOfZion/neo-go/pkg/core/state" "github.com/CityOfZion/neo-go/pkg/core/state"
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
@ -429,7 +430,6 @@ func (ic *interopContext) accountIsStandard(v *vm.VM) error {
return nil return nil
} }
/*
// storageFind finds stored key-value pair. // storageFind finds stored key-value pair.
func (ic *interopContext) storageFind(v *vm.VM) error { func (ic *interopContext) storageFind(v *vm.VM) error {
stcInterface := v.Estack().Pop().Value() stcInterface := v.Estack().Pop().Value()
@ -446,16 +446,20 @@ func (ic *interopContext) storageFind(v *vm.VM) error {
if err != nil { if err != nil {
return err return err
} }
filteredMap := make(map[interface{}]vm.StackItem)
for k, v := range siMap { for k, v := range siMap {
if strings.HasPrefix(k, prefix) { if strings.HasPrefix(k, prefix) {
_ = v filteredMap[k] = vm.NewByteArrayItem(v.Value)
panic("TODO")
} }
} }
item := vm.NewMapIterator(filteredMap)
v.Estack().PushVal(item)
return nil return nil
} }
*/
// createContractStateFromVM pops all contract state elements from the VM // createContractStateFromVM pops all contract state elements from the VM
// evaluation stack, does a lot of checks and returns Contract if it // evaluation stack, does a lot of checks and returns Contract if it
// succeeds. // succeeds.

View file

@ -34,6 +34,72 @@ import (
* TestRuntimeDeserialize * TestRuntimeDeserialize
*/ */
func TestStorageFind(t *testing.T) {
v, contractState, context := createVMAndContractState(t)
skeys := [][]byte{{0x01, 0x02}, {0x02, 0x01}}
items := []*state.StorageItem{
{
Value: []byte{0x01, 0x02, 0x03, 0x04},
},
{
Value: []byte{0x04, 0x03, 0x02, 0x01},
},
}
require.NoError(t, context.dao.PutContractState(contractState))
scriptHash := contractState.ScriptHash()
for i := range skeys {
err := context.dao.PutStorageItem(scriptHash, skeys[i], items[i])
require.NoError(t, err)
}
t.Run("normal invocation", func(t *testing.T) {
v.Estack().PushVal([]byte{0x01})
v.Estack().PushVal(vm.NewInteropItem(&StorageContext{ScriptHash: scriptHash}))
err := context.storageFind(v)
require.NoError(t, err)
var iter *vm.InteropItem
require.NotPanics(t, func() { iter = v.Estack().Top().Interop() })
require.NoError(t, context.enumeratorNext(v))
require.True(t, v.Estack().Pop().Bool())
v.Estack().PushVal(iter)
require.NoError(t, context.iteratorKey(v))
require.Equal(t, []byte{0x01, 0x02}, v.Estack().Pop().Bytes())
v.Estack().PushVal(iter)
require.NoError(t, context.enumeratorValue(v))
require.Equal(t, []byte{0x01, 0x02, 0x03, 0x04}, v.Estack().Pop().Bytes())
v.Estack().PushVal(iter)
require.NoError(t, context.enumeratorNext(v))
require.False(t, v.Estack().Pop().Bool())
})
t.Run("invalid type for StorageContext", func(t *testing.T) {
v.Estack().PushVal([]byte{0x01})
v.Estack().PushVal(vm.NewInteropItem(nil))
require.Error(t, context.storageFind(v))
})
t.Run("invalid script hash", func(t *testing.T) {
invalidHash := scriptHash
invalidHash[0] = ^invalidHash[0]
v.Estack().PushVal([]byte{0x01})
v.Estack().PushVal(vm.NewInteropItem(&StorageContext{ScriptHash: invalidHash}))
require.Error(t, context.storageFind(v))
})
}
func TestHeaderGetVersion(t *testing.T) { func TestHeaderGetVersion(t *testing.T) {
v, block, context := createVMAndPushBlock(t) v, block, context := createVMAndPushBlock(t)

View file

@ -173,6 +173,7 @@ var neoInterops = []interopedFunction{
{Name: "Neo.Runtime.Notify", Func: (*interopContext).runtimeNotify, Price: 1}, {Name: "Neo.Runtime.Notify", Func: (*interopContext).runtimeNotify, Price: 1},
{Name: "Neo.Runtime.Serialize", Func: (*interopContext).runtimeSerialize, Price: 1}, {Name: "Neo.Runtime.Serialize", Func: (*interopContext).runtimeSerialize, Price: 1},
{Name: "Neo.Storage.Delete", Func: (*interopContext).storageDelete, Price: 100}, {Name: "Neo.Storage.Delete", Func: (*interopContext).storageDelete, Price: 100},
{Name: "Neo.Storage.Find", Func: (*interopContext).storageFind, Price: 1},
{Name: "Neo.Storage.Get", Func: (*interopContext).storageGet, Price: 100}, {Name: "Neo.Storage.Get", Func: (*interopContext).storageGet, Price: 100},
{Name: "Neo.Storage.GetContext", Func: (*interopContext).storageGetContext, Price: 1}, {Name: "Neo.Storage.GetContext", Func: (*interopContext).storageGetContext, Price: 1},
{Name: "Neo.Storage.GetReadOnlyContext", Func: (*interopContext).storageGetReadOnlyContext, Price: 1}, {Name: "Neo.Storage.GetReadOnlyContext", Func: (*interopContext).storageGetReadOnlyContext, Price: 1},
@ -187,7 +188,6 @@ var neoInterops = []interopedFunction{
{Name: "Neo.Transaction.GetUnspentCoins", Func: (*interopContext).txGetUnspentCoins, Price: 200}, {Name: "Neo.Transaction.GetUnspentCoins", Func: (*interopContext).txGetUnspentCoins, Price: 200},
{Name: "Neo.Transaction.GetWitnesses", Func: (*interopContext).txGetWitnesses, Price: 200}, {Name: "Neo.Transaction.GetWitnesses", Func: (*interopContext).txGetWitnesses, Price: 200},
{Name: "Neo.Witness.GetVerificationScript", Func: (*interopContext).witnessGetVerificationScript, Price: 100}, {Name: "Neo.Witness.GetVerificationScript", Func: (*interopContext).witnessGetVerificationScript, Price: 100},
// {Name: "Neo.Storage.Find", Func: (*interopContext).storageFind, Price: 1},
// Aliases. // Aliases.
{Name: "Neo.Iterator.Next", Func: (*interopContext).enumeratorNext, Price: 1}, {Name: "Neo.Iterator.Next", Func: (*interopContext).enumeratorNext, Price: 1},

View file

@ -64,6 +64,7 @@ func TestUnexpectedNonInterops(t *testing.T) {
(*interopContext).outputGetValue, (*interopContext).outputGetValue,
(*interopContext).storageContextAsReadOnly, (*interopContext).storageContextAsReadOnly,
(*interopContext).storageDelete, (*interopContext).storageDelete,
(*interopContext).storageFind,
(*interopContext).storageGet, (*interopContext).storageGet,
(*interopContext).storagePut, (*interopContext).storagePut,
(*interopContext).storagePutEx, (*interopContext).storagePutEx,