generated from TrueCloudLab/basic
router: Make defaultChainRouter match a request by listing chains with iterator #62
3 changed files with 63 additions and 35 deletions
2
go.mod
2
go.mod
|
@ -3,7 +3,7 @@ module git.frostfs.info/TrueCloudLab/policy-engine
|
||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.0
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240409111539-e7a05a49ff45
|
||||||
github.com/google/uuid v1.3.1
|
github.com/google/uuid v1.3.1
|
||||||
github.com/mailru/easyjson v0.7.7
|
github.com/mailru/easyjson v0.7.7
|
||||||
github.com/nspcc-dev/neo-go v0.105.0
|
github.com/nspcc-dev/neo-go v0.105.0
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -1,5 +1,5 @@
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.0 h1:FzurjElUwC7InY9v5rzXReKbfBL5yRJKSWJPq6BKhH0=
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240409111539-e7a05a49ff45 h1:Tp4I+XOLp3VCJORfxSamQtj3RZNISbaLM4WD5iIzXxg=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.0/go.mod h1:F/fe1OoIDKr5Bz99q4sriuHDuf3aZefZy9ZsCqEtgxc=
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240409111539-e7a05a49ff45/go.mod h1:F/fe1OoIDKr5Bz99q4sriuHDuf3aZefZy9ZsCqEtgxc=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
|
github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||||
"math/big"
|
"math/big"
|
||||||||
"strings"
|
"strings"
|
||||||||
|
|
||||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/commonclient"
|
||||||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
||||||||
client "git.frostfs.info/TrueCloudLab/frostfs-contract/rpcclient/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/chain"
|
||||||||
|
@ -13,6 +14,7 @@ import (
|
||||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||||||
|
neoinvoker "github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||||
aarifullin marked this conversation as resolved
Outdated
|
|||||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||||
|
@ -26,6 +28,10 @@ var (
|
||||||||
|
|
||||||||
// ContractStorage is the interface to manage chain rules within Policy contract.
|
// ContractStorage is the interface to manage chain rules within Policy contract.
|
||||||||
type ContractStorage struct {
|
type ContractStorage struct {
|
||||||||
|
hash util.Uint160
|
||||||||
|
|
||||||||
|
actor ContractStorageActor
|
||||||||
|
|
||||||||
contractInterface *client.Contract
|
contractInterface *client.Contract
|
||||||||
}
|
}
|
||||||||
|
|
||||||||
|
@ -33,23 +39,49 @@ var _ engine.MorphRuleChainStorage = (*ContractStorage)(nil)
|
||||||||
|
|
||||||||
// ContractStorageReader is the interface to read data from Policy contract.
|
// ContractStorageReader is the interface to read data from Policy contract.
|
||||||||
type ContractStorageReader struct {
|
type ContractStorageReader struct {
|
||||||||
|
hash util.Uint160
|
||||||||
|
|
||||||||
|
invoker ContractStorageInvoker
|
||||||||
|
|
||||||||
contractReaderInterface *client.ContractReader
|
contractReaderInterface *client.ContractReader
|
||||||||
}
|
}
|
||||||||
|
|
||||||||
|
type ContractStorageActor interface {
|
||||||||
|
client.Actor
|
||||||||
|
GetRPCInvoker() neoinvoker.RPCInvoke
|
||||||||
|
}
|
||||||||
dkirillov marked this conversation as resolved
Outdated
dkirillov
commented
Do we really need pass actor and invoker separately? Maybe we can pass just more general actor? Do we really need pass actor and invoker separately? Maybe we can pass just more general actor?
aarifullin
commented
It is a good point. Actually, I've already tried many ways to generilize that and here is a final solution:
It is a good point. Actually, I've already tried many ways to generilize that and here is a final solution:
```go
type ContractStorageActor interface {
client.Actor
GetRPCInvoker() neoinvoker.RPCInvoke
}
type ContractStorageInvoker interface {
client.Invoker
GetRPCInvoker() neoinvoker.RPCInvoke
}
```
1. I cannot unite `client.Actor` and `neoinvoker.RPCInvoke` in one interface, because they are intersected by method `TraverseIterator`, `TerminateSession` (`duplicate method` **error**)
2. Getter is needed because client, who's going to implement these interfaces, must guarantee that he returns valid `Invoker` that uses working connection (basically, websocket connection)
|
|||||||||
|
|
||||||||
var _ engine.MorphRuleChainStorageReader = (*ContractStorageReader)(nil)
|
var _ engine.MorphRuleChainStorageReader = (*ContractStorageReader)(nil)
|
||||||||
|
|
||||||||
func NewContractStorage(actor client.Actor, contract util.Uint160) *ContractStorage {
|
func NewContractStorage(actor ContractStorageActor, contract util.Uint160) *ContractStorage {
|
||||||||
return &ContractStorage{
|
return &ContractStorage{
|
||||||||
|
hash: contract,
|
||||||||
|
actor: actor,
|
||||||||
contractInterface: client.New(actor, contract),
|
contractInterface: client.New(actor, contract),
|
||||||||
}
|
}
|
||||||||
}
|
}
|
||||||||
|
|
||||||||
|
type contractStorageActorImpl struct {
|
||||||||
|
client.Actor
|
||||||||
|
rpcActor actor.RPCActor
|
||||||||
|
}
|
||||||||
|
|
||||||||
|
var _ ContractStorageActor = &contractStorageActorImpl{}
|
||||||||
|
|
||||||||
|
func (c *contractStorageActorImpl) GetRPCInvoker() neoinvoker.RPCInvoke {
|
||||||||
|
return c.rpcActor
|
||||||||
|
}
|
||||||||
|
|
||||||||
|
// NewContractStorageWithSimpleActor constructs core actor from `rpcActor`.
|
||||||||
|
//
|
||||||||
|
// Note: NewContractStorageWithSimpleActor is appropriate only for call-only-once cases (for example, in CLIs). Otherwise, it is unsafe,
|
||||||||
|
// because core actor may use invalidated `rpcActor` if some connection errors occurred.
|
||||||||
func NewContractStorageWithSimpleActor(rpcActor actor.RPCActor, acc *wallet.Account, contract util.Uint160) (*ContractStorage, error) {
|
func NewContractStorageWithSimpleActor(rpcActor actor.RPCActor, acc *wallet.Account, contract util.Uint160) (*ContractStorage, error) {
|
||||||||
act, err := actor.NewSimple(rpcActor, acc)
|
act, err := actor.NewSimple(rpcActor, acc)
|
||||||||
if err != nil {
|
if err != nil {
|
||||||||
return nil, fmt.Errorf("failed to create simple actor: %w", err)
|
return nil, fmt.Errorf("failed to create simple actor: %w", err)
|
||||||||
}
|
}
|
||||||||
return NewContractStorage(act, contract), nil
|
return NewContractStorage(&contractStorageActorImpl{Actor: act, rpcActor: rpcActor}, contract), nil
|
||||||||
}
|
}
|
||||||||
|
|
||||||||
func (s *ContractStorage) AddMorphRuleChain(name chain.Name, target engine.Target, c *chain.Chain) (txHash util.Uint256, vub uint32, err error) {
|
func (s *ContractStorage) AddMorphRuleChain(name chain.Name, target engine.Target, c *chain.Chain) (txHash util.Uint256, vub uint32, err error) {
|
||||||||
|
@ -98,17 +130,26 @@ func (s *ContractStorage) RemoveMorphRuleChainsByTarget(name chain.Name, target
|
||||||||
return
|
return
|
||||||||
}
|
}
|
||||||||
|
|
||||||||
func (s *ContractStorage) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) {
|
func listChains(name chain.Name, target engine.Target, rpcInvoker neoinvoker.RPCInvoke, hash util.Uint160) ([]*chain.Chain, error) {
|
||||||||
kind, err := policyKind(target.Type)
|
kind, err := policyKind(target.Type)
|
||||||||
if err != nil {
|
if err != nil {
|
||||||||
return nil, err
|
return nil, err
|
||||||||
}
|
}
|
||||||||
|
|
||||||||
items, err := s.contractInterface.ListChainsByPrefix(big.NewInt(int64(kind)), target.Name, []byte(name))
|
const (
|
||||||||
if err != nil {
|
method = "iteratorChainsByPrefix"
|
||||||||
return nil, err
|
batchSize = neoinvoker.DefaultIteratorResultItems
|
||||||||
|
)
|
||||||||
|
|
||||||||
|
inv := neoinvoker.New(rpcInvoker, nil)
|
||||||||
|
params := []any{
|
||||||||
|
big.NewInt(int64(kind)), target.Name, []byte(name),
|
||||||||
dkirillov marked this conversation as resolved
Outdated
dkirillov
commented
Question: Can we use Line 14 in TrueCloudLab/frostfs-contract@694daeb
? Question: Can we use https://git.frostfs.info/TrueCloudLab/frostfs-contract/src/commit/694daebb1928ffc4eb54e314933dfafe121dad93/commonclient/iterator.go#L14 ?
aarifullin
commented
Oh, that's a good find! I am going to check if I can use this, thank you! Oh, that's a good find! I am going to check if I can use this, thank you!
aarifullin
commented
That worked out, thanks! That worked out, thanks!
|
|||||||||
}
|
}
|
||||||||
|
|
||||||||
|
items, err := commonclient.ReadIteratorItems(inv, batchSize, hash, method, params...)
|
||||||||
dkirillov marked this conversation as resolved
Outdated
dkirillov
commented
Inside this method we don't explicitly terminate session so it can lead to Inside this method we don't explicitly terminate session so it can lead to `unwrap session iterator: Internal error (-32603) - max session capacity reached`. Maybe we can update this method in contract first?
aarifullin
commented
You're absolutely correct. I'll fix this in You're absolutely correct. I'll fix this in `frostfs-contract`
aarifullin
commented
`go.mod` has been updated with https://git.frostfs.info/TrueCloudLab/frostfs-contract/pulls/85
|
|||||||||
|
if err != nil {
|
||||||||
|
return nil, fmt.Errorf("read items error: %w", err)
|
||||||||
|
}
|
||||||||
var chains []*chain.Chain
|
var chains []*chain.Chain
|
||||||||
for _, item := range items {
|
for _, item := range items {
|
||||||||
serialized, err := bytesFromStackItem(item)
|
serialized, err := bytesFromStackItem(item)
|
||||||||
|
@ -121,10 +162,13 @@ func (s *ContractStorage) ListMorphRuleChains(name chain.Name, target engine.Tar
|
||||||||
}
|
}
|
||||||||
chains = append(chains, c)
|
chains = append(chains, c)
|
||||||||
}
|
}
|
||||||||
|
|
||||||||
return chains, nil
|
return chains, nil
|
||||||||
}
|
}
|
||||||||
|
|
||||||||
|
func (s *ContractStorage) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) {
|
||||||||
|
return listChains(name, target, s.actor.GetRPCInvoker(), s.hash)
|
||||||||
|
}
|
||||||||
|
|
||||||||
func (s *ContractStorage) ListTargetsIterator(targetType engine.TargetType) (uuid.UUID, result.Iterator, error) {
|
func (s *ContractStorage) ListTargetsIterator(targetType engine.TargetType) (uuid.UUID, result.Iterator, error) {
|
||||||||
kind, err := policyKind(targetType)
|
kind, err := policyKind(targetType)
|
||||||||
if err != nil {
|
if err != nil {
|
||||||||
|
@ -141,37 +185,21 @@ func (s *ContractStorage) SetAdmin(addr util.Uint160) (util.Uint256, uint32, err
|
||||||||
return s.contractInterface.SetAdmin(addr)
|
return s.contractInterface.SetAdmin(addr)
|
||||||||
}
|
}
|
||||||||
|
|
||||||||
func NewContractStorageReader(inv client.Invoker, contract util.Uint160) *ContractStorageReader {
|
type ContractStorageInvoker interface {
|
||||||||
|
client.Invoker
|
||||||||
|
GetRPCInvoker() neoinvoker.RPCInvoke
|
||||||||
|
}
|
||||||||
|
|
||||||||
|
func NewContractStorageReader(inv ContractStorageInvoker, contract util.Uint160) *ContractStorageReader {
|
||||||||
return &ContractStorageReader{
|
return &ContractStorageReader{
|
||||||||
|
hash: contract,
|
||||||||
|
invoker: inv,
|
||||||||
contractReaderInterface: client.NewReader(inv, contract),
|
contractReaderInterface: client.NewReader(inv, contract),
|
||||||||
}
|
}
|
||||||||
}
|
}
|
||||||||
|
|
||||||||
func (s *ContractStorageReader) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) {
|
func (s *ContractStorageReader) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) {
|
||||||||
kind, err := policyKind(target.Type)
|
return listChains(name, target, s.invoker.GetRPCInvoker(), s.hash)
|
||||||||
if err != nil {
|
|
||||||||
return nil, err
|
|
||||||||
}
|
|
||||||||
|
|
||||||||
items, err := s.contractReaderInterface.ListChainsByPrefix(big.NewInt(int64(kind)), target.Name, []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 (s *ContractStorageReader) GetAdmin() (util.Uint160, error) {
|
func (s *ContractStorageReader) GetAdmin() (util.Uint160, error) {
|
||||||||
|
|
Loading…
Reference in a new issue
Empty line
fixed