package contractstorage import ( "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain" "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine" policy_morph "git.frostfs.info/TrueCloudLab/policy-engine/pkg/morph/policy" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" "github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker" "github.com/nspcc-dev/neo-go/pkg/rpcclient/notary" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/wallet" ) type ProxyAdaptedContractStorage interface { AddMorphRuleChain(name chain.Name, target engine.Target, c *chain.Chain) (util.Uint256, uint32, error) RemoveMorphRuleChain(name chain.Name, target engine.Target, chainID chain.ID) (util.Uint256, uint32, error) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) } var _ ProxyAdaptedContractStorage = (engine.MorphRuleChainStorage)(nil) type RPCActorProvider interface { GetRPCActor() actor.RPCActor } // ProxyVerificationContractStorage uses decorated MorphRuleChainStorage with actor where cosigner is a proxy contract. type ProxyVerificationContractStorage struct { rpcActorProvider RPCActorProvider acc *wallet.Account proxyScriptHash util.Uint160 policyScriptHash util.Uint160 } var _ ProxyAdaptedContractStorage = (*ProxyVerificationContractStorage)(nil) func NewProxyVerificationContractStorage(rpcActorProvider RPCActorProvider, key *keys.PrivateKey, proxyScriptHash, policyScriptHash util.Uint160) *ProxyVerificationContractStorage { return &ProxyVerificationContractStorage{ rpcActorProvider: rpcActorProvider, acc: wallet.NewAccountFromPrivateKey(key), proxyScriptHash: proxyScriptHash, policyScriptHash: policyScriptHash, } } // contractStorageActorAdapter adapats *actor.Actor to policy_morph.ContractStorageActor interface. type contractStorageActorAdapter struct { *actor.Actor rpcActor invoker.RPCInvoke } func (n *contractStorageActorAdapter) GetRPCInvoker() invoker.RPCInvoke { return n.rpcActor } func (contractStorage *ProxyVerificationContractStorage) newContractStorageActor() (policy_morph.ContractStorageActor, error) { rpcActor := contractStorage.rpcActorProvider.GetRPCActor() act, err := actor.New(rpcActor, cosigners(contractStorage.acc, contractStorage.proxyScriptHash, contractStorage.policyScriptHash)) if err != nil { return nil, err } return &contractStorageActorAdapter{ Actor: act, rpcActor: rpcActor, }, nil } // AddMorphRuleChain add morph rule chain to Policy contract using both Proxy contract and storage account as consigners. func (contractStorage *ProxyVerificationContractStorage) AddMorphRuleChain(name chain.Name, target engine.Target, c *chain.Chain) (util.Uint256, uint32, error) { // contractStorageActor is reconstructed per each method invocation because RPCActor's (that is, basically, WSClient) connection may get invalidated, but // ProxyVerificationContractStorage does not manage reconnections. contractStorageActor, err := contractStorage.newContractStorageActor() if err != nil { return util.Uint256{}, 0, err } return policy_morph.NewContractStorage(contractStorageActor, contractStorage.policyScriptHash).AddMorphRuleChain(name, target, c) } // RemoveMorphRuleChain removes morph rule chain from Policy contract using both Proxy contract and storage account as consigners. func (contractStorage *ProxyVerificationContractStorage) RemoveMorphRuleChain(name chain.Name, target engine.Target, chainID chain.ID) (util.Uint256, uint32, error) { // contractStorageActor is reconstructed per each method invocation because RPCActor's (that is, basically, WSClient) connection may get invalidated, but // ProxyVerificationContractStorage does not manage reconnections. contractStorageActor, err := contractStorage.newContractStorageActor() if err != nil { return util.Uint256{}, 0, err } return policy_morph.NewContractStorage(contractStorageActor, contractStorage.policyScriptHash).RemoveMorphRuleChain(name, target, chainID) } // ListMorphRuleChains lists morph rule chains from Policy contract using both Proxy contract and storage account as consigners. func (contractStorage *ProxyVerificationContractStorage) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) { // contractStorageActor is reconstructed per each method invocation because RPCActor's (that is, basically, WSClient) connection may get invalidated, but // ProxyVerificationContractStorage does not manage reconnections. contractStorageActor, err := contractStorage.newContractStorageActor() if err != nil { return nil, err } return policy_morph.NewContractStorage(contractStorageActor, contractStorage.policyScriptHash).ListMorphRuleChains(name, target) } func cosigners(acc *wallet.Account, proxyScriptHash, policyScriptHash util.Uint160) []actor.SignerAccount { return []actor.SignerAccount{ { Signer: transaction.Signer{ Account: proxyScriptHash, Scopes: transaction.CustomContracts, AllowedContracts: []util.Uint160{policyScriptHash}, }, Account: notary.FakeContractAccount(proxyScriptHash), }, { Signer: transaction.Signer{ Account: acc.Contract.ScriptHash(), Scopes: transaction.CalledByEntry, }, Account: acc, }, } }