[#51] policy: Support Get and ListByPrefix methods

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
Denis Kirillov 2023-11-17 11:06:08 +03:00
parent dd5919348d
commit 5cc34f98e9
4 changed files with 62 additions and 1 deletions

View file

@ -1,2 +1,2 @@
name: "APE" name: "APE"
safemethods: ["listChains"] safemethods: ["listChains","getChain","listChainsByPrefix"]

View file

@ -35,6 +35,17 @@ func AddChain(entity Kind, entityName, name string, chain []byte) {
storage.Put(ctx, key, chain) storage.Put(ctx, key, chain)
} }
func GetChain(entity Kind, entityName, name string) []byte {
ctx := storage.GetReadOnlyContext()
key := storageKey(entity, entityName, name)
data := storage.Get(ctx, key).([]byte)
if data == nil {
panic("not found")
}
return data
}
func RemoveChain(entity Kind, entityName string, name string) { func RemoveChain(entity Kind, entityName string, name string) {
common.CheckAlphabetWitness() common.CheckAlphabetWitness()
@ -77,3 +88,18 @@ func ListChains(namespace, container, name string) [][]byte {
return result return result
} }
// ListChainsByPrefix list all chains for the provided kind and entity by prefix.
func ListChainsByPrefix(entity Kind, entityName, prefix string) [][]byte {
ctx := storage.GetReadOnlyContext()
result := [][]byte{}
keyPrefix := storageKey(entity, entityName, prefix)
it := storage.Find(ctx, keyPrefix, storage.ValuesOnly)
for iterator.Next(it) {
result = append(result, iterator.Value(it).([]byte))
}
return result
}

View file

@ -52,11 +52,21 @@ func New(actor Actor, hash util.Uint160) *Contract {
return &Contract{ContractReader{actor, hash}, actor, hash} return &Contract{ContractReader{actor, hash}, actor, hash}
} }
// GetChain invokes `getChain` method of contract.
func (c *ContractReader) GetChain(entity *big.Int, entityName string, name string) ([]byte, error) {
return unwrap.Bytes(c.invoker.Call(c.hash, "getChain", entity, entityName, name))
}
// ListChains invokes `listChains` method of contract. // ListChains invokes `listChains` method of contract.
func (c *ContractReader) ListChains(namespace string, container string, name string) ([]stackitem.Item, error) { func (c *ContractReader) ListChains(namespace string, container string, name string) ([]stackitem.Item, error) {
return unwrap.Array(c.invoker.Call(c.hash, "listChains", namespace, container, name)) return unwrap.Array(c.invoker.Call(c.hash, "listChains", namespace, container, name))
} }
// ListChainsByPrefix invokes `listChainsByPrefix` method of contract.
func (c *ContractReader) ListChainsByPrefix(entity *big.Int, entityName string, prefix string) ([]stackitem.Item, error) {
return unwrap.Array(c.invoker.Call(c.hash, "listChainsByPrefix", entity, entityName, prefix))
}
// AddChain creates a transaction invoking `addChain` method of the contract. // AddChain creates a transaction invoking `addChain` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.

View file

@ -1,12 +1,14 @@
package tests package tests
import ( import (
"bytes"
"path" "path"
"testing" "testing"
"git.frostfs.info/TrueCloudLab/frostfs-contract/policy" "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
"github.com/nspcc-dev/neo-go/pkg/neotest" "github.com/nspcc-dev/neo-go/pkg/neotest"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -49,7 +51,10 @@ func TestPolicy(t *testing.T) {
checkChains(t, e, "mynamespace", "cnr1", "ingress", [][]byte{p1, p2, p3}) checkChains(t, e, "mynamespace", "cnr1", "ingress", [][]byte{p1, p2, p3})
e.Invoke(t, stackitem.Null{}, "addChain", policy.Container, "cnr1", "ingress:myrule3", p33) e.Invoke(t, stackitem.Null{}, "addChain", policy.Container, "cnr1", "ingress:myrule3", p33)
checkChain(t, e, policy.Container, "cnr1", "ingress:myrule3", p33)
checkChains(t, e, "mynamespace", "cnr1", "ingress", [][]byte{p1, p2, p33}) // Override chain. checkChains(t, e, "mynamespace", "cnr1", "ingress", [][]byte{p1, p2, p33}) // Override chain.
checkChainsByPrefix(t, e, policy.Container, "cnr1", "", [][]byte{p2, p33})
checkChainsByPrefix(t, e, policy.IAM, "", "", nil)
t.Run("removal", func(t *testing.T) { t.Run("removal", func(t *testing.T) {
t.Run("wrong name", func(t *testing.T) { t.Run("wrong name", func(t *testing.T) {
@ -70,6 +75,18 @@ func TestPolicy(t *testing.T) {
func checkChains(t *testing.T, e *neotest.ContractInvoker, namespace, container, name string, expected [][]byte) { func checkChains(t *testing.T, e *neotest.ContractInvoker, namespace, container, name string, expected [][]byte) {
s, err := e.TestInvoke(t, "listChains", namespace, container, name) s, err := e.TestInvoke(t, "listChains", namespace, container, name)
require.NoError(t, err) require.NoError(t, err)
checksChainsOnStack(t, s, expected)
}
func checkChainsByPrefix(t *testing.T, e *neotest.ContractInvoker, kind byte, entityName, prefix string, expected [][]byte) {
s, err := e.TestInvoke(t, "listChainsByPrefix", kind, entityName, prefix)
require.NoError(t, err)
checksChainsOnStack(t, s, expected)
}
func checksChainsOnStack(t *testing.T, s *vm.Stack, expected [][]byte) {
require.Equal(t, 1, s.Len()) require.Equal(t, 1, s.Len())
if len(expected) == 0 { if len(expected) == 0 {
@ -89,3 +106,11 @@ func checkChains(t *testing.T, e *neotest.ContractInvoker, namespace, container,
require.ElementsMatch(t, expected, actual) require.ElementsMatch(t, expected, actual)
} }
func checkChain(t *testing.T, e *neotest.ContractInvoker, kind byte, entityName, name string, expected []byte) {
s, err := e.TestInvoke(t, "getChain", kind, entityName, name)
require.NoError(t, err)
require.Equal(t, 1, s.Len())
require.True(t, bytes.Equal(expected, s.Pop().Bytes()))
}