forked from TrueCloudLab/policy-engine
218 lines
6.1 KiB
Go
218 lines
6.1 KiB
Go
package policy
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
"strings"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
|
client "git.frostfs.info/TrueCloudLab/frostfs-contract/rpcclient/policy"
|
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
|
"github.com/google/uuid"
|
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
|
"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"
|
|
)
|
|
|
|
var (
|
|
ErrEmptyChainID = errors.New("chain id is not set")
|
|
|
|
ErrEngineTargetTypeUnsupported = errors.New("this target type is not supported yet")
|
|
)
|
|
|
|
// ContractStorage is the interface to manage chain rules within Policy contract.
|
|
type ContractStorage struct {
|
|
contractInterface *client.Contract
|
|
}
|
|
|
|
var _ engine.MorphRuleChainStorage = (*ContractStorage)(nil)
|
|
|
|
// ContractStorageReader is the interface to read data from Policy contract.
|
|
type ContractStorageReader struct {
|
|
contractReaderInterface *client.ContractReader
|
|
}
|
|
|
|
var _ engine.MorphRuleChainStorageReader = (*ContractStorageReader)(nil)
|
|
|
|
func NewContractStorage(actor client.Actor, contract util.Uint160) *ContractStorage {
|
|
return &ContractStorage{
|
|
contractInterface: client.New(actor, contract),
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
func (s *ContractStorage) AddMorphRuleChain(name chain.Name, target engine.Target, c *chain.Chain) (txHash util.Uint256, vub uint32, err error) {
|
|
if len(c.ID) == 0 {
|
|
err = ErrEmptyChainID
|
|
return
|
|
}
|
|
|
|
var kind policy.Kind
|
|
kind, err = policyKind(target.Type)
|
|
if err != nil {
|
|
return
|
|
}
|
|
fullName := prefixedChainName(name, c.ID)
|
|
|
|
txHash, vub, err = s.contractInterface.AddChain(big.NewInt(int64(kind)), target.Name, fullName, c.Bytes())
|
|
return
|
|
}
|
|
|
|
func (s *ContractStorage) RemoveMorphRuleChain(name chain.Name, target engine.Target, chainID chain.ID) (txHash util.Uint256, vub uint32, err error) {
|
|
if len(chainID) == 0 {
|
|
err = ErrEmptyChainID
|
|
return
|
|
}
|
|
|
|
var kind policy.Kind
|
|
kind, err = policyKind(target.Type)
|
|
if err != nil {
|
|
return
|
|
}
|
|
fullName := prefixedChainName(name, chainID)
|
|
|
|
txHash, vub, err = s.contractInterface.RemoveChain(big.NewInt(int64(kind)), target.Name, fullName)
|
|
return
|
|
}
|
|
|
|
func (s *ContractStorage) RemoveMorphRuleChainsByTarget(name chain.Name, target engine.Target) (txHash util.Uint256, vub uint32, err error) {
|
|
var kind policy.Kind
|
|
kind, err = policyKind(target.Type)
|
|
if err != nil {
|
|
return
|
|
}
|
|
fullName := prefixedChainName(name, nil)
|
|
|
|
txHash, vub, err = s.contractInterface.RemoveChainsByPrefix(big.NewInt(int64(kind)), target.Name, fullName)
|
|
return
|
|
}
|
|
|
|
func (s *ContractStorage) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
func (s *ContractStorage) ListTargetsIterator(targetType engine.TargetType) (uuid.UUID, result.Iterator, error) {
|
|
kind, err := policyKind(targetType)
|
|
if err != nil {
|
|
return uuid.UUID{}, result.Iterator{}, err
|
|
}
|
|
return s.contractInterface.ListTargets(big.NewInt(int64(kind)))
|
|
}
|
|
|
|
func (s *ContractStorage) GetAdmin() (util.Uint160, error) {
|
|
return s.contractInterface.GetAdmin()
|
|
}
|
|
|
|
func (s *ContractStorage) SetAdmin(addr util.Uint160) (util.Uint256, uint32, error) {
|
|
return s.contractInterface.SetAdmin(addr)
|
|
}
|
|
|
|
func NewContractStorageReader(inv client.Invoker, contract util.Uint160) *ContractStorageReader {
|
|
return &ContractStorageReader{
|
|
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
|
|
}
|
|
|
|
func (s *ContractStorageReader) GetAdmin() (util.Uint160, error) {
|
|
return s.contractReaderInterface.GetAdmin()
|
|
}
|
|
|
|
func (s *ContractStorageReader) ListTargetsIterator(targetType engine.TargetType) (uuid.UUID, result.Iterator, error) {
|
|
kind, err := policyKind(targetType)
|
|
if err != nil {
|
|
return uuid.UUID{}, result.Iterator{}, err
|
|
}
|
|
return s.contractReaderInterface.ListTargets(big.NewInt(int64(kind)))
|
|
}
|
|
|
|
func bytesFromStackItem(param stackitem.Item) ([]byte, error) {
|
|
switch param.Type() {
|
|
case stackitem.BufferT, stackitem.ByteArrayT, stackitem.IntegerT:
|
|
return param.TryBytes()
|
|
case stackitem.AnyT:
|
|
if param.Value() == nil {
|
|
return nil, nil
|
|
}
|
|
fallthrough
|
|
default:
|
|
return nil, fmt.Errorf("chain/client: %s is not a byte array type", param.Type())
|
|
}
|
|
}
|
|
|
|
func prefixedChainName(name chain.Name, chainID chain.ID) []byte {
|
|
return []byte(strings.ToLower(fmt.Sprintf("%s:%s", name, chainID)))
|
|
}
|
|
|
|
func policyKind(typ engine.TargetType) (policy.Kind, error) {
|
|
if typ == engine.Namespace {
|
|
return policy.Namespace, nil
|
|
} else if typ == engine.Container {
|
|
return policy.Container, nil
|
|
} else if typ == engine.User {
|
|
return 'u', nil
|
|
} else if typ == engine.Group {
|
|
return 'g', nil
|
|
}
|
|
return policy.Kind(0), ErrEngineTargetTypeUnsupported
|
|
}
|