[#1105] ape: Introduce contract storage with proxy contract verification
* `ProxyVerificationContractStorage` uses Proxy contract as a cosigner. * `ProxyVerificationContractStorage` recreates a contract storage for each handler invocation because of an issue: rpc-actor from morph client may be expired. This way won't create a bottlenecks because it is expected that this contract storage implementation will be used not so often. * Make morph client return `RPCActor` (that is websocket client in fact). * Make `SwitchRPCGuardedActor` return `RPCActor` as it will be used for `ProxyVerificationContractStorage`. Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
This commit is contained in:
parent
40b04c00ef
commit
a8a33a5e1d
1 changed files with 128 additions and 0 deletions
128
pkg/ape/contract_storage/proxy.go
Normal file
128
pkg/ape/contract_storage/proxy.go
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue