[#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