generated from TrueCloudLab/basic
147 lines
4 KiB
Go
147 lines
4 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/mr-tron/base58"
|
||
|
"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 the policy contract.
|
||
|
type ContractStorage struct {
|
||
|
contractInterface *client.Contract
|
||
|
}
|
||
|
|
||
|
var _ engine.MorphRuleChainStorage = (*ContractStorage)(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 transformNameIfContainer(target engine.Target) (name string) {
|
||
|
name = target.Name
|
||
|
if target.Type == engine.Container {
|
||
|
// Container name can be too long and, thus, cannot be
|
||
|
// used as a key name for policy-contract storage.
|
||
|
name = base58.FastBase58Encoding([]byte(target.Name))
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (s *ContractStorage) AddMorphRuleChain(name chain.Name, target engine.Target, c *chain.Chain) (txHash util.Uint256, vub uint32, err error) {
|
||
|
if c.ID == "" {
|
||
|
err = ErrEmptyChainID
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var kind policy.Kind
|
||
|
kind, err = policyKind(target.Type)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
fullName := prefixedChainName(name, c.ID)
|
||
|
targetName := transformNameIfContainer(target)
|
||
|
|
||
|
txHash, vub, err = s.contractInterface.AddChain(big.NewInt(int64(kind)), targetName, 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 chainID == "" {
|
||
|
err = ErrEmptyChainID
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var kind policy.Kind
|
||
|
kind, err = policyKind(target.Type)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
fullName := prefixedChainName(name, chainID)
|
||
|
targetName := transformNameIfContainer(target)
|
||
|
|
||
|
txHash, vub, err = s.contractInterface.RemoveChain(big.NewInt(int64(kind)), targetName, 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
|
||
|
}
|
||
|
targetName := transformNameIfContainer(target)
|
||
|
|
||
|
items, err := s.contractInterface.ListChainsByPrefix(big.NewInt(int64(kind)), targetName, []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 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
|
||
|
}
|
||
|
return policy.Kind(0), ErrEngineTargetTypeUnsupported
|
||
|
}
|