forked from TrueCloudLab/policy-engine
[#62] morph: List morph rules chains by traversing iterator
* Make `ListMorphRuleChains` methods use `commonclient.ReadIteratorItems`. * Introduce `ContractStorageActor` interface. * Iterators are used because listing by `ListChainsByPrefix` may cause stack overflow from neo-go side (len(items) > 1024). Signed-off-by: Airat Arifullin <aarifullin@yadro.com>
This commit is contained in:
parent
42497ad242
commit
4acfe0e62f
3 changed files with 63 additions and 35 deletions
2
go.mod
2
go.mod
|
@ -3,7 +3,7 @@ module git.frostfs.info/TrueCloudLab/policy-engine
|
|||
go 1.20
|
||||
|
||||
require (
|
||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.0
|
||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240409111539-e7a05a49ff45
|
||||
github.com/google/uuid v1.3.1
|
||||
github.com/mailru/easyjson v0.7.7
|
||||
github.com/nspcc-dev/neo-go v0.105.0
|
||||
|
|
4
go.sum
4
go.sum
|
@ -1,5 +1,5 @@
|
|||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.0 h1:FzurjElUwC7InY9v5rzXReKbfBL5yRJKSWJPq6BKhH0=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.0/go.mod h1:F/fe1OoIDKr5Bz99q4sriuHDuf3aZefZy9ZsCqEtgxc=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240409111539-e7a05a49ff45 h1:Tp4I+XOLp3VCJORfxSamQtj3RZNISbaLM4WD5iIzXxg=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240409111539-e7a05a49ff45/go.mod h1:F/fe1OoIDKr5Bz99q4sriuHDuf3aZefZy9ZsCqEtgxc=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"math/big"
|
||||
"strings"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/commonclient"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
||||
client "git.frostfs.info/TrueCloudLab/frostfs-contract/rpcclient/policy"
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
|
@ -13,6 +14,7 @@ import (
|
|||
"github.com/google/uuid"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||
neoinvoker "github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
|
@ -26,6 +28,10 @@ var (
|
|||
|
||||
// ContractStorage is the interface to manage chain rules within Policy contract.
|
||||
type ContractStorage struct {
|
||||
hash util.Uint160
|
||||
|
||||
actor ContractStorageActor
|
||||
|
||||
contractInterface *client.Contract
|
||||
}
|
||||
|
||||
|
@ -33,23 +39,49 @@ var _ engine.MorphRuleChainStorage = (*ContractStorage)(nil)
|
|||
|
||||
// ContractStorageReader is the interface to read data from Policy contract.
|
||||
type ContractStorageReader struct {
|
||||
hash util.Uint160
|
||||
|
||||
invoker ContractStorageInvoker
|
||||
|
||||
contractReaderInterface *client.ContractReader
|
||||
}
|
||||
|
||||
type ContractStorageActor interface {
|
||||
client.Actor
|
||||
GetRPCInvoker() neoinvoker.RPCInvoke
|
||||
}
|
||||
|
||||
var _ engine.MorphRuleChainStorageReader = (*ContractStorageReader)(nil)
|
||||
|
||||
func NewContractStorage(actor client.Actor, contract util.Uint160) *ContractStorage {
|
||||
func NewContractStorage(actor ContractStorageActor, contract util.Uint160) *ContractStorage {
|
||||
return &ContractStorage{
|
||||
hash: contract,
|
||||
actor: actor,
|
||||
contractInterface: client.New(actor, contract),
|
||||
}
|
||||
}
|
||||
|
||||
type contractStorageActorImpl struct {
|
||||
client.Actor
|
||||
rpcActor actor.RPCActor
|
||||
}
|
||||
|
||||
var _ ContractStorageActor = &contractStorageActorImpl{}
|
||||
|
||||
func (c *contractStorageActorImpl) GetRPCInvoker() neoinvoker.RPCInvoke {
|
||||
return c.rpcActor
|
||||
}
|
||||
|
||||
// NewContractStorageWithSimpleActor constructs core actor from `rpcActor`.
|
||||
//
|
||||
// Note: NewContractStorageWithSimpleActor is appropriate only for call-only-once cases (for example, in CLIs). Otherwise, it is unsafe,
|
||||
// because core actor may use invalidated `rpcActor` if some connection errors occurred.
|
||||
func NewContractStorageWithSimpleActor(rpcActor actor.RPCActor, acc *wallet.Account, contract util.Uint160) (*ContractStorage, error) {
|
||||
act, err := actor.NewSimple(rpcActor, acc)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create simple actor: %w", err)
|
||||
}
|
||||
return NewContractStorage(act, contract), nil
|
||||
return NewContractStorage(&contractStorageActorImpl{Actor: act, rpcActor: rpcActor}, contract), nil
|
||||
}
|
||||
|
||||
func (s *ContractStorage) AddMorphRuleChain(name chain.Name, target engine.Target, c *chain.Chain) (txHash util.Uint256, vub uint32, err error) {
|
||||
|
@ -98,17 +130,26 @@ func (s *ContractStorage) RemoveMorphRuleChainsByTarget(name chain.Name, target
|
|||
return
|
||||
}
|
||||
|
||||
func (s *ContractStorage) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) {
|
||||
func listChains(name chain.Name, target engine.Target, rpcInvoker neoinvoker.RPCInvoke, hash util.Uint160) ([]*chain.Chain, error) {
|
||||
kind, err := policyKind(target.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items, err := s.contractInterface.ListChainsByPrefix(big.NewInt(int64(kind)), target.Name, []byte(name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
const (
|
||||
method = "iteratorChainsByPrefix"
|
||||
batchSize = neoinvoker.DefaultIteratorResultItems
|
||||
)
|
||||
|
||||
inv := neoinvoker.New(rpcInvoker, nil)
|
||||
params := []any{
|
||||
big.NewInt(int64(kind)), target.Name, []byte(name),
|
||||
}
|
||||
|
||||
items, err := commonclient.ReadIteratorItems(inv, batchSize, hash, method, params...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read items error: %w", err)
|
||||
}
|
||||
var chains []*chain.Chain
|
||||
for _, item := range items {
|
||||
serialized, err := bytesFromStackItem(item)
|
||||
|
@ -121,10 +162,13 @@ func (s *ContractStorage) ListMorphRuleChains(name chain.Name, target engine.Tar
|
|||
}
|
||||
chains = append(chains, c)
|
||||
}
|
||||
|
||||
return chains, nil
|
||||
}
|
||||
|
||||
func (s *ContractStorage) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) {
|
||||
return listChains(name, target, s.actor.GetRPCInvoker(), s.hash)
|
||||
}
|
||||
|
||||
func (s *ContractStorage) ListTargetsIterator(targetType engine.TargetType) (uuid.UUID, result.Iterator, error) {
|
||||
kind, err := policyKind(targetType)
|
||||
if err != nil {
|
||||
|
@ -141,37 +185,21 @@ func (s *ContractStorage) SetAdmin(addr util.Uint160) (util.Uint256, uint32, err
|
|||
return s.contractInterface.SetAdmin(addr)
|
||||
}
|
||||
|
||||
func NewContractStorageReader(inv client.Invoker, contract util.Uint160) *ContractStorageReader {
|
||||
type ContractStorageInvoker interface {
|
||||
client.Invoker
|
||||
GetRPCInvoker() neoinvoker.RPCInvoke
|
||||
}
|
||||
|
||||
func NewContractStorageReader(inv ContractStorageInvoker, contract util.Uint160) *ContractStorageReader {
|
||||
return &ContractStorageReader{
|
||||
hash: contract,
|
||||
invoker: inv,
|
||||
contractReaderInterface: client.NewReader(inv, contract),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ContractStorageReader) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) {
|
||||
kind, err := policyKind(target.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items, err := s.contractReaderInterface.ListChainsByPrefix(big.NewInt(int64(kind)), target.Name, []byte(name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var chains []*chain.Chain
|
||||
for _, item := range items {
|
||||
serialized, err := bytesFromStackItem(item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c := new(chain.Chain)
|
||||
if err := c.DecodeBytes(serialized); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
chains = append(chains, c)
|
||||
}
|
||||
|
||||
return chains, nil
|
||||
return listChains(name, target, s.invoker.GetRPCInvoker(), s.hash)
|
||||
}
|
||||
|
||||
func (s *ContractStorageReader) GetAdmin() (util.Uint160, error) {
|
||||
|
|
Loading…
Reference in a new issue