forked from TrueCloudLab/neoneo-go
core: implement Neo.Storage.Find interop
This commit is contained in:
parent
7b5c47e7f5
commit
48cf4f4a84
4 changed files with 76 additions and 5 deletions
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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},
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue