package contract import ( "context" "fmt" "math/big" policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy" policyclient "git.frostfs.info/TrueCloudLab/frostfs-contract/rpcclient/policy" frostfsutil "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util" "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain" "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/rpcclient" "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/wallet" ) type Client struct { actor *actor.Actor policyContract *policyclient.Contract } type Config struct { // RPCAddress is an endpoint to connect to neo rpc. RPCAddress string // Contract is hash of contract or its name in NNS. Contract string // Key is used to interact with policy contract. // If this is nil than random key will be generated. Key *keys.PrivateKey } var _ engine.MorphRuleChainStorage = (*Client)(nil) // New creates new Policy contract wrapper. func New(ctx context.Context, cfg Config) (*Client, error) { contractHash, err := frostfsutil.ResolveContractHash(cfg.Contract, cfg.RPCAddress) if err != nil { return nil, fmt.Errorf("resolve frostfs contract hash: %w", err) } key := cfg.Key if key == nil { if key, err = keys.NewPrivateKey(); err != nil { return nil, fmt.Errorf("generate anon private key for policy: %w", err) } } rpcCli, err := rpcclient.New(ctx, cfg.RPCAddress, rpcclient.Options{}) if err != nil { return nil, fmt.Errorf("create policy rpc client: %w", err) } acc := wallet.NewAccountFromPrivateKey(key) act, err := actor.NewSimple(rpcCli, acc) if err != nil { return nil, fmt.Errorf("create new actor: %w", err) } return &Client{ actor: act, policyContract: policyclient.New(act, contractHash), }, nil } func (c *Client) AddMorphRuleChain(name chain.Name, target engine.Target, policyChain *chain.Chain) (util.Uint256, uint32, error) { chainName := append([]byte(name), []byte(policyChain.ID)...) return c.policyContract.AddChain(getKind(target), target.Name, chainName, policyChain.Bytes()) } func (c *Client) RemoveMorphRuleChain(name chain.Name, target engine.Target, chainID chain.ID) (util.Uint256, uint32, error) { chainName := append([]byte(name), []byte(chainID)...) return c.policyContract.RemoveChain(getKind(target), target.Name, chainName) } func (c *Client) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) { items, err := c.policyContract.ListChainsByPrefix(getKind(target), target.Name, []byte(name)) if err != nil { return nil, err } res := make([]*chain.Chain, len(items)) for i, item := range items { data, err := item.TryBytes() if err != nil { return nil, err } var policyChain chain.Chain if err = policyChain.DecodeBytes(data); err != nil { return nil, err } res[i] = &policyChain } return res, nil } func getKind(target engine.Target) *big.Int { var kind int64 = policycontract.Container if target.Type != engine.Container { kind = policycontract.Namespace } return big.NewInt(kind) }