Merge pull request #14 from anytypeio/add-client-functionality
This commit is contained in:
commit
8263bbfde2
7
.gitignore
vendored
7
.gitignore
vendored
@ -8,12 +8,19 @@
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Golang vendor folder
|
||||
vendor
|
||||
|
||||
# database
|
||||
db
|
||||
|
||||
# artefacts for Intelli-J fleet
|
||||
.fleet
|
||||
|
||||
# Intelli-J files
|
||||
.idea
|
||||
|
||||
|
||||
@ -1,20 +1,125 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/clientspace"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/document"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/symmetric"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
type Controller interface {
|
||||
// DeriveSpace derives the space from current account
|
||||
DeriveSpace() (id string, err error)
|
||||
// CreateSpace creates new space with random data
|
||||
CreateSpace() (id string, err error)
|
||||
GetAllSpacesIds() (ids []string, err error)
|
||||
// AllSpaceIds returns ids of all spaces
|
||||
AllSpaceIds() (ids []string, err error)
|
||||
// LoadSpace asks node to load a particular space
|
||||
LoadSpace(id string) (err error)
|
||||
|
||||
// CreateDocument creates new document in space
|
||||
CreateDocument(spaceId string) (id string, err error)
|
||||
GetAllDocumentIds(spaceId string) (ids []string, err error)
|
||||
AddText(documentId, text string) (err error)
|
||||
DumpDocumentTree(documentId string) (err error)
|
||||
// AllDocumentIds gets all ids of documents in space
|
||||
AllDocumentIds(spaceId string) (ids []string, err error)
|
||||
// AddText adds text to space document
|
||||
AddText(spaceId, documentId, text string) (err error)
|
||||
// DumpDocumentTree dumps the tree data into string
|
||||
DumpDocumentTree(spaceId, documentId string) (dump string, err error)
|
||||
|
||||
GetValidInvites(spaceId string) (invites []string, err error)
|
||||
ValidInvites(spaceId string) (invites []string, err error)
|
||||
GenerateInvite(spaceId string) (invite string, err error)
|
||||
JoinSpace(invite string) (err error)
|
||||
}
|
||||
|
||||
type controller struct {
|
||||
spaceService clientspace.Service
|
||||
storageService storage.ClientStorage
|
||||
docService document.Service
|
||||
account account.Service
|
||||
}
|
||||
|
||||
func newController(spaceService clientspace.Service,
|
||||
storageService storage.ClientStorage,
|
||||
docService document.Service,
|
||||
account account.Service) Controller {
|
||||
return &controller{
|
||||
spaceService: spaceService,
|
||||
storageService: storageService,
|
||||
docService: docService,
|
||||
account: account,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *controller) DeriveSpace() (id string, err error) {
|
||||
sp, err := c.spaceService.DeriveSpace(context.Background(), commonspace.SpaceDerivePayload{
|
||||
SigningKey: c.account.Account().SignKey,
|
||||
EncryptionKey: c.account.Account().EncKey,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
id = sp.Id()
|
||||
return
|
||||
}
|
||||
|
||||
func (c *controller) CreateSpace() (id string, err error) {
|
||||
key, err := symmetric.NewRandom()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
sp, err := c.spaceService.CreateSpace(context.Background(), commonspace.SpaceCreatePayload{
|
||||
SigningKey: c.account.Account().SignKey,
|
||||
EncryptionKey: c.account.Account().EncKey,
|
||||
ReadKey: key.Bytes(),
|
||||
ReplicationKey: rand.Uint64(),
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
id = sp.Id()
|
||||
return
|
||||
}
|
||||
|
||||
func (c *controller) AllSpaceIds() (ids []string, err error) {
|
||||
return c.storageService.AllSpaceIds()
|
||||
}
|
||||
|
||||
func (c *controller) LoadSpace(id string) (err error) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (c *controller) CreateDocument(spaceId string) (id string, err error) {
|
||||
return c.docService.CreateDocument(spaceId)
|
||||
}
|
||||
|
||||
func (c *controller) AllDocumentIds(spaceId string) (ids []string, err error) {
|
||||
return c.docService.AllDocumentIds(spaceId)
|
||||
}
|
||||
|
||||
func (c *controller) AddText(spaceId, documentId, text string) (err error) {
|
||||
return c.docService.AddText(spaceId, documentId, text)
|
||||
}
|
||||
|
||||
func (c *controller) DumpDocumentTree(spaceId, documentId string) (dump string, err error) {
|
||||
return c.docService.DumpDocumentTree(spaceId, documentId)
|
||||
}
|
||||
|
||||
func (c *controller) ValidInvites(spaceId string) (invites []string, err error) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (c *controller) GenerateInvite(spaceId string) (invite string, err error) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (c *controller) JoinSpace(invite string) (err error) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
169
client/api/service.go
Normal file
169
client/api/service.go
Normal file
@ -0,0 +1,169 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/clientspace"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/document"
|
||||
clientstorage "github.com/anytypeio/go-anytype-infrastructure-experiments/client/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/config"
|
||||
"go.uber.org/zap"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const CName = "api.service"
|
||||
|
||||
var log = logger.NewNamed("api")
|
||||
|
||||
func New() Service {
|
||||
return &service{}
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
app.ComponentRunnable
|
||||
}
|
||||
|
||||
type service struct {
|
||||
controller Controller
|
||||
srv *http.Server
|
||||
cfg *config.Config
|
||||
}
|
||||
|
||||
func (s *service) Init(a *app.App) (err error) {
|
||||
s.controller = newController(
|
||||
a.MustComponent(clientspace.CName).(clientspace.Service),
|
||||
a.MustComponent(storage.CName).(clientstorage.ClientStorage),
|
||||
a.MustComponent(document.CName).(document.Service),
|
||||
a.MustComponent(account.CName).(account.Service))
|
||||
s.cfg = a.MustComponent(config.CName).(*config.Config)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) Name() (name string) {
|
||||
return CName
|
||||
}
|
||||
|
||||
func (s *service) Run(ctx context.Context) (err error) {
|
||||
defer func() {
|
||||
if err == nil {
|
||||
log.With(zap.String("port", s.cfg.APIServer.Port)).Info("api server started running")
|
||||
}
|
||||
}()
|
||||
|
||||
s.srv = &http.Server{
|
||||
Addr: fmt.Sprintf(":%s", s.cfg.APIServer.Port),
|
||||
}
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/deriveSpace", s.deriveSpace)
|
||||
mux.HandleFunc("/createSpace", s.createSpace)
|
||||
mux.HandleFunc("/allSpaceIds", s.allSpaceIds)
|
||||
mux.HandleFunc("/createDocument", s.createDocument)
|
||||
mux.HandleFunc("/allDocumentIds", s.allDocumentIds)
|
||||
mux.HandleFunc("/addText", s.addText)
|
||||
mux.HandleFunc("/dumpDocumentTree", s.dumpDocumentTree)
|
||||
s.srv.Handler = mux
|
||||
|
||||
go s.runServer()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) runServer() {
|
||||
err := s.srv.ListenAndServe()
|
||||
if err != nil {
|
||||
log.With(zap.Error(err)).Error("could not run api server")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) Close(ctx context.Context) (err error) {
|
||||
return s.srv.Shutdown(ctx)
|
||||
}
|
||||
|
||||
func (s *service) deriveSpace(w http.ResponseWriter, req *http.Request) {
|
||||
id, err := s.controller.DeriveSpace()
|
||||
if err != nil {
|
||||
sendText(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
sendText(w, http.StatusOK, id)
|
||||
}
|
||||
|
||||
func (s *service) createSpace(w http.ResponseWriter, req *http.Request) {
|
||||
id, err := s.controller.CreateSpace()
|
||||
if err != nil {
|
||||
sendText(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
sendText(w, http.StatusOK, id)
|
||||
}
|
||||
|
||||
func (s *service) allSpaceIds(w http.ResponseWriter, req *http.Request) {
|
||||
ids, err := s.controller.AllSpaceIds()
|
||||
if err != nil {
|
||||
sendText(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
sendText(w, http.StatusOK, strings.Join(ids, "\n"))
|
||||
}
|
||||
|
||||
func (s *service) createDocument(w http.ResponseWriter, req *http.Request) {
|
||||
query := req.URL.Query()
|
||||
spaceId := query.Get("spaceId")
|
||||
id, err := s.controller.CreateDocument(spaceId)
|
||||
if err != nil {
|
||||
sendText(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
sendText(w, http.StatusOK, id)
|
||||
}
|
||||
|
||||
func (s *service) allDocumentIds(w http.ResponseWriter, req *http.Request) {
|
||||
query := req.URL.Query()
|
||||
spaceId := query.Get("spaceId")
|
||||
ids, err := s.controller.AllDocumentIds(spaceId)
|
||||
if err != nil {
|
||||
sendText(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
sendText(w, http.StatusOK, strings.Join(ids, "\n"))
|
||||
}
|
||||
|
||||
func (s *service) addText(w http.ResponseWriter, req *http.Request) {
|
||||
query := req.URL.Query()
|
||||
spaceId := query.Get("spaceId")
|
||||
documentId := query.Get("documentId")
|
||||
text := query.Get("text")
|
||||
err := s.controller.AddText(spaceId, documentId, text)
|
||||
if err != nil {
|
||||
sendText(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
sendText(w, http.StatusOK, "Text added")
|
||||
}
|
||||
|
||||
func (s *service) dumpDocumentTree(w http.ResponseWriter, req *http.Request) {
|
||||
query := req.URL.Query()
|
||||
spaceId := query.Get("spaceId")
|
||||
documentId := query.Get("documentId")
|
||||
dump, err := s.controller.DumpDocumentTree(spaceId, documentId)
|
||||
if err != nil {
|
||||
sendText(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
sendText(w, http.StatusOK, dump)
|
||||
}
|
||||
|
||||
func sendText(r http.ResponseWriter, code int, body string) {
|
||||
r.Header().Set("Content-Type", "text/plain")
|
||||
r.WriteHeader(code)
|
||||
|
||||
_, err := io.WriteString(r, fmt.Sprintf("%s\n", body))
|
||||
if err != nil {
|
||||
log.Error("writing response failed", zap.Error(err))
|
||||
}
|
||||
}
|
||||
@ -18,6 +18,10 @@ type service struct {
|
||||
db *badger.DB
|
||||
}
|
||||
|
||||
func New() BadgerProvider {
|
||||
return &service{}
|
||||
}
|
||||
|
||||
func (s *service) Init(a *app.App) (err error) {
|
||||
cfg := a.MustComponent(config.CName).(*config.Config)
|
||||
s.db, err = badger.Open(badger.DefaultOptions(cfg.Storage.Path))
|
||||
|
||||
@ -3,11 +3,15 @@ package clientcache
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/clientspace"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/document/textdocument"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/clientspace"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ocache"
|
||||
"go.uber.org/zap"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -21,10 +25,33 @@ const spaceKey ctxKey = 0
|
||||
type treeCache struct {
|
||||
gcttl int
|
||||
cache ocache.OCache
|
||||
account account.Service
|
||||
clientService clientspace.Service
|
||||
}
|
||||
|
||||
func New(ttl int) cache.TreeCache {
|
||||
type TreeCache interface {
|
||||
treegetter.TreeGetter
|
||||
GetDocument(ctx context.Context, spaceId, id string) (doc textdocument.TextDocument, err error)
|
||||
}
|
||||
|
||||
type updateListener struct {
|
||||
}
|
||||
|
||||
func (u *updateListener) Update(tree tree.ObjectTree) {
|
||||
log.With(
|
||||
zap.Strings("heads", tree.Heads()),
|
||||
zap.String("tree id", tree.ID())).
|
||||
Debug("updating tree")
|
||||
}
|
||||
|
||||
func (u *updateListener) Rebuild(tree tree.ObjectTree) {
|
||||
log.With(
|
||||
zap.Strings("heads", tree.Heads()),
|
||||
zap.String("tree id", tree.ID())).
|
||||
Debug("rebuilding tree")
|
||||
}
|
||||
|
||||
func New(ttl int) TreeCache {
|
||||
return &treeCache{
|
||||
gcttl: ttl,
|
||||
}
|
||||
@ -40,6 +67,7 @@ func (c *treeCache) Close(ctx context.Context) (err error) {
|
||||
|
||||
func (c *treeCache) Init(a *app.App) (err error) {
|
||||
c.clientService = a.MustComponent(clientspace.CName).(clientspace.Service)
|
||||
c.account = a.MustComponent(account.CName).(account.Service)
|
||||
c.cache = ocache.New(
|
||||
func(ctx context.Context, id string) (value ocache.Object, err error) {
|
||||
spaceId := ctx.Value(spaceKey).(string)
|
||||
@ -47,39 +75,34 @@ func (c *treeCache) Init(a *app.App) (err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return space.BuildTree(ctx, id, nil)
|
||||
return textdocument.NewTextDocument(context.Background(), space, id, &updateListener{}, c.account)
|
||||
},
|
||||
ocache.WithLogger(log.Sugar()),
|
||||
ocache.WithGCPeriod(time.Minute),
|
||||
ocache.WithTTL(time.Duration(c.gcttl)*time.Second),
|
||||
ocache.WithRefCounter(false),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *treeCache) Name() (name string) {
|
||||
return cache.CName
|
||||
return treegetter.CName
|
||||
}
|
||||
|
||||
func (c *treeCache) GetTree(ctx context.Context, spaceId, id string) (res cache.TreeResult, err error) {
|
||||
var cacheRes ocache.Object
|
||||
func (c *treeCache) GetDocument(ctx context.Context, spaceId, id string) (doc textdocument.TextDocument, err error) {
|
||||
ctx = context.WithValue(ctx, spaceKey, spaceId)
|
||||
cacheRes, err = c.cache.Get(ctx, id)
|
||||
v, err := c.cache.Get(ctx, id)
|
||||
if err != nil {
|
||||
return cache.TreeResult{}, err
|
||||
}
|
||||
|
||||
treeContainer, ok := cacheRes.(cache.TreeContainer)
|
||||
if !ok {
|
||||
err = ErrCacheObjectWithoutTree
|
||||
return
|
||||
}
|
||||
|
||||
res = cache.TreeResult{
|
||||
Release: func() {
|
||||
c.cache.Release(id)
|
||||
},
|
||||
TreeContainer: treeContainer,
|
||||
}
|
||||
doc = v.(textdocument.TextDocument)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *treeCache) GetTree(ctx context.Context, spaceId, id string) (tr tree.ObjectTree, err error) {
|
||||
doc, err := c.GetDocument(ctx, spaceId, id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tr = doc.Tree()
|
||||
return
|
||||
}
|
||||
|
||||
@ -2,9 +2,10 @@ package clientspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||
)
|
||||
|
||||
type rpcHandler struct {
|
||||
@ -17,16 +18,19 @@ func (r *rpcHandler) PushSpace(ctx context.Context, req *spacesyncproto.PushSpac
|
||||
err = spacesyncproto.ErrSpaceExists
|
||||
return
|
||||
}
|
||||
if err != cache.ErrSpaceNotFound {
|
||||
if err != treegetter.ErrSpaceNotFound {
|
||||
err = spacesyncproto.ErrUnexpected
|
||||
return
|
||||
}
|
||||
|
||||
payload := storage.SpaceStorageCreatePayload{
|
||||
RecWithId: req.AclRoot,
|
||||
RecWithId: &aclrecordproto.RawACLRecordWithId{
|
||||
Payload: req.AclPayload,
|
||||
Id: req.AclPayloadId,
|
||||
},
|
||||
SpaceHeaderWithId: req.SpaceHeader,
|
||||
}
|
||||
_, err = r.s.spaceStorageProvider.CreateSpaceStorage(payload)
|
||||
st, err := r.s.spaceStorageProvider.CreateSpaceStorage(payload)
|
||||
if err != nil {
|
||||
err = spacesyncproto.ErrUnexpected
|
||||
if err == storage.ErrSpaceStorageExists {
|
||||
@ -34,6 +38,7 @@ func (r *rpcHandler) PushSpace(ctx context.Context, req *spacesyncproto.PushSpac
|
||||
}
|
||||
return
|
||||
}
|
||||
st.Close()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -46,7 +46,6 @@ func (s *service) Init(a *app.App) (err error) {
|
||||
ocache.WithLogger(log.Sugar()),
|
||||
ocache.WithGCPeriod(time.Minute),
|
||||
ocache.WithTTL(time.Duration(s.conf.GCTTL)*time.Second),
|
||||
ocache.WithRefCounter(false),
|
||||
)
|
||||
return spacesyncproto.DRPCRegisterSpace(a.MustComponent(server.CName).(server.DRPCServer), &rpcHandler{s})
|
||||
}
|
||||
@ -56,43 +55,39 @@ func (s *service) Name() (name string) {
|
||||
}
|
||||
|
||||
func (s *service) Run(ctx context.Context) (err error) {
|
||||
go func() {
|
||||
time.Sleep(time.Second * 5)
|
||||
_, _ = s.GetSpace(ctx, "testDSpace")
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
func (s *service) CreateSpace(ctx context.Context, payload commonspace.SpaceCreatePayload) (space commonspace.Space, err error) {
|
||||
func (s *service) CreateSpace(ctx context.Context, payload commonspace.SpaceCreatePayload) (container commonspace.Space, err error) {
|
||||
id, err := s.commonSpace.CreateSpace(ctx, payload)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
obj, err := s.commonSpace.GetSpace(ctx, id)
|
||||
obj, err := s.spaceCache.Get(ctx, id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return obj.(commonspace.Space), nil
|
||||
}
|
||||
|
||||
func (s *service) DeriveSpace(ctx context.Context, payload commonspace.SpaceDerivePayload) (space commonspace.Space, err error) {
|
||||
func (s *service) DeriveSpace(ctx context.Context, payload commonspace.SpaceDerivePayload) (container commonspace.Space, err error) {
|
||||
id, err := s.commonSpace.DeriveSpace(ctx, payload)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
obj, err := s.commonSpace.GetSpace(ctx, id)
|
||||
obj, err := s.spaceCache.Get(ctx, id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return obj.(commonspace.Space), nil
|
||||
}
|
||||
|
||||
func (s *service) GetSpace(ctx context.Context, id string) (commonspace.Space, error) {
|
||||
func (s *service) GetSpace(ctx context.Context, id string) (container commonspace.Space, err error) {
|
||||
v, err := s.spaceCache.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
return v.(commonspace.Space), nil
|
||||
}
|
||||
|
||||
112
client/cmd/client.go
Normal file
112
client/cmd/client.go
Normal file
@ -0,0 +1,112 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/account"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/api"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/badgerprovider"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/clientspace"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/clientspace/clientcache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/document"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/config"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/metric"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/dialer"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/server"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/secure"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
"go.uber.org/zap"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
var log = logger.NewNamed("main")
|
||||
|
||||
var (
|
||||
flagConfigFile = flag.String("c", "etc/client.yml", "path to config file")
|
||||
// we can't use "v" here because of glog init (through badger) setting flag.Bool with "v"
|
||||
flagVersion = flag.Bool("ver", false, "show version and exit")
|
||||
flagHelp = flag.Bool("h", false, "show help and exit")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
if *flagVersion {
|
||||
fmt.Println(app.VersionDescription())
|
||||
return
|
||||
}
|
||||
if *flagHelp {
|
||||
flag.PrintDefaults()
|
||||
return
|
||||
}
|
||||
|
||||
if debug, ok := os.LookupEnv("ANYPROF"); ok && debug != "" {
|
||||
go func() {
|
||||
http.ListenAndServe(debug, nil)
|
||||
}()
|
||||
}
|
||||
|
||||
// create app
|
||||
ctx := context.Background()
|
||||
a := new(app.App)
|
||||
|
||||
// open config file
|
||||
conf, err := config.NewFromFile(*flagConfigFile)
|
||||
if err != nil {
|
||||
log.Fatal("can't open config file", zap.Error(err))
|
||||
}
|
||||
|
||||
// bootstrap components
|
||||
a.Register(conf)
|
||||
Bootstrap(a)
|
||||
|
||||
// start app
|
||||
if err := a.Start(ctx); err != nil {
|
||||
log.Fatal("can't start app", zap.Error(err))
|
||||
}
|
||||
log.Info("app started", zap.String("version", a.Version()))
|
||||
|
||||
// wait exit signal
|
||||
exit := make(chan os.Signal, 1)
|
||||
signal.Notify(exit, os.Interrupt, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGQUIT)
|
||||
sig := <-exit
|
||||
log.Info("received exit signal, stop app...", zap.String("signal", fmt.Sprint(sig)))
|
||||
|
||||
// close app
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Minute)
|
||||
defer cancel()
|
||||
if err := a.Close(ctx); err != nil {
|
||||
log.Fatal("close error", zap.Error(err))
|
||||
} else {
|
||||
log.Info("goodbye!")
|
||||
}
|
||||
time.Sleep(time.Second / 3)
|
||||
}
|
||||
|
||||
func Bootstrap(a *app.App) {
|
||||
a.Register(account.New()).
|
||||
Register(nodeconf.New()).
|
||||
Register(metric.New()).
|
||||
Register(badgerprovider.New()).
|
||||
Register(storage.New()).
|
||||
Register(clientcache.New(200)).
|
||||
Register(secure.New()).
|
||||
Register(dialer.New()).
|
||||
Register(pool.New()).
|
||||
Register(commonspace.New()).
|
||||
Register(clientspace.New()).
|
||||
Register(server.New()).
|
||||
Register(document.New()).
|
||||
Register(api.New())
|
||||
}
|
||||
@ -1,13 +1,83 @@
|
||||
package document
|
||||
|
||||
import "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/clientspace"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/clientspace/clientcache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/document/textdocument"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
app.Component
|
||||
CreateDocument(spaceId string) (id string, err error)
|
||||
GetAllDocumentIds(spaceId string) (ids []string, err error)
|
||||
AddText(documentId, text string) (err error)
|
||||
DumpDocumentTree(documentId string) (err error)
|
||||
AllDocumentIds(spaceId string) (ids []string, err error)
|
||||
AddText(spaceId, documentId, text string) (err error)
|
||||
DumpDocumentTree(spaceId, documentId string) (dump string, err error)
|
||||
}
|
||||
|
||||
const CName = "client.document"
|
||||
|
||||
var log = logger.NewNamed(CName)
|
||||
|
||||
type service struct {
|
||||
account account.Service
|
||||
spaceService clientspace.Service
|
||||
cache clientcache.TreeCache
|
||||
}
|
||||
|
||||
func New() Service {
|
||||
return &service{}
|
||||
}
|
||||
|
||||
func (s *service) Init(a *app.App) (err error) {
|
||||
s.account = a.MustComponent(account.CName).(account.Service)
|
||||
s.spaceService = a.MustComponent(clientspace.CName).(clientspace.Service)
|
||||
s.cache = a.MustComponent(treegetter.CName).(clientcache.TreeCache)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *service) Name() (name string) {
|
||||
return CName
|
||||
}
|
||||
|
||||
func (s *service) CreateDocument(spaceId string) (id string, err error) {
|
||||
space, err := s.spaceService.GetSpace(context.Background(), spaceId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
doc, err := textdocument.CreateTextDocument(context.Background(), space, s.account, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
id = doc.Tree().ID()
|
||||
return
|
||||
}
|
||||
|
||||
func (s *service) AllDocumentIds(spaceId string) (ids []string, err error) {
|
||||
space, err := s.spaceService.GetSpace(context.Background(), spaceId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ids = space.StoredIds()
|
||||
return
|
||||
}
|
||||
|
||||
func (s *service) AddText(spaceId, documentId, text string) (err error) {
|
||||
doc, err := s.cache.GetDocument(context.Background(), spaceId, documentId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return doc.AddText(text)
|
||||
}
|
||||
|
||||
func (s *service) DumpDocumentTree(spaceId, documentId string) (dump string, err error) {
|
||||
doc, err := s.cache.GetDocument(context.Background(), spaceId, documentId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return doc.Tree().DebugDump()
|
||||
}
|
||||
|
||||
116
client/document/textdocument/textdocument.go
Normal file
116
client/document/textdocument/textdocument.go
Normal file
@ -0,0 +1,116 @@
|
||||
package textdocument
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener"
|
||||
testchanges "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/testutils/testchanges/proto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
type TextDocument interface {
|
||||
Tree() tree.ObjectTree
|
||||
AddText(text string) error
|
||||
Text() (string, error)
|
||||
TreeDump() string
|
||||
Close() error
|
||||
}
|
||||
|
||||
type textDocument struct {
|
||||
objTree tree.ObjectTree
|
||||
account account.Service
|
||||
}
|
||||
|
||||
func CreateTextDocument(
|
||||
ctx context.Context,
|
||||
space commonspace.Space,
|
||||
account account.Service,
|
||||
listener updatelistener.UpdateListener) (doc TextDocument, err error) {
|
||||
payload := tree.ObjectTreeCreatePayload{
|
||||
SignKey: account.Account().SignKey,
|
||||
SpaceId: space.Id(),
|
||||
Identity: account.Account().Identity,
|
||||
}
|
||||
t, err := space.CreateTree(ctx, payload, listener)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return &textDocument{
|
||||
objTree: t,
|
||||
account: account,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewTextDocument(ctx context.Context, space commonspace.Space, id string, listener updatelistener.UpdateListener, account account.Service) (doc TextDocument, err error) {
|
||||
t, err := space.BuildTree(ctx, id, listener)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return &textDocument{
|
||||
objTree: t,
|
||||
account: account,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *textDocument) Tree() tree.ObjectTree {
|
||||
return t.objTree
|
||||
}
|
||||
|
||||
func (t *textDocument) AddText(text string) (err error) {
|
||||
content := &testchanges.TextContent_TextAppend{
|
||||
TextAppend: &testchanges.TextAppend{Text: text},
|
||||
}
|
||||
change := &testchanges.TextData{
|
||||
Content: []*testchanges.TextContent{
|
||||
{content},
|
||||
},
|
||||
Snapshot: nil,
|
||||
}
|
||||
res, err := change.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
t.objTree.Lock()
|
||||
defer t.objTree.Unlock()
|
||||
_, err = t.objTree.AddContent(context.Background(), tree.SignableChangeContent{
|
||||
Data: res,
|
||||
Key: t.account.Account().SignKey,
|
||||
Identity: t.account.Account().Identity,
|
||||
IsSnapshot: false,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (t *textDocument) Text() (text string, err error) {
|
||||
t.objTree.RLock()
|
||||
defer t.objTree.RUnlock()
|
||||
|
||||
err = t.objTree.Iterate(
|
||||
func(decrypted []byte) (any, error) {
|
||||
textChange := &testchanges.TextData{}
|
||||
err = proto.Unmarshal(decrypted, textChange)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, cnt := range textChange.Content {
|
||||
if cnt.GetTextAppend() != nil {
|
||||
text += cnt.GetTextAppend().Text
|
||||
}
|
||||
}
|
||||
return textChange, nil
|
||||
}, func(change *tree.Change) bool {
|
||||
return true
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (t *textDocument) TreeDump() string {
|
||||
return t.TreeDump()
|
||||
}
|
||||
|
||||
func (t *textDocument) Close() error {
|
||||
return nil
|
||||
}
|
||||
@ -2,10 +2,70 @@ module github.com/anytypeio/go-anytype-infrastructure-experiments/client
|
||||
|
||||
replace github.com/anytypeio/go-anytype-infrastructure-experiments/common => ../common
|
||||
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/anytypeio/go-anytype-infrastructure-experiments/common v0.0.0-00010101000000-000000000000
|
||||
github.com/dgraph-io/badger/v3 v3.2103.3
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
go.uber.org/zap v1.23.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/anytypeio/go-chash v0.0.0-20220629194632-4ad1154fe232 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
|
||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/fogleman/gg v1.3.0 // indirect
|
||||
github.com/goccy/go-graphviz v0.0.9 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.3 // indirect
|
||||
github.com/google/flatbuffers v1.12.1 // indirect
|
||||
github.com/huandu/skiplist v1.2.0 // indirect
|
||||
github.com/ipfs/go-cid v0.3.2 // indirect
|
||||
github.com/ipfs/go-log/v2 v2.5.1 // indirect
|
||||
github.com/klauspost/compress v1.15.10 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.1.1 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
||||
github.com/libp2p/go-libp2p v0.23.2 // indirect
|
||||
github.com/libp2p/go-libp2p-core v0.20.1 // indirect
|
||||
github.com/libp2p/go-openssl v0.1.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mattn/go-pointer v0.0.1 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.1.0 // indirect
|
||||
github.com/multiformats/go-base36 v0.1.0 // indirect
|
||||
github.com/multiformats/go-multiaddr v0.7.0 // indirect
|
||||
github.com/multiformats/go-multibase v0.1.1 // indirect
|
||||
github.com/multiformats/go-multicodec v0.6.0 // indirect
|
||||
github.com/multiformats/go-multihash v0.2.1 // indirect
|
||||
github.com/multiformats/go-varint v0.0.6 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/prometheus/client_golang v1.13.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
github.com/zeebo/errs v1.3.0 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
|
||||
golang.org/x/image v0.0.0-20200119044424-58c23975cae1 // indirect
|
||||
golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 // indirect
|
||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/blake3 v1.1.7 // indirect
|
||||
storj.io/drpc v0.0.32 // indirect
|
||||
)
|
||||
|
||||
@ -65,7 +65,7 @@ type spaceKeys struct {
|
||||
|
||||
func newSpaceKeys(spaceId string) spaceKeys {
|
||||
return spaceKeys{
|
||||
headerKey: storage.JoinStringsToBytes("space", spaceId),
|
||||
headerKey: storage.JoinStringsToBytes("space", "header", spaceId),
|
||||
treePrefixKey: storage.JoinStringsToBytes("space", spaceId, "t", "rootId"),
|
||||
}
|
||||
}
|
||||
@ -77,3 +77,15 @@ func (s spaceKeys) HeaderKey() []byte {
|
||||
func (s spaceKeys) TreeRootPrefix() []byte {
|
||||
return s.treePrefixKey
|
||||
}
|
||||
|
||||
type storageServiceKeys struct {
|
||||
spacePrefix []byte
|
||||
}
|
||||
|
||||
func newStorageServiceKeys() storageServiceKeys {
|
||||
return storageServiceKeys{spacePrefix: []byte("space/header")}
|
||||
}
|
||||
|
||||
func (s storageServiceKeys) SpacePrefix() []byte {
|
||||
return s.spacePrefix
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ func newListStorage(spaceId string, db *badger.DB, txn *badger.Txn) (ls storage.
|
||||
|
||||
ls = &listStorage{
|
||||
db: db,
|
||||
keys: aclKeys{},
|
||||
keys: newACLKeys(spaceId),
|
||||
id: stringId,
|
||||
root: rootWithId,
|
||||
}
|
||||
@ -70,7 +70,7 @@ func createListStorage(spaceId string, db *badger.DB, txn *badger.Txn, root *acl
|
||||
|
||||
ls = &listStorage{
|
||||
db: db,
|
||||
keys: aclKeys{},
|
||||
keys: newACLKeys(spaceId),
|
||||
id: root.Id,
|
||||
root: root,
|
||||
}
|
||||
|
||||
@ -125,5 +125,5 @@ func (s *spaceStorage) StoredIds() (ids []string, err error) {
|
||||
}
|
||||
|
||||
func (s *spaceStorage) Close() (err error) {
|
||||
return s.objDb.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1,23 +1,32 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/badgerprovider"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
"github.com/dgraph-io/badger/v3"
|
||||
)
|
||||
|
||||
type storageService struct {
|
||||
db *badger.DB
|
||||
keys storageServiceKeys
|
||||
db *badger.DB
|
||||
}
|
||||
|
||||
func New() storage.SpaceStorageProvider {
|
||||
type ClientStorage interface {
|
||||
storage.SpaceStorageProvider
|
||||
app.ComponentRunnable
|
||||
AllSpaceIds() (ids []string, err error)
|
||||
}
|
||||
|
||||
func New() ClientStorage {
|
||||
return &storageService{}
|
||||
}
|
||||
|
||||
func (s *storageService) Init(a *app.App) (err error) {
|
||||
provider := a.MustComponent(badgerprovider.CName).(badgerprovider.BadgerProvider)
|
||||
s.db = provider.Badger()
|
||||
s.keys = newStorageServiceKeys()
|
||||
return
|
||||
}
|
||||
|
||||
@ -32,3 +41,34 @@ func (s *storageService) SpaceStorage(id string) (storage.SpaceStorage, error) {
|
||||
func (s *storageService) CreateSpaceStorage(payload storage.SpaceStorageCreatePayload) (storage.SpaceStorage, error) {
|
||||
return createSpaceStorage(s.db, payload)
|
||||
}
|
||||
|
||||
func (s *storageService) AllSpaceIds() (ids []string, err error) {
|
||||
err = s.db.View(func(txn *badger.Txn) error {
|
||||
opts := badger.DefaultIteratorOptions
|
||||
opts.PrefetchValues = false
|
||||
opts.Prefix = s.keys.SpacePrefix()
|
||||
|
||||
it := txn.NewIterator(opts)
|
||||
defer it.Close()
|
||||
|
||||
for it.Rewind(); it.Valid(); it.Next() {
|
||||
item := it.Item()
|
||||
id := item.Key()
|
||||
if len(id) <= len(s.keys.SpacePrefix())+1 {
|
||||
continue
|
||||
}
|
||||
id = id[len(s.keys.SpacePrefix())+1:]
|
||||
ids = append(ids, string(id))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (s *storageService) Run(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *storageService) Close(ctx context.Context) (err error) {
|
||||
return s.db.Close()
|
||||
}
|
||||
|
||||
30
common/commonspace/cache/treecache.go
vendored
30
common/commonspace/cache/treecache.go
vendored
@ -1,30 +0,0 @@
|
||||
//go:generate mockgen -destination mock_cache/mock_cache.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache TreeCache
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
)
|
||||
|
||||
const CName = "commonspace.cache"
|
||||
|
||||
var ErrSpaceNotFound = errors.New("space not found")
|
||||
|
||||
type TreeContainer interface {
|
||||
Tree() tree.ObjectTree
|
||||
}
|
||||
|
||||
type TreeResult struct {
|
||||
Release func()
|
||||
TreeContainer TreeContainer
|
||||
}
|
||||
|
||||
type BuildFunc = func(ctx context.Context, id string, listener updatelistener.UpdateListener) (tree.ObjectTree, error)
|
||||
|
||||
type TreeCache interface {
|
||||
app.ComponentRunnable
|
||||
GetTree(ctx context.Context, spaceId, treeId string) (TreeResult, error)
|
||||
}
|
||||
35
common/commonspace/commongetter.go
Normal file
35
common/commonspace/commongetter.go
Normal file
@ -0,0 +1,35 @@
|
||||
package commonspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/objectgetter"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncacl"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
|
||||
)
|
||||
|
||||
type commonSpaceGetter struct {
|
||||
spaceId string
|
||||
aclList *syncacl.SyncACL
|
||||
treeGetter treegetter.TreeGetter
|
||||
}
|
||||
|
||||
func newCommonSpaceGetter(spaceId string, aclList *syncacl.SyncACL, treeGetter treegetter.TreeGetter) objectgetter.ObjectGetter {
|
||||
return &commonSpaceGetter{
|
||||
spaceId: spaceId,
|
||||
aclList: aclList,
|
||||
treeGetter: treeGetter,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *commonSpaceGetter) GetObject(ctx context.Context, objectId string) (obj objectgetter.Object, err error) {
|
||||
if c.aclList.ID() == objectId {
|
||||
obj = c.aclList
|
||||
return
|
||||
}
|
||||
t, err := c.treeGetter.GetTree(ctx, c.spaceId, objectId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
obj = t.(objectgetter.Object)
|
||||
return
|
||||
}
|
||||
@ -3,10 +3,10 @@ package diffservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff"
|
||||
"go.uber.org/zap"
|
||||
@ -14,9 +14,10 @@ import (
|
||||
)
|
||||
|
||||
type DiffService interface {
|
||||
HeadNotifiable
|
||||
HandleRangeRequest(ctx context.Context, req *spacesyncproto.HeadSyncRequest) (resp *spacesyncproto.HeadSyncResponse, err error)
|
||||
UpdateHeads(id string, heads []string)
|
||||
RemoveObject(id string)
|
||||
AllIds() []string
|
||||
|
||||
Init(objectIds []string)
|
||||
Close() (err error)
|
||||
@ -37,7 +38,7 @@ func NewDiffService(
|
||||
syncPeriod int,
|
||||
storage storage.SpaceStorage,
|
||||
confConnector nodeconf.ConfConnector,
|
||||
cache cache.TreeCache,
|
||||
cache treegetter.TreeGetter,
|
||||
log *zap.Logger) DiffService {
|
||||
|
||||
diff := ldiff.New(16, 16)
|
||||
@ -72,6 +73,10 @@ func (d *diffService) UpdateHeads(id string, heads []string) {
|
||||
})
|
||||
}
|
||||
|
||||
func (d *diffService) AllIds() []string {
|
||||
return d.diff.Ids()
|
||||
}
|
||||
|
||||
func (d *diffService) RemoveObject(id string) {
|
||||
// TODO: add space document to remove ids
|
||||
d.diff.RemoveId(id)
|
||||
|
||||
@ -2,10 +2,10 @@ package diffservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
@ -22,7 +22,7 @@ func newDiffSyncer(
|
||||
spaceId string,
|
||||
diff ldiff.Diff,
|
||||
confConnector nodeconf.ConfConnector,
|
||||
cache cache.TreeCache,
|
||||
cache treegetter.TreeGetter,
|
||||
storage storage.SpaceStorage,
|
||||
clientFactory spacesyncproto.ClientFactory,
|
||||
log *zap.Logger) DiffSyncer {
|
||||
@ -41,7 +41,7 @@ type diffSyncer struct {
|
||||
spaceId string
|
||||
diff ldiff.Diff
|
||||
confConnector nodeconf.ConfConnector
|
||||
cache cache.TreeCache
|
||||
cache treegetter.TreeGetter
|
||||
storage storage.SpaceStorage
|
||||
clientFactory spacesyncproto.ClientFactory
|
||||
log *zap.Logger
|
||||
@ -77,6 +77,7 @@ func (d *diffSyncer) syncWithPeer(ctx context.Context, p peer.Peer) (err error)
|
||||
|
||||
d.pingTreesInCache(ctx, newIds)
|
||||
d.pingTreesInCache(ctx, changedIds)
|
||||
d.pingTreesInCache(ctx, removedIds)
|
||||
|
||||
d.log.Info("sync done:", zap.Int("newIds", len(newIds)),
|
||||
zap.Int("changedIds", len(changedIds)),
|
||||
@ -107,8 +108,9 @@ func (d *diffSyncer) sendPushSpaceRequest(ctx context.Context, cl spacesyncproto
|
||||
}
|
||||
|
||||
_, err = cl.PushSpace(ctx, &spacesyncproto.PushSpaceRequest{
|
||||
SpaceHeader: header,
|
||||
AclRoot: root,
|
||||
SpaceHeader: header,
|
||||
AclPayload: root.Payload,
|
||||
AclPayloadId: root.Id,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
@ -4,12 +4,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache/mock_cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto/mock_spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter/mock_treegetter"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf/mock_nodeconf"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||
@ -24,7 +23,7 @@ import (
|
||||
|
||||
type pushSpaceRequestMatcher struct {
|
||||
spaceId string
|
||||
aclRoot *aclrecordproto.RawACLRecordWithId
|
||||
aclRootId string
|
||||
spaceHeader *spacesyncproto.RawSpaceHeaderWithId
|
||||
}
|
||||
|
||||
@ -34,7 +33,7 @@ func (p pushSpaceRequestMatcher) Matches(x interface{}) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
return res.AclRoot == p.aclRoot && res.SpaceHeader == p.spaceHeader
|
||||
return res.AclPayloadId == p.aclRootId && res.SpaceHeader == p.spaceHeader
|
||||
}
|
||||
|
||||
func (p pushSpaceRequestMatcher) String() string {
|
||||
@ -72,11 +71,11 @@ func (m mockPeer) NewStream(ctx context.Context, rpc string, enc drpc.Encoding)
|
||||
|
||||
func newPushSpaceRequestMatcher(
|
||||
spaceId string,
|
||||
aclRoot *aclrecordproto.RawACLRecordWithId,
|
||||
aclRootId string,
|
||||
spaceHeader *spacesyncproto.RawSpaceHeaderWithId) *pushSpaceRequestMatcher {
|
||||
return &pushSpaceRequestMatcher{
|
||||
spaceId: spaceId,
|
||||
aclRoot: aclRoot,
|
||||
aclRootId: aclRootId,
|
||||
spaceHeader: spaceHeader,
|
||||
}
|
||||
}
|
||||
@ -89,13 +88,14 @@ func TestDiffSyncer_Sync(t *testing.T) {
|
||||
|
||||
diffMock := mock_ldiff.NewMockDiff(ctrl)
|
||||
connectorMock := mock_nodeconf.NewMockConfConnector(ctrl)
|
||||
cacheMock := mock_cache.NewMockTreeCache(ctrl)
|
||||
cacheMock := mock_treegetter.NewMockTreeGetter(ctrl)
|
||||
stMock := mock_storage.NewMockSpaceStorage(ctrl)
|
||||
clientMock := mock_spacesyncproto.NewMockDRPCSpaceClient(ctrl)
|
||||
factory := spacesyncproto.ClientFactoryFunc(func(cc drpc.Conn) spacesyncproto.DRPCSpaceClient {
|
||||
return clientMock
|
||||
})
|
||||
spaceId := "spaceId"
|
||||
aclRootId := "aclRootId"
|
||||
l := logger.NewNamed(spaceId)
|
||||
diffSyncer := newDiffSyncer(spaceId, diffMock, connectorMock, cacheMock, stMock, factory, l)
|
||||
|
||||
@ -109,7 +109,7 @@ func TestDiffSyncer_Sync(t *testing.T) {
|
||||
for _, arg := range []string{"new", "changed"} {
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, arg).
|
||||
Return(cache.TreeResult{}, nil)
|
||||
Return(nil, nil)
|
||||
}
|
||||
require.NoError(t, diffSyncer.Sync(ctx))
|
||||
})
|
||||
@ -124,7 +124,9 @@ func TestDiffSyncer_Sync(t *testing.T) {
|
||||
|
||||
t.Run("diff syncer sync space missing", func(t *testing.T) {
|
||||
aclStorageMock := mock_aclstorage.NewMockListStorage(ctrl)
|
||||
aclRoot := &aclrecordproto.RawACLRecordWithId{}
|
||||
aclRoot := &aclrecordproto.RawACLRecordWithId{
|
||||
Id: aclRootId,
|
||||
}
|
||||
spaceHeader := &spacesyncproto.RawSpaceHeaderWithId{}
|
||||
|
||||
connectorMock.EXPECT().
|
||||
@ -143,7 +145,7 @@ func TestDiffSyncer_Sync(t *testing.T) {
|
||||
Root().
|
||||
Return(aclRoot, nil)
|
||||
clientMock.EXPECT().
|
||||
PushSpace(gomock.Any(), newPushSpaceRequestMatcher(spaceId, aclRoot, spaceHeader)).
|
||||
PushSpace(gomock.Any(), newPushSpaceRequestMatcher(spaceId, aclRootId, spaceHeader)).
|
||||
Return(nil, nil)
|
||||
|
||||
require.NoError(t, diffSyncer.Sync(ctx))
|
||||
|
||||
5
common/commonspace/diffservice/headnotifiable.go
Normal file
5
common/commonspace/diffservice/headnotifiable.go
Normal file
@ -0,0 +1,5 @@
|
||||
package diffservice
|
||||
|
||||
type HeadNotifiable interface {
|
||||
UpdateHeads(id string, heads []string)
|
||||
}
|
||||
14
common/commonspace/objectgetter/objectgetter.go
Normal file
14
common/commonspace/objectgetter/objectgetter.go
Normal file
@ -0,0 +1,14 @@
|
||||
package objectgetter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/synchandler"
|
||||
)
|
||||
|
||||
type Object interface {
|
||||
synchandler.SyncHandler
|
||||
}
|
||||
|
||||
type ObjectGetter interface {
|
||||
GetObject(ctx context.Context, objectId string) (Object, error)
|
||||
}
|
||||
@ -19,5 +19,5 @@ func (r *rpcHandler) HeadSync(ctx context.Context, req *spacesyncproto.HeadSyncR
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Stream(stream spacesyncproto.DRPCSpace_StreamStream) (err error) {
|
||||
return r.s.SyncService().SyncClient().AddAndReadStreamSync(stream)
|
||||
return r.s.SyncService().StreamPool().AddAndReadStreamSync(stream)
|
||||
}
|
||||
|
||||
@ -2,12 +2,13 @@ package commonspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
|
||||
config2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/config"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
@ -30,17 +31,19 @@ type Service interface {
|
||||
|
||||
type service struct {
|
||||
config config2.Space
|
||||
account account.Service
|
||||
configurationService nodeconf.Service
|
||||
storageProvider storage.SpaceStorageProvider
|
||||
cache cache.TreeCache
|
||||
treeGetter treegetter.TreeGetter
|
||||
pool pool.Pool
|
||||
}
|
||||
|
||||
func (s *service) Init(a *app.App) (err error) {
|
||||
s.config = a.MustComponent(config2.CName).(*config2.Config).Space
|
||||
s.account = a.MustComponent(account.CName).(account.Service)
|
||||
s.storageProvider = a.MustComponent(storage.CName).(storage.SpaceStorageProvider)
|
||||
s.configurationService = a.MustComponent(nodeconf.CName).(nodeconf.Service)
|
||||
s.cache = a.MustComponent(cache.CName).(cache.TreeCache)
|
||||
s.treeGetter = a.MustComponent(treegetter.CName).(treegetter.TreeGetter)
|
||||
s.pool = a.MustComponent(pool.CName).(pool.Pool)
|
||||
return nil
|
||||
}
|
||||
@ -84,16 +87,19 @@ func (s *service) GetSpace(ctx context.Context, id string) (Space, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lastConfiguration := s.configurationService.GetLast()
|
||||
confConnector := nodeconf.NewConfConnector(lastConfiguration, s.pool)
|
||||
diffService := diffservice.NewDiffService(id, s.config.SyncPeriod, st, confConnector, s.cache, log)
|
||||
syncService := syncservice.NewSyncService(id, diffService, s.cache, lastConfiguration, confConnector)
|
||||
diffService := diffservice.NewDiffService(id, s.config.SyncPeriod, st, confConnector, s.treeGetter, log)
|
||||
syncService := syncservice.NewSyncService(id, confConnector)
|
||||
sp := &space{
|
||||
id: id,
|
||||
syncService: syncService,
|
||||
diffService: diffService,
|
||||
cache: s.cache,
|
||||
storage: st,
|
||||
id: id,
|
||||
syncService: syncService,
|
||||
diffService: diffService,
|
||||
cache: s.treeGetter,
|
||||
account: s.account,
|
||||
configuration: lastConfiguration,
|
||||
storage: st,
|
||||
}
|
||||
if err := sp.Init(ctx); err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -2,22 +2,29 @@ package commonspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncacl"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list"
|
||||
storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
tree2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
tree "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/encryptionkey"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey"
|
||||
"go.uber.org/zap"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ErrSpaceClosed = errors.New("space is closed")
|
||||
|
||||
type SpaceCreatePayload struct {
|
||||
// SigningKey is the signing key of the owner
|
||||
SigningKey signingkey.PrivKey
|
||||
@ -44,12 +51,13 @@ func NewSpaceId(id string, repKey uint64) string {
|
||||
|
||||
type Space interface {
|
||||
Id() string
|
||||
StoredIds() []string
|
||||
|
||||
SpaceSyncRpc() RpcHandler
|
||||
|
||||
DeriveTree(ctx context.Context, payload tree2.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree2.ObjectTree, error)
|
||||
CreateTree(ctx context.Context, payload tree2.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree2.ObjectTree, error)
|
||||
BuildTree(ctx context.Context, id string, listener updatelistener.UpdateListener) (tree2.ObjectTree, error)
|
||||
DeriveTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error)
|
||||
CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error)
|
||||
BuildTree(ctx context.Context, id string, listener updatelistener.UpdateListener) (tree.ObjectTree, error)
|
||||
|
||||
Close() error
|
||||
}
|
||||
@ -60,11 +68,19 @@ type space struct {
|
||||
|
||||
rpc *rpcHandler
|
||||
|
||||
syncService syncservice.SyncService
|
||||
diffService diffservice.DiffService
|
||||
storage storage.SpaceStorage
|
||||
cache cache.TreeCache
|
||||
aclList list.ACLList
|
||||
syncService syncservice.SyncService
|
||||
diffService diffservice.DiffService
|
||||
storage storage.SpaceStorage
|
||||
cache treegetter.TreeGetter
|
||||
account account.Service
|
||||
aclList *syncacl.SyncACL
|
||||
configuration nodeconf.Configuration
|
||||
|
||||
isClosed atomic.Bool
|
||||
}
|
||||
|
||||
func (s *space) LastUsage() time.Time {
|
||||
return s.syncService.LastUsage()
|
||||
}
|
||||
|
||||
func (s *space) Id() string {
|
||||
@ -77,8 +93,18 @@ func (s *space) Init(ctx context.Context) (err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
aclStorage, err := s.storage.ACLStorage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
aclList, err := list.BuildACLListWithIdentity(s.account.Account(), aclStorage)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
s.aclList = syncacl.NewSyncACL(aclList, s.syncService.StreamPool())
|
||||
objectGetter := newCommonSpaceGetter(s.id, s.aclList, s.cache)
|
||||
s.syncService.Init(objectGetter)
|
||||
s.diffService.Init(initialIds)
|
||||
s.syncService.Init()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -94,62 +120,69 @@ func (s *space) DiffService() diffservice.DiffService {
|
||||
return s.diffService
|
||||
}
|
||||
|
||||
func (s *space) DeriveTree(ctx context.Context, payload tree2.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree2.ObjectTree, error) {
|
||||
return synctree.DeriveSyncTree(ctx, payload, s.syncService.SyncClient(), listener, s.aclList, s.storage.CreateTreeStorage)
|
||||
func (s *space) StoredIds() []string {
|
||||
return s.diffService.AllIds()
|
||||
}
|
||||
|
||||
func (s *space) CreateTree(ctx context.Context, payload tree2.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree2.ObjectTree, error) {
|
||||
return synctree.CreateSyncTree(ctx, payload, s.syncService.SyncClient(), listener, s.aclList, s.storage.CreateTreeStorage)
|
||||
}
|
||||
|
||||
func (s *space) BuildTree(ctx context.Context, id string, listener updatelistener.UpdateListener) (t tree2.ObjectTree, err error) {
|
||||
getTreeRemote := func() (*spacesyncproto.ObjectSyncMessage, error) {
|
||||
// TODO: add empty context handling (when this is not happening due to head update)
|
||||
peerId, err := syncservice.GetPeerIdFromStreamContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.syncService.SyncClient().SendSync(
|
||||
peerId,
|
||||
s.syncService.SyncClient().CreateNewTreeRequest(id),
|
||||
)
|
||||
}
|
||||
|
||||
store, err := s.storage.TreeStorage(id)
|
||||
if err != nil && err != storage2.ErrUnknownTreeId {
|
||||
func (s *space) DeriveTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tr tree.ObjectTree, err error) {
|
||||
if s.isClosed.Load() {
|
||||
err = ErrSpaceClosed
|
||||
return
|
||||
}
|
||||
|
||||
if err == storage2.ErrUnknownTreeId {
|
||||
var resp *spacesyncproto.ObjectSyncMessage
|
||||
resp, err = getTreeRemote()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fullSyncResp := resp.GetContent().GetFullSyncResponse()
|
||||
|
||||
payload := storage2.TreeStorageCreatePayload{
|
||||
TreeId: resp.TreeId,
|
||||
RootRawChange: resp.RootChange,
|
||||
Changes: fullSyncResp.Changes,
|
||||
Heads: fullSyncResp.Heads,
|
||||
}
|
||||
|
||||
// basically building tree with inmemory storage and validating that it was without errors
|
||||
err = tree2.ValidateRawTree(payload, s.aclList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// now we are sure that we can save it to the storage
|
||||
store, err = s.storage.CreateTreeStorage(payload)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
deps := synctree.CreateDeps{
|
||||
SpaceId: s.id,
|
||||
Payload: payload,
|
||||
StreamPool: s.syncService.StreamPool(),
|
||||
Configuration: s.configuration,
|
||||
HeadNotifiable: s.diffService,
|
||||
Listener: listener,
|
||||
AclList: s.aclList,
|
||||
CreateStorage: s.storage.CreateTreeStorage,
|
||||
}
|
||||
return synctree.BuildSyncTree(ctx, s.syncService.SyncClient(), store.(storage2.TreeStorage), listener, s.aclList)
|
||||
return synctree.DeriveSyncTree(ctx, deps)
|
||||
}
|
||||
|
||||
func (s *space) CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tr tree.ObjectTree, err error) {
|
||||
if s.isClosed.Load() {
|
||||
err = ErrSpaceClosed
|
||||
return
|
||||
}
|
||||
deps := synctree.CreateDeps{
|
||||
SpaceId: s.id,
|
||||
Payload: payload,
|
||||
StreamPool: s.syncService.StreamPool(),
|
||||
Configuration: s.configuration,
|
||||
HeadNotifiable: s.diffService,
|
||||
Listener: listener,
|
||||
AclList: s.aclList,
|
||||
CreateStorage: s.storage.CreateTreeStorage,
|
||||
}
|
||||
return synctree.CreateSyncTree(ctx, deps)
|
||||
}
|
||||
|
||||
func (s *space) BuildTree(ctx context.Context, id string, listener updatelistener.UpdateListener) (t tree.ObjectTree, err error) {
|
||||
if s.isClosed.Load() {
|
||||
err = ErrSpaceClosed
|
||||
return
|
||||
}
|
||||
deps := synctree.BuildDeps{
|
||||
SpaceId: s.id,
|
||||
StreamPool: s.syncService.StreamPool(),
|
||||
Configuration: s.configuration,
|
||||
HeadNotifiable: s.diffService,
|
||||
Listener: listener,
|
||||
AclList: s.aclList,
|
||||
SpaceStorage: s.storage,
|
||||
}
|
||||
return synctree.BuildSyncTreeOrGetRemote(ctx, id, deps)
|
||||
}
|
||||
|
||||
func (s *space) Close() error {
|
||||
log.With(zap.String("id", s.id)).Debug("space is closing")
|
||||
defer func() {
|
||||
s.isClosed.Store(true)
|
||||
log.With(zap.String("id", s.id)).Debug("space closed")
|
||||
}()
|
||||
s.diffService.Close()
|
||||
s.syncService.Close()
|
||||
return s.storage.Close()
|
||||
|
||||
@ -2,8 +2,6 @@ syntax = "proto3";
|
||||
package anySpace;
|
||||
|
||||
option go_package = "commonspace/spacesyncproto";
|
||||
import "pkg/acl/treechangeproto/protos/treechange.proto";
|
||||
import "pkg/acl/aclrecordproto/protos/aclrecord.proto";
|
||||
|
||||
enum ErrCodes {
|
||||
Unexpected = 0;
|
||||
@ -55,55 +53,18 @@ message HeadSyncResponse {
|
||||
// ObjectSyncMessage is a message sent on object sync
|
||||
message ObjectSyncMessage {
|
||||
string spaceId = 1;
|
||||
ObjectSyncContentValue content = 2;
|
||||
treechange.RawTreeChangeWithId rootChange = 3;
|
||||
string treeId = 4;
|
||||
string trackingId = 5;
|
||||
|
||||
string replyId = 2;
|
||||
bytes payload = 3;
|
||||
string objectId = 4;
|
||||
// string identity = 5;
|
||||
// string peerSignature = 6;
|
||||
}
|
||||
|
||||
// ObjectSyncContentValue provides different types for object sync
|
||||
message ObjectSyncContentValue {
|
||||
oneof value {
|
||||
ObjectHeadUpdate headUpdate = 1;
|
||||
ObjectFullSyncRequest fullSyncRequest = 2;
|
||||
ObjectFullSyncResponse fullSyncResponse = 3;
|
||||
ObjectErrorResponse errorResponse = 4;
|
||||
}
|
||||
}
|
||||
|
||||
// ObjectHeadUpdate is a message sent on document head update
|
||||
message ObjectHeadUpdate {
|
||||
repeated string heads = 1;
|
||||
repeated treechange.RawTreeChangeWithId changes = 2;
|
||||
repeated string snapshotPath = 3;
|
||||
}
|
||||
|
||||
// ObjectHeadUpdate is a message sent when document needs full sync
|
||||
message ObjectFullSyncRequest {
|
||||
repeated string heads = 1;
|
||||
repeated treechange.RawTreeChangeWithId changes = 2;
|
||||
repeated string snapshotPath = 3;
|
||||
}
|
||||
|
||||
// ObjectFullSyncResponse is a message sent as a response for a specific full sync
|
||||
message ObjectFullSyncResponse {
|
||||
repeated string heads = 1;
|
||||
repeated treechange.RawTreeChangeWithId changes = 2;
|
||||
repeated string snapshotPath = 3;
|
||||
}
|
||||
|
||||
// ObjectErrorResponse is an error sent as a response for a full sync request
|
||||
message ObjectErrorResponse {
|
||||
string error = 1;
|
||||
}
|
||||
|
||||
// PushSpaceRequest is a request to add space on a node containing only one acl record
|
||||
message PushSpaceRequest {
|
||||
RawSpaceHeaderWithId spaceHeader = 2;
|
||||
aclrecord.RawACLRecordWithId aclRoot = 3;
|
||||
RawSpaceHeaderWithId spaceHeader = 1;
|
||||
bytes aclPayload = 2;
|
||||
string aclPayloadId = 3;
|
||||
}
|
||||
|
||||
// PushSpaceResponse is an empty response
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
package spacesyncproto
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
"storj.io/drpc"
|
||||
)
|
||||
|
||||
@ -17,43 +16,3 @@ func (c ClientFactoryFunc) Client(cc drpc.Conn) DRPCSpaceClient {
|
||||
type ClientFactory interface {
|
||||
Client(cc drpc.Conn) DRPCSpaceClient
|
||||
}
|
||||
|
||||
func WrapHeadUpdate(update *ObjectHeadUpdate, rootChange *treechangeproto.RawTreeChangeWithId, treeId, trackingId string) *ObjectSyncMessage {
|
||||
return &ObjectSyncMessage{
|
||||
Content: &ObjectSyncContentValue{
|
||||
Value: &ObjectSyncContentValue_HeadUpdate{HeadUpdate: update},
|
||||
},
|
||||
RootChange: rootChange,
|
||||
TreeId: treeId,
|
||||
}
|
||||
}
|
||||
|
||||
func WrapFullRequest(request *ObjectFullSyncRequest, rootChange *treechangeproto.RawTreeChangeWithId, treeId, trackingId string) *ObjectSyncMessage {
|
||||
return &ObjectSyncMessage{
|
||||
Content: &ObjectSyncContentValue{
|
||||
Value: &ObjectSyncContentValue_FullSyncRequest{FullSyncRequest: request},
|
||||
},
|
||||
RootChange: rootChange,
|
||||
TreeId: treeId,
|
||||
}
|
||||
}
|
||||
|
||||
func WrapFullResponse(response *ObjectFullSyncResponse, rootChange *treechangeproto.RawTreeChangeWithId, treeId, trackingId string) *ObjectSyncMessage {
|
||||
return &ObjectSyncMessage{
|
||||
Content: &ObjectSyncContentValue{
|
||||
Value: &ObjectSyncContentValue_FullSyncResponse{FullSyncResponse: response},
|
||||
},
|
||||
RootChange: rootChange,
|
||||
TreeId: treeId,
|
||||
}
|
||||
}
|
||||
|
||||
func WrapError(err error, rootChange *treechangeproto.RawTreeChangeWithId, treeId, trackingId string) *ObjectSyncMessage {
|
||||
return &ObjectSyncMessage{
|
||||
Content: &ObjectSyncContentValue{
|
||||
Value: &ObjectSyncContentValue_ErrorResponse{ErrorResponse: &ObjectErrorResponse{Error: err.Error()}},
|
||||
},
|
||||
RootChange: rootChange,
|
||||
TreeId: treeId,
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -5,12 +5,12 @@
|
||||
package mock_storage
|
||||
|
||||
import (
|
||||
storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
reflect "reflect"
|
||||
|
||||
app "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
storage0 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
@ -119,10 +119,10 @@ func (m *MockSpaceStorage) EXPECT() *MockSpaceStorageMockRecorder {
|
||||
}
|
||||
|
||||
// ACLStorage mocks base method.
|
||||
func (m *MockSpaceStorage) ACLStorage() (storage2.ListStorage, error) {
|
||||
func (m *MockSpaceStorage) ACLStorage() (storage0.ListStorage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ACLStorage")
|
||||
ret0, _ := ret[0].(storage2.ListStorage)
|
||||
ret0, _ := ret[0].(storage0.ListStorage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@ -148,10 +148,10 @@ func (mr *MockSpaceStorageMockRecorder) Close() *gomock.Call {
|
||||
}
|
||||
|
||||
// CreateTreeStorage mocks base method.
|
||||
func (m *MockSpaceStorage) CreateTreeStorage(arg0 storage2.TreeStorageCreatePayload) (storage2.TreeStorage, error) {
|
||||
func (m *MockSpaceStorage) CreateTreeStorage(arg0 storage0.TreeStorageCreatePayload) (storage0.TreeStorage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateTreeStorage", arg0)
|
||||
ret0, _ := ret[0].(storage2.TreeStorage)
|
||||
ret0, _ := ret[0].(storage0.TreeStorage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@ -208,10 +208,10 @@ func (mr *MockSpaceStorageMockRecorder) StoredIds() *gomock.Call {
|
||||
}
|
||||
|
||||
// TreeStorage mocks base method.
|
||||
func (m *MockSpaceStorage) TreeStorage(arg0 string) (storage2.TreeStorage, error) {
|
||||
func (m *MockSpaceStorage) TreeStorage(arg0 string) (storage0.TreeStorage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "TreeStorage", arg0)
|
||||
ret0, _ := ret[0].(storage2.TreeStorage)
|
||||
ret0, _ := ret[0].(storage0.TreeStorage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
21
common/commonspace/syncacl/syncacl.go
Normal file
21
common/commonspace/syncacl/syncacl.go
Normal file
@ -0,0 +1,21 @@
|
||||
package syncacl
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/synchandler"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list"
|
||||
)
|
||||
|
||||
type SyncACL struct {
|
||||
list.ACLList
|
||||
synchandler.SyncHandler
|
||||
streamPool syncservice.StreamPool
|
||||
}
|
||||
|
||||
func NewSyncACL(aclList list.ACLList, streamPool syncservice.StreamPool) *SyncACL {
|
||||
return &SyncACL{
|
||||
ACLList: aclList,
|
||||
SyncHandler: nil,
|
||||
streamPool: streamPool,
|
||||
}
|
||||
}
|
||||
@ -1,206 +0,0 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice (interfaces: SyncClient)
|
||||
|
||||
// Package mock_syncservice is a generated GoMock package.
|
||||
package mock_syncservice
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
reflect "reflect"
|
||||
|
||||
spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockSyncClient is a mock of SyncClient interface.
|
||||
type MockSyncClient struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockSyncClientMockRecorder
|
||||
}
|
||||
|
||||
// MockSyncClientMockRecorder is the mock recorder for MockSyncClient.
|
||||
type MockSyncClientMockRecorder struct {
|
||||
mock *MockSyncClient
|
||||
}
|
||||
|
||||
// NewMockSyncClient creates a new mock instance.
|
||||
func NewMockSyncClient(ctrl *gomock.Controller) *MockSyncClient {
|
||||
mock := &MockSyncClient{ctrl: ctrl}
|
||||
mock.recorder = &MockSyncClientMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockSyncClient) EXPECT() *MockSyncClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// AddAndReadStreamAsync mocks base method.
|
||||
func (m *MockSyncClient) AddAndReadStreamAsync(arg0 spacesyncproto.DRPCSpace_StreamStream) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "AddAndReadStreamAsync", arg0)
|
||||
}
|
||||
|
||||
// AddAndReadStreamAsync indicates an expected call of AddAndReadStreamAsync.
|
||||
func (mr *MockSyncClientMockRecorder) AddAndReadStreamAsync(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAndReadStreamAsync", reflect.TypeOf((*MockSyncClient)(nil).AddAndReadStreamAsync), arg0)
|
||||
}
|
||||
|
||||
// AddAndReadStreamSync mocks base method.
|
||||
func (m *MockSyncClient) AddAndReadStreamSync(arg0 spacesyncproto.DRPCSpace_StreamStream) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AddAndReadStreamSync", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AddAndReadStreamSync indicates an expected call of AddAndReadStreamSync.
|
||||
func (mr *MockSyncClientMockRecorder) AddAndReadStreamSync(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAndReadStreamSync", reflect.TypeOf((*MockSyncClient)(nil).AddAndReadStreamSync), arg0)
|
||||
}
|
||||
|
||||
// BroadcastAsync mocks base method.
|
||||
func (m *MockSyncClient) BroadcastAsync(arg0 *spacesyncproto.ObjectSyncMessage) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BroadcastAsync", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// BroadcastAsync indicates an expected call of BroadcastAsync.
|
||||
func (mr *MockSyncClientMockRecorder) BroadcastAsync(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastAsync", reflect.TypeOf((*MockSyncClient)(nil).BroadcastAsync), arg0)
|
||||
}
|
||||
|
||||
// BroadcastAsyncOrSendResponsible mocks base method.
|
||||
func (m *MockSyncClient) BroadcastAsyncOrSendResponsible(arg0 *spacesyncproto.ObjectSyncMessage) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BroadcastAsyncOrSendResponsible", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// BroadcastAsyncOrSendResponsible indicates an expected call of BroadcastAsyncOrSendResponsible.
|
||||
func (mr *MockSyncClientMockRecorder) BroadcastAsyncOrSendResponsible(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastAsyncOrSendResponsible", reflect.TypeOf((*MockSyncClient)(nil).BroadcastAsyncOrSendResponsible), arg0)
|
||||
}
|
||||
|
||||
// Close mocks base method.
|
||||
func (m *MockSyncClient) Close() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Close")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Close indicates an expected call of Close.
|
||||
func (mr *MockSyncClientMockRecorder) Close() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockSyncClient)(nil).Close))
|
||||
}
|
||||
|
||||
// CreateFullSyncRequest mocks base method.
|
||||
func (m *MockSyncClient) CreateFullSyncRequest(arg0 tree.ObjectTree, arg1, arg2 []string, arg3 string) (*spacesyncproto.ObjectSyncMessage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateFullSyncRequest", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateFullSyncRequest indicates an expected call of CreateFullSyncRequest.
|
||||
func (mr *MockSyncClientMockRecorder) CreateFullSyncRequest(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFullSyncRequest", reflect.TypeOf((*MockSyncClient)(nil).CreateFullSyncRequest), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// CreateFullSyncResponse mocks base method.
|
||||
func (m *MockSyncClient) CreateFullSyncResponse(arg0 tree.ObjectTree, arg1, arg2 []string, arg3 string) (*spacesyncproto.ObjectSyncMessage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateFullSyncResponse", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateFullSyncResponse indicates an expected call of CreateFullSyncResponse.
|
||||
func (mr *MockSyncClientMockRecorder) CreateFullSyncResponse(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFullSyncResponse", reflect.TypeOf((*MockSyncClient)(nil).CreateFullSyncResponse), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// CreateHeadUpdate mocks base method.
|
||||
func (m *MockSyncClient) CreateHeadUpdate(arg0 tree.ObjectTree, arg1 []*treechangeproto.RawTreeChangeWithId) *spacesyncproto.ObjectSyncMessage {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateHeadUpdate", arg0, arg1)
|
||||
ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CreateHeadUpdate indicates an expected call of CreateHeadUpdate.
|
||||
func (mr *MockSyncClientMockRecorder) CreateHeadUpdate(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateHeadUpdate", reflect.TypeOf((*MockSyncClient)(nil).CreateHeadUpdate), arg0, arg1)
|
||||
}
|
||||
|
||||
// CreateNewTreeRequest mocks base method.
|
||||
func (m *MockSyncClient) CreateNewTreeRequest(arg0 string) *spacesyncproto.ObjectSyncMessage {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateNewTreeRequest", arg0)
|
||||
ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CreateNewTreeRequest indicates an expected call of CreateNewTreeRequest.
|
||||
func (mr *MockSyncClientMockRecorder) CreateNewTreeRequest(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateNewTreeRequest", reflect.TypeOf((*MockSyncClient)(nil).CreateNewTreeRequest), arg0)
|
||||
}
|
||||
|
||||
// HasActiveStream mocks base method.
|
||||
func (m *MockSyncClient) HasActiveStream(arg0 string) bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HasActiveStream", arg0)
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HasActiveStream indicates an expected call of HasActiveStream.
|
||||
func (mr *MockSyncClientMockRecorder) HasActiveStream(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasActiveStream", reflect.TypeOf((*MockSyncClient)(nil).HasActiveStream), arg0)
|
||||
}
|
||||
|
||||
// SendAsync mocks base method.
|
||||
func (m *MockSyncClient) SendAsync(arg0 []string, arg1 *spacesyncproto.ObjectSyncMessage) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SendAsync", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SendAsync indicates an expected call of SendAsync.
|
||||
func (mr *MockSyncClientMockRecorder) SendAsync(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendAsync", reflect.TypeOf((*MockSyncClient)(nil).SendAsync), arg0, arg1)
|
||||
}
|
||||
|
||||
// SendSync mocks base method.
|
||||
func (m *MockSyncClient) SendSync(arg0 string, arg1 *spacesyncproto.ObjectSyncMessage) (*spacesyncproto.ObjectSyncMessage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SendSync", arg0, arg1)
|
||||
ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SendSync indicates an expected call of SendSync.
|
||||
func (mr *MockSyncClientMockRecorder) SendSync(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendSync", reflect.TypeOf((*MockSyncClient)(nil).SendSync), arg0, arg1)
|
||||
}
|
||||
@ -5,30 +5,34 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ocache"
|
||||
"github.com/libp2p/go-libp2p/core/sec"
|
||||
"storj.io/drpc/drpcctx"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ErrEmptyPeer = errors.New("don't have such a peer")
|
||||
var ErrStreamClosed = errors.New("stream is already closed")
|
||||
|
||||
const maxSimultaneousOperationsPerStream = 10
|
||||
var maxSimultaneousOperationsPerStream = 10
|
||||
var syncWaitPeriod = 2 * time.Second
|
||||
|
||||
var ErrSyncTimeout = errors.New("too long wait on sync receive")
|
||||
|
||||
// StreamPool can be made generic to work with different streams
|
||||
type StreamPool interface {
|
||||
Sender
|
||||
ocache.ObjectLastUsage
|
||||
AddAndReadStreamSync(stream spacesyncproto.SpaceStream) (err error)
|
||||
AddAndReadStreamAsync(stream spacesyncproto.SpaceStream)
|
||||
HasActiveStream(peerId string) bool
|
||||
Close() (err error)
|
||||
}
|
||||
|
||||
type Sender interface {
|
||||
SendSync(peerId string, message *spacesyncproto.ObjectSyncMessage) (reply *spacesyncproto.ObjectSyncMessage, err error)
|
||||
SendAsync(peers []string, message *spacesyncproto.ObjectSyncMessage) (err error)
|
||||
BroadcastAsync(message *spacesyncproto.ObjectSyncMessage) (err error)
|
||||
|
||||
HasActiveStream(peerId string) bool
|
||||
Close() (err error)
|
||||
}
|
||||
|
||||
type MessageHandler func(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error)
|
||||
@ -44,15 +48,23 @@ type streamPool struct {
|
||||
wg *sync.WaitGroup
|
||||
waiters map[string]responseWaiter
|
||||
waitersMx sync.Mutex
|
||||
counter uint64
|
||||
counter atomic.Uint64
|
||||
lastUsage atomic.Int64
|
||||
}
|
||||
|
||||
func newStreamPool(messageHandler MessageHandler) StreamPool {
|
||||
return &streamPool{
|
||||
s := &streamPool{
|
||||
peerStreams: make(map[string]spacesyncproto.SpaceStream),
|
||||
messageHandler: messageHandler,
|
||||
waiters: make(map[string]responseWaiter),
|
||||
wg: &sync.WaitGroup{},
|
||||
}
|
||||
s.lastUsage.Store(time.Now().Unix())
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *streamPool) LastUsage() time.Time {
|
||||
return time.Unix(s.lastUsage.Load(), 0)
|
||||
}
|
||||
|
||||
func (s *streamPool) HasActiveStream(peerId string) (res bool) {
|
||||
@ -65,26 +77,39 @@ func (s *streamPool) HasActiveStream(peerId string) (res bool) {
|
||||
func (s *streamPool) SendSync(
|
||||
peerId string,
|
||||
msg *spacesyncproto.ObjectSyncMessage) (reply *spacesyncproto.ObjectSyncMessage, err error) {
|
||||
newCounter := atomic.AddUint64(&s.counter, 1)
|
||||
msg.TrackingId = genStreamPoolKey(peerId, msg.TreeId, newCounter)
|
||||
newCounter := s.counter.Add(1)
|
||||
msg.ReplyId = genStreamPoolKey(peerId, msg.ObjectId, newCounter)
|
||||
|
||||
s.waitersMx.Lock()
|
||||
waiter := responseWaiter{
|
||||
ch: make(chan *spacesyncproto.ObjectSyncMessage),
|
||||
ch: make(chan *spacesyncproto.ObjectSyncMessage, 1),
|
||||
}
|
||||
s.waiters[msg.TrackingId] = waiter
|
||||
s.waiters[msg.ReplyId] = waiter
|
||||
s.waitersMx.Unlock()
|
||||
|
||||
err = s.SendAsync([]string{peerId}, msg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
delay := time.NewTimer(syncWaitPeriod)
|
||||
select {
|
||||
case <-delay.C:
|
||||
s.waitersMx.Lock()
|
||||
delete(s.waiters, msg.ReplyId)
|
||||
s.waitersMx.Unlock()
|
||||
|
||||
reply = <-waiter.ch
|
||||
log.With("replyId", msg.ReplyId).Error("time elapsed when waiting")
|
||||
err = ErrSyncTimeout
|
||||
case reply = <-waiter.ch:
|
||||
if !delay.Stop() {
|
||||
<-delay.C
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *streamPool) SendAsync(peers []string, message *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
s.lastUsage.Store(time.Now().Unix())
|
||||
getStreams := func() (streams []spacesyncproto.SpaceStream) {
|
||||
for _, pId := range peers {
|
||||
stream, err := s.getOrDeleteStream(pId)
|
||||
@ -100,10 +125,13 @@ func (s *streamPool) SendAsync(peers []string, message *spacesyncproto.ObjectSyn
|
||||
streams := getStreams()
|
||||
s.Unlock()
|
||||
|
||||
log.With("objectId", message.ObjectId).
|
||||
Debugf("sending message to %d peers", len(streams))
|
||||
for _, s := range streams {
|
||||
if len(peers) == 1 {
|
||||
err = s.Send(message)
|
||||
}
|
||||
err = s.Send(message)
|
||||
}
|
||||
if len(peers) != 1 {
|
||||
err = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
@ -145,6 +173,8 @@ Loop:
|
||||
|
||||
func (s *streamPool) BroadcastAsync(message *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
streams := s.getAllStreams()
|
||||
log.With("objectId", message.ObjectId).
|
||||
Debugf("broadcasting message to %d peers", len(streams))
|
||||
for _, stream := range streams {
|
||||
if err = stream.Send(message); err != nil {
|
||||
// TODO: add logging
|
||||
@ -191,21 +221,24 @@ func (s *streamPool) readPeerLoop(peerId string, stream spacesyncproto.SpaceStre
|
||||
}
|
||||
|
||||
process := func(msg *spacesyncproto.ObjectSyncMessage) {
|
||||
if msg.TrackingId == "" {
|
||||
s.lastUsage.Store(time.Now().Unix())
|
||||
if msg.ReplyId == "" {
|
||||
s.messageHandler(stream.Context(), peerId, msg)
|
||||
return
|
||||
}
|
||||
|
||||
log.With("replyId", msg.ReplyId).Debug("getting message with reply id")
|
||||
s.waitersMx.Lock()
|
||||
waiter, exists := s.waiters[msg.TrackingId]
|
||||
waiter, exists := s.waiters[msg.ReplyId]
|
||||
|
||||
if !exists {
|
||||
log.With("replyId", msg.ReplyId).Debug("reply id not exists")
|
||||
s.waitersMx.Unlock()
|
||||
s.messageHandler(stream.Context(), peerId, msg)
|
||||
return
|
||||
}
|
||||
log.With("replyId", msg.ReplyId).Debug("reply id exists")
|
||||
|
||||
delete(s.waiters, msg.TrackingId)
|
||||
delete(s.waiters, msg.ReplyId)
|
||||
s.waitersMx.Unlock()
|
||||
waiter.ch <- msg
|
||||
}
|
||||
@ -213,6 +246,7 @@ func (s *streamPool) readPeerLoop(peerId string, stream spacesyncproto.SpaceStre
|
||||
Loop:
|
||||
for {
|
||||
msg, err := stream.Recv()
|
||||
s.lastUsage.Store(time.Now().Unix())
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
package syncservice
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
)
|
||||
|
||||
type SyncClient interface {
|
||||
StreamPool
|
||||
RequestFactory
|
||||
BroadcastAsyncOrSendResponsible(message *spacesyncproto.ObjectSyncMessage) (err error)
|
||||
}
|
||||
|
||||
type syncClient struct {
|
||||
StreamPool
|
||||
RequestFactory
|
||||
spaceId string
|
||||
notifiable HeadNotifiable
|
||||
configuration nodeconf.Configuration
|
||||
}
|
||||
|
||||
func newSyncClient(spaceId string, pool StreamPool, notifiable HeadNotifiable, factory RequestFactory, configuration nodeconf.Configuration) SyncClient {
|
||||
return &syncClient{
|
||||
StreamPool: pool,
|
||||
RequestFactory: factory,
|
||||
notifiable: notifiable,
|
||||
configuration: configuration,
|
||||
spaceId: spaceId,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *syncClient) BroadcastAsync(message *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
s.notifyIfNeeded(message)
|
||||
return s.BroadcastAsync(message)
|
||||
}
|
||||
|
||||
func (s *syncClient) BroadcastAsyncOrSendResponsible(message *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
if s.configuration.IsResponsible(s.spaceId) {
|
||||
return s.SendAsync(s.configuration.NodeIds(s.spaceId), message)
|
||||
}
|
||||
return s.BroadcastAsync(message)
|
||||
}
|
||||
|
||||
func (s *syncClient) notifyIfNeeded(message *spacesyncproto.ObjectSyncMessage) {
|
||||
if message.GetContent().GetHeadUpdate() != nil {
|
||||
update := message.GetContent().GetHeadUpdate()
|
||||
s.notifiable.UpdateHeads(message.TreeId, update.Heads)
|
||||
}
|
||||
}
|
||||
@ -1,172 +0,0 @@
|
||||
package syncservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/slice"
|
||||
)
|
||||
|
||||
type syncHandler struct {
|
||||
spaceId string
|
||||
treeCache cache.TreeCache
|
||||
syncClient SyncClient
|
||||
}
|
||||
|
||||
type SyncHandler interface {
|
||||
HandleMessage(ctx context.Context, senderId string, request *spacesyncproto.ObjectSyncMessage) (err error)
|
||||
}
|
||||
|
||||
func newSyncHandler(spaceId string, treeCache cache.TreeCache, syncClient SyncClient) *syncHandler {
|
||||
return &syncHandler{
|
||||
spaceId: spaceId,
|
||||
treeCache: treeCache,
|
||||
syncClient: syncClient,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *syncHandler) HandleMessage(ctx context.Context, senderId string, msg *spacesyncproto.ObjectSyncMessage) error {
|
||||
content := msg.GetContent()
|
||||
switch {
|
||||
case content.GetFullSyncRequest() != nil:
|
||||
return s.handleFullSyncRequest(ctx, senderId, content.GetFullSyncRequest(), msg)
|
||||
case content.GetFullSyncResponse() != nil:
|
||||
return s.handleFullSyncResponse(ctx, senderId, content.GetFullSyncResponse(), msg)
|
||||
case content.GetHeadUpdate() != nil:
|
||||
return s.handleHeadUpdate(ctx, senderId, content.GetHeadUpdate(), msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *syncHandler) handleHeadUpdate(
|
||||
ctx context.Context,
|
||||
senderId string,
|
||||
update *spacesyncproto.ObjectHeadUpdate,
|
||||
msg *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
|
||||
var (
|
||||
fullRequest *spacesyncproto.ObjectSyncMessage
|
||||
isEmptyUpdate = len(update.Changes) == 0
|
||||
)
|
||||
res, err := s.treeCache.GetTree(ctx, s.spaceId, msg.TreeId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = func() error {
|
||||
objTree := res.TreeContainer.Tree()
|
||||
objTree.Lock()
|
||||
defer res.Release()
|
||||
defer objTree.Unlock()
|
||||
|
||||
// isEmptyUpdate is sent when the tree is brought up from cache
|
||||
if isEmptyUpdate {
|
||||
if slice.UnsortedEquals(objTree.Heads(), update.Heads) {
|
||||
return nil
|
||||
}
|
||||
// we need to sync in any case
|
||||
fullRequest, err = s.syncClient.CreateFullSyncRequest(objTree, update.Heads, update.SnapshotPath, msg.TrackingId)
|
||||
return err
|
||||
}
|
||||
|
||||
if s.alreadyHasHeads(objTree, update.Heads) {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = objTree.AddRawChanges(ctx, update.Changes...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if s.alreadyHasHeads(objTree, update.Heads) {
|
||||
return nil
|
||||
}
|
||||
|
||||
fullRequest, err = s.syncClient.CreateFullSyncRequest(objTree, update.Heads, update.SnapshotPath, msg.TrackingId)
|
||||
return err
|
||||
}()
|
||||
|
||||
if fullRequest != nil {
|
||||
return s.syncClient.SendAsync([]string{senderId}, fullRequest)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *syncHandler) handleFullSyncRequest(
|
||||
ctx context.Context,
|
||||
senderId string,
|
||||
request *spacesyncproto.ObjectFullSyncRequest,
|
||||
msg *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
var (
|
||||
fullResponse *spacesyncproto.ObjectSyncMessage
|
||||
header = msg.RootChange
|
||||
)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
s.syncClient.SendAsync([]string{senderId}, spacesyncproto.WrapError(err, header, msg.TreeId, msg.TrackingId))
|
||||
}
|
||||
}()
|
||||
|
||||
res, err := s.treeCache.GetTree(ctx, s.spaceId, msg.TreeId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = func() error {
|
||||
objTree := res.TreeContainer.Tree()
|
||||
objTree.Lock()
|
||||
defer res.Release()
|
||||
defer objTree.Unlock()
|
||||
|
||||
if header == nil {
|
||||
header = objTree.Header()
|
||||
}
|
||||
|
||||
if len(request.Changes) != 0 && !s.alreadyHasHeads(objTree, request.Heads) {
|
||||
_, err = objTree.AddRawChanges(ctx, request.Changes...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
fullResponse, err = s.syncClient.CreateFullSyncResponse(objTree, request.Heads, request.SnapshotPath, msg.TrackingId)
|
||||
return err
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return s.syncClient.SendAsync([]string{senderId}, fullResponse)
|
||||
}
|
||||
|
||||
func (s *syncHandler) handleFullSyncResponse(
|
||||
ctx context.Context,
|
||||
senderId string,
|
||||
response *spacesyncproto.ObjectFullSyncResponse,
|
||||
msg *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
res, err := s.treeCache.GetTree(ctx, s.spaceId, msg.TreeId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = func() error {
|
||||
objTree := res.TreeContainer.Tree()
|
||||
objTree.Lock()
|
||||
defer res.Release()
|
||||
defer objTree.Unlock()
|
||||
|
||||
if s.alreadyHasHeads(objTree, response.Heads) {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = objTree.AddRawChanges(ctx, response.Changes...)
|
||||
return err
|
||||
}()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *syncHandler) alreadyHasHeads(t tree.ObjectTree, heads []string) bool {
|
||||
return slice.UnsortedEquals(t.Heads(), heads) || t.HasChanges(heads...)
|
||||
}
|
||||
10
common/commonspace/syncservice/synchandler/synchhandler.go
Normal file
10
common/commonspace/syncservice/synchandler/synchhandler.go
Normal file
@ -0,0 +1,10 @@
|
||||
package synchandler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
)
|
||||
|
||||
type SyncHandler interface {
|
||||
HandleMessage(ctx context.Context, senderId string, request *spacesyncproto.ObjectSyncMessage) (err error)
|
||||
}
|
||||
@ -1,36 +1,36 @@
|
||||
//go:generate mockgen -destination mock_syncservice/mock_syncservice.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice SyncClient
|
||||
package syncservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/objectgetter"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/synchandler"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ocache"
|
||||
"time"
|
||||
)
|
||||
|
||||
var log = logger.NewNamed("syncservice").Sugar()
|
||||
|
||||
type SyncService interface {
|
||||
SyncClient() SyncClient
|
||||
ocache.ObjectLastUsage
|
||||
synchandler.SyncHandler
|
||||
StreamPool() StreamPool
|
||||
|
||||
Init()
|
||||
Init(getter objectgetter.ObjectGetter)
|
||||
Close() (err error)
|
||||
}
|
||||
|
||||
type HeadNotifiable interface {
|
||||
UpdateHeads(id string, heads []string)
|
||||
}
|
||||
|
||||
const respPeersStreamCheckInterval = time.Second * 10
|
||||
|
||||
type syncService struct {
|
||||
spaceId string
|
||||
|
||||
syncClient SyncClient
|
||||
streamPool StreamPool
|
||||
clientFactory spacesyncproto.ClientFactory
|
||||
objectGetter objectgetter.ObjectGetter
|
||||
|
||||
streamLoopCtx context.Context
|
||||
stopStreamLoop context.CancelFunc
|
||||
@ -40,31 +40,25 @@ type syncService struct {
|
||||
|
||||
func NewSyncService(
|
||||
spaceId string,
|
||||
headNotifiable HeadNotifiable,
|
||||
cache cache.TreeCache,
|
||||
configuration nodeconf.Configuration,
|
||||
confConnector nodeconf.ConfConnector) SyncService {
|
||||
var syncHandler SyncHandler
|
||||
confConnector nodeconf.ConfConnector) (syncService SyncService) {
|
||||
streamPool := newStreamPool(func(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
return syncHandler.HandleMessage(ctx, senderId, message)
|
||||
return syncService.HandleMessage(ctx, senderId, message)
|
||||
})
|
||||
factory := newRequestFactory()
|
||||
syncClient := newSyncClient(spaceId, streamPool, headNotifiable, factory, configuration)
|
||||
syncHandler = newSyncHandler(spaceId, cache, syncClient)
|
||||
return newSyncService(
|
||||
syncService = newSyncService(
|
||||
spaceId,
|
||||
syncClient,
|
||||
streamPool,
|
||||
spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient),
|
||||
confConnector)
|
||||
return
|
||||
}
|
||||
|
||||
func newSyncService(
|
||||
spaceId string,
|
||||
syncClient SyncClient,
|
||||
streamPool StreamPool,
|
||||
clientFactory spacesyncproto.ClientFactory,
|
||||
connector nodeconf.ConfConnector) *syncService {
|
||||
return &syncService{
|
||||
syncClient: syncClient,
|
||||
streamPool: streamPool,
|
||||
connector: connector,
|
||||
clientFactory: clientFactory,
|
||||
spaceId: spaceId,
|
||||
@ -72,7 +66,8 @@ func newSyncService(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *syncService) Init() {
|
||||
func (s *syncService) Init(objectGetter objectgetter.ObjectGetter) {
|
||||
s.objectGetter = objectGetter
|
||||
s.streamLoopCtx, s.stopStreamLoop = context.WithCancel(context.Background())
|
||||
go s.responsibleStreamCheckLoop(s.streamLoopCtx)
|
||||
}
|
||||
@ -80,7 +75,19 @@ func (s *syncService) Init() {
|
||||
func (s *syncService) Close() (err error) {
|
||||
s.stopStreamLoop()
|
||||
<-s.streamLoopDone
|
||||
return s.syncClient.Close()
|
||||
return s.streamPool.Close()
|
||||
}
|
||||
|
||||
func (s *syncService) LastUsage() time.Time {
|
||||
return s.streamPool.LastUsage()
|
||||
}
|
||||
|
||||
func (s *syncService) HandleMessage(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
obj, err := s.objectGetter.GetObject(ctx, message.ObjectId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return obj.HandleMessage(ctx, senderId, message)
|
||||
}
|
||||
|
||||
func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) {
|
||||
@ -91,7 +98,7 @@ func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
for _, peer := range respPeers {
|
||||
if s.syncClient.HasActiveStream(peer.Id()) {
|
||||
if s.streamPool.HasActiveStream(peer.Id()) {
|
||||
continue
|
||||
}
|
||||
stream, err := s.clientFactory.Client(peer).Stream(ctx)
|
||||
@ -109,7 +116,7 @@ func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) {
|
||||
log.With("spaceId", s.spaceId).Errorf("failed to send first message to stream: %v", err)
|
||||
continue
|
||||
}
|
||||
s.syncClient.AddAndReadStreamAsync(stream)
|
||||
s.streamPool.AddAndReadStreamAsync(stream)
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,6 +133,6 @@ func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *syncService) SyncClient() SyncClient {
|
||||
return s.syncClient
|
||||
func (s *syncService) StreamPool() StreamPool {
|
||||
return s.streamPool
|
||||
}
|
||||
|
||||
151
common/commonspace/synctree/mock_synctree/mock_synctree.go
Normal file
151
common/commonspace/synctree/mock_synctree/mock_synctree.go
Normal file
@ -0,0 +1,151 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree (interfaces: SyncClient)
|
||||
|
||||
// Package mock_synctree is a generated GoMock package.
|
||||
package mock_synctree
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
tree "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
treechangeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockSyncClient is a mock of SyncClient interface.
|
||||
type MockSyncClient struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockSyncClientMockRecorder
|
||||
}
|
||||
|
||||
// MockSyncClientMockRecorder is the mock recorder for MockSyncClient.
|
||||
type MockSyncClientMockRecorder struct {
|
||||
mock *MockSyncClient
|
||||
}
|
||||
|
||||
// NewMockSyncClient creates a new mock instance.
|
||||
func NewMockSyncClient(ctrl *gomock.Controller) *MockSyncClient {
|
||||
mock := &MockSyncClient{ctrl: ctrl}
|
||||
mock.recorder = &MockSyncClientMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockSyncClient) EXPECT() *MockSyncClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// BroadcastAsync mocks base method.
|
||||
func (m *MockSyncClient) BroadcastAsync(arg0 *treechangeproto.TreeSyncMessage) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BroadcastAsync", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// BroadcastAsync indicates an expected call of BroadcastAsync.
|
||||
func (mr *MockSyncClientMockRecorder) BroadcastAsync(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastAsync", reflect.TypeOf((*MockSyncClient)(nil).BroadcastAsync), arg0)
|
||||
}
|
||||
|
||||
// BroadcastAsyncOrSendResponsible mocks base method.
|
||||
func (m *MockSyncClient) BroadcastAsyncOrSendResponsible(arg0 *treechangeproto.TreeSyncMessage) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BroadcastAsyncOrSendResponsible", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// BroadcastAsyncOrSendResponsible indicates an expected call of BroadcastAsyncOrSendResponsible.
|
||||
func (mr *MockSyncClientMockRecorder) BroadcastAsyncOrSendResponsible(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastAsyncOrSendResponsible", reflect.TypeOf((*MockSyncClient)(nil).BroadcastAsyncOrSendResponsible), arg0)
|
||||
}
|
||||
|
||||
// CreateFullSyncRequest mocks base method.
|
||||
func (m *MockSyncClient) CreateFullSyncRequest(arg0 tree.ObjectTree, arg1, arg2 []string) (*treechangeproto.TreeSyncMessage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateFullSyncRequest", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*treechangeproto.TreeSyncMessage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateFullSyncRequest indicates an expected call of CreateFullSyncRequest.
|
||||
func (mr *MockSyncClientMockRecorder) CreateFullSyncRequest(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFullSyncRequest", reflect.TypeOf((*MockSyncClient)(nil).CreateFullSyncRequest), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// CreateFullSyncResponse mocks base method.
|
||||
func (m *MockSyncClient) CreateFullSyncResponse(arg0 tree.ObjectTree, arg1, arg2 []string) (*treechangeproto.TreeSyncMessage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateFullSyncResponse", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*treechangeproto.TreeSyncMessage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateFullSyncResponse indicates an expected call of CreateFullSyncResponse.
|
||||
func (mr *MockSyncClientMockRecorder) CreateFullSyncResponse(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFullSyncResponse", reflect.TypeOf((*MockSyncClient)(nil).CreateFullSyncResponse), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// CreateHeadUpdate mocks base method.
|
||||
func (m *MockSyncClient) CreateHeadUpdate(arg0 tree.ObjectTree, arg1 []*treechangeproto.RawTreeChangeWithId) *treechangeproto.TreeSyncMessage {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateHeadUpdate", arg0, arg1)
|
||||
ret0, _ := ret[0].(*treechangeproto.TreeSyncMessage)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CreateHeadUpdate indicates an expected call of CreateHeadUpdate.
|
||||
func (mr *MockSyncClientMockRecorder) CreateHeadUpdate(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateHeadUpdate", reflect.TypeOf((*MockSyncClient)(nil).CreateHeadUpdate), arg0, arg1)
|
||||
}
|
||||
|
||||
// CreateNewTreeRequest mocks base method.
|
||||
func (m *MockSyncClient) CreateNewTreeRequest() *treechangeproto.TreeSyncMessage {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateNewTreeRequest")
|
||||
ret0, _ := ret[0].(*treechangeproto.TreeSyncMessage)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CreateNewTreeRequest indicates an expected call of CreateNewTreeRequest.
|
||||
func (mr *MockSyncClientMockRecorder) CreateNewTreeRequest() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateNewTreeRequest", reflect.TypeOf((*MockSyncClient)(nil).CreateNewTreeRequest))
|
||||
}
|
||||
|
||||
// LastUsage mocks base method.
|
||||
func (m *MockSyncClient) LastUsage() time.Time {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "LastUsage")
|
||||
ret0, _ := ret[0].(time.Time)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// LastUsage indicates an expected call of LastUsage.
|
||||
func (mr *MockSyncClientMockRecorder) LastUsage() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LastUsage", reflect.TypeOf((*MockSyncClient)(nil).LastUsage))
|
||||
}
|
||||
|
||||
// SendAsync mocks base method.
|
||||
func (m *MockSyncClient) SendAsync(arg0 string, arg1 *treechangeproto.TreeSyncMessage, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SendAsync", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SendAsync indicates an expected call of SendAsync.
|
||||
func (mr *MockSyncClientMockRecorder) SendAsync(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendAsync", reflect.TypeOf((*MockSyncClient)(nil).SendAsync), arg0, arg1, arg2)
|
||||
}
|
||||
@ -1,40 +1,41 @@
|
||||
package syncservice
|
||||
package synctree
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/slice"
|
||||
)
|
||||
|
||||
type RequestFactory interface {
|
||||
CreateHeadUpdate(t tree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *spacesyncproto.ObjectSyncMessage)
|
||||
CreateNewTreeRequest(id string) (msg *spacesyncproto.ObjectSyncMessage)
|
||||
CreateFullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (req *spacesyncproto.ObjectSyncMessage, err error)
|
||||
CreateFullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (*spacesyncproto.ObjectSyncMessage, error)
|
||||
CreateHeadUpdate(t tree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *treechangeproto.TreeSyncMessage)
|
||||
CreateNewTreeRequest() (msg *treechangeproto.TreeSyncMessage)
|
||||
CreateFullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string) (req *treechangeproto.TreeSyncMessage, err error)
|
||||
CreateFullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string) (*treechangeproto.TreeSyncMessage, error)
|
||||
}
|
||||
|
||||
func newRequestFactory() RequestFactory {
|
||||
return &requestFactory{}
|
||||
var sharedFactory = &requestFactory{}
|
||||
|
||||
func GetRequestFactory() RequestFactory {
|
||||
return sharedFactory
|
||||
}
|
||||
|
||||
type requestFactory struct{}
|
||||
|
||||
func (r *requestFactory) CreateHeadUpdate(t tree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *spacesyncproto.ObjectSyncMessage) {
|
||||
return spacesyncproto.WrapHeadUpdate(&spacesyncproto.ObjectHeadUpdate{
|
||||
func (r *requestFactory) CreateHeadUpdate(t tree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *treechangeproto.TreeSyncMessage) {
|
||||
return treechangeproto.WrapHeadUpdate(&treechangeproto.TreeHeadUpdate{
|
||||
Heads: t.Heads(),
|
||||
Changes: added,
|
||||
SnapshotPath: t.SnapshotPath(),
|
||||
}, t.Header(), t.ID(), "")
|
||||
}, t.Header())
|
||||
}
|
||||
|
||||
func (r *requestFactory) CreateNewTreeRequest(id string) (msg *spacesyncproto.ObjectSyncMessage) {
|
||||
return spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{}, nil, id, "")
|
||||
func (r *requestFactory) CreateNewTreeRequest() (msg *treechangeproto.TreeSyncMessage) {
|
||||
return treechangeproto.WrapFullRequest(&treechangeproto.TreeFullSyncRequest{}, nil)
|
||||
}
|
||||
|
||||
func (r *requestFactory) CreateFullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (msg *spacesyncproto.ObjectSyncMessage, err error) {
|
||||
req := &spacesyncproto.ObjectFullSyncRequest{}
|
||||
func (r *requestFactory) CreateFullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string) (msg *treechangeproto.TreeSyncMessage, err error) {
|
||||
req := &treechangeproto.TreeFullSyncRequest{}
|
||||
if t == nil {
|
||||
return nil, fmt.Errorf("tree should not be empty")
|
||||
}
|
||||
@ -49,17 +50,17 @@ func (r *requestFactory) CreateFullSyncRequest(t tree.ObjectTree, theirHeads, th
|
||||
}
|
||||
|
||||
req.Changes = changesAfterSnapshot
|
||||
msg = spacesyncproto.WrapFullRequest(req, t.Header(), t.ID(), trackingId)
|
||||
msg = treechangeproto.WrapFullRequest(req, t.Header())
|
||||
return
|
||||
}
|
||||
|
||||
func (r *requestFactory) CreateFullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (msg *spacesyncproto.ObjectSyncMessage, err error) {
|
||||
resp := &spacesyncproto.ObjectFullSyncResponse{
|
||||
func (r *requestFactory) CreateFullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string) (msg *treechangeproto.TreeSyncMessage, err error) {
|
||||
resp := &treechangeproto.TreeFullSyncResponse{
|
||||
Heads: t.Heads(),
|
||||
SnapshotPath: t.SnapshotPath(),
|
||||
}
|
||||
if slice.UnsortedEquals(theirHeads, t.Heads()) {
|
||||
msg = spacesyncproto.WrapFullResponse(resp, t.Header(), t.ID(), trackingId)
|
||||
msg = treechangeproto.WrapFullResponse(resp, t.Header())
|
||||
return
|
||||
}
|
||||
|
||||
@ -68,6 +69,6 @@ func (r *requestFactory) CreateFullSyncResponse(t tree.ObjectTree, theirHeads, t
|
||||
return
|
||||
}
|
||||
resp.Changes = ourChanges
|
||||
msg = spacesyncproto.WrapFullResponse(resp, t.Header(), t.ID(), trackingId)
|
||||
msg = treechangeproto.WrapFullResponse(resp, t.Header())
|
||||
return
|
||||
}
|
||||
89
common/commonspace/synctree/syncclient.go
Normal file
89
common/commonspace/synctree/syncclient.go
Normal file
@ -0,0 +1,89 @@
|
||||
//go:generate mockgen -destination mock_synctree/mock_synctree.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree SyncClient
|
||||
package synctree
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
)
|
||||
|
||||
type SyncClient interface {
|
||||
RequestFactory
|
||||
BroadcastAsync(message *treechangeproto.TreeSyncMessage) (err error)
|
||||
BroadcastAsyncOrSendResponsible(message *treechangeproto.TreeSyncMessage) (err error)
|
||||
SendAsync(peerId string, message *treechangeproto.TreeSyncMessage, replyId string) (err error)
|
||||
}
|
||||
|
||||
type syncClient struct {
|
||||
syncservice.StreamPool
|
||||
RequestFactory
|
||||
spaceId string
|
||||
notifiable diffservice.HeadNotifiable
|
||||
configuration nodeconf.Configuration
|
||||
}
|
||||
|
||||
func newSyncClient(
|
||||
spaceId string,
|
||||
pool syncservice.StreamPool,
|
||||
notifiable diffservice.HeadNotifiable,
|
||||
factory RequestFactory,
|
||||
configuration nodeconf.Configuration) SyncClient {
|
||||
return &syncClient{
|
||||
StreamPool: pool,
|
||||
RequestFactory: factory,
|
||||
notifiable: notifiable,
|
||||
configuration: configuration,
|
||||
spaceId: spaceId,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *syncClient) BroadcastAsync(message *treechangeproto.TreeSyncMessage) (err error) {
|
||||
s.notifyIfNeeded(message)
|
||||
objMsg, err := marshallTreeMessage(message, message.RootChange.Id, "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return s.StreamPool.BroadcastAsync(objMsg)
|
||||
}
|
||||
|
||||
func (s *syncClient) SendAsync(peerId string, message *treechangeproto.TreeSyncMessage, replyId string) (err error) {
|
||||
objMsg, err := marshallTreeMessage(message, message.RootChange.Id, replyId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return s.StreamPool.SendAsync([]string{peerId}, objMsg)
|
||||
}
|
||||
|
||||
func (s *syncClient) BroadcastAsyncOrSendResponsible(message *treechangeproto.TreeSyncMessage) (err error) {
|
||||
s.notifyIfNeeded(message)
|
||||
objMsg, err := marshallTreeMessage(message, message.RootChange.Id, "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if s.configuration.IsResponsible(s.spaceId) {
|
||||
return s.StreamPool.SendAsync(s.configuration.NodeIds(s.spaceId), objMsg)
|
||||
}
|
||||
return s.BroadcastAsync(message)
|
||||
}
|
||||
|
||||
func (s *syncClient) notifyIfNeeded(message *treechangeproto.TreeSyncMessage) {
|
||||
if message.GetContent().GetHeadUpdate() != nil {
|
||||
update := message.GetContent().GetHeadUpdate()
|
||||
s.notifiable.UpdateHeads(message.RootChange.Id, update.Heads)
|
||||
}
|
||||
}
|
||||
|
||||
func marshallTreeMessage(message *treechangeproto.TreeSyncMessage, id, replyId string) (objMsg *spacesyncproto.ObjectSyncMessage, err error) {
|
||||
payload, err := message.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
objMsg = &spacesyncproto.ObjectSyncMessage{
|
||||
ReplyId: replyId,
|
||||
Payload: payload,
|
||||
ObjectId: id,
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -2,41 +2,84 @@ package synctree
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice"
|
||||
spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/synchandler"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
tree2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var ErrSyncTreeClosed = errors.New("sync tree is closed")
|
||||
|
||||
// SyncTree sends head updates to sync service and also sends new changes to update listener
|
||||
type SyncTree struct {
|
||||
tree2.ObjectTree
|
||||
syncClient syncservice.SyncClient
|
||||
tree.ObjectTree
|
||||
synchandler.SyncHandler
|
||||
syncClient SyncClient
|
||||
listener updatelistener.UpdateListener
|
||||
isClosed bool
|
||||
}
|
||||
|
||||
var createDerivedObjectTree = tree2.CreateDerivedObjectTree
|
||||
var createObjectTree = tree2.CreateObjectTree
|
||||
var buildObjectTree = tree2.BuildObjectTree
|
||||
var log = logger.NewNamed("commonspace.synctree").Sugar()
|
||||
|
||||
var createDerivedObjectTree = tree.CreateDerivedObjectTree
|
||||
var createObjectTree = tree.CreateObjectTree
|
||||
var buildObjectTree = tree.BuildObjectTree
|
||||
var createSyncClient = newSyncClient
|
||||
|
||||
type CreateDeps struct {
|
||||
SpaceId string
|
||||
Payload tree.ObjectTreeCreatePayload
|
||||
Configuration nodeconf.Configuration
|
||||
HeadNotifiable diffservice.HeadNotifiable
|
||||
StreamPool syncservice.StreamPool
|
||||
Listener updatelistener.UpdateListener
|
||||
AclList list.ACLList
|
||||
CreateStorage storage.TreeStorageCreatorFunc
|
||||
}
|
||||
|
||||
type BuildDeps struct {
|
||||
SpaceId string
|
||||
StreamPool syncservice.StreamPool
|
||||
Configuration nodeconf.Configuration
|
||||
HeadNotifiable diffservice.HeadNotifiable
|
||||
Listener updatelistener.UpdateListener
|
||||
AclList list.ACLList
|
||||
SpaceStorage spacestorage.SpaceStorage
|
||||
TreeStorage storage.TreeStorage
|
||||
}
|
||||
|
||||
func DeriveSyncTree(
|
||||
ctx context.Context,
|
||||
payload tree2.ObjectTreeCreatePayload,
|
||||
syncClient syncservice.SyncClient,
|
||||
listener updatelistener.UpdateListener,
|
||||
aclList list.ACLList,
|
||||
createStorage storage.TreeStorageCreatorFunc) (t tree2.ObjectTree, err error) {
|
||||
t, err = createDerivedObjectTree(payload, aclList, createStorage)
|
||||
deps CreateDeps) (t tree.ObjectTree, err error) {
|
||||
t, err = createDerivedObjectTree(deps.Payload, deps.AclList, deps.CreateStorage)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
t = &SyncTree{
|
||||
syncClient := createSyncClient(
|
||||
deps.SpaceId,
|
||||
deps.StreamPool,
|
||||
deps.HeadNotifiable,
|
||||
sharedFactory,
|
||||
deps.Configuration)
|
||||
syncTree := &SyncTree{
|
||||
ObjectTree: t,
|
||||
syncClient: syncClient,
|
||||
listener: listener,
|
||||
listener: deps.Listener,
|
||||
}
|
||||
syncHandler := newSyncTreeHandler(syncTree, syncClient)
|
||||
syncTree.SyncHandler = syncHandler
|
||||
t = syncTree
|
||||
|
||||
headUpdate := syncClient.CreateHeadUpdate(t, nil)
|
||||
err = syncClient.BroadcastAsync(headUpdate)
|
||||
@ -45,58 +88,134 @@ func DeriveSyncTree(
|
||||
|
||||
func CreateSyncTree(
|
||||
ctx context.Context,
|
||||
payload tree2.ObjectTreeCreatePayload,
|
||||
syncClient syncservice.SyncClient,
|
||||
listener updatelistener.UpdateListener,
|
||||
aclList list.ACLList,
|
||||
createStorage storage.TreeStorageCreatorFunc) (t tree2.ObjectTree, err error) {
|
||||
t, err = createObjectTree(payload, aclList, createStorage)
|
||||
deps CreateDeps) (t tree.ObjectTree, err error) {
|
||||
t, err = createObjectTree(deps.Payload, deps.AclList, deps.CreateStorage)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
t = &SyncTree{
|
||||
syncClient := createSyncClient(
|
||||
deps.SpaceId,
|
||||
deps.StreamPool,
|
||||
deps.HeadNotifiable,
|
||||
GetRequestFactory(),
|
||||
deps.Configuration)
|
||||
syncTree := &SyncTree{
|
||||
ObjectTree: t,
|
||||
syncClient: syncClient,
|
||||
listener: listener,
|
||||
listener: deps.Listener,
|
||||
}
|
||||
syncHandler := newSyncTreeHandler(syncTree, syncClient)
|
||||
syncTree.SyncHandler = syncHandler
|
||||
t = syncTree
|
||||
|
||||
headUpdate := syncClient.CreateHeadUpdate(t, nil)
|
||||
err = syncClient.BroadcastAsync(headUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
func BuildSyncTree(
|
||||
ctx context.Context,
|
||||
syncClient syncservice.SyncClient,
|
||||
treeStorage storage.TreeStorage,
|
||||
listener updatelistener.UpdateListener,
|
||||
aclList list.ACLList) (t tree2.ObjectTree, err error) {
|
||||
return buildSyncTree(ctx, syncClient, treeStorage, listener, aclList)
|
||||
func BuildSyncTreeOrGetRemote(ctx context.Context, id string, deps BuildDeps) (t tree.ObjectTree, err error) {
|
||||
getTreeRemote := func() (msg *treechangeproto.TreeSyncMessage, err error) {
|
||||
// TODO: add empty context handling (when this is not happening due to head update)
|
||||
peerId, err := syncservice.GetPeerIdFromStreamContext(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
newTreeRequest := GetRequestFactory().CreateNewTreeRequest()
|
||||
objMsg, err := marshallTreeMessage(newTreeRequest, id, "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := deps.StreamPool.SendSync(peerId, objMsg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
msg = &treechangeproto.TreeSyncMessage{}
|
||||
err = proto.Unmarshal(resp.Payload, msg)
|
||||
return
|
||||
}
|
||||
|
||||
deps.TreeStorage, err = deps.SpaceStorage.TreeStorage(id)
|
||||
if err == nil {
|
||||
return buildSyncTree(ctx, false, deps)
|
||||
}
|
||||
|
||||
if err != nil && err != storage.ErrUnknownTreeId {
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := getTreeRemote()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if resp.GetContent().GetFullSyncResponse() == nil {
|
||||
err = fmt.Errorf("expected to get full sync response, but got something else")
|
||||
return
|
||||
}
|
||||
fullSyncResp := resp.GetContent().GetFullSyncResponse()
|
||||
|
||||
payload := storage.TreeStorageCreatePayload{
|
||||
TreeId: id,
|
||||
RootRawChange: resp.RootChange,
|
||||
Changes: fullSyncResp.Changes,
|
||||
Heads: fullSyncResp.Heads,
|
||||
}
|
||||
|
||||
// basically building tree with in-memory storage and validating that it was without errors
|
||||
log.With(zap.String("id", id)).Debug("validating tree")
|
||||
err = tree.ValidateRawTree(payload, deps.AclList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// now we are sure that we can save it to the storage
|
||||
deps.TreeStorage, err = deps.SpaceStorage.CreateTreeStorage(payload)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return buildSyncTree(ctx, true, deps)
|
||||
}
|
||||
|
||||
func buildSyncTree(
|
||||
ctx context.Context,
|
||||
syncClient syncservice.SyncClient,
|
||||
treeStorage storage.TreeStorage,
|
||||
listener updatelistener.UpdateListener,
|
||||
aclList list.ACLList) (t tree2.ObjectTree, err error) {
|
||||
t, err = buildObjectTree(treeStorage, aclList)
|
||||
isFirstBuild bool,
|
||||
deps BuildDeps) (t tree.ObjectTree, err error) {
|
||||
|
||||
t, err = buildObjectTree(deps.TreeStorage, deps.AclList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
t = &SyncTree{
|
||||
syncClient := createSyncClient(
|
||||
deps.SpaceId,
|
||||
deps.StreamPool,
|
||||
deps.HeadNotifiable,
|
||||
GetRequestFactory(),
|
||||
deps.Configuration)
|
||||
syncTree := &SyncTree{
|
||||
ObjectTree: t,
|
||||
syncClient: syncClient,
|
||||
listener: listener,
|
||||
listener: deps.Listener,
|
||||
}
|
||||
syncHandler := newSyncTreeHandler(syncTree, syncClient)
|
||||
syncTree.SyncHandler = syncHandler
|
||||
t = syncTree
|
||||
|
||||
headUpdate := syncClient.CreateHeadUpdate(t, nil)
|
||||
headUpdate := syncTree.syncClient.CreateHeadUpdate(t, nil)
|
||||
// here we will have different behaviour based on who is sending this update
|
||||
err = syncClient.BroadcastAsyncOrSendResponsible(headUpdate)
|
||||
if isFirstBuild {
|
||||
// send to everybody, because everybody should know that the node or client got new tree
|
||||
err = syncTree.syncClient.BroadcastAsync(headUpdate)
|
||||
} else {
|
||||
// send either to everybody if client or to replica set if node
|
||||
err = syncTree.syncClient.BroadcastAsyncOrSendResponsible(headUpdate)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *SyncTree) AddContent(ctx context.Context, content tree2.SignableChangeContent) (res tree2.AddResult, err error) {
|
||||
func (s *SyncTree) AddContent(ctx context.Context, content tree.SignableChangeContent) (res tree.AddResult, err error) {
|
||||
if s.isClosed {
|
||||
err = ErrSyncTreeClosed
|
||||
return
|
||||
}
|
||||
res, err = s.ObjectTree.AddContent(ctx, content)
|
||||
if err != nil {
|
||||
return
|
||||
@ -106,25 +225,41 @@ func (s *SyncTree) AddContent(ctx context.Context, content tree2.SignableChangeC
|
||||
return
|
||||
}
|
||||
|
||||
func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (res tree2.AddResult, err error) {
|
||||
func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (res tree.AddResult, err error) {
|
||||
if s.isClosed {
|
||||
err = ErrSyncTreeClosed
|
||||
return
|
||||
}
|
||||
res, err = s.ObjectTree.AddRawChanges(ctx, changes...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
switch res.Mode {
|
||||
case tree2.Nothing:
|
||||
return
|
||||
case tree2.Append:
|
||||
s.listener.Update(s)
|
||||
case tree2.Rebuild:
|
||||
s.listener.Rebuild(s)
|
||||
if s.listener != nil {
|
||||
switch res.Mode {
|
||||
case tree.Nothing:
|
||||
return
|
||||
case tree.Append:
|
||||
s.listener.Update(s)
|
||||
case tree.Rebuild:
|
||||
s.listener.Rebuild(s)
|
||||
}
|
||||
}
|
||||
|
||||
//if res.Mode != tree.Nothing {
|
||||
headUpdate := s.syncClient.CreateHeadUpdate(s, res.Added)
|
||||
err = s.syncClient.BroadcastAsync(headUpdate)
|
||||
//}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *SyncTree) Tree() tree2.ObjectTree {
|
||||
return s
|
||||
func (s *SyncTree) Close() (err error) {
|
||||
log.With("id", s.ID()).Debug("closing sync tree")
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
log.With("id", s.ID()).Debug("taken lock on sync tree")
|
||||
if s.isClosed {
|
||||
err = ErrSyncTreeClosed
|
||||
return
|
||||
}
|
||||
s.isClosed = true
|
||||
return
|
||||
}
|
||||
|
||||
@ -2,16 +2,16 @@ package synctree
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/mock_syncservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/mock_synctree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener/mock_updatelistener"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list/mock_list"
|
||||
storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage/mock_storage"
|
||||
tree2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
tree "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree/mock_objecttree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
"github.com/golang/mock/gomock"
|
||||
@ -20,8 +20,8 @@ import (
|
||||
)
|
||||
|
||||
type syncTreeMatcher struct {
|
||||
objTree tree2.ObjectTree
|
||||
client syncservice.SyncClient
|
||||
objTree tree.ObjectTree
|
||||
client SyncClient
|
||||
listener updatelistener.UpdateListener
|
||||
}
|
||||
|
||||
@ -43,21 +43,25 @@ func Test_DeriveSyncTree(t *testing.T) {
|
||||
defer ctrl.Finish()
|
||||
|
||||
updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl)
|
||||
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
|
||||
syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
|
||||
aclListMock := mock_list.NewMockACLList(ctrl)
|
||||
createStorage := storage2.TreeStorageCreatorFunc(func(payload storage2.TreeStorageCreatePayload) (storage2.TreeStorage, error) {
|
||||
return nil, nil
|
||||
})
|
||||
objTreeMock := mock_tree.NewMockObjectTree(ctrl)
|
||||
createDerivedObjectTree = func(payload tree2.ObjectTreeCreatePayload, l list.ACLList, create storage2.TreeStorageCreatorFunc) (objTree tree2.ObjectTree, err error) {
|
||||
spaceId := "spaceId"
|
||||
expectedPayload := tree.ObjectTreeCreatePayload{SpaceId: spaceId}
|
||||
createDerivedObjectTree = func(payload tree.ObjectTreeCreatePayload, l list.ACLList, create storage2.TreeStorageCreatorFunc) (objTree tree.ObjectTree, err error) {
|
||||
require.Equal(t, l, aclListMock)
|
||||
require.Equal(t, expectedPayload, payload)
|
||||
return objTreeMock, nil
|
||||
}
|
||||
headUpdate := &spacesyncproto.ObjectSyncMessage{}
|
||||
createSyncClient = func(spaceId string, pool syncservice.StreamPool, notifiable diffservice.HeadNotifiable, factory RequestFactory, configuration nodeconf.Configuration) SyncClient {
|
||||
return syncClientMock
|
||||
}
|
||||
headUpdate := &treechangeproto.TreeSyncMessage{}
|
||||
syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate)
|
||||
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
|
||||
deps := CreateDeps{AclList: aclListMock, SpaceId: spaceId, Payload: expectedPayload, Listener: updateListenerMock}
|
||||
|
||||
_, err := DeriveSyncTree(ctx, tree2.ObjectTreeCreatePayload{}, syncClientMock, updateListenerMock, aclListMock, createStorage)
|
||||
_, err := DeriveSyncTree(ctx, deps)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@ -67,21 +71,25 @@ func Test_CreateSyncTree(t *testing.T) {
|
||||
defer ctrl.Finish()
|
||||
|
||||
updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl)
|
||||
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
|
||||
syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
|
||||
aclListMock := mock_list.NewMockACLList(ctrl)
|
||||
createStorage := storage2.TreeStorageCreatorFunc(func(payload storage2.TreeStorageCreatePayload) (storage2.TreeStorage, error) {
|
||||
return nil, nil
|
||||
})
|
||||
objTreeMock := mock_tree.NewMockObjectTree(ctrl)
|
||||
createObjectTree = func(payload tree2.ObjectTreeCreatePayload, l list.ACLList, create storage2.TreeStorageCreatorFunc) (objTree tree2.ObjectTree, err error) {
|
||||
spaceId := "spaceId"
|
||||
expectedPayload := tree.ObjectTreeCreatePayload{SpaceId: spaceId}
|
||||
createObjectTree = func(payload tree.ObjectTreeCreatePayload, l list.ACLList, create storage2.TreeStorageCreatorFunc) (objTree tree.ObjectTree, err error) {
|
||||
require.Equal(t, l, aclListMock)
|
||||
require.Equal(t, expectedPayload, payload)
|
||||
return objTreeMock, nil
|
||||
}
|
||||
headUpdate := &spacesyncproto.ObjectSyncMessage{}
|
||||
createSyncClient = func(spaceId string, pool syncservice.StreamPool, notifiable diffservice.HeadNotifiable, factory RequestFactory, configuration nodeconf.Configuration) SyncClient {
|
||||
return syncClientMock
|
||||
}
|
||||
headUpdate := &treechangeproto.TreeSyncMessage{}
|
||||
syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate)
|
||||
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
|
||||
deps := CreateDeps{AclList: aclListMock, SpaceId: spaceId, Payload: expectedPayload, Listener: updateListenerMock}
|
||||
|
||||
_, err := CreateSyncTree(ctx, tree2.ObjectTreeCreatePayload{}, syncClientMock, updateListenerMock, aclListMock, createStorage)
|
||||
_, err := CreateSyncTree(ctx, deps)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@ -91,27 +99,22 @@ func Test_BuildSyncTree(t *testing.T) {
|
||||
defer ctrl.Finish()
|
||||
|
||||
updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl)
|
||||
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
|
||||
aclListMock := mock_list.NewMockACLList(ctrl)
|
||||
storageMock := mock_storage.NewMockTreeStorage(ctrl)
|
||||
syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
|
||||
objTreeMock := mock_tree.NewMockObjectTree(ctrl)
|
||||
buildObjectTree = func(store storage2.TreeStorage, l list.ACLList) (objTree tree2.ObjectTree, err error) {
|
||||
require.Equal(t, aclListMock, l)
|
||||
require.Equal(t, store, storageMock)
|
||||
return objTreeMock, nil
|
||||
tr := &SyncTree{
|
||||
ObjectTree: objTreeMock,
|
||||
SyncHandler: nil,
|
||||
syncClient: syncClientMock,
|
||||
listener: updateListenerMock,
|
||||
isClosed: false,
|
||||
}
|
||||
headUpdate := &spacesyncproto.ObjectSyncMessage{}
|
||||
syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate)
|
||||
syncClientMock.EXPECT().BroadcastAsyncOrSendResponsible(gomock.Eq(headUpdate)).Return(nil)
|
||||
|
||||
tr, err := BuildSyncTree(ctx, syncClientMock, storageMock, updateListenerMock, aclListMock)
|
||||
require.NoError(t, err)
|
||||
|
||||
headUpdate := &treechangeproto.TreeSyncMessage{}
|
||||
t.Run("AddRawChanges update", func(t *testing.T) {
|
||||
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
|
||||
expectedRes := tree2.AddResult{
|
||||
expectedRes := tree.AddResult{
|
||||
Added: changes,
|
||||
Mode: tree2.Append,
|
||||
Mode: tree.Append,
|
||||
}
|
||||
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)).
|
||||
Return(expectedRes, nil)
|
||||
@ -126,9 +129,9 @@ func Test_BuildSyncTree(t *testing.T) {
|
||||
|
||||
t.Run("AddRawChanges rebuild", func(t *testing.T) {
|
||||
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
|
||||
expectedRes := tree2.AddResult{
|
||||
expectedRes := tree.AddResult{
|
||||
Added: changes,
|
||||
Mode: tree2.Rebuild,
|
||||
Mode: tree.Rebuild,
|
||||
}
|
||||
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)).
|
||||
Return(expectedRes, nil)
|
||||
@ -143,9 +146,9 @@ func Test_BuildSyncTree(t *testing.T) {
|
||||
|
||||
t.Run("AddRawChanges nothing", func(t *testing.T) {
|
||||
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
|
||||
expectedRes := tree2.AddResult{
|
||||
expectedRes := tree.AddResult{
|
||||
Added: changes,
|
||||
Mode: tree2.Nothing,
|
||||
Mode: tree.Nothing,
|
||||
}
|
||||
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)).
|
||||
Return(expectedRes, nil)
|
||||
@ -157,11 +160,11 @@ func Test_BuildSyncTree(t *testing.T) {
|
||||
|
||||
t.Run("AddContent", func(t *testing.T) {
|
||||
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
|
||||
content := tree2.SignableChangeContent{
|
||||
content := tree.SignableChangeContent{
|
||||
Data: []byte("abcde"),
|
||||
}
|
||||
expectedRes := tree2.AddResult{
|
||||
Mode: tree2.Append,
|
||||
expectedRes := tree.AddResult{
|
||||
Mode: tree.Append,
|
||||
Added: changes,
|
||||
}
|
||||
objTreeMock.EXPECT().AddContent(gomock.Any(), gomock.Eq(content)).
|
||||
|
||||
184
common/commonspace/synctree/synctreehandler.go
Normal file
184
common/commonspace/synctree/synctreehandler.go
Normal file
@ -0,0 +1,184 @@
|
||||
package synctree
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/synchandler"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/slice"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
type syncTreeHandler struct {
|
||||
objTree tree.ObjectTree
|
||||
syncClient SyncClient
|
||||
}
|
||||
|
||||
func newSyncTreeHandler(objTree tree.ObjectTree, syncClient SyncClient) synchandler.SyncHandler {
|
||||
return &syncTreeHandler{
|
||||
objTree: objTree,
|
||||
syncClient: syncClient,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *syncTreeHandler) HandleMessage(ctx context.Context, senderId string, msg *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
unmarshalled := &treechangeproto.TreeSyncMessage{}
|
||||
err = proto.Unmarshal(msg.Payload, unmarshalled)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content := unmarshalled.GetContent()
|
||||
switch {
|
||||
case content.GetHeadUpdate() != nil:
|
||||
return s.handleHeadUpdate(ctx, senderId, content.GetHeadUpdate(), msg.ReplyId)
|
||||
case content.GetFullSyncRequest() != nil:
|
||||
return s.handleFullSyncRequest(ctx, senderId, content.GetFullSyncRequest(), msg.ReplyId)
|
||||
case content.GetFullSyncResponse() != nil:
|
||||
return s.handleFullSyncResponse(ctx, senderId, content.GetFullSyncResponse())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *syncTreeHandler) handleHeadUpdate(
|
||||
ctx context.Context,
|
||||
senderId string,
|
||||
update *treechangeproto.TreeHeadUpdate,
|
||||
replyId string) (err error) {
|
||||
log.With("senderId", senderId).
|
||||
With("heads", update.Heads).
|
||||
With("treeId", s.objTree.ID()).
|
||||
Debug("received head update message")
|
||||
var (
|
||||
fullRequest *treechangeproto.TreeSyncMessage
|
||||
isEmptyUpdate = len(update.Changes) == 0
|
||||
objTree = s.objTree
|
||||
)
|
||||
|
||||
err = func() error {
|
||||
objTree.Lock()
|
||||
defer objTree.Unlock()
|
||||
|
||||
// isEmptyUpdate is sent when the tree is brought up from cache
|
||||
if isEmptyUpdate {
|
||||
log.With("treeId", objTree.ID()).Debug("is empty update")
|
||||
if slice.UnsortedEquals(objTree.Heads(), update.Heads) {
|
||||
return nil
|
||||
}
|
||||
// we need to sync in any case
|
||||
fullRequest, err = s.syncClient.CreateFullSyncRequest(objTree, update.Heads, update.SnapshotPath)
|
||||
return err
|
||||
}
|
||||
|
||||
if s.alreadyHasHeads(objTree, update.Heads) {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = objTree.AddRawChanges(ctx, update.Changes...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if s.alreadyHasHeads(objTree, update.Heads) {
|
||||
return nil
|
||||
}
|
||||
|
||||
fullRequest, err = s.syncClient.CreateFullSyncRequest(objTree, update.Heads, update.SnapshotPath)
|
||||
return err
|
||||
}()
|
||||
|
||||
if fullRequest != nil {
|
||||
log.With("senderId", senderId).
|
||||
With("heads", objTree.Heads()).
|
||||
With("treeId", objTree.ID()).
|
||||
Debug("sending full sync request")
|
||||
return s.syncClient.SendAsync(senderId, fullRequest, replyId)
|
||||
}
|
||||
log.With("senderId", senderId).
|
||||
With("heads", update.Heads).
|
||||
With("treeId", objTree.ID()).
|
||||
Debug("head update finished correctly")
|
||||
return
|
||||
}
|
||||
|
||||
func (s *syncTreeHandler) handleFullSyncRequest(
|
||||
ctx context.Context,
|
||||
senderId string,
|
||||
request *treechangeproto.TreeFullSyncRequest,
|
||||
replyId string) (err error) {
|
||||
log.With("senderId", senderId).
|
||||
With("heads", request.Heads).
|
||||
With("treeId", s.objTree.ID()).
|
||||
With("trackingId", replyId).
|
||||
Debug("received full sync request message")
|
||||
var (
|
||||
fullResponse *treechangeproto.TreeSyncMessage
|
||||
header = s.objTree.Header()
|
||||
objTree = s.objTree
|
||||
)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
s.syncClient.SendAsync(senderId, treechangeproto.WrapError(err, header), replyId)
|
||||
}
|
||||
}()
|
||||
|
||||
err = func() error {
|
||||
objTree.Lock()
|
||||
defer objTree.Unlock()
|
||||
|
||||
if len(request.Changes) != 0 && !s.alreadyHasHeads(objTree, request.Heads) {
|
||||
_, err = objTree.AddRawChanges(ctx, request.Changes...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
fullResponse, err = s.syncClient.CreateFullSyncResponse(objTree, request.Heads, request.SnapshotPath)
|
||||
return err
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return s.syncClient.SendAsync(senderId, fullResponse, replyId)
|
||||
}
|
||||
|
||||
func (s *syncTreeHandler) handleFullSyncResponse(
|
||||
ctx context.Context,
|
||||
senderId string,
|
||||
response *treechangeproto.TreeFullSyncResponse) (err error) {
|
||||
log.With("senderId", senderId).
|
||||
With("heads", response.Heads).
|
||||
With("treeId", s.objTree.ID()).
|
||||
Debug("received full sync response message")
|
||||
objTree := s.objTree
|
||||
if err != nil {
|
||||
log.With("senderId", senderId).
|
||||
With("heads", response.Heads).
|
||||
With("treeId", s.objTree.ID()).
|
||||
Debug("failed to find the tree in full sync response")
|
||||
return
|
||||
}
|
||||
err = func() error {
|
||||
objTree.Lock()
|
||||
defer objTree.Unlock()
|
||||
|
||||
if s.alreadyHasHeads(objTree, response.Heads) {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = objTree.AddRawChanges(ctx, response.Changes...)
|
||||
return err
|
||||
}()
|
||||
log.With("error", err != nil).
|
||||
With("heads", response.Heads).
|
||||
With("treeId", s.objTree.ID()).
|
||||
Debug("finished full sync response")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *syncTreeHandler) alreadyHasHeads(t tree.ObjectTree, heads []string) bool {
|
||||
return slice.UnsortedEquals(t.Heads(), heads) || t.HasChanges(heads...)
|
||||
}
|
||||
@ -1,29 +1,19 @@
|
||||
package syncservice
|
||||
package synctree
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache/mock_cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/mock_syncservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/mock_synctree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree/mock_objecttree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type treeContainer struct {
|
||||
objTree tree.ObjectTree
|
||||
}
|
||||
|
||||
func (t treeContainer) Tree() tree.ObjectTree {
|
||||
return t.objTree
|
||||
}
|
||||
|
||||
type testObjTreeMock struct {
|
||||
*mock_tree.MockObjectTree
|
||||
m sync.Mutex
|
||||
@ -48,28 +38,26 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
|
||||
defer ctrl.Finish()
|
||||
|
||||
ctx := context.Background()
|
||||
spaceId := "spaceId"
|
||||
cacheMock := mock_cache.NewMockTreeCache(ctrl)
|
||||
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
|
||||
syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
|
||||
objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl))
|
||||
|
||||
syncHandler := newSyncHandler(spaceId, cacheMock, syncClientMock)
|
||||
syncHandler := newSyncTreeHandler(objectTreeMock, syncClientMock)
|
||||
log = zap.NewNop().Sugar()
|
||||
|
||||
t.Run("head update non empty all heads added", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
headUpdate := &spacesyncproto.ObjectHeadUpdate{
|
||||
headUpdate := &treechangeproto.TreeHeadUpdate{
|
||||
Heads: []string{"h1"},
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}
|
||||
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "")
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
treeMsg := treechangeproto.WrapHeadUpdate(headUpdate, chWithId)
|
||||
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
|
||||
|
||||
objectTreeMock.EXPECT().
|
||||
ID().AnyTimes().Return(treeId)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"})
|
||||
@ -86,7 +74,7 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
|
||||
HasChanges(gomock.Eq([]string{"h1"})).
|
||||
Return(true)
|
||||
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
@ -94,19 +82,17 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
headUpdate := &spacesyncproto.ObjectHeadUpdate{
|
||||
headUpdate := &treechangeproto.TreeHeadUpdate{
|
||||
Heads: []string{"h1"},
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}
|
||||
fullRequest := &spacesyncproto.ObjectSyncMessage{}
|
||||
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "")
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
treeMsg := treechangeproto.WrapHeadUpdate(headUpdate, chWithId)
|
||||
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
|
||||
fullRequest := &treechangeproto.TreeSyncMessage{}
|
||||
|
||||
objectTreeMock.EXPECT().
|
||||
ID().AnyTimes().Return(treeId)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"})
|
||||
@ -123,11 +109,15 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
|
||||
HasChanges(gomock.Eq([]string{"h1"})).
|
||||
Return(false)
|
||||
syncClientMock.EXPECT().
|
||||
CreateFullSyncRequest(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")).
|
||||
CreateFullSyncRequest(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
|
||||
Return(fullRequest, nil)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"})
|
||||
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest))
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Eq(fullRequest), gomock.Eq(""))
|
||||
|
||||
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
@ -135,23 +125,21 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
headUpdate := &spacesyncproto.ObjectHeadUpdate{
|
||||
headUpdate := &treechangeproto.TreeHeadUpdate{
|
||||
Heads: []string{"h1"},
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}
|
||||
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "")
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
treeMsg := treechangeproto.WrapHeadUpdate(headUpdate, chWithId)
|
||||
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
|
||||
|
||||
objectTreeMock.EXPECT().
|
||||
ID().AnyTimes().Return(treeId)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h1"})
|
||||
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
@ -159,28 +147,30 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
headUpdate := &spacesyncproto.ObjectHeadUpdate{
|
||||
headUpdate := &treechangeproto.TreeHeadUpdate{
|
||||
Heads: []string{"h1"},
|
||||
Changes: nil,
|
||||
SnapshotPath: []string{"h1"},
|
||||
}
|
||||
fullRequest := &spacesyncproto.ObjectSyncMessage{}
|
||||
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "")
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
treeMsg := treechangeproto.WrapHeadUpdate(headUpdate, chWithId)
|
||||
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
|
||||
fullRequest := &treechangeproto.TreeSyncMessage{}
|
||||
|
||||
objectTreeMock.EXPECT().
|
||||
ID().AnyTimes().Return(treeId)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"})
|
||||
syncClientMock.EXPECT().
|
||||
CreateFullSyncRequest(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")).
|
||||
CreateFullSyncRequest(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
|
||||
Return(fullRequest, nil)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"})
|
||||
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest))
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Eq(fullRequest), gomock.Eq(""))
|
||||
|
||||
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
@ -188,24 +178,21 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
headUpdate := &spacesyncproto.ObjectHeadUpdate{
|
||||
headUpdate := &treechangeproto.TreeHeadUpdate{
|
||||
Heads: []string{"h1"},
|
||||
Changes: nil,
|
||||
SnapshotPath: []string{"h1"},
|
||||
}
|
||||
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "")
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
treeMsg := treechangeproto.WrapHeadUpdate(headUpdate, chWithId)
|
||||
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
|
||||
|
||||
objectTreeMock.EXPECT().
|
||||
ID().AnyTimes().Return(treeId)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h1"})
|
||||
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
@ -215,29 +202,26 @@ func TestSyncHandler_HandleFullSyncRequest(t *testing.T) {
|
||||
defer ctrl.Finish()
|
||||
|
||||
ctx := context.Background()
|
||||
spaceId := "spaceId"
|
||||
cacheMock := mock_cache.NewMockTreeCache(ctrl)
|
||||
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
|
||||
syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
|
||||
objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl))
|
||||
|
||||
syncHandler := newSyncHandler(spaceId, cacheMock, syncClientMock)
|
||||
syncHandler := newSyncTreeHandler(objectTreeMock, syncClientMock)
|
||||
log = zap.NewNop().Sugar()
|
||||
t.Run("full sync request with change", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{
|
||||
fullSyncRequest := &treechangeproto.TreeFullSyncRequest{
|
||||
Heads: []string{"h1"},
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}, chWithId, treeId, "")
|
||||
fullRequest := &spacesyncproto.ObjectSyncMessage{}
|
||||
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
}
|
||||
treeMsg := treechangeproto.WrapFullRequest(fullSyncRequest, chWithId)
|
||||
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
|
||||
fullResponse := &treechangeproto.TreeSyncMessage{}
|
||||
objectTreeMock.EXPECT().
|
||||
ID().AnyTimes().Return(treeId)
|
||||
objectTreeMock.EXPECT().Header().Return(nil)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"})
|
||||
@ -248,11 +232,10 @@ func TestSyncHandler_HandleFullSyncRequest(t *testing.T) {
|
||||
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
|
||||
Return(tree.AddResult{}, nil)
|
||||
syncClientMock.EXPECT().
|
||||
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")).
|
||||
Return(fullRequest, nil)
|
||||
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest))
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
|
||||
Return(fullResponse, nil)
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Eq(fullResponse), gomock.Eq(""))
|
||||
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
@ -260,72 +243,76 @@ func TestSyncHandler_HandleFullSyncRequest(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{
|
||||
Heads: []string{"h2"},
|
||||
fullSyncRequest := &treechangeproto.TreeFullSyncRequest{
|
||||
Heads: []string{"h1"},
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||
SnapshotPath: []string{"h2"},
|
||||
}, chWithId, treeId, "")
|
||||
fullRequest := &spacesyncproto.ObjectSyncMessage{}
|
||||
SnapshotPath: []string{"h1"},
|
||||
}
|
||||
treeMsg := treechangeproto.WrapFullRequest(fullSyncRequest, chWithId)
|
||||
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
|
||||
fullResponse := &treechangeproto.TreeSyncMessage{}
|
||||
objectTreeMock.EXPECT().
|
||||
ID().AnyTimes().Return(treeId)
|
||||
objectTreeMock.EXPECT().Header().Return(nil)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h1"})
|
||||
syncClientMock.EXPECT().
|
||||
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
|
||||
Return(fullResponse, nil)
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Eq(fullResponse), gomock.Eq(""))
|
||||
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
t.Run("full sync request without change but with reply id", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
replyId := "replyId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
fullSyncRequest := &treechangeproto.TreeFullSyncRequest{
|
||||
Heads: []string{"h1"},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}
|
||||
treeMsg := treechangeproto.WrapFullRequest(fullSyncRequest, chWithId)
|
||||
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, replyId)
|
||||
fullResponse := &treechangeproto.TreeSyncMessage{}
|
||||
objectTreeMock.EXPECT().
|
||||
ID().AnyTimes().Return(treeId)
|
||||
objectTreeMock.EXPECT().Header().Return(nil)
|
||||
syncClientMock.EXPECT().
|
||||
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
|
||||
Return(fullResponse, nil)
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Eq(fullResponse), gomock.Eq(replyId))
|
||||
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("full sync request with add raw changes error", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
fullSyncRequest := &treechangeproto.TreeFullSyncRequest{
|
||||
Heads: []string{"h1"},
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}
|
||||
treeMsg := treechangeproto.WrapFullRequest(fullSyncRequest, chWithId)
|
||||
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
|
||||
objectTreeMock.EXPECT().
|
||||
ID().AnyTimes().Return(treeId)
|
||||
objectTreeMock.EXPECT().Header().Return(nil)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"})
|
||||
syncClientMock.EXPECT().
|
||||
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h2"}), gomock.Eq([]string{"h2"}), gomock.Eq("")).
|
||||
Return(fullRequest, nil)
|
||||
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest))
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("full sync request without change", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{
|
||||
Heads: []string{"h1"},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}, chWithId, treeId, "")
|
||||
fullRequest := &spacesyncproto.ObjectSyncMessage{}
|
||||
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
syncClientMock.EXPECT().
|
||||
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")).
|
||||
Return(fullRequest, nil)
|
||||
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest))
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("full sync request with get tree error", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{
|
||||
Heads: []string{"h1"},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}, chWithId, treeId, "")
|
||||
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{}, fmt.Errorf("some"))
|
||||
|
||||
syncClientMock.EXPECT().
|
||||
SendAsync(gomock.Eq([]string{senderId}), gomock.Any())
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
objectTreeMock.EXPECT().
|
||||
HasChanges(gomock.Eq([]string{"h1"})).
|
||||
Return(false)
|
||||
objectTreeMock.EXPECT().
|
||||
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
|
||||
Return(tree.AddResult{}, fmt.Errorf(""))
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Any(), gomock.Eq(""))
|
||||
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
@ -335,28 +322,25 @@ func TestSyncHandler_HandleFullSyncResponse(t *testing.T) {
|
||||
defer ctrl.Finish()
|
||||
|
||||
ctx := context.Background()
|
||||
spaceId := "spaceId"
|
||||
cacheMock := mock_cache.NewMockTreeCache(ctrl)
|
||||
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
|
||||
syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
|
||||
objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl))
|
||||
|
||||
syncHandler := newSyncHandler(spaceId, cacheMock, syncClientMock)
|
||||
syncHandler := newSyncTreeHandler(objectTreeMock, syncClientMock)
|
||||
log = zap.NewNop().Sugar()
|
||||
|
||||
t.Run("full sync response with change", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
replyId := "replyId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
msg := spacesyncproto.WrapFullResponse(&spacesyncproto.ObjectFullSyncResponse{
|
||||
fullSyncResponse := &treechangeproto.TreeFullSyncResponse{
|
||||
Heads: []string{"h1"},
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}, chWithId, treeId, "")
|
||||
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
}
|
||||
treeMsg := treechangeproto.WrapFullResponse(fullSyncResponse, chWithId)
|
||||
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, replyId)
|
||||
objectTreeMock.EXPECT().ID().AnyTimes().Return(treeId)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"})
|
||||
@ -367,31 +351,28 @@ func TestSyncHandler_HandleFullSyncResponse(t *testing.T) {
|
||||
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
|
||||
Return(tree.AddResult{}, nil)
|
||||
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("full sync response same heads", func(t *testing.T) {
|
||||
t.Run("full sync response with same heads", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
replyId := "replyId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
msg := spacesyncproto.WrapFullResponse(&spacesyncproto.ObjectFullSyncResponse{
|
||||
fullSyncResponse := &treechangeproto.TreeFullSyncResponse{
|
||||
Heads: []string{"h1"},
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}, chWithId, treeId, "")
|
||||
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
}
|
||||
treeMsg := treechangeproto.WrapFullResponse(fullSyncResponse, chWithId)
|
||||
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, replyId)
|
||||
objectTreeMock.EXPECT().ID().AnyTimes().Return(treeId)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h1"})
|
||||
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
@ -5,9 +5,9 @@
|
||||
package mock_updatelistener
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
reflect "reflect"
|
||||
|
||||
tree "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
|
||||
@ -1,43 +1,43 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache (interfaces: TreeCache)
|
||||
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter (interfaces: TreeGetter)
|
||||
|
||||
// Package mock_cache is a generated GoMock package.
|
||||
package mock_cache
|
||||
// Package mock_treegetter is a generated GoMock package.
|
||||
package mock_treegetter
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
app "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
cache "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
tree "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockTreeCache is a mock of TreeCache interface.
|
||||
type MockTreeCache struct {
|
||||
// MockTreeGetter is a mock of TreeGetter interface.
|
||||
type MockTreeGetter struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockTreeCacheMockRecorder
|
||||
recorder *MockTreeGetterMockRecorder
|
||||
}
|
||||
|
||||
// MockTreeCacheMockRecorder is the mock recorder for MockTreeCache.
|
||||
type MockTreeCacheMockRecorder struct {
|
||||
mock *MockTreeCache
|
||||
// MockTreeGetterMockRecorder is the mock recorder for MockTreeGetter.
|
||||
type MockTreeGetterMockRecorder struct {
|
||||
mock *MockTreeGetter
|
||||
}
|
||||
|
||||
// NewMockTreeCache creates a new mock instance.
|
||||
func NewMockTreeCache(ctrl *gomock.Controller) *MockTreeCache {
|
||||
mock := &MockTreeCache{ctrl: ctrl}
|
||||
mock.recorder = &MockTreeCacheMockRecorder{mock}
|
||||
// NewMockTreeGetter creates a new mock instance.
|
||||
func NewMockTreeGetter(ctrl *gomock.Controller) *MockTreeGetter {
|
||||
mock := &MockTreeGetter{ctrl: ctrl}
|
||||
mock.recorder = &MockTreeGetterMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockTreeCache) EXPECT() *MockTreeCacheMockRecorder {
|
||||
func (m *MockTreeGetter) EXPECT() *MockTreeGetterMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Close mocks base method.
|
||||
func (m *MockTreeCache) Close(arg0 context.Context) error {
|
||||
func (m *MockTreeGetter) Close(arg0 context.Context) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Close", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -45,28 +45,28 @@ func (m *MockTreeCache) Close(arg0 context.Context) error {
|
||||
}
|
||||
|
||||
// Close indicates an expected call of Close.
|
||||
func (mr *MockTreeCacheMockRecorder) Close(arg0 interface{}) *gomock.Call {
|
||||
func (mr *MockTreeGetterMockRecorder) Close(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockTreeCache)(nil).Close), arg0)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockTreeGetter)(nil).Close), arg0)
|
||||
}
|
||||
|
||||
// GetTree mocks base method.
|
||||
func (m *MockTreeCache) GetTree(arg0 context.Context, arg1, arg2 string) (cache.TreeResult, error) {
|
||||
func (m *MockTreeGetter) GetTree(arg0 context.Context, arg1, arg2 string) (tree.ObjectTree, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetTree", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(cache.TreeResult)
|
||||
ret0, _ := ret[0].(tree.ObjectTree)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetTree indicates an expected call of GetTree.
|
||||
func (mr *MockTreeCacheMockRecorder) GetTree(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
func (mr *MockTreeGetterMockRecorder) GetTree(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTree", reflect.TypeOf((*MockTreeCache)(nil).GetTree), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTree", reflect.TypeOf((*MockTreeGetter)(nil).GetTree), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// Init mocks base method.
|
||||
func (m *MockTreeCache) Init(arg0 *app.App) error {
|
||||
func (m *MockTreeGetter) Init(arg0 *app.App) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Init", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -74,13 +74,13 @@ func (m *MockTreeCache) Init(arg0 *app.App) error {
|
||||
}
|
||||
|
||||
// Init indicates an expected call of Init.
|
||||
func (mr *MockTreeCacheMockRecorder) Init(arg0 interface{}) *gomock.Call {
|
||||
func (mr *MockTreeGetterMockRecorder) Init(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockTreeCache)(nil).Init), arg0)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockTreeGetter)(nil).Init), arg0)
|
||||
}
|
||||
|
||||
// Name mocks base method.
|
||||
func (m *MockTreeCache) Name() string {
|
||||
func (m *MockTreeGetter) Name() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Name")
|
||||
ret0, _ := ret[0].(string)
|
||||
@ -88,13 +88,13 @@ func (m *MockTreeCache) Name() string {
|
||||
}
|
||||
|
||||
// Name indicates an expected call of Name.
|
||||
func (mr *MockTreeCacheMockRecorder) Name() *gomock.Call {
|
||||
func (mr *MockTreeGetterMockRecorder) Name() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockTreeCache)(nil).Name))
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockTreeGetter)(nil).Name))
|
||||
}
|
||||
|
||||
// Run mocks base method.
|
||||
func (m *MockTreeCache) Run(arg0 context.Context) error {
|
||||
func (m *MockTreeGetter) Run(arg0 context.Context) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Run", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -102,7 +102,7 @@ func (m *MockTreeCache) Run(arg0 context.Context) error {
|
||||
}
|
||||
|
||||
// Run indicates an expected call of Run.
|
||||
func (mr *MockTreeCacheMockRecorder) Run(arg0 interface{}) *gomock.Call {
|
||||
func (mr *MockTreeGetterMockRecorder) Run(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockTreeCache)(nil).Run), arg0)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockTreeGetter)(nil).Run), arg0)
|
||||
}
|
||||
18
common/commonspace/treegetter/treegetter.go
Normal file
18
common/commonspace/treegetter/treegetter.go
Normal file
@ -0,0 +1,18 @@
|
||||
//go:generate mockgen -destination mock_treegetter/mock_treegetter.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter TreeGetter
|
||||
package treegetter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
)
|
||||
|
||||
const CName = "commonspace.treeGetter"
|
||||
|
||||
var ErrSpaceNotFound = errors.New("space not found")
|
||||
|
||||
type TreeGetter interface {
|
||||
app.ComponentRunnable
|
||||
GetTree(ctx context.Context, spaceId, treeId string) (tree.ObjectTree, error)
|
||||
}
|
||||
@ -54,3 +54,7 @@ func (c Config) GetGRPCServer() GrpcServer {
|
||||
func (c Config) GetAccount() Account {
|
||||
return c.Account
|
||||
}
|
||||
|
||||
func (c Config) GetMetric() Metric {
|
||||
return c.Metric
|
||||
}
|
||||
|
||||
@ -54,7 +54,6 @@ func (p *pool) Init(a *app.App) (err error) {
|
||||
ocache.WithLogger(log.Sugar()),
|
||||
ocache.WithGCPeriod(time.Minute),
|
||||
ocache.WithTTL(time.Minute*5),
|
||||
ocache.WithRefCounter(false),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -63,20 +63,17 @@ message ACLUserAdd {
|
||||
ACLUserPermissions permissions = 4;
|
||||
}
|
||||
|
||||
// signing accept key
|
||||
// rsa encryption key -> read keys
|
||||
|
||||
// accept key, encrypt key, invite id
|
||||
// GetSpace(id) -> ... (space header + acl root) -> diff
|
||||
// Join(ACLJoinRecord) -> Ok
|
||||
|
||||
//
|
||||
|
||||
message ACLUserInvite {
|
||||
bytes acceptPublicKey = 1;
|
||||
// TODO: change to read key
|
||||
bytes encryptPublicKey = 2;
|
||||
repeated bytes encryptedReadKeys = 3;
|
||||
ACLUserPermissions permissions = 4;
|
||||
// TODO: either derive inviteId from pub keys or think if it is possible to just use ACL record id
|
||||
string inviteId = 5;
|
||||
}
|
||||
|
||||
|
||||
@ -5,10 +5,10 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||
aclrecordproto2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/common"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/encryptionkey"
|
||||
signingkey2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/symmetric"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"go.uber.org/zap"
|
||||
@ -30,17 +30,17 @@ var ErrIncorrectRoot = errors.New("incorrect root")
|
||||
|
||||
type UserPermissionPair struct {
|
||||
Identity string
|
||||
Permission aclrecordproto2.ACLUserPermissions
|
||||
Permission aclrecordproto.ACLUserPermissions
|
||||
}
|
||||
|
||||
type ACLState struct {
|
||||
id string
|
||||
currentReadKeyHash uint64
|
||||
userReadKeys map[uint64]*symmetric.Key
|
||||
userStates map[string]*aclrecordproto2.ACLUserState
|
||||
userInvites map[string]*aclrecordproto2.ACLUserInvite
|
||||
userStates map[string]*aclrecordproto.ACLUserState
|
||||
userInvites map[string]*aclrecordproto.ACLUserInvite
|
||||
encryptionKey encryptionkey.PrivKey
|
||||
signingKey signingkey2.PrivKey
|
||||
signingKey signingkey.PrivKey
|
||||
|
||||
identity string
|
||||
permissionsAtRecord map[string][]UserPermissionPair
|
||||
@ -50,9 +50,9 @@ type ACLState struct {
|
||||
|
||||
func newACLStateWithKeys(
|
||||
id string,
|
||||
signingKey signingkey2.PrivKey,
|
||||
signingKey signingkey.PrivKey,
|
||||
encryptionKey encryptionkey.PrivKey) (*ACLState, error) {
|
||||
identity, err := signingKey.Raw()
|
||||
identity, err := signingKey.GetPublic().Raw()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -62,8 +62,8 @@ func newACLStateWithKeys(
|
||||
signingKey: signingKey,
|
||||
encryptionKey: encryptionKey,
|
||||
userReadKeys: make(map[uint64]*symmetric.Key),
|
||||
userStates: make(map[string]*aclrecordproto2.ACLUserState),
|
||||
userInvites: make(map[string]*aclrecordproto2.ACLUserInvite),
|
||||
userStates: make(map[string]*aclrecordproto.ACLUserState),
|
||||
userInvites: make(map[string]*aclrecordproto.ACLUserInvite),
|
||||
permissionsAtRecord: make(map[string][]UserPermissionPair),
|
||||
}, nil
|
||||
}
|
||||
@ -72,8 +72,8 @@ func newACLState(id string) *ACLState {
|
||||
return &ACLState{
|
||||
id: id,
|
||||
userReadKeys: make(map[uint64]*symmetric.Key),
|
||||
userStates: make(map[string]*aclrecordproto2.ACLUserState),
|
||||
userInvites: make(map[string]*aclrecordproto2.ACLUserInvite),
|
||||
userStates: make(map[string]*aclrecordproto.ACLUserState),
|
||||
userInvites: make(map[string]*aclrecordproto.ACLUserInvite),
|
||||
permissionsAtRecord: make(map[string][]UserPermissionPair),
|
||||
}
|
||||
}
|
||||
@ -111,16 +111,19 @@ func (st *ACLState) PermissionsAtRecord(id string, identity string) (UserPermiss
|
||||
|
||||
func (st *ACLState) applyRecord(record *ACLRecord) (err error) {
|
||||
if record.Id == st.id {
|
||||
root, ok := record.Model.(*aclrecordproto2.ACLRoot)
|
||||
root, ok := record.Model.(*aclrecordproto.ACLRoot)
|
||||
if !ok {
|
||||
return ErrIncorrectRoot
|
||||
}
|
||||
st.permissionsAtRecord[record.Id] = []UserPermissionPair{
|
||||
{Identity: string(root.Identity), Permission: aclrecordproto.ACLUserPermissions_Admin},
|
||||
}
|
||||
return st.applyRoot(root)
|
||||
}
|
||||
aclData := &aclrecordproto2.ACLData{}
|
||||
aclData := &aclrecordproto.ACLData{}
|
||||
|
||||
if record.Model != nil {
|
||||
aclData = record.Model.(*aclrecordproto2.ACLData)
|
||||
aclData = record.Model.(*aclrecordproto.ACLData)
|
||||
} else {
|
||||
err = proto.Unmarshal(record.Data, aclData)
|
||||
if err != nil {
|
||||
@ -148,8 +151,8 @@ func (st *ACLState) applyRecord(record *ACLRecord) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *ACLState) applyRoot(root *aclrecordproto2.ACLRoot) (err error) {
|
||||
if st.signingKey != nil && st.encryptionKey != nil {
|
||||
func (st *ACLState) applyRoot(root *aclrecordproto.ACLRoot) (err error) {
|
||||
if st.signingKey != nil && st.encryptionKey != nil && st.identity == string(root.Identity) {
|
||||
err = st.saveReadKeyFromRoot(root)
|
||||
if err != nil {
|
||||
return
|
||||
@ -157,16 +160,16 @@ func (st *ACLState) applyRoot(root *aclrecordproto2.ACLRoot) (err error) {
|
||||
}
|
||||
|
||||
// adding user to the list
|
||||
userState := &aclrecordproto2.ACLUserState{
|
||||
userState := &aclrecordproto.ACLUserState{
|
||||
Identity: root.Identity,
|
||||
EncryptionKey: root.EncryptionKey,
|
||||
Permissions: aclrecordproto2.ACLUserPermissions_Admin,
|
||||
Permissions: aclrecordproto.ACLUserPermissions_Admin,
|
||||
}
|
||||
st.userStates[string(root.Identity)] = userState
|
||||
return
|
||||
}
|
||||
|
||||
func (st *ACLState) saveReadKeyFromRoot(root *aclrecordproto2.ACLRoot) (err error) {
|
||||
func (st *ACLState) saveReadKeyFromRoot(root *aclrecordproto.ACLRoot) (err error) {
|
||||
var readKey *symmetric.Key
|
||||
if len(root.GetDerivationScheme()) != 0 {
|
||||
var encPubKey []byte
|
||||
@ -175,7 +178,7 @@ func (st *ACLState) saveReadKeyFromRoot(root *aclrecordproto2.ACLRoot) (err erro
|
||||
return
|
||||
}
|
||||
|
||||
readKey, err = aclrecordproto2.ACLReadKeyDerive([]byte(st.identity), encPubKey)
|
||||
readKey, err = aclrecordproto.ACLReadKeyDerive([]byte(st.identity), encPubKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -199,7 +202,7 @@ func (st *ACLState) saveReadKeyFromRoot(root *aclrecordproto2.ACLRoot) (err erro
|
||||
return
|
||||
}
|
||||
|
||||
func (st *ACLState) applyChangeData(changeData *aclrecordproto2.ACLData, hash uint64, identity []byte) (err error) {
|
||||
func (st *ACLState) applyChangeData(changeData *aclrecordproto.ACLData, hash uint64, identity []byte) (err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
return
|
||||
@ -214,7 +217,7 @@ func (st *ACLState) applyChangeData(changeData *aclrecordproto2.ACLData, hash ui
|
||||
return
|
||||
}
|
||||
|
||||
if !st.hasPermission(identity, aclrecordproto2.ACLUserPermissions_Admin) {
|
||||
if !st.hasPermission(identity, aclrecordproto.ACLUserPermissions_Admin) {
|
||||
err = fmt.Errorf("user %s must have admin permissions", identity)
|
||||
return
|
||||
}
|
||||
@ -230,7 +233,7 @@ func (st *ACLState) applyChangeData(changeData *aclrecordproto2.ACLData, hash ui
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *ACLState) applyChangeContent(ch *aclrecordproto2.ACLContentValue) error {
|
||||
func (st *ACLState) applyChangeContent(ch *aclrecordproto.ACLContentValue) error {
|
||||
switch {
|
||||
case ch.GetUserPermissionChange() != nil:
|
||||
return st.applyUserPermissionChange(ch.GetUserPermissionChange())
|
||||
@ -247,7 +250,7 @@ func (st *ACLState) applyChangeContent(ch *aclrecordproto2.ACLContentValue) erro
|
||||
}
|
||||
}
|
||||
|
||||
func (st *ACLState) applyUserPermissionChange(ch *aclrecordproto2.ACLUserPermissionChange) error {
|
||||
func (st *ACLState) applyUserPermissionChange(ch *aclrecordproto.ACLUserPermissionChange) error {
|
||||
chIdentity := string(ch.Identity)
|
||||
state, exists := st.userStates[chIdentity]
|
||||
if !exists {
|
||||
@ -258,12 +261,12 @@ func (st *ACLState) applyUserPermissionChange(ch *aclrecordproto2.ACLUserPermiss
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *ACLState) applyUserInvite(ch *aclrecordproto2.ACLUserInvite) error {
|
||||
func (st *ACLState) applyUserInvite(ch *aclrecordproto.ACLUserInvite) error {
|
||||
st.userInvites[ch.InviteId] = ch
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *ACLState) applyUserJoin(ch *aclrecordproto2.ACLUserJoin) error {
|
||||
func (st *ACLState) applyUserJoin(ch *aclrecordproto.ACLUserJoin) error {
|
||||
invite, exists := st.userInvites[ch.InviteId]
|
||||
if !exists {
|
||||
return fmt.Errorf("no such invite with id %s", ch.InviteId)
|
||||
@ -276,12 +279,12 @@ func (st *ACLState) applyUserJoin(ch *aclrecordproto2.ACLUserJoin) error {
|
||||
|
||||
// validating signature
|
||||
signature := ch.GetAcceptSignature()
|
||||
verificationKey, err := signingkey2.NewSigningEd25519PubKeyFromBytes(invite.AcceptPublicKey)
|
||||
verificationKey, err := signingkey.NewSigningEd25519PubKeyFromBytes(invite.AcceptPublicKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("public key verifying invite accepts is given in incorrect format: %v", err)
|
||||
}
|
||||
|
||||
res, err := verificationKey.(signingkey2.PubKey).Verify(ch.Identity, signature)
|
||||
res, err := verificationKey.(signingkey.PubKey).Verify(ch.Identity, signature)
|
||||
if err != nil {
|
||||
return fmt.Errorf("verification returned error: %w", err)
|
||||
}
|
||||
@ -302,7 +305,7 @@ func (st *ACLState) applyUserJoin(ch *aclrecordproto2.ACLUserJoin) error {
|
||||
}
|
||||
|
||||
// adding user to the list
|
||||
userState := &aclrecordproto2.ACLUserState{
|
||||
userState := &aclrecordproto.ACLUserState{
|
||||
Identity: ch.Identity,
|
||||
EncryptionKey: ch.EncryptionKey,
|
||||
Permissions: invite.Permissions,
|
||||
@ -311,13 +314,13 @@ func (st *ACLState) applyUserJoin(ch *aclrecordproto2.ACLUserJoin) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *ACLState) applyUserAdd(ch *aclrecordproto2.ACLUserAdd) error {
|
||||
func (st *ACLState) applyUserAdd(ch *aclrecordproto.ACLUserAdd) error {
|
||||
chIdentity := string(ch.Identity)
|
||||
if _, exists := st.userStates[chIdentity]; exists {
|
||||
return ErrUserAlreadyExists
|
||||
}
|
||||
|
||||
st.userStates[chIdentity] = &aclrecordproto2.ACLUserState{
|
||||
st.userStates[chIdentity] = &aclrecordproto.ACLUserState{
|
||||
Identity: ch.Identity,
|
||||
EncryptionKey: ch.EncryptionKey,
|
||||
Permissions: ch.Permissions,
|
||||
@ -337,7 +340,7 @@ func (st *ACLState) applyUserAdd(ch *aclrecordproto2.ACLUserAdd) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *ACLState) applyUserRemove(ch *aclrecordproto2.ACLUserRemove) error {
|
||||
func (st *ACLState) applyUserRemove(ch *aclrecordproto.ACLUserRemove) error {
|
||||
chIdentity := string(ch.Identity)
|
||||
if chIdentity == st.identity {
|
||||
return ErrDocumentForbidden
|
||||
@ -381,7 +384,7 @@ func (st *ACLState) decryptReadKeyAndHash(msg []byte) (*symmetric.Key, uint64, e
|
||||
return key, hasher.Sum64(), nil
|
||||
}
|
||||
|
||||
func (st *ACLState) hasPermission(identity []byte, permission aclrecordproto2.ACLUserPermissions) bool {
|
||||
func (st *ACLState) hasPermission(identity []byte, permission aclrecordproto.ACLUserPermissions) bool {
|
||||
state, exists := st.userStates[string(identity)]
|
||||
if !exists {
|
||||
return false
|
||||
@ -390,17 +393,17 @@ func (st *ACLState) hasPermission(identity []byte, permission aclrecordproto2.AC
|
||||
return state.Permissions == permission
|
||||
}
|
||||
|
||||
func (st *ACLState) isUserJoin(data *aclrecordproto2.ACLData) bool {
|
||||
func (st *ACLState) isUserJoin(data *aclrecordproto.ACLData) bool {
|
||||
// if we have a UserJoin, then it should always be the first one applied
|
||||
return data.GetAclContent() != nil && data.GetAclContent()[0].GetUserJoin() != nil
|
||||
}
|
||||
|
||||
func (st *ACLState) isUserAdd(data *aclrecordproto2.ACLData, identity []byte) bool {
|
||||
func (st *ACLState) isUserAdd(data *aclrecordproto.ACLData, identity []byte) bool {
|
||||
// if we have a UserAdd, then it should always be the first one applied
|
||||
userAdd := data.GetAclContent()[0].GetUserAdd()
|
||||
return data.GetAclContent() != nil && userAdd != nil && bytes.Compare(userAdd.GetIdentity(), identity) == 0
|
||||
}
|
||||
|
||||
func (st *ACLState) GetUserStates() map[string]*aclrecordproto2.ACLUserState {
|
||||
func (st *ACLState) GetUserStates() map[string]*aclrecordproto.ACLUserState {
|
||||
return st.userStates
|
||||
}
|
||||
|
||||
@ -5,10 +5,10 @@
|
||||
package mock_list
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||
list2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list"
|
||||
reflect "reflect"
|
||||
|
||||
aclrecordproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||
list "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
@ -36,10 +36,10 @@ func (m *MockACLList) EXPECT() *MockACLListMockRecorder {
|
||||
}
|
||||
|
||||
// ACLState mocks base method.
|
||||
func (m *MockACLList) ACLState() *list2.ACLState {
|
||||
func (m *MockACLList) ACLState() *list.ACLState {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ACLState")
|
||||
ret0, _ := ret[0].(*list2.ACLState)
|
||||
ret0, _ := ret[0].(*list.ACLState)
|
||||
return ret0
|
||||
}
|
||||
|
||||
@ -64,10 +64,10 @@ func (mr *MockACLListMockRecorder) Close() *gomock.Call {
|
||||
}
|
||||
|
||||
// Get mocks base method.
|
||||
func (m *MockACLList) Get(arg0 string) (*list2.ACLRecord, error) {
|
||||
func (m *MockACLList) Get(arg0 string) (*list.ACLRecord, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Get", arg0)
|
||||
ret0, _ := ret[0].(*list2.ACLRecord)
|
||||
ret0, _ := ret[0].(*list.ACLRecord)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@ -79,10 +79,10 @@ func (mr *MockACLListMockRecorder) Get(arg0 interface{}) *gomock.Call {
|
||||
}
|
||||
|
||||
// Head mocks base method.
|
||||
func (m *MockACLList) Head() *list2.ACLRecord {
|
||||
func (m *MockACLList) Head() *list.ACLRecord {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Head")
|
||||
ret0, _ := ret[0].(*list2.ACLRecord)
|
||||
ret0, _ := ret[0].(*list.ACLRecord)
|
||||
return ret0
|
||||
}
|
||||
|
||||
@ -122,7 +122,7 @@ func (mr *MockACLListMockRecorder) IsAfter(arg0, arg1 interface{}) *gomock.Call
|
||||
}
|
||||
|
||||
// Iterate mocks base method.
|
||||
func (m *MockACLList) Iterate(arg0 func(*list2.ACLRecord) bool) {
|
||||
func (m *MockACLList) Iterate(arg0 func(*list.ACLRecord) bool) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Iterate", arg0)
|
||||
}
|
||||
@ -134,7 +134,7 @@ func (mr *MockACLListMockRecorder) Iterate(arg0 interface{}) *gomock.Call {
|
||||
}
|
||||
|
||||
// IterateFrom mocks base method.
|
||||
func (m *MockACLList) IterateFrom(arg0 string, arg1 func(*list2.ACLRecord) bool) {
|
||||
func (m *MockACLList) IterateFrom(arg0 string, arg1 func(*list.ACLRecord) bool) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "IterateFrom", arg0, arg1)
|
||||
}
|
||||
@ -182,10 +182,10 @@ func (mr *MockACLListMockRecorder) RUnlock() *gomock.Call {
|
||||
}
|
||||
|
||||
// Records mocks base method.
|
||||
func (m *MockACLList) Records() []*list2.ACLRecord {
|
||||
func (m *MockACLList) Records() []*list.ACLRecord {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Records")
|
||||
ret0, _ := ret[0].([]*list2.ACLRecord)
|
||||
ret0, _ := ret[0].([]*list.ACLRecord)
|
||||
return ret0
|
||||
}
|
||||
|
||||
|
||||
@ -6,10 +6,10 @@ package mock_storage
|
||||
|
||||
import (
|
||||
context "context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
reflect "reflect"
|
||||
|
||||
aclrecordproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||
treechangeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
|
||||
@ -22,61 +22,25 @@ var _ = math.Inf
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type PlainTextChange struct {
|
||||
}
|
||||
|
||||
func (m *PlainTextChange) Reset() { *m = PlainTextChange{} }
|
||||
func (m *PlainTextChange) String() string { return proto.CompactTextString(m) }
|
||||
func (*PlainTextChange) ProtoMessage() {}
|
||||
func (*PlainTextChange) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_37f33c266ada4318, []int{0}
|
||||
}
|
||||
func (m *PlainTextChange) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *PlainTextChange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_PlainTextChange.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *PlainTextChange) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_PlainTextChange.Merge(m, src)
|
||||
}
|
||||
func (m *PlainTextChange) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *PlainTextChange) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_PlainTextChange.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_PlainTextChange proto.InternalMessageInfo
|
||||
|
||||
type PlainTextChange_Content struct {
|
||||
type TextContent struct {
|
||||
// Types that are valid to be assigned to Value:
|
||||
//
|
||||
// *PlainTextChange_Content_TextAppend
|
||||
Value isPlainTextChange_Content_Value `protobuf_oneof:"value"`
|
||||
// *TextContent_TextAppend
|
||||
Value isTextContent_Value `protobuf_oneof:"value"`
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Content) Reset() { *m = PlainTextChange_Content{} }
|
||||
func (m *PlainTextChange_Content) String() string { return proto.CompactTextString(m) }
|
||||
func (*PlainTextChange_Content) ProtoMessage() {}
|
||||
func (*PlainTextChange_Content) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_37f33c266ada4318, []int{0, 0}
|
||||
func (m *TextContent) Reset() { *m = TextContent{} }
|
||||
func (m *TextContent) String() string { return proto.CompactTextString(m) }
|
||||
func (*TextContent) ProtoMessage() {}
|
||||
func (*TextContent) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_37f33c266ada4318, []int{0}
|
||||
}
|
||||
func (m *PlainTextChange_Content) XXX_Unmarshal(b []byte) error {
|
||||
func (m *TextContent) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *PlainTextChange_Content) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
func (m *TextContent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_PlainTextChange_Content.Marshal(b, m, deterministic)
|
||||
return xxx_messageInfo_TextContent.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
@ -86,67 +50,67 @@ func (m *PlainTextChange_Content) XXX_Marshal(b []byte, deterministic bool) ([]b
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *PlainTextChange_Content) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_PlainTextChange_Content.Merge(m, src)
|
||||
func (m *TextContent) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_TextContent.Merge(m, src)
|
||||
}
|
||||
func (m *PlainTextChange_Content) XXX_Size() int {
|
||||
func (m *TextContent) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *PlainTextChange_Content) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_PlainTextChange_Content.DiscardUnknown(m)
|
||||
func (m *TextContent) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_TextContent.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_PlainTextChange_Content proto.InternalMessageInfo
|
||||
var xxx_messageInfo_TextContent proto.InternalMessageInfo
|
||||
|
||||
type isPlainTextChange_Content_Value interface {
|
||||
isPlainTextChange_Content_Value()
|
||||
type isTextContent_Value interface {
|
||||
isTextContent_Value()
|
||||
MarshalTo([]byte) (int, error)
|
||||
Size() int
|
||||
}
|
||||
|
||||
type PlainTextChange_Content_TextAppend struct {
|
||||
TextAppend *PlainTextChange_TextAppend `protobuf:"bytes,1,opt,name=textAppend,proto3,oneof" json:"textAppend,omitempty"`
|
||||
type TextContent_TextAppend struct {
|
||||
TextAppend *TextAppend `protobuf:"bytes,1,opt,name=textAppend,proto3,oneof" json:"textAppend,omitempty"`
|
||||
}
|
||||
|
||||
func (*PlainTextChange_Content_TextAppend) isPlainTextChange_Content_Value() {}
|
||||
func (*TextContent_TextAppend) isTextContent_Value() {}
|
||||
|
||||
func (m *PlainTextChange_Content) GetValue() isPlainTextChange_Content_Value {
|
||||
func (m *TextContent) GetValue() isTextContent_Value {
|
||||
if m != nil {
|
||||
return m.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Content) GetTextAppend() *PlainTextChange_TextAppend {
|
||||
if x, ok := m.GetValue().(*PlainTextChange_Content_TextAppend); ok {
|
||||
func (m *TextContent) GetTextAppend() *TextAppend {
|
||||
if x, ok := m.GetValue().(*TextContent_TextAppend); ok {
|
||||
return x.TextAppend
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// XXX_OneofWrappers is for the internal use of the proto package.
|
||||
func (*PlainTextChange_Content) XXX_OneofWrappers() []interface{} {
|
||||
func (*TextContent) XXX_OneofWrappers() []interface{} {
|
||||
return []interface{}{
|
||||
(*PlainTextChange_Content_TextAppend)(nil),
|
||||
(*TextContent_TextAppend)(nil),
|
||||
}
|
||||
}
|
||||
|
||||
type PlainTextChange_TextAppend struct {
|
||||
type TextAppend struct {
|
||||
Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"`
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_TextAppend) Reset() { *m = PlainTextChange_TextAppend{} }
|
||||
func (m *PlainTextChange_TextAppend) String() string { return proto.CompactTextString(m) }
|
||||
func (*PlainTextChange_TextAppend) ProtoMessage() {}
|
||||
func (*PlainTextChange_TextAppend) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_37f33c266ada4318, []int{0, 1}
|
||||
func (m *TextAppend) Reset() { *m = TextAppend{} }
|
||||
func (m *TextAppend) String() string { return proto.CompactTextString(m) }
|
||||
func (*TextAppend) ProtoMessage() {}
|
||||
func (*TextAppend) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_37f33c266ada4318, []int{1}
|
||||
}
|
||||
func (m *PlainTextChange_TextAppend) XXX_Unmarshal(b []byte) error {
|
||||
func (m *TextAppend) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *PlainTextChange_TextAppend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
func (m *TextAppend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_PlainTextChange_TextAppend.Marshal(b, m, deterministic)
|
||||
return xxx_messageInfo_TextAppend.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
@ -156,41 +120,41 @@ func (m *PlainTextChange_TextAppend) XXX_Marshal(b []byte, deterministic bool) (
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *PlainTextChange_TextAppend) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_PlainTextChange_TextAppend.Merge(m, src)
|
||||
func (m *TextAppend) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_TextAppend.Merge(m, src)
|
||||
}
|
||||
func (m *PlainTextChange_TextAppend) XXX_Size() int {
|
||||
func (m *TextAppend) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *PlainTextChange_TextAppend) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_PlainTextChange_TextAppend.DiscardUnknown(m)
|
||||
func (m *TextAppend) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_TextAppend.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_PlainTextChange_TextAppend proto.InternalMessageInfo
|
||||
var xxx_messageInfo_TextAppend proto.InternalMessageInfo
|
||||
|
||||
func (m *PlainTextChange_TextAppend) GetText() string {
|
||||
func (m *TextAppend) GetText() string {
|
||||
if m != nil {
|
||||
return m.Text
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type PlainTextChange_Snapshot struct {
|
||||
type TextSnapshot struct {
|
||||
Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"`
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Snapshot) Reset() { *m = PlainTextChange_Snapshot{} }
|
||||
func (m *PlainTextChange_Snapshot) String() string { return proto.CompactTextString(m) }
|
||||
func (*PlainTextChange_Snapshot) ProtoMessage() {}
|
||||
func (*PlainTextChange_Snapshot) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_37f33c266ada4318, []int{0, 2}
|
||||
func (m *TextSnapshot) Reset() { *m = TextSnapshot{} }
|
||||
func (m *TextSnapshot) String() string { return proto.CompactTextString(m) }
|
||||
func (*TextSnapshot) ProtoMessage() {}
|
||||
func (*TextSnapshot) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_37f33c266ada4318, []int{2}
|
||||
}
|
||||
func (m *PlainTextChange_Snapshot) XXX_Unmarshal(b []byte) error {
|
||||
func (m *TextSnapshot) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *PlainTextChange_Snapshot) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
func (m *TextSnapshot) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_PlainTextChange_Snapshot.Marshal(b, m, deterministic)
|
||||
return xxx_messageInfo_TextSnapshot.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
@ -200,42 +164,42 @@ func (m *PlainTextChange_Snapshot) XXX_Marshal(b []byte, deterministic bool) ([]
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *PlainTextChange_Snapshot) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_PlainTextChange_Snapshot.Merge(m, src)
|
||||
func (m *TextSnapshot) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_TextSnapshot.Merge(m, src)
|
||||
}
|
||||
func (m *PlainTextChange_Snapshot) XXX_Size() int {
|
||||
func (m *TextSnapshot) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *PlainTextChange_Snapshot) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_PlainTextChange_Snapshot.DiscardUnknown(m)
|
||||
func (m *TextSnapshot) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_TextSnapshot.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_PlainTextChange_Snapshot proto.InternalMessageInfo
|
||||
var xxx_messageInfo_TextSnapshot proto.InternalMessageInfo
|
||||
|
||||
func (m *PlainTextChange_Snapshot) GetText() string {
|
||||
func (m *TextSnapshot) GetText() string {
|
||||
if m != nil {
|
||||
return m.Text
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type PlainTextChange_Data struct {
|
||||
Content []*PlainTextChange_Content `protobuf:"bytes,1,rep,name=content,proto3" json:"content,omitempty"`
|
||||
Snapshot *PlainTextChange_Snapshot `protobuf:"bytes,2,opt,name=snapshot,proto3" json:"snapshot,omitempty"`
|
||||
type TextData struct {
|
||||
Content []*TextContent `protobuf:"bytes,1,rep,name=content,proto3" json:"content,omitempty"`
|
||||
Snapshot *TextSnapshot `protobuf:"bytes,2,opt,name=snapshot,proto3" json:"snapshot,omitempty"`
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Data) Reset() { *m = PlainTextChange_Data{} }
|
||||
func (m *PlainTextChange_Data) String() string { return proto.CompactTextString(m) }
|
||||
func (*PlainTextChange_Data) ProtoMessage() {}
|
||||
func (*PlainTextChange_Data) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_37f33c266ada4318, []int{0, 3}
|
||||
func (m *TextData) Reset() { *m = TextData{} }
|
||||
func (m *TextData) String() string { return proto.CompactTextString(m) }
|
||||
func (*TextData) ProtoMessage() {}
|
||||
func (*TextData) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_37f33c266ada4318, []int{3}
|
||||
}
|
||||
func (m *PlainTextChange_Data) XXX_Unmarshal(b []byte) error {
|
||||
func (m *TextData) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *PlainTextChange_Data) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
func (m *TextData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_PlainTextChange_Data.Marshal(b, m, deterministic)
|
||||
return xxx_messageInfo_TextData.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
@ -245,26 +209,26 @@ func (m *PlainTextChange_Data) XXX_Marshal(b []byte, deterministic bool) ([]byte
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *PlainTextChange_Data) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_PlainTextChange_Data.Merge(m, src)
|
||||
func (m *TextData) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_TextData.Merge(m, src)
|
||||
}
|
||||
func (m *PlainTextChange_Data) XXX_Size() int {
|
||||
func (m *TextData) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *PlainTextChange_Data) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_PlainTextChange_Data.DiscardUnknown(m)
|
||||
func (m *TextData) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_TextData.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_PlainTextChange_Data proto.InternalMessageInfo
|
||||
var xxx_messageInfo_TextData proto.InternalMessageInfo
|
||||
|
||||
func (m *PlainTextChange_Data) GetContent() []*PlainTextChange_Content {
|
||||
func (m *TextData) GetContent() []*TextContent {
|
||||
if m != nil {
|
||||
return m.Content
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Data) GetSnapshot() *PlainTextChange_Snapshot {
|
||||
func (m *TextData) GetSnapshot() *TextSnapshot {
|
||||
if m != nil {
|
||||
return m.Snapshot
|
||||
}
|
||||
@ -272,11 +236,10 @@ func (m *PlainTextChange_Data) GetSnapshot() *PlainTextChange_Snapshot {
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*PlainTextChange)(nil), "anytype.PlainTextChange")
|
||||
proto.RegisterType((*PlainTextChange_Content)(nil), "anytype.PlainTextChange.Content")
|
||||
proto.RegisterType((*PlainTextChange_TextAppend)(nil), "anytype.PlainTextChange.TextAppend")
|
||||
proto.RegisterType((*PlainTextChange_Snapshot)(nil), "anytype.PlainTextChange.Snapshot")
|
||||
proto.RegisterType((*PlainTextChange_Data)(nil), "anytype.PlainTextChange.Data")
|
||||
proto.RegisterType((*TextContent)(nil), "anytype.TextContent")
|
||||
proto.RegisterType((*TextAppend)(nil), "anytype.TextAppend")
|
||||
proto.RegisterType((*TextSnapshot)(nil), "anytype.TextSnapshot")
|
||||
proto.RegisterType((*TextData)(nil), "anytype.TextData")
|
||||
}
|
||||
|
||||
func init() {
|
||||
@ -284,27 +247,26 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_37f33c266ada4318 = []byte{
|
||||
// 266 bytes of a gzipped FileDescriptorProto
|
||||
// 252 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x2b, 0xc8, 0x4e, 0xd7,
|
||||
0x4f, 0x4c, 0xce, 0xd1, 0x2f, 0x49, 0x2d, 0x2e, 0x29, 0x2d, 0xc9, 0xcc, 0x29, 0x06, 0xb3, 0x92,
|
||||
0x33, 0x12, 0xf3, 0xd2, 0x53, 0x8b, 0xf5, 0x0b, 0x8a, 0xf2, 0x4b, 0xf2, 0xc1, 0x22, 0x7a, 0x60,
|
||||
0xa6, 0x10, 0x7b, 0x62, 0x5e, 0x65, 0x49, 0x65, 0x41, 0xaa, 0xd2, 0x26, 0x26, 0x2e, 0xfe, 0x80,
|
||||
0x9c, 0xc4, 0xcc, 0xbc, 0x90, 0xd4, 0x8a, 0x12, 0x67, 0xb0, 0x72, 0xa9, 0x48, 0x2e, 0x76, 0xe7,
|
||||
0xfc, 0xbc, 0x92, 0xd4, 0xbc, 0x12, 0x21, 0x57, 0x2e, 0xae, 0x92, 0xd4, 0x8a, 0x12, 0xc7, 0x82,
|
||||
0x82, 0xd4, 0xbc, 0x14, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x6e, 0x23, 0x65, 0x3d, 0xa8, 0x66, 0x3d,
|
||||
0x34, 0x8d, 0x7a, 0x21, 0x70, 0xa5, 0x1e, 0x0c, 0x41, 0x48, 0x1a, 0x9d, 0xd8, 0xb9, 0x58, 0xcb,
|
||||
0x12, 0x73, 0x4a, 0x53, 0xa5, 0x14, 0xb8, 0xb8, 0x10, 0x8a, 0x84, 0x84, 0xb8, 0x58, 0x40, 0x8a,
|
||||
0xc0, 0xe6, 0x72, 0x06, 0x81, 0xd9, 0x52, 0x72, 0x5c, 0x1c, 0xc1, 0x79, 0x89, 0x05, 0xc5, 0x19,
|
||||
0xf9, 0x25, 0x58, 0xe5, 0x1b, 0x19, 0xb9, 0x58, 0x5c, 0x12, 0x4b, 0x12, 0x85, 0xac, 0xb8, 0xd8,
|
||||
0x93, 0x21, 0xae, 0x94, 0x60, 0x54, 0x60, 0xd6, 0xe0, 0x36, 0x52, 0xc0, 0xe9, 0x2e, 0xa8, 0x6f,
|
||||
0x82, 0x60, 0x1a, 0x84, 0x6c, 0xb9, 0x38, 0x8a, 0xa1, 0x96, 0x48, 0x30, 0x81, 0x3d, 0xa5, 0x88,
|
||||
0x53, 0x33, 0xcc, 0x35, 0x41, 0x70, 0x2d, 0x4e, 0xaa, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24,
|
||||
0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78,
|
||||
0x2c, 0xc7, 0x10, 0xc5, 0x8d, 0x14, 0xea, 0x49, 0x6c, 0xe0, 0xb0, 0x36, 0x06, 0x04, 0x00, 0x00,
|
||||
0xff, 0xff, 0xf8, 0x8c, 0x6a, 0x1d, 0x9d, 0x01, 0x00, 0x00,
|
||||
0xa6, 0x10, 0x7b, 0x62, 0x5e, 0x65, 0x49, 0x65, 0x41, 0xaa, 0x92, 0x2f, 0x17, 0x77, 0x48, 0x6a,
|
||||
0x45, 0x89, 0x73, 0x7e, 0x5e, 0x49, 0x6a, 0x5e, 0x89, 0x90, 0x29, 0x17, 0x57, 0x49, 0x6a, 0x45,
|
||||
0x89, 0x63, 0x41, 0x41, 0x6a, 0x5e, 0x8a, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xb7, 0x91, 0xb0, 0x1e,
|
||||
0x54, 0xb1, 0x5e, 0x08, 0x5c, 0xca, 0x83, 0x21, 0x08, 0x49, 0xa1, 0x13, 0x3b, 0x17, 0x6b, 0x59,
|
||||
0x62, 0x4e, 0x69, 0xaa, 0x92, 0x02, 0x17, 0x17, 0x42, 0x91, 0x90, 0x10, 0x17, 0x0b, 0x48, 0x11,
|
||||
0xd8, 0x1c, 0xce, 0x20, 0x30, 0x5b, 0x49, 0x89, 0x8b, 0x07, 0xa4, 0x22, 0x38, 0x2f, 0xb1, 0xa0,
|
||||
0x38, 0x23, 0xbf, 0x04, 0xab, 0x9a, 0x5c, 0x2e, 0x0e, 0x90, 0x1a, 0x97, 0xc4, 0x92, 0x44, 0x21,
|
||||
0x3d, 0x2e, 0xf6, 0x64, 0x88, 0xe3, 0x24, 0x18, 0x15, 0x98, 0x35, 0xb8, 0x8d, 0x44, 0x50, 0x9c,
|
||||
0x03, 0x75, 0x78, 0x10, 0x4c, 0x91, 0x90, 0x21, 0x17, 0x47, 0x31, 0xd4, 0x6c, 0x09, 0x26, 0xb0,
|
||||
0xfb, 0x45, 0x51, 0x34, 0xc0, 0x2c, 0x0e, 0x82, 0x2b, 0x73, 0x52, 0x3d, 0xf1, 0x48, 0x8e, 0xf1,
|
||||
0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e,
|
||||
0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0x6e, 0xa4, 0x40, 0x4c, 0x62, 0x03, 0x07, 0x9d, 0x31, 0x20,
|
||||
0x00, 0x00, 0xff, 0xff, 0xdc, 0xbf, 0x78, 0xe5, 0x6c, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *PlainTextChange) Marshal() (dAtA []byte, err error) {
|
||||
func (m *TextContent) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
@ -314,35 +276,12 @@ func (m *PlainTextChange) Marshal() (dAtA []byte, err error) {
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *PlainTextChange) MarshalTo(dAtA []byte) (int, error) {
|
||||
func (m *TextContent) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *PlainTextChange) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Content) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Content) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Content) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
func (m *TextContent) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
@ -359,12 +298,12 @@ func (m *PlainTextChange_Content) MarshalToSizedBuffer(dAtA []byte) (int, error)
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Content_TextAppend) MarshalTo(dAtA []byte) (int, error) {
|
||||
func (m *TextContent_TextAppend) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Content_TextAppend) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
func (m *TextContent_TextAppend) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
if m.TextAppend != nil {
|
||||
{
|
||||
@ -380,7 +319,7 @@ func (m *PlainTextChange_Content_TextAppend) MarshalToSizedBuffer(dAtA []byte) (
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
func (m *PlainTextChange_TextAppend) Marshal() (dAtA []byte, err error) {
|
||||
func (m *TextAppend) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
@ -390,12 +329,12 @@ func (m *PlainTextChange_TextAppend) Marshal() (dAtA []byte, err error) {
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_TextAppend) MarshalTo(dAtA []byte) (int, error) {
|
||||
func (m *TextAppend) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_TextAppend) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
func (m *TextAppend) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
@ -410,7 +349,7 @@ func (m *PlainTextChange_TextAppend) MarshalToSizedBuffer(dAtA []byte) (int, err
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Snapshot) Marshal() (dAtA []byte, err error) {
|
||||
func (m *TextSnapshot) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
@ -420,12 +359,12 @@ func (m *PlainTextChange_Snapshot) Marshal() (dAtA []byte, err error) {
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Snapshot) MarshalTo(dAtA []byte) (int, error) {
|
||||
func (m *TextSnapshot) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Snapshot) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
func (m *TextSnapshot) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
@ -440,7 +379,7 @@ func (m *PlainTextChange_Snapshot) MarshalToSizedBuffer(dAtA []byte) (int, error
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Data) Marshal() (dAtA []byte, err error) {
|
||||
func (m *TextData) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
@ -450,12 +389,12 @@ func (m *PlainTextChange_Data) Marshal() (dAtA []byte, err error) {
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Data) MarshalTo(dAtA []byte) (int, error) {
|
||||
func (m *TextData) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Data) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
func (m *TextData) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
@ -500,16 +439,7 @@ func encodeVarintTest(dAtA []byte, offset int, v uint64) int {
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *PlainTextChange) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Content) Size() (n int) {
|
||||
func (m *TextContent) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
@ -521,7 +451,7 @@ func (m *PlainTextChange_Content) Size() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Content_TextAppend) Size() (n int) {
|
||||
func (m *TextContent_TextAppend) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
@ -533,7 +463,7 @@ func (m *PlainTextChange_Content_TextAppend) Size() (n int) {
|
||||
}
|
||||
return n
|
||||
}
|
||||
func (m *PlainTextChange_TextAppend) Size() (n int) {
|
||||
func (m *TextAppend) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
@ -546,7 +476,7 @@ func (m *PlainTextChange_TextAppend) Size() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Snapshot) Size() (n int) {
|
||||
func (m *TextSnapshot) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
@ -559,7 +489,7 @@ func (m *PlainTextChange_Snapshot) Size() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *PlainTextChange_Data) Size() (n int) {
|
||||
func (m *TextData) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
@ -584,7 +514,7 @@ func sovTest(x uint64) (n int) {
|
||||
func sozTest(x uint64) (n int) {
|
||||
return sovTest(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *PlainTextChange) Unmarshal(dAtA []byte) error {
|
||||
func (m *TextContent) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
@ -607,60 +537,10 @@ func (m *PlainTextChange) Unmarshal(dAtA []byte) error {
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: PlainTextChange: wiretype end group for non-group")
|
||||
return fmt.Errorf("proto: TextContent: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: PlainTextChange: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipTest(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *PlainTextChange_Content) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: Content: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: Content: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
return fmt.Errorf("proto: TextContent: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
@ -692,11 +572,11 @@ func (m *PlainTextChange_Content) Unmarshal(dAtA []byte) error {
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
v := &PlainTextChange_TextAppend{}
|
||||
v := &TextAppend{}
|
||||
if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
m.Value = &PlainTextChange_Content_TextAppend{v}
|
||||
m.Value = &TextContent_TextAppend{v}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
@ -719,7 +599,7 @@ func (m *PlainTextChange_Content) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *PlainTextChange_TextAppend) Unmarshal(dAtA []byte) error {
|
||||
func (m *TextAppend) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
@ -801,7 +681,7 @@ func (m *PlainTextChange_TextAppend) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *PlainTextChange_Snapshot) Unmarshal(dAtA []byte) error {
|
||||
func (m *TextSnapshot) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
@ -824,10 +704,10 @@ func (m *PlainTextChange_Snapshot) Unmarshal(dAtA []byte) error {
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: Snapshot: wiretype end group for non-group")
|
||||
return fmt.Errorf("proto: TextSnapshot: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: Snapshot: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
return fmt.Errorf("proto: TextSnapshot: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
@ -883,7 +763,7 @@ func (m *PlainTextChange_Snapshot) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
|
||||
func (m *TextData) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
@ -906,10 +786,10 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: Data: wiretype end group for non-group")
|
||||
return fmt.Errorf("proto: TextData: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: Data: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
return fmt.Errorf("proto: TextData: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
@ -941,7 +821,7 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Content = append(m.Content, &PlainTextChange_Content{})
|
||||
m.Content = append(m.Content, &TextContent{})
|
||||
if err := m.Content[len(m.Content)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -976,7 +856,7 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.Snapshot == nil {
|
||||
m.Snapshot = &PlainTextChange_Snapshot{}
|
||||
m.Snapshot = &TextSnapshot{}
|
||||
}
|
||||
if err := m.Snapshot.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
|
||||
@ -2,23 +2,21 @@ syntax = "proto3";
|
||||
package anytype;
|
||||
option go_package = "testchanges";
|
||||
|
||||
message PlainTextChange {
|
||||
message Content {
|
||||
oneof value {
|
||||
TextAppend textAppend = 1;
|
||||
}
|
||||
message TextContent {
|
||||
oneof value {
|
||||
TextAppend textAppend = 1;
|
||||
}
|
||||
}
|
||||
|
||||
message TextAppend {
|
||||
string text = 1;
|
||||
}
|
||||
message TextAppend {
|
||||
string text = 1;
|
||||
}
|
||||
|
||||
message Snapshot {
|
||||
string text = 1;
|
||||
}
|
||||
message TextSnapshot {
|
||||
string text = 1;
|
||||
}
|
||||
|
||||
message Data {
|
||||
repeated Content content = 1;
|
||||
Snapshot snapshot = 2;
|
||||
}
|
||||
}
|
||||
message TextData {
|
||||
repeated TextContent content = 1;
|
||||
TextSnapshot snapshot = 2;
|
||||
}
|
||||
|
||||
@ -71,6 +71,10 @@ func (c *changeBuilder) ConvertFromRaw(rawIdChange *treechangeproto.RawTreeChang
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ch, err = c.unmarshallRawChange(raw, rawIdChange.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if verify {
|
||||
var identityKey signingkey.PubKey
|
||||
@ -90,8 +94,7 @@ func (c *changeBuilder) ConvertFromRaw(rawIdChange *treechangeproto.RawTreeChang
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return c.unmarshallRawChange(raw, rawIdChange.Id)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *changeBuilder) SetRootRawChange(rawIdChange *treechangeproto.RawTreeChangeWithId) {
|
||||
|
||||
@ -53,6 +53,10 @@ func (v *objectTreeValidator) validateChange(tree *Tree, aclList list2.ACLList,
|
||||
return
|
||||
}
|
||||
|
||||
if c.Id == tree.RootId() {
|
||||
return
|
||||
}
|
||||
|
||||
// checking if the change refers to later acl heads than its previous ids
|
||||
for _, id := range c.PreviousIds {
|
||||
prevChange := tree.attached[id]
|
||||
|
||||
@ -6,11 +6,11 @@ package mock_tree
|
||||
|
||||
import (
|
||||
context "context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
tree2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
reflect "reflect"
|
||||
|
||||
storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
tree "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
treechangeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
@ -38,10 +38,10 @@ func (m *MockObjectTree) EXPECT() *MockObjectTreeMockRecorder {
|
||||
}
|
||||
|
||||
// AddContent mocks base method.
|
||||
func (m *MockObjectTree) AddContent(arg0 context.Context, arg1 tree2.SignableChangeContent) (tree2.AddResult, error) {
|
||||
func (m *MockObjectTree) AddContent(arg0 context.Context, arg1 tree.SignableChangeContent) (tree.AddResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AddContent", arg0, arg1)
|
||||
ret0, _ := ret[0].(tree2.AddResult)
|
||||
ret0, _ := ret[0].(tree.AddResult)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@ -53,14 +53,14 @@ func (mr *MockObjectTreeMockRecorder) AddContent(arg0, arg1 interface{}) *gomock
|
||||
}
|
||||
|
||||
// AddRawChanges mocks base method.
|
||||
func (m *MockObjectTree) AddRawChanges(arg0 context.Context, arg1 ...*treechangeproto.RawTreeChangeWithId) (tree2.AddResult, error) {
|
||||
func (m *MockObjectTree) AddRawChanges(arg0 context.Context, arg1 ...*treechangeproto.RawTreeChangeWithId) (tree.AddResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0}
|
||||
for _, a := range arg1 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "AddRawChanges", varargs...)
|
||||
ret0, _ := ret[0].(tree2.AddResult)
|
||||
ret0, _ := ret[0].(tree.AddResult)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@ -177,7 +177,7 @@ func (mr *MockObjectTreeMockRecorder) ID() *gomock.Call {
|
||||
}
|
||||
|
||||
// Iterate mocks base method.
|
||||
func (m *MockObjectTree) Iterate(arg0 func([]byte) (interface{}, error), arg1 func(*tree2.Change) bool) error {
|
||||
func (m *MockObjectTree) Iterate(arg0 func([]byte) (interface{}, error), arg1 func(*tree.Change) bool) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Iterate", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -191,7 +191,7 @@ func (mr *MockObjectTreeMockRecorder) Iterate(arg0, arg1 interface{}) *gomock.Ca
|
||||
}
|
||||
|
||||
// IterateFrom mocks base method.
|
||||
func (m *MockObjectTree) IterateFrom(arg0 string, arg1 func([]byte) (interface{}, error), arg2 func(*tree2.Change) bool) error {
|
||||
func (m *MockObjectTree) IterateFrom(arg0 string, arg1 func([]byte) (interface{}, error), arg2 func(*tree.Change) bool) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IterateFrom", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -241,10 +241,10 @@ func (mr *MockObjectTreeMockRecorder) RUnlock() *gomock.Call {
|
||||
}
|
||||
|
||||
// Root mocks base method.
|
||||
func (m *MockObjectTree) Root() *tree2.Change {
|
||||
func (m *MockObjectTree) Root() *tree.Change {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Root")
|
||||
ret0, _ := ret[0].(*tree2.Change)
|
||||
ret0, _ := ret[0].(*tree.Change)
|
||||
return ret0
|
||||
}
|
||||
|
||||
|
||||
@ -177,6 +177,8 @@ func (ot *objectTree) AddContent(ctx context.Context, content SignableChangeCont
|
||||
Added: []*treechangeproto.RawTreeChangeWithId{rawChange},
|
||||
Mode: Append,
|
||||
}
|
||||
log.With("treeId", ot.id).With("head", objChange.Id).
|
||||
Debug("finished adding content")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package tree
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/common"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list"
|
||||
storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
@ -54,10 +55,7 @@ func createObjectTree(
|
||||
aclList list.ACLList,
|
||||
createStorage storage2.TreeStorageCreatorFunc) (objTree ObjectTree, err error) {
|
||||
aclList.RLock()
|
||||
var (
|
||||
deps = defaultObjectTreeDeps(nil, nil, aclList)
|
||||
aclHeadId = aclList.Head().Id
|
||||
)
|
||||
aclHeadId := aclList.Head().Id
|
||||
aclList.RUnlock()
|
||||
|
||||
if err != nil {
|
||||
@ -73,11 +71,10 @@ func createObjectTree(
|
||||
Seed: seed,
|
||||
}
|
||||
|
||||
_, raw, err := deps.changeBuilder.BuildInitialContent(cnt)
|
||||
_, raw, err := newChangeBuilder(common.NewKeychain(), nil).BuildInitialContent(cnt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
deps.changeBuilder.SetRootRawChange(raw)
|
||||
|
||||
// create storage
|
||||
st, err := createStorage(storage2.TreeStorageCreatePayload{
|
||||
@ -90,8 +87,7 @@ func createObjectTree(
|
||||
return
|
||||
}
|
||||
|
||||
deps.treeStorage = st
|
||||
return buildObjectTree(deps)
|
||||
return BuildObjectTree(st, aclList)
|
||||
}
|
||||
|
||||
func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
|
||||
|
||||
@ -73,7 +73,9 @@ func (r *rawChangeLoader) LoadFromTree(t *Tree, breakpoints []string) ([]*treech
|
||||
// now starting from breakpoints
|
||||
stack = stack[:0]
|
||||
for _, h := range breakpoints {
|
||||
stack = append(stack, t.attached[h])
|
||||
if c, exists := t.attached[h]; exists {
|
||||
stack = append(stack, c)
|
||||
}
|
||||
}
|
||||
|
||||
// doing another dfs to get all changes before breakpoints, we need to exclude them from results
|
||||
|
||||
@ -53,3 +53,44 @@ message RawTreeChangeWithId {
|
||||
// Id is a cid made from rawChange payload
|
||||
string id = 2;
|
||||
}
|
||||
|
||||
message TreeSyncMessage {
|
||||
TreeSyncContentValue content = 1;
|
||||
RawTreeChangeWithId rootChange = 2;
|
||||
}
|
||||
|
||||
// TreeSyncContentValue provides different types for tree sync
|
||||
message TreeSyncContentValue {
|
||||
oneof value {
|
||||
TreeHeadUpdate headUpdate = 1;
|
||||
TreeFullSyncRequest fullSyncRequest = 2;
|
||||
TreeFullSyncResponse fullSyncResponse = 3;
|
||||
TreeErrorResponse errorResponse = 4;
|
||||
}
|
||||
}
|
||||
|
||||
// TreeHeadUpdate is a message sent on document head update
|
||||
message TreeHeadUpdate {
|
||||
repeated string heads = 1;
|
||||
repeated RawTreeChangeWithId changes = 2;
|
||||
repeated string snapshotPath = 3;
|
||||
}
|
||||
|
||||
// TreeHeadUpdate is a message sent when document needs full sync
|
||||
message TreeFullSyncRequest {
|
||||
repeated string heads = 1;
|
||||
repeated RawTreeChangeWithId changes = 2;
|
||||
repeated string snapshotPath = 3;
|
||||
}
|
||||
|
||||
// TreeFullSyncResponse is a message sent as a response for a specific full sync
|
||||
message TreeFullSyncResponse {
|
||||
repeated string heads = 1;
|
||||
repeated RawTreeChangeWithId changes = 2;
|
||||
repeated string snapshotPath = 3;
|
||||
}
|
||||
|
||||
// TreeErrorResponse is an error sent as a response for a full sync request
|
||||
message TreeErrorResponse {
|
||||
string error = 1;
|
||||
}
|
||||
|
||||
37
common/pkg/acl/treechangeproto/treechange.go
Normal file
37
common/pkg/acl/treechangeproto/treechange.go
Normal file
@ -0,0 +1,37 @@
|
||||
package treechangeproto
|
||||
|
||||
func WrapHeadUpdate(update *TreeHeadUpdate, rootChange *RawTreeChangeWithId) *TreeSyncMessage {
|
||||
return &TreeSyncMessage{
|
||||
Content: &TreeSyncContentValue{
|
||||
Value: &TreeSyncContentValue_HeadUpdate{HeadUpdate: update},
|
||||
},
|
||||
RootChange: rootChange,
|
||||
}
|
||||
}
|
||||
|
||||
func WrapFullRequest(request *TreeFullSyncRequest, rootChange *RawTreeChangeWithId) *TreeSyncMessage {
|
||||
return &TreeSyncMessage{
|
||||
Content: &TreeSyncContentValue{
|
||||
Value: &TreeSyncContentValue_FullSyncRequest{FullSyncRequest: request},
|
||||
},
|
||||
RootChange: rootChange,
|
||||
}
|
||||
}
|
||||
|
||||
func WrapFullResponse(response *TreeFullSyncResponse, rootChange *RawTreeChangeWithId) *TreeSyncMessage {
|
||||
return &TreeSyncMessage{
|
||||
Content: &TreeSyncContentValue{
|
||||
Value: &TreeSyncContentValue_FullSyncResponse{FullSyncResponse: response},
|
||||
},
|
||||
RootChange: rootChange,
|
||||
}
|
||||
}
|
||||
|
||||
func WrapError(err error, rootChange *RawTreeChangeWithId) *TreeSyncMessage {
|
||||
return &TreeSyncMessage{
|
||||
Content: &TreeSyncContentValue{
|
||||
Value: &TreeSyncContentValue_ErrorResponse{ErrorResponse: &TreeErrorResponse{Error: err.Error()}},
|
||||
},
|
||||
RootChange: rootChange,
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
||||
//go:generate mockgen -destination mock_ldiff/mock_ldiff.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff Diff,Remote
|
||||
// Package ldiff provides a container of elements with fixed id and changeable content.
|
||||
// Diff can calculate the difference with another diff container (you can make it remote) with minimum hops and traffic.
|
||||
//
|
||||
//go:generate mockgen -destination mock_ldiff/mock_ldiff.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff Diff,Remote
|
||||
package ldiff
|
||||
|
||||
import (
|
||||
@ -84,6 +85,10 @@ type Diff interface {
|
||||
RemoveId(id string) error
|
||||
// Diff makes diff with remote container
|
||||
Diff(ctx context.Context, dl Remote) (newIds, changedIds, removedIds []string, err error)
|
||||
// Elements retrieves all elements in the Diff
|
||||
Elements() []Element
|
||||
// Ids retrieves ids of all elements in the Diff
|
||||
Ids() []string
|
||||
}
|
||||
|
||||
// Remote interface for using in the Diff
|
||||
@ -134,6 +139,36 @@ func (d *diff) Set(elements ...Element) {
|
||||
}
|
||||
}
|
||||
|
||||
func (d *diff) Ids() (ids []string) {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
|
||||
ids = make([]string, 0, d.sl.Len())
|
||||
|
||||
cur := d.sl.Front()
|
||||
for cur != nil {
|
||||
el := cur.Key().(*element).Element
|
||||
ids = append(ids, el.Id)
|
||||
cur = cur.Next()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *diff) Elements() (elements []Element) {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
|
||||
elements = make([]Element, 0, d.sl.Len())
|
||||
|
||||
cur := d.sl.Front()
|
||||
for cur != nil {
|
||||
el := cur.Key().(*element).Element
|
||||
elements = append(elements, el)
|
||||
cur = cur.Next()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RemoveId removes element by id
|
||||
func (d *diff) RemoveId(id string) error {
|
||||
d.mu.Lock()
|
||||
@ -182,6 +217,7 @@ func (d *diff) getRange(r Range) (rr RangeResult) {
|
||||
func (d *diff) Ranges(ctx context.Context, ranges []Range, resBuf []RangeResult) (results []RangeResult, err error) {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
|
||||
results = resBuf[:0]
|
||||
for _, r := range ranges {
|
||||
results = append(results, d.getRange(r))
|
||||
@ -200,9 +236,6 @@ var errMismatched = errors.New("query and results mismatched")
|
||||
|
||||
// Diff makes diff with remote container
|
||||
func (d *diff) Diff(ctx context.Context, dl Remote) (newIds, changedIds, removedIds []string, err error) {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
|
||||
dctx := &diffCtx{}
|
||||
dctx.toSend = append(dctx.toSend, Range{
|
||||
From: 0,
|
||||
@ -216,10 +249,10 @@ func (d *diff) Diff(ctx context.Context, dl Remote) (newIds, changedIds, removed
|
||||
return
|
||||
default:
|
||||
}
|
||||
if dctx.myRes, err = d.Ranges(ctx, dctx.toSend, dctx.myRes); err != nil {
|
||||
if dctx.otherRes, err = dl.Ranges(ctx, dctx.toSend, dctx.otherRes); err != nil {
|
||||
return
|
||||
}
|
||||
if dctx.otherRes, err = dl.Ranges(ctx, dctx.toSend, dctx.otherRes); err != nil {
|
||||
if dctx.myRes, err = d.Ranges(ctx, dctx.toSend, dctx.myRes); err != nil {
|
||||
return
|
||||
}
|
||||
if len(dctx.otherRes) != len(dctx.toSend) || len(dctx.myRes) != len(dctx.toSend) {
|
||||
|
||||
@ -6,9 +6,9 @@ package mock_ldiff
|
||||
|
||||
import (
|
||||
context "context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff"
|
||||
reflect "reflect"
|
||||
|
||||
ldiff "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
@ -52,6 +52,34 @@ func (mr *MockDiffMockRecorder) Diff(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Diff", reflect.TypeOf((*MockDiff)(nil).Diff), arg0, arg1)
|
||||
}
|
||||
|
||||
// Elements mocks base method.
|
||||
func (m *MockDiff) Elements() []ldiff.Element {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Elements")
|
||||
ret0, _ := ret[0].([]ldiff.Element)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Elements indicates an expected call of Elements.
|
||||
func (mr *MockDiffMockRecorder) Elements() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Elements", reflect.TypeOf((*MockDiff)(nil).Elements))
|
||||
}
|
||||
|
||||
// Ids mocks base method.
|
||||
func (m *MockDiff) Ids() []string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Ids")
|
||||
ret0, _ := ret[0].([]string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Ids indicates an expected call of Ids.
|
||||
func (mr *MockDiffMockRecorder) Ids() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ids", reflect.TypeOf((*MockDiff)(nil).Ids))
|
||||
}
|
||||
|
||||
// Ranges mocks base method.
|
||||
func (m *MockDiff) Ranges(arg0 context.Context, arg1 []ldiff.Range, arg2 []ldiff.RangeResult) ([]ldiff.RangeResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@ -46,7 +46,7 @@ var WithGCPeriod = func(gcPeriod time.Duration) Option {
|
||||
|
||||
var WithRefCounter = func(enable bool) Option {
|
||||
return func(cache *oCache) {
|
||||
cache.noRefCounter = !enable
|
||||
cache.refCounter = enable
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,17 +131,17 @@ type OCache interface {
|
||||
}
|
||||
|
||||
type oCache struct {
|
||||
mu sync.Mutex
|
||||
data map[string]*entry
|
||||
loadFunc LoadFunc
|
||||
timeNow func() time.Time
|
||||
ttl time.Duration
|
||||
gc time.Duration
|
||||
closed bool
|
||||
closeCh chan struct{}
|
||||
log *zap.SugaredLogger
|
||||
metrics *metrics
|
||||
noRefCounter bool
|
||||
mu sync.Mutex
|
||||
data map[string]*entry
|
||||
loadFunc LoadFunc
|
||||
timeNow func() time.Time
|
||||
ttl time.Duration
|
||||
gc time.Duration
|
||||
closed bool
|
||||
closeCh chan struct{}
|
||||
log *zap.SugaredLogger
|
||||
metrics *metrics
|
||||
refCounter bool
|
||||
}
|
||||
|
||||
func (c *oCache) Get(ctx context.Context, id string) (value Object, err error) {
|
||||
@ -167,7 +167,7 @@ Load:
|
||||
closing := e.isClosing
|
||||
if !e.isClosing {
|
||||
e.lastUsage = c.timeNow()
|
||||
if !c.noRefCounter {
|
||||
if c.refCounter {
|
||||
e.refCount++
|
||||
}
|
||||
}
|
||||
@ -237,7 +237,7 @@ func (c *oCache) Release(id string) bool {
|
||||
return false
|
||||
}
|
||||
if e, ok := c.data[id]; ok {
|
||||
if !c.noRefCounter && e.refCount > 0 {
|
||||
if c.refCounter && e.refCount > 0 {
|
||||
e.refCount--
|
||||
return true
|
||||
}
|
||||
|
||||
@ -119,7 +119,7 @@ func TestOCache_GC(t *testing.T) {
|
||||
t.Run("test without close wait", func(t *testing.T) {
|
||||
c := New(func(ctx context.Context, id string) (value Object, err error) {
|
||||
return &testObject{name: id}, nil
|
||||
}, WithTTL(time.Millisecond*10))
|
||||
}, WithTTL(time.Millisecond*10), WithRefCounter(true))
|
||||
val, err := c.Get(context.TODO(), "id")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, val)
|
||||
@ -140,7 +140,7 @@ func TestOCache_GC(t *testing.T) {
|
||||
|
||||
c := New(func(ctx context.Context, id string) (value Object, err error) {
|
||||
return NewTestObject(id, closeCh), nil
|
||||
}, WithTTL(time.Millisecond*10))
|
||||
}, WithTTL(time.Millisecond*10), WithRefCounter(true))
|
||||
val, err := c.Get(context.TODO(), "id")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, val)
|
||||
|
||||
@ -48,10 +48,8 @@ type service struct {
|
||||
|
||||
func (s *service) Init(a *app.App) (err error) {
|
||||
s.db = a.MustComponent(db.CName).(db.Service)
|
||||
|
||||
cacheOpts := []ocache.Option{
|
||||
ocache.WithTTL(cacheTTL),
|
||||
ocache.WithRefCounter(false),
|
||||
ocache.WithLogger(log.Named("cache").Sugar()),
|
||||
}
|
||||
if ms := a.Component(metric.CName); ms != nil {
|
||||
|
||||
36
etc/client.yml
Normal file
36
etc/client.yml
Normal file
@ -0,0 +1,36 @@
|
||||
anytype:
|
||||
swarmKey: /key/swarm/psk/1.0.0/base16/209992e611c27d5dce8fbd2e7389f6b51da9bee980992ef60739460b536139ec
|
||||
grpcServer:
|
||||
listenAddrs:
|
||||
- 127.0.0.1:4630
|
||||
tls: false
|
||||
account:
|
||||
peerId: 12D3KooWC2SctmKSLWqmzsKCpQBo4iqNzbZhWivM3jbhovB4JFug
|
||||
signingKey: Maen+w6qwWuS79RZyMbuW7wnWAox0+rMinAb/gsOSl8gz2BLCfMlwXjlo8NLKfFFZFNUzl0ANTxbrK45Be7CPw==
|
||||
encryptionKey: MIIEowIBAAKCAQEAonOsG0DzAzGlR7cd0u31DS0xoHihxdfJwut5JMtLKqGwkUC5RM+/eTa96hKYp8ED6B8Q4ZBhmt2gQnOUQJpoAnJ6uU/HgQVVhsJD7uMQcyVWr2KZbRK2GAohxOiW8JaB8pLiIRJbOxaeIu8dGRTrTTxYnh4IbIUgMu5x3iPW1/6YT/LCN1r/CBgHnPLtxMjAdUYzz9+LC13sZJsanUot83MTgl+5unEPh+ogbrSJ6P8FAAWW8HHD5lUSSb2l8NFRafYWP4o3vF9fqtmpt5I2nK6PaNh+4YXB7CX8Nak3AYuSO/aLGUtZMGYv9Qqwewjk/ewEGNWz33D/Hve8+hctXQIDAQABAoIBAQCNY7/XuJ/Jl9wSnv4GJ7Ww0jTvRg8G8tlYHTpDG+1AHZpf0cVubqJoDY0dvTHAT+3miaNXryJEd8CUFaRi1gDQoHLP9u/dC5d0wn/92wLmNQlNfLOsiyyRn7/kccttepF/XvgRcLiWpQjdvt/EhMCHaI54kAsk6Hkt2vqgLPFA66MH/5AMyf+8RmouYvc1m8jPUVmkIZVkoO4/6kh0tZS+rGdjxB65zDaoBx6CcXAMkTWe27Ce87vfGwCRySGVGRg7RuTJQR8VO3oSmsPVIZ8A48fKPQvryrl/5ztvE35lL4i3pdIbd/CJ9zTKIEM4nyPWSmxsaxs1yIllsj3BFpDBAoGBAMzWUEBYm5FH6wG2GXigkou4VSUBAoKCi5XmA2bwCUZx6CaG4uk43cbYpkbLpIRchfLHAeVCiaOYe5VFvYMth6o+OICEKfXWEwGqjtWeHkyIQIZ1Yo+BKk1rbzkYa/n3a7Mw+C6HsweFq1v01eTChmMr/PF6trFQiJJhTGkGKS2/AoGBAMsHKMEmgw1/hRqiEai73AVLSzXGoHSUWsM1vV05EzDyoxkk8Q/+sJR/BOp4HvJidXiM9B0hSOBhkPZjP3TZSQTKXwMGY+Hcs0XhwGxV5Eb9XdbD5rhCT6eVUeQeP9W9J34RdobJauG1Ld9E1U0nKEI+ls6VZf6/k+ixDOa3TaPjAoGADI+7/iYw7Bjf9YvoRfh65CyatBk6wSwmSTwAy2g++V304Z/1/F1rZE1W7RKB9UgDQt8nY5rP/ANW2NGdDJVXM357Uo5IUHYfVkPSXJFExGa6pkQ+lhRStsq22GaCAKNGrId9QMU7mmN9HbeHAm9XdG93JIvk9jy9E1T6LZqeHdsCgYAXsvQ856PwlWwSGcz550PdklZrJo5gTVjy5HkAQsNMuWX0b218MnymONV4ESF7paaUtc9g/xukpX7oY9lqaFqvpnfEwKA0IzEB/UIa40PMTZMAmMl7xLHLnBB9ElLdPkE35A3z2dsSEbYTE9PaN7HpWaj84E+RlwdK6C/bVpZHhQKBgBv8Up6nOfQyW4jiRo5CPOzXPYu+tXfsV0lKbYAjlp3rcczsi/BPXF6tLZ74/f5Cp2NJxx1GIitjqGzZ1mhkB8Eimuw1o+uNRBRh5BcmQTXPTxrrbOsYzjBJNb7n9HcHlGivcmDooxP7TgRJydEiFdpoBhjU+7yGJTJk7YdDLI3I
|
||||
apiServer:
|
||||
port: "8090"
|
||||
nodes:
|
||||
- peerId: 12D3KooWC9DkXiYK8MiQb87ffW51ggZR4FWASadh4UENXdaa16iz
|
||||
address: 127.0.0.1:4430
|
||||
signingKey: yfFJv5klknUeG8rROCNTktCk5rsBvz16aEanYBAl9oYii+Q8XwH8mVXr5hHSiP+HYxEaSSozlMAAXUjdW2vK5w==
|
||||
encryptionKey: MIIEowIBAAKCAQEA5zUOQ42SFUYJyX86llYopUE4Q+RQvbCakTPd9LBKt6pBWyW3PA9sjFisxVFFwYOVwghzF8QDSRrWdkjGmRPPOSRNmNiJFGtk6wb26eihenFECdb4nJyTDZVhvayHpByCKleAl7dHLjHCIsVaaFfn5rntm47IdDSNFgZnNDrNrdS2SchXWHamcfWBJSQirdp+8kSh5RC6/J53LVa+Sff6D49BsF8VsevcjvFcdlpxG6GKhr6kzvnEwCCk8DIqjpF3geUVj/QbT9tGa12bAgDQuckW4DavIN1zT7BAUbZPcbFZ9Bd2bbKzXDFNt2mRXafDPL07KhnXSZ2YAxHf5M4s7QIDAQABAoIBABV5aQy/Lm1JZwlPBtsFv5qxtw8fOpyTtZd88MWURixO5OkZVK6AZD2Y0ts01DzIAvXVoRL5ArEcjATKd5+qJloRVB+5JOo/m0z1BaPuFmlv8bjUPZ0WMdZWJJDgYGzOtQxHukrdHABfYL+oAuCkIYbdiAMlvNqGMwBzscw5FfdqGBRwC0bus+YD103Hhc8pN0REwLZmiOvHR6b4Agwv4ruFsqthg13EwcqDVTnS1/sZyodLZaAGBUXlqUxuFakI/9CqpPuOkDgxelTYdXbS4yhfRF4zwoBGZx1462iJs4XM8TXhDcZpTRwCChM5Qf7jvvgbi7+gYTX9B1dxg7gZUyUCgYEA/cd/NqOyx7bn0twiuMEdq8bCi5Y/GvWLrQ3pf58DPanIydGPJU5/obKZw5Tv5LWbE5rUEeC2YpFleNh01oc0xHCveIR6JNGihN8u0DZPmcx2B1lwEzdYefRJfGcYXYhm/nCpzYn3VH0TfKA6qci+KLarYaeDpUCXAihZMUZxSfcCgYEA6Tr+fSXmHIYoKcewIpwSTvcFOJ6spMRSG+mxQAFit8vUQTw2e/aTESEECo24XJ/SKVK01CSoWXrw3t9eBgziyHI3GaaZ5LaXMZLLZhmGUT5kZiTR7083h+9bHt2+MzRXpaAEEc1FNgV3T2sSl1S+oKDL1MAcR42JaQtC1P2epzsCgYBKDdD9bL9ar/DuAvbO2uuBmLpkaS94+nYLxaeBajFT6RuCaPhQdpuf37Im9GscXjImgmOn497U3ICzxtYxU7r+J7PMgzvxSosWItpSP8bypks60cp2kQvsanCXMK5XfNoxHUcvhzb5HJZ3I3p62O1EjClukadErZhjNMryKhAc+QKBgFwvpUdyI3JC1L0u4L/NUK9FlBq9HSBDOPEvfY/+/DYJquveEOsOmzK6Cg7h1W1G/pq2xiLUGnbD0VFGmLNrhHgWLRFGeK2ePkSp8Rt6G00hjC2TgCdG+HwSb8HTg8pZdgtRJEqlCCZCItaRS9fk9zQmWmrNRGBD4XxTpybo2DzhAoGBAIxRN8WZc9HYVq8t20MieKP3pp5Nrl0wj9Z9EPvC60CwQRdv/FvWzDwF5/9Kg79rvbguZgjD6FNy35BGC5sN/24awWJ/mKYosctRwZVFpogoZ0qAdOwxowfAJXLRC5Chgim8vCFFdKdrMo2a6V+MQuhrTv06QAV1sYAH5P7abfPy
|
||||
- peerId: 12D3KooWC6sZYJXFagZtRjY4Jc4dzBLpEgYsUhJRauYheSAGk26y
|
||||
address: 127.0.0.1:4431
|
||||
signingKey: mLzjMshSbtOkUKZha0bNIHvW9nlqOPX6VM/mvKicx6kh8ebP2mfrkCS0qz5GwlFEqTgtuSnWsHdvGZnuan2Ahg==
|
||||
encryptionKey: MIIEogIBAAKCAQEAuJcCEM4sM5I1Aj2y0HDgR/UrKEVF1iZ1CYWv4jVOt/e1avDn7XjF9ArB7lngq7lOTxpCNeLMQXeBl1gY1SBCPeTrs+tltyAUeSOZStwP9qhjUhI9TntfW3QfVlC2lB17liGa4b2F10x9vW/0f3R7m5xgz8NyqcFOZip0Ehe9UJbNFwPr00by0D4/XptkDT44wAIDlw7lgOmXWR3RpCYAYFonYeE2HK7FFNTIOJucfJ8kbK7wLp5EZRARYfCDUFq7czFu97FIrmQfS4Fyg8ESB+R28+dJIQ6G8U1MicX4Ibf9IkufK+r2fMYPv13F33omrwSGhNIWtX9WjAQ4bjmA6wIDAQABAoIBACHuaEvMimWEd8gMrWURirjPgXpqmXbPJO52K6mqYOkCWM/qrseBTuoYXCPDU8BdVN7Hleov4ZobLLA0WoQ65NJZ1VYCbHUoKXtHJvOS1kBiHbfFcI2PsiyugOAuABHkBYbIcJ8UZpj4D5kWDlyrfdlR+p3WcKpxxUaUgTeeM4evkMg2dg1/S4psgu1SKdGYMtafKBgvxxE0R/fjfP9MRD260/ydcUT0gRE+uUu6WFm92MLV72W3hoKfNqgGnQWCTG8UJGGK3KC/c9lAvLiDygo3GJLEjhnrIGkSbbd0uHtAYD8Uc+gq3z3o5Rger4P/FyWSbJ6Vz20iYHTeYUEDkKECgYEA5KK5/Z6XQHwsEGXSSCXKvUjJ7ZOV5k3D2im0F1dTtQaOjFgwZ9SPW/k7tQfcwfZLeDSm5V98FXSAu9XgT/Zrd+/RrfbgmKLMcNVet+l2OPq1cOeKE7io7wAXlkO5CmiMXMCRVcgqaENutUSTsmadFqd2NE7/gEUjeNIQLGkSsXECgYEAzq6+HtOxhfbTEC8ZUz6Y7+CphmtYiuX7G42lwv70mg+sap7mVlZzOHNNM1p9BOVEo2K1RKNWtXMgXDbt/KakBLCab9sR4R68tS7JX281I8RK/kYOLqlVE0CahujcCJATZAsDLMCpjeN85vwqJ9Cy1errf69thZwo1QI1BvRIahsCgYAkmz1GMycqZvczJOpXLN3aEpZqGHAusJLEEltIRW4clNEr/U66wRi29B+wK3MYBxQsSdnS7cfTM5UM/gBtLRol2NrsjJOHPMGY60DAF3wbQWDdk+TSpYU+xvf/0hYFaZnXm+lpH6RSj0FhenpfXPiX0PYnB+L2qZs1VATM54HbsQKBgG9nVwkMuCpqUXfuuyrYmdzqbtYKdG5h6kj+v7Nsc3G7MwdBYQx2iqKJ27nrc2m5HpcmtGgr1qf1RyMNZJgDRnNUsdnK7kc2pybN8jMjoTQHMRj/r9NM6JN5BhHj3/4pkpohKXPs4TeewAtNLnfJkSum9Yscht82vfeaufRmpcWzAoGAfxcnMvi2EhE6uNjDENqnFH9XD2zAAeKhiQumz2ts3cSUd1QOfPMeytsBML/jdmOMQNaTbMryhWPaqTewHky8P+l/7oVbMTTFnaaaZRZCSOSXe+2R3mJkRQzE+DkVhgfpEku/BVGRHRvltM+ehk3m64j5vHWC97cP52qZ0bkxKHo=
|
||||
- peerId: 12D3KooWFWyDckUJBtHtARzRDTRpo4XzeKAo8oN23MXh3Xwbp2fd
|
||||
address: 127.0.0.1:4432
|
||||
signingKey: YpCGjsSuT8O6mkYTOExkdwNRODBaJ20hYJHFO/A/RUFUsUwxIME9X9FIp69VYvKuL6er973p0iG7UVVvLgLjnA==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA2T4/6T5etB9W7qzJ1sNfWFdOTa2koXKcQkaLBUTervApLPZtaVsbNtyVFtqqdsck1qpu+AVif19EFlYqSRtn/dxEN5/2myqVA6lZMm0Bd9mWpfoDQx20KAYwWBwzKSH1EQiTte0bw1zf0RpztxQ3nCOLCU4Y6x2lfk6Ea2XEayPxx0FDmeY3JSqUDOwx33Sz8Imx8R7+Dfjl6Og3DEqGxXoPfZ6hj9LynqNswjRIdmMZPsuEHguKXMbp+cncErGWcyzH417XYSDPoRn/3awpLfQ9F+KSjAe5cUltC7M4veSZW+t3VcJypvfRlU4ayTZMuvMHPlMcl/0jP5w0Q2+2pQIDAQABAoIBAGMvmrqBcXfHv0cluNnHRebtpaCtoTbdPx67WonDUfCJUiNnN7kckaZQu/k9SQsGDXm9QwEWZExHUKzqFlBepPIw+Sx0aoGZxYNwdHsjbcIspC2PoqGoFDMZ8ESqS2mCSYPHaLltUnm2E7JC44Y5QtKVH8vVzma6mG68ppTqV+2aGfGiPDq8cAYeH9/8Ys8/S28IwCp/M7lnXZhJ38bHD3YyPpcgbyGI/Zr5xaPd0hqHH08Z+S9V7QPJUGY0Y21s99DhkUGctb4B17d0/3Nzk/iWY1rp7A/kbdBeWonsHrTc6OnmbdiOcjC8seOIKMJ/WE3JznqnI1oydFb/dp6raNkCgYEA+pn1akGIKnVP0oFh5PZfUpuZtVV9u9xccIXyeFmCAXyFuUz1KYbfwwqZnm9r6kHAO+aBtRtVsCVle5oVWNQq1pdv117hPhRnVrDtvL80z50a5L9gEVu4Yz24Q3vs3RglcVpafSaRuyPbiYHMmQ4Ly+9nbwEbOVDbzK5A3Wrny2cCgYEA3exS3aG7+7mbSnNTYkkTgl7goLXZgEST/0EM2CvayxZ2QUS94Vq5HjGRpWnni3YttLiYlgCLe3CqeiIh6E3n6b9sory8Oy6lik/elj28kcZIuNvPU0xVcqrmGCg/KEnYkXjsGKsBDk6SV9nKH7880oIe0Rh3gc0hHHIl0Z4CshMCgYBifXHLkffPIA4AIKN11jJ+h/LwJqpk0+Vsv+gczqjepq7ztcBA0uZMhHT9pLLX/YFsyVo+8IBL21a4LkWnhLNVZW0qSvrhaCl5E85LuSYrVoaEUoaSK+ca8d3if+kGt/+3PhiESU1LLHuS3nWnzbJrMysGoHuvmgzYs7+AhgyVjwKBgQCoVgrFc1lUqIXTA4fMlgHmcnGRdl91nI9mn8FOeHWOd4tcFvixaE/jR1ZjUuIAN7ST0TJtFhy3lc66tgliXTX9aObOyrs9aTTIpa0B6fKP4QhosNOjK9PlFx1SVbUSqnFMZ50vWQeEArWfTeS0ECviwjD+CsEcBK2JFkz5pBIHYQKBgQD3zcYdYwvGkolLXNN3vbgTVnbNe2YMUBwgp5i1XGzAiG8XpwKTi4vDFIYgCZAG5wsyqUPdTOY2wyLjHwGdUfl7P3tCsHVzVh/xvuSl3nzW3OdCniKaBBdtZS6+s25Ijzdwiwnp21NWE6XU2BptIwTMHrKOc7BpZykgHsORMtptsQ==
|
||||
space:
|
||||
gcTTL: 60
|
||||
syncPeriod: 10
|
||||
storage:
|
||||
path: db
|
||||
metric:
|
||||
addr: ""
|
||||
log:
|
||||
production: false
|
||||
defaultLevel: ""
|
||||
namedLevels: {}
|
||||
@ -5,41 +5,32 @@ grpcServer:
|
||||
- 127.0.0.1:4430
|
||||
tls: false
|
||||
account:
|
||||
peerId: 12D3KooWNGRznbh4RCYY1hDnG1RLCtWviWwVnZGjKHtsXVgPckNk
|
||||
signingKey: buHKTg4VF6lskoFWDdjtjWNj2c/fz0zAxKrOW05pRRu4+aw/tClrubW5wpeCOJxPSMHJBTj/8bJ8icwKfe7yMQ==
|
||||
encryptionKey: MIIEpAIBAAKCAQEAtoc/5YBUSzPUISHv/COa2wTeWpsuxuLGOd+IYLXe8xXIry0GHCqCN7orZq5iz7BFs2i6o0ttK2PpRa5xz/GnKtTkQowmfDNwh/f+jIlMo+CcL54Qq4sURexChBCg6z3XbSQK1C9yGA4QaNFRDgSzAs1IC8BCRFf7XDbK06zxWw/As7D3Bo1V3TO0LWi/URkV1PBZdQxX6unt5VplhTQ92o22xczb15zfBQW59qEZYyPa2apwUfmhZgjoAbSOIQm96U7P+HrLa8va1h9q9o+eYefco2N7wv40MYsDXll09Tfc/VhDEfmuKfwmSe5AEnpsg1gD94fX/4KVt7Usb7u6gwIDAQABAoIBAC7POqS5p2Rt0z33/RqVavY2JmvoFjPtHlbjK49ZtOZ0NLYv/rwkbqap+M1pdW+7zfQ3rH2KL2IMSluTZB6m428Jj8w9MvVxH6/O+pnB8ESqqoNPrwi/LyDLeTdzKEGL535W2uwVitX+bVjkLTxCGkJisNJKqPPr+EtqxdNJK9BlJ9VdOLFLi67mOsu3F6AtDtBC3VFXZJa8Wbocu0A7hm8QWa23AL7+EZdV9kJ8Dw2qEYXyYRwmhExuZWNsPsnMvNhlCj8By9IPuICDzW87SfcsIQd7vjSg3y60mmGvl9WGxJbpEkSa+MxCA175k3E30KP1tYMOBQyhlCr7qRYWpdkCgYEA4a7CJGqtdMB8KByzrfGazm8koI0Y+qcriYaOWeoZayoxshwmemqJQTEP29D5SumxOcobKnKRHhKBhhlJenc5xNwppgMIgexZtLLAB2pZzLZ/bIy39T+lAEVOQWIEWDUQ0MwqaGNvaZ2bXyM1Xq6Bovurs8gSwmRIQspskeD/fy8CgYEAzwxpLa/W+BcRPH7VpLSkwSPgsAXW+TCoxWuCMj/W7MmCplyohW8a8wc42RFwKCH4ULpyNbv0VWdCM910/U1sf+0s7B3+IeW/0oMlLIPOd/Z39Legm+h0o1l3rD7deWdL7AMnaJIJsMBOUp0DRBSE5Bj6iUr1MnIEMX/3zFqdxO0CgYEAo4FSZMHpA3JFQWZyAy7M4o0Bc1RmaYrd7xhOX/RMECkUsh7U/dHbuSCLhc1kH5Mp9F1pyxoP60KrFnWRl6lzcB22CvGdo0uSPmlW2MiDYN5DeWiGCqfeqlCL/rC9xw5DLZMNkm2gFVu7anT+wKcbgvJlFq54cN/ovoMbn6DsWr8CgYEAgUVIbgP5fdA5LMIr9bfrncMeyAf9XnwpA4nKMkF1mUV/UwtLFHR4KQB7V9vxYL1E4nJmWHJPbPsZdHRyVKyAb6bPg2R+hP+DMpY7IX3x7ShvYNU9a9pI6Kw1cc+WS/RYjLSzaDC16CtJO39YyKrfBeMqmYm5aZOSVq2FM4voMUkCgYBudtWqqwKvA/Ig32hPBa/pqh+R11LeN8F/NsjrCA3geo8MlDqD0To+r9FTv14AksR7BsAfhoGglbvpddTL+CqHgtA4igNWp2/UCaomfnCgnFl/rvo+OGiVR5DgaC4ALw9onsdfeNgrQ5PkqCCi2crb3txdRWGA2QyGvsBmb1u8+A==
|
||||
peerId: 12D3KooWC9DkXiYK8MiQb87ffW51ggZR4FWASadh4UENXdaa16iz
|
||||
signingKey: yfFJv5klknUeG8rROCNTktCk5rsBvz16aEanYBAl9oYii+Q8XwH8mVXr5hHSiP+HYxEaSSozlMAAXUjdW2vK5w==
|
||||
encryptionKey: MIIEowIBAAKCAQEA5zUOQ42SFUYJyX86llYopUE4Q+RQvbCakTPd9LBKt6pBWyW3PA9sjFisxVFFwYOVwghzF8QDSRrWdkjGmRPPOSRNmNiJFGtk6wb26eihenFECdb4nJyTDZVhvayHpByCKleAl7dHLjHCIsVaaFfn5rntm47IdDSNFgZnNDrNrdS2SchXWHamcfWBJSQirdp+8kSh5RC6/J53LVa+Sff6D49BsF8VsevcjvFcdlpxG6GKhr6kzvnEwCCk8DIqjpF3geUVj/QbT9tGa12bAgDQuckW4DavIN1zT7BAUbZPcbFZ9Bd2bbKzXDFNt2mRXafDPL07KhnXSZ2YAxHf5M4s7QIDAQABAoIBABV5aQy/Lm1JZwlPBtsFv5qxtw8fOpyTtZd88MWURixO5OkZVK6AZD2Y0ts01DzIAvXVoRL5ArEcjATKd5+qJloRVB+5JOo/m0z1BaPuFmlv8bjUPZ0WMdZWJJDgYGzOtQxHukrdHABfYL+oAuCkIYbdiAMlvNqGMwBzscw5FfdqGBRwC0bus+YD103Hhc8pN0REwLZmiOvHR6b4Agwv4ruFsqthg13EwcqDVTnS1/sZyodLZaAGBUXlqUxuFakI/9CqpPuOkDgxelTYdXbS4yhfRF4zwoBGZx1462iJs4XM8TXhDcZpTRwCChM5Qf7jvvgbi7+gYTX9B1dxg7gZUyUCgYEA/cd/NqOyx7bn0twiuMEdq8bCi5Y/GvWLrQ3pf58DPanIydGPJU5/obKZw5Tv5LWbE5rUEeC2YpFleNh01oc0xHCveIR6JNGihN8u0DZPmcx2B1lwEzdYefRJfGcYXYhm/nCpzYn3VH0TfKA6qci+KLarYaeDpUCXAihZMUZxSfcCgYEA6Tr+fSXmHIYoKcewIpwSTvcFOJ6spMRSG+mxQAFit8vUQTw2e/aTESEECo24XJ/SKVK01CSoWXrw3t9eBgziyHI3GaaZ5LaXMZLLZhmGUT5kZiTR7083h+9bHt2+MzRXpaAEEc1FNgV3T2sSl1S+oKDL1MAcR42JaQtC1P2epzsCgYBKDdD9bL9ar/DuAvbO2uuBmLpkaS94+nYLxaeBajFT6RuCaPhQdpuf37Im9GscXjImgmOn497U3ICzxtYxU7r+J7PMgzvxSosWItpSP8bypks60cp2kQvsanCXMK5XfNoxHUcvhzb5HJZ3I3p62O1EjClukadErZhjNMryKhAc+QKBgFwvpUdyI3JC1L0u4L/NUK9FlBq9HSBDOPEvfY/+/DYJquveEOsOmzK6Cg7h1W1G/pq2xiLUGnbD0VFGmLNrhHgWLRFGeK2ePkSp8Rt6G00hjC2TgCdG+HwSb8HTg8pZdgtRJEqlCCZCItaRS9fk9zQmWmrNRGBD4XxTpybo2DzhAoGBAIxRN8WZc9HYVq8t20MieKP3pp5Nrl0wj9Z9EPvC60CwQRdv/FvWzDwF5/9Kg79rvbguZgjD6FNy35BGC5sN/24awWJ/mKYosctRwZVFpogoZ0qAdOwxowfAJXLRC5Chgim8vCFFdKdrMo2a6V+MQuhrTv06QAV1sYAH5P7abfPy
|
||||
apiServer:
|
||||
port: "8080"
|
||||
nodes:
|
||||
- peerId: 12D3KooWNGRznbh4RCYY1hDnG1RLCtWviWwVnZGjKHtsXVgPckNk
|
||||
- peerId: 12D3KooWC9DkXiYK8MiQb87ffW51ggZR4FWASadh4UENXdaa16iz
|
||||
address: 127.0.0.1:4430
|
||||
signingKey: buHKTg4VF6lskoFWDdjtjWNj2c/fz0zAxKrOW05pRRu4+aw/tClrubW5wpeCOJxPSMHJBTj/8bJ8icwKfe7yMQ==
|
||||
encryptionKey: MIIEpAIBAAKCAQEAtoc/5YBUSzPUISHv/COa2wTeWpsuxuLGOd+IYLXe8xXIry0GHCqCN7orZq5iz7BFs2i6o0ttK2PpRa5xz/GnKtTkQowmfDNwh/f+jIlMo+CcL54Qq4sURexChBCg6z3XbSQK1C9yGA4QaNFRDgSzAs1IC8BCRFf7XDbK06zxWw/As7D3Bo1V3TO0LWi/URkV1PBZdQxX6unt5VplhTQ92o22xczb15zfBQW59qEZYyPa2apwUfmhZgjoAbSOIQm96U7P+HrLa8va1h9q9o+eYefco2N7wv40MYsDXll09Tfc/VhDEfmuKfwmSe5AEnpsg1gD94fX/4KVt7Usb7u6gwIDAQABAoIBAC7POqS5p2Rt0z33/RqVavY2JmvoFjPtHlbjK49ZtOZ0NLYv/rwkbqap+M1pdW+7zfQ3rH2KL2IMSluTZB6m428Jj8w9MvVxH6/O+pnB8ESqqoNPrwi/LyDLeTdzKEGL535W2uwVitX+bVjkLTxCGkJisNJKqPPr+EtqxdNJK9BlJ9VdOLFLi67mOsu3F6AtDtBC3VFXZJa8Wbocu0A7hm8QWa23AL7+EZdV9kJ8Dw2qEYXyYRwmhExuZWNsPsnMvNhlCj8By9IPuICDzW87SfcsIQd7vjSg3y60mmGvl9WGxJbpEkSa+MxCA175k3E30KP1tYMOBQyhlCr7qRYWpdkCgYEA4a7CJGqtdMB8KByzrfGazm8koI0Y+qcriYaOWeoZayoxshwmemqJQTEP29D5SumxOcobKnKRHhKBhhlJenc5xNwppgMIgexZtLLAB2pZzLZ/bIy39T+lAEVOQWIEWDUQ0MwqaGNvaZ2bXyM1Xq6Bovurs8gSwmRIQspskeD/fy8CgYEAzwxpLa/W+BcRPH7VpLSkwSPgsAXW+TCoxWuCMj/W7MmCplyohW8a8wc42RFwKCH4ULpyNbv0VWdCM910/U1sf+0s7B3+IeW/0oMlLIPOd/Z39Legm+h0o1l3rD7deWdL7AMnaJIJsMBOUp0DRBSE5Bj6iUr1MnIEMX/3zFqdxO0CgYEAo4FSZMHpA3JFQWZyAy7M4o0Bc1RmaYrd7xhOX/RMECkUsh7U/dHbuSCLhc1kH5Mp9F1pyxoP60KrFnWRl6lzcB22CvGdo0uSPmlW2MiDYN5DeWiGCqfeqlCL/rC9xw5DLZMNkm2gFVu7anT+wKcbgvJlFq54cN/ovoMbn6DsWr8CgYEAgUVIbgP5fdA5LMIr9bfrncMeyAf9XnwpA4nKMkF1mUV/UwtLFHR4KQB7V9vxYL1E4nJmWHJPbPsZdHRyVKyAb6bPg2R+hP+DMpY7IX3x7ShvYNU9a9pI6Kw1cc+WS/RYjLSzaDC16CtJO39YyKrfBeMqmYm5aZOSVq2FM4voMUkCgYBudtWqqwKvA/Ig32hPBa/pqh+R11LeN8F/NsjrCA3geo8MlDqD0To+r9FTv14AksR7BsAfhoGglbvpddTL+CqHgtA4igNWp2/UCaomfnCgnFl/rvo+OGiVR5DgaC4ALw9onsdfeNgrQ5PkqCCi2crb3txdRWGA2QyGvsBmb1u8+A==
|
||||
- peerId: 12D3KooWKtsepiMYrDtok7AU4itPcmHQaLuwzzfYYyjEW1KoLeXp
|
||||
signingKey: yfFJv5klknUeG8rROCNTktCk5rsBvz16aEanYBAl9oYii+Q8XwH8mVXr5hHSiP+HYxEaSSozlMAAXUjdW2vK5w==
|
||||
encryptionKey: MIIEowIBAAKCAQEA5zUOQ42SFUYJyX86llYopUE4Q+RQvbCakTPd9LBKt6pBWyW3PA9sjFisxVFFwYOVwghzF8QDSRrWdkjGmRPPOSRNmNiJFGtk6wb26eihenFECdb4nJyTDZVhvayHpByCKleAl7dHLjHCIsVaaFfn5rntm47IdDSNFgZnNDrNrdS2SchXWHamcfWBJSQirdp+8kSh5RC6/J53LVa+Sff6D49BsF8VsevcjvFcdlpxG6GKhr6kzvnEwCCk8DIqjpF3geUVj/QbT9tGa12bAgDQuckW4DavIN1zT7BAUbZPcbFZ9Bd2bbKzXDFNt2mRXafDPL07KhnXSZ2YAxHf5M4s7QIDAQABAoIBABV5aQy/Lm1JZwlPBtsFv5qxtw8fOpyTtZd88MWURixO5OkZVK6AZD2Y0ts01DzIAvXVoRL5ArEcjATKd5+qJloRVB+5JOo/m0z1BaPuFmlv8bjUPZ0WMdZWJJDgYGzOtQxHukrdHABfYL+oAuCkIYbdiAMlvNqGMwBzscw5FfdqGBRwC0bus+YD103Hhc8pN0REwLZmiOvHR6b4Agwv4ruFsqthg13EwcqDVTnS1/sZyodLZaAGBUXlqUxuFakI/9CqpPuOkDgxelTYdXbS4yhfRF4zwoBGZx1462iJs4XM8TXhDcZpTRwCChM5Qf7jvvgbi7+gYTX9B1dxg7gZUyUCgYEA/cd/NqOyx7bn0twiuMEdq8bCi5Y/GvWLrQ3pf58DPanIydGPJU5/obKZw5Tv5LWbE5rUEeC2YpFleNh01oc0xHCveIR6JNGihN8u0DZPmcx2B1lwEzdYefRJfGcYXYhm/nCpzYn3VH0TfKA6qci+KLarYaeDpUCXAihZMUZxSfcCgYEA6Tr+fSXmHIYoKcewIpwSTvcFOJ6spMRSG+mxQAFit8vUQTw2e/aTESEECo24XJ/SKVK01CSoWXrw3t9eBgziyHI3GaaZ5LaXMZLLZhmGUT5kZiTR7083h+9bHt2+MzRXpaAEEc1FNgV3T2sSl1S+oKDL1MAcR42JaQtC1P2epzsCgYBKDdD9bL9ar/DuAvbO2uuBmLpkaS94+nYLxaeBajFT6RuCaPhQdpuf37Im9GscXjImgmOn497U3ICzxtYxU7r+J7PMgzvxSosWItpSP8bypks60cp2kQvsanCXMK5XfNoxHUcvhzb5HJZ3I3p62O1EjClukadErZhjNMryKhAc+QKBgFwvpUdyI3JC1L0u4L/NUK9FlBq9HSBDOPEvfY/+/DYJquveEOsOmzK6Cg7h1W1G/pq2xiLUGnbD0VFGmLNrhHgWLRFGeK2ePkSp8Rt6G00hjC2TgCdG+HwSb8HTg8pZdgtRJEqlCCZCItaRS9fk9zQmWmrNRGBD4XxTpybo2DzhAoGBAIxRN8WZc9HYVq8t20MieKP3pp5Nrl0wj9Z9EPvC60CwQRdv/FvWzDwF5/9Kg79rvbguZgjD6FNy35BGC5sN/24awWJ/mKYosctRwZVFpogoZ0qAdOwxowfAJXLRC5Chgim8vCFFdKdrMo2a6V+MQuhrTv06QAV1sYAH5P7abfPy
|
||||
- peerId: 12D3KooWC6sZYJXFagZtRjY4Jc4dzBLpEgYsUhJRauYheSAGk26y
|
||||
address: 127.0.0.1:4431
|
||||
signingKey: bqnCY+BB93A2nTM59zyP1CGZg5seSIeoGM/ATCOMy4+VvIfB1kwEK2VM5QVx3ub8zV/kqND8xuuQCC2NIrAFxw==
|
||||
encryptionKey: MIIEowIBAAKCAQEAxaNDIGlEwkYRtcw6eoM1wRReJJUgHbEPTGSazEHTIp9Vza0Ob5GqT0yTFbWQWec1+vfCCVj49Z0usKiIa78iViiZxN/EZtdbimM2b2LTOPPkHTBNM3KawuBtVd34CYOLyFFhc+m4dtquGTsOGC0q2YQlS/XF+vGNWO/j8LnriF47Vv3Vr2YDfYeLo3aMexjzLKDiL1TC8fxtcSHqwrJnhgkFEHV/BIadPBlCpVukTPPMusEaoMshHVViS2emStf7j7Iq6KDdbIMGRCTAKhLNMOnHDwmDlBo/RSS/iYtEXFEADDfiYPOeIKIExPnAfdbku5I1y3/IaxeSpk+jQDFfMQIDAQABAoIBACLEgsWL3z2x5+GsaMkuleE+fQVAeqLeiAtvU1AFcGgR0Z1aCUUVQfmrReC2zQsTwopA1ZChZ0KGATWwoDccK6UuhUZ9+uYAkqj4pRXZM8E8HnAIFDytt436vyEw6DZ8PrXhoxwqDHpUI/ZqTiNwpq4XMhx3wvlPTwdLRDUP7+BQK7EmmZLZPiU+oq7f8Fo3ag2gkRKakatPIjwKRDSXcLNW+Rz2YrxUOAdEir2KiK0CKYAkqmcZy/O1xBjQ0YgQpYgxgBXRHTgd5iIFjGG/bCIHsLyV+FkpMpgO7oFw0aJa6zISFeoZ3Zekpf0qqSQNrI+Tpc3uStSE8/95nIo+fxUCgYEAxuvt8VRl1W16ddYpGAFO7ytTdzFSg4e07rKPLvZbvQ4M21CASluNPPKn/S9KFaLZDagBM2jl2cjGYdHVfVlVu/fmM8nlTCIhxkjU9iHkyspJWXNxzUcnh12GEjcNb1i7Oc1QTof7HFjEG4TrsRmGdAee4ZjXYyIEPAHCgxAdc7sCgYEA/lkGdggdLfw6HkXceLaiuq8FA7asJ0JK7L5XCptAXZ9ci10oQuwC+58S8eFVkOUmnVwFovc7CF5EtWjUkSdI+AIL3WCnj2Xjm/S/ASNL1Urw7Q7A7QKu0kGawadUQ00/oSRApEC3f3XK0rdkRlryp8mj2WRfUyBEjh+NgLzgzAMCgYBHQK1Le3K6n2t1GBBCM/3FN9y+3iDzUkHiGn2lUcOMlaLPUCeT+vU9dqHr0+uSknFzLdG4S4PBneRJl7MEImLOYL7JoDENM1CryNzXiU59wTXC39JMuIcVOs/SaHvcfYka7EsuxhCRl84vGU6fckgx+aTUpD3KmZ2wrOSys6wJDwKBgC+VrjzE1di1mJXzUgUPfjBY8CI6uch6gZP7JEOqugcJ+oFkQ1UJ3KEAqMWx95UtGeVUwwUzJcsx/77ExwgFBoTHtTqMi6yrTkLuLhHjbZuQ8rQXD4cH+ncBqRdT29Lfj+jw5FsWdH4XJoP3pX34I++6LLpOKfteTRUd2BZev9vLAoGBAL24XaIkqAECCqdGLiID3PEIRLGacnjEoAqS7fT5A8CV0Cle1KKZzkJlJvxU/pzSgp5AjI1TwIiH4jYE/Xtc2+61Kx1C7jqK5tNK4lJ3BkHUY9d1Etr+HdnDZYKZ32XdGfh4nUU7dx+OI965oQJISsLVVmu2GBllsbg6sA+w3LnK
|
||||
- peerId: 12D3KooWJ2259GQZxf1PBkLBR8J37QN4PMiLedBU9h5PNbUwfaXE
|
||||
signingKey: mLzjMshSbtOkUKZha0bNIHvW9nlqOPX6VM/mvKicx6kh8ebP2mfrkCS0qz5GwlFEqTgtuSnWsHdvGZnuan2Ahg==
|
||||
encryptionKey: MIIEogIBAAKCAQEAuJcCEM4sM5I1Aj2y0HDgR/UrKEVF1iZ1CYWv4jVOt/e1avDn7XjF9ArB7lngq7lOTxpCNeLMQXeBl1gY1SBCPeTrs+tltyAUeSOZStwP9qhjUhI9TntfW3QfVlC2lB17liGa4b2F10x9vW/0f3R7m5xgz8NyqcFOZip0Ehe9UJbNFwPr00by0D4/XptkDT44wAIDlw7lgOmXWR3RpCYAYFonYeE2HK7FFNTIOJucfJ8kbK7wLp5EZRARYfCDUFq7czFu97FIrmQfS4Fyg8ESB+R28+dJIQ6G8U1MicX4Ibf9IkufK+r2fMYPv13F33omrwSGhNIWtX9WjAQ4bjmA6wIDAQABAoIBACHuaEvMimWEd8gMrWURirjPgXpqmXbPJO52K6mqYOkCWM/qrseBTuoYXCPDU8BdVN7Hleov4ZobLLA0WoQ65NJZ1VYCbHUoKXtHJvOS1kBiHbfFcI2PsiyugOAuABHkBYbIcJ8UZpj4D5kWDlyrfdlR+p3WcKpxxUaUgTeeM4evkMg2dg1/S4psgu1SKdGYMtafKBgvxxE0R/fjfP9MRD260/ydcUT0gRE+uUu6WFm92MLV72W3hoKfNqgGnQWCTG8UJGGK3KC/c9lAvLiDygo3GJLEjhnrIGkSbbd0uHtAYD8Uc+gq3z3o5Rger4P/FyWSbJ6Vz20iYHTeYUEDkKECgYEA5KK5/Z6XQHwsEGXSSCXKvUjJ7ZOV5k3D2im0F1dTtQaOjFgwZ9SPW/k7tQfcwfZLeDSm5V98FXSAu9XgT/Zrd+/RrfbgmKLMcNVet+l2OPq1cOeKE7io7wAXlkO5CmiMXMCRVcgqaENutUSTsmadFqd2NE7/gEUjeNIQLGkSsXECgYEAzq6+HtOxhfbTEC8ZUz6Y7+CphmtYiuX7G42lwv70mg+sap7mVlZzOHNNM1p9BOVEo2K1RKNWtXMgXDbt/KakBLCab9sR4R68tS7JX281I8RK/kYOLqlVE0CahujcCJATZAsDLMCpjeN85vwqJ9Cy1errf69thZwo1QI1BvRIahsCgYAkmz1GMycqZvczJOpXLN3aEpZqGHAusJLEEltIRW4clNEr/U66wRi29B+wK3MYBxQsSdnS7cfTM5UM/gBtLRol2NrsjJOHPMGY60DAF3wbQWDdk+TSpYU+xvf/0hYFaZnXm+lpH6RSj0FhenpfXPiX0PYnB+L2qZs1VATM54HbsQKBgG9nVwkMuCpqUXfuuyrYmdzqbtYKdG5h6kj+v7Nsc3G7MwdBYQx2iqKJ27nrc2m5HpcmtGgr1qf1RyMNZJgDRnNUsdnK7kc2pybN8jMjoTQHMRj/r9NM6JN5BhHj3/4pkpohKXPs4TeewAtNLnfJkSum9Yscht82vfeaufRmpcWzAoGAfxcnMvi2EhE6uNjDENqnFH9XD2zAAeKhiQumz2ts3cSUd1QOfPMeytsBML/jdmOMQNaTbMryhWPaqTewHky8P+l/7oVbMTTFnaaaZRZCSOSXe+2R3mJkRQzE+DkVhgfpEku/BVGRHRvltM+ehk3m64j5vHWC97cP52qZ0bkxKHo=
|
||||
- peerId: 12D3KooWFWyDckUJBtHtARzRDTRpo4XzeKAo8oN23MXh3Xwbp2fd
|
||||
address: 127.0.0.1:4432
|
||||
signingKey: RHl/cHYoPtAGXgJl7F3upI2OAnD4hd9aJztiqo08w/V52b3qKvFr2TWnpbNvBlXSxeyXpo4WB1jH+pMslW0irQ==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA2vHQaQ5U/PzvNFTk3G9t/IMELaxM5OBFV0/HcjDnF3jtc/ADtqG4zsr/VCs7/tiXiEIxn5aMFrvS7APh2/EHLlAnyrjYLyyxvgwqUtV06Gf5K2V7HmFTLch7VFc5HckU4Zg1B61EYAtnWu5JTmsZAmP1v3afsnfpdwTA3LEH65oOyEAXqCeNUtrrwZXYnt77gk1zC0NSdtE4Hf25OJ5to0kckmQf+TMxj5seA5+u55Bg/Hd9sorFl0X0JrAkIxnVcWYt9lCNZk4frPHl1deX9BwOJ5KKrz1Af/617rl8b8H5F+KzkHXpgpJfxtMLWUnUuaX7qm+R3qe1HeMCIAmOLQIDAQABAoIBAGPVHT25/kC5KG1JRG3LFXCtYOtehFVceeG9C+liqQzH5CYYS+krxrPsVg5QBHRI2JeV70CgidIX5K4few4p0ido/yvtqw2fqJBKxcWtdTg/qJsEE+afZCkdIDct6mpNdQsEtzF/7QyKRp9sxdpO9UFkyPp7oYfkK31MmpBG3KCtb57dyIKqfBoIrp9E54X+MtHHQsqpVo7wgdSufUAWA5OtrebqrUGhWrZCRVT5l+BbPp5WliTN12jVU3jdA6rkUzrdyt5jyZQZ1eIm89mBi3wQod3arUx+DnXeICroyWW7eumXqvPdYO9Y2eaGpXY9sjXioGARi97vD/qCB9qB/sECgYEA8L169WaUBfPU6qlD+qZN1Be6PprjBqoTYu3clQikYhF1HGcXT4ri1/8CT8gf9QsUt2NHzNf0vkhyqJ3bD+mxG/c62C7ff4mhLRR2MRiDnqFaYKJL4snFG6eachD7IqgXEJ8Uw8s+LUqljhMa3NlXgDyCdrazVto/J3iDx6/B2/ECgYEA6NKniFEFrJBEVr7neEsMzKSuu8S7VT8bZGNY5yLIHM7+E1YeyJko1BtaQ2f+x9nnRzRPpjO5H+oVLeRWj496retGmvQ24K6VPCq8b7I9QUdYOvhzgo+go6sCM4dzfespIi932EAHGFA0frZ29o9W9a8rgFZUoigde9KAYxVLQf0CgYEAlfUBfZFLDTYoX4/WV3B2NHIfQlYKqqEQeGRALdl3Q9sp/uo8fADActlXIElBlsszOVSvaervegP44A2MYiood4oV7omsEG6zpjgDs2tYuVw6xszxxi/3BtXs/7aSKLFZxLHDJn8YmO/RlmFSL1V3CtsmTTpbFfPWuQh51c4mTJECgYBQEhqR9CN6bIdEOhWLNmxpeP2rEAbJU5HNHam2nCysU7fn2Idvv9Td1aZeZkamXtd+kowOAd3aDvxHsy7d4p9zbuXyZqj07rXeYmg6FdehOrMqXMYFEfZSM37nT981YAneeurBkYufHf5f0crqEvP6PMs+MPKcbiVtr0B+UxV11QKBgQCmNz/q1pPxEltFBOZmsyfmplKgeDyexB8nb0z1NNc00tpKtWL+hvLqGQwYnECJ7kcJDNetKM1J6rDCoLg6hObf/Ze6/BFXTZF8bM6Xqz1elQPYgHl5P+vlJ7yVI5FClVG8RgI73vxr67CZk+4zsZbvTLscaZ1ZPkPR9m+YMJWUrA==
|
||||
- peerId: 12D3KooWNJdqtKLZAxT3szMrWoSLS1F1JkyKgJ4YQ1rAKfeVPMm6
|
||||
address: 127.0.0.1:4530
|
||||
signingKey: BwEWqy5XqOeEUy4BmMzv1WltI5TvLPfP2l2mtioxb+a5ijq4aSATKZSFfcm2hpbGDObWOzeyi06BarLOfQsTnQ==
|
||||
encryptionKey: MIIEpQIBAAKCAQEA2sTIJSgwRRwPVINYyC5lHtZGsBth87wV+mwMVHkt1/Er8WVstudDFj7dvpO4wHE9vzOQi8+VobNT+xZSB1hlLbOuyBMDzdg+0vs1rMmYruKWb12VZ4+ir1xhnqpm5sKhPuPylZFp+m2GuyEeMHjUNnbQDgPSxkh9jNnTnlwG86h8r5BlhbiISZUs0Jh+IiAbgf55xTdYp0UmVREJYpmk8SBOQS4HfkWM7ih85zMrA0lzi6bfghN7CSABpAMYSgLJc9XeP3le8iMSKQsT+RRvXgUAniPT7ftbWg0tZMNjJ9CXF12Mp0ElC95UIwOnJJydgrLMLvQ0Lggie/WdN0PpCwIDAQABAoIBAQCvg37bqLGJUKjP8gzxlZ9VLS5LLbzZUgYEAlmmEA6CmB/cLLYay9Fb8JXwxw1Lf869Ln6CXMm8kGYJJPAsqnOKRgUsyWyc4igNFrQKazbO4EU3Fcq+6lLoA+Lh6+5gpre9AB5oduCipOqaCUjyNI51H79t7w1UPWZU8ZHBFC4TnpanTYTqyYwUThqDR/PExyV7mhYN5gEi3cg4W0cA7qlDaGgwaKBrMphRt2xwNlAlYAhdkwdgRmbnB/zrWb0FHqJAsz6biqqNh0N0EgIsF0ZMO0ZFGRt+Ou36500Z1cRpGurbO1zrpNV2R2Gg0Ssun2tfjoYJN22HqwwLY71s/xXRAoGBAOx5KeiD07zkRCUzfVa9oHd9CxFSpStz0mCauFDpW0nhzgonjSaOmEotGvVRLDF1eqbtji2QOx3WSPXdnNlncyYAsWFJMyupygqsxBxnVBX3yFFicOE6PCaZocwDVmdKNNfg/52U13qS4pxFFclUPHlVvEcovR1VAPP08MvyV4x5AoGBAOzVW7FmVgzAUc9E8ro6pXD4dFyNkE6Hasq5ApQzFbqcaHSUjbS2lF5dKhvur4OABy6XO/wgD78b/bC+vMryxC+yHm4FP+ANpQ+/DSrn+g2X80J0wqC2tIIVqYMOzn3L+gSfRnhW+28vEx5SSofa7aZl/NOoXtXD47amJELwYzijAoGAVH9vJDCG5oZCe3CMpwQXZNr/q272qjI2yGJA3likUCApuaMsYsytSkQXz/Tzb7Dk5OUZ2tog5aZ+Z6yKsXyvvrKcr4CykjWXhnz5jpS1jSv/HmWopDJk7/4RvI6svzfa7hDuBeb7oEcARorBIDHDci/amSrLeMG5F3M84AN2mTECgYEAvx+PV6JWXwP1AWeK2m7phDl87hPwGO9/ZwnW4vI23tnKEgqwMN4G7gARM2lzipOPODIj3luhWYClQjUq9jzjxfngRLlHyvA3/HUZkz6RtNajIUZIqpnHIhOJMJKKYUpzAbfnjsXjMt6ydw3Bx9ENZ/N2DPkbTzc+VO/O45ZK/DECgYEAvhovek7Jk4ZmC1OsxedqudrgQugNGTMnc6gFZR/CUXrtBs1vq4zKe003Nx5WPGaYooySVraSgBplamtsL+dUsVRqWjCyuUrSkuv7XtP6rdSuRJEHTs7vumnGsF2pp+I08W1Bg0zUFToGy0PqFX9pVeR1f63COI4Ca1Vy6+BIw1Q=
|
||||
isConsensus: true
|
||||
- peerId: 12D3KooWP2cwtzkokAGAr8UzdW1pmU4NS2D4dvHJtK2q75TBEeKq
|
||||
address: 127.0.0.1:4531
|
||||
signingKey: RyKkgbAlAmo+suhJf1mYau3uneQD93XO9Dks/a8lpXDES5wfPb3dO/8oefEFllI+c/m3bTVkAYBdTHtCZq7lYA==
|
||||
encryptionKey: MIIEowIBAAKCAQEA6Dhjs/8s/uiTFIopCjoYLTq8JGIM3otbUktYXSnqpBVVUU4TwSJonpyeRCgcYy9FlDWrUPfCNEv/kG6ruNUZQs2UuPbaOMZ1Z5TZRokwZF26rlkmaTlwJLKmKy0wwT9koZT/e5G4NkRO4rOLK/O4NyDlZ/HvWaZPxQtcC4en0CDaaIcDSSKaL5OMz0fcXayQlWKiOsuuP7cSUYlBDybbJPLSPMVYUjGjzIBqZkV6nBgjKGIIBGlknqZpRwX1mgq4vG0UYTfGCOFF1iHQ4TiLM2EiiZw203PVA4ifSyvkZOkMngItBfYcnD5MRYtLXlps2LWW6auN6olAkyUwFQeHLwIDAQABAoIBAGq7kEfo3xuCdieYoOhMb1RKjLMERfn7f0vByal4XJpyG7a09itszz0nqy6UaQfFcGuAh289kQtMavhNhav8dhHYP6UMAJzbypaDOaJL5+wZkHYWD6uJdNvJKMrriF8p7ey+ePaosUxv9PoJn8vhxye/fPFbp7FC2aMtZ279OMpVjyhbBekWlHfAnRbmDaFjMH+7wHfaAArpYsmRaOJ+/ckqhHSWSCXHO7dOyTcRNx4J0NoZ+192J6VsD1bbGxfHEgtVac/3+fj0Uia3mjkA+e9+oe7kfiGAheLs7G+kC0rEht1VLkviwjM0oCPd3zcu50HjqSrQ1q+i4vKJLrPWQFECgYEA8Uz+PlwghCWcJ7c+TYL1Y4UpYMXavRYi+XCHyn5x2PtxLDgK9j38CbLtIJFDY739RxEDLsOAkC3ba5p71EAx2ZF8i4ylmw0ekTe8BhEo/PHhCmLL+12zUrDbmUqsb1/NJBRDVZ9975nqWiT1KWqm3XKrwfBRTvgiP3+dC3XrtiMCgYEA9l3KBUK0oc6RWftNQTbehrwMuG0M4wv05peTHHqlMsYV0b5nKCr1FWU+gA4zhEDNPcs7PkZRl+HHMalkKH/aLpxeafN5a4PkMsQD6ZK5Mz88IENzXbFswBjCI8s5NyAAK+aI4JqXiRoia6fRnWVp+VrC4A1o2dvD6GaZAta3bYUCgYALFhF8RflMePnirT2UjBbAGsca5hw1ocW7lhr3B7YtVOgPMwf15kUlIO5aF7Jz66+uSy7NQDgw55p0KCXWS5i+uTtyoeSd6g1keJ4P3Uv3yxkexAlBJD3v56Y/NboUZ99h7/hj/67mijjFKXuGCpteAz227Faf/TB9oFxTwXgx5wKBgEMOeCRCacP445soSXjMpHjrylKQbAeIg5oX+5Su1TQismGqf41xU9AFBKP6OY9vy+1b2b4ziZXbgEpGHtrfIdW5/gC8onnfJkejDqWOqBYIyibF9Sq1VjJbCsyPTf1xGlrYnrzzlvdcQ64luWor5lJWn+A4Bif2JzakZlVdeAO5AoGBAMynKpkB8vqTLU31yt5SzBroQj8TgZKGbzB2apO1a+2XE8WfmtFOxnS1/iQ67sMkv6Rh/N5SUxMnBLXjsYJFpuNkKjvE+RqO9f4PzklTIJuT49pexheAMKBA9zWv5YPEmMV8xGbqXooSuEP0ixlM07DiqaC7aBzSyIfGdTOvI5w/
|
||||
isConsensus: true
|
||||
- peerId: 12D3KooWMg5c9wHkuXQ48qyHVa72UKerKWAVZRC2dc1ibSadYxTQ
|
||||
address: 127.0.0.1:4532
|
||||
signingKey: gSyxSnCL8NsewJmdFwgVpjQ2hDwDvrbZrLnA1007ymCwLN67/Xd/42q4vsvZAovsXBrv4PuWuoQUqmXhX7OJrw==
|
||||
encryptionKey: MIIEowIBAAKCAQEAptyiobOzgLUuVfUQetYQD638+kOUAjf+V7uny+9Qhtt0LZM5v4lsJ8DK+NIbJU6fo9sMNJ8Mc2A7QNEZ6iyppI4zszUIMfF9Ixhew8g5zBlaDzieAf1XSGuEd89vj1ikM3Nhp8AXzxxoFOTsgUCMlnAzsHalcVyqXRzN/glAA1Ob6R0pIEIz4LchvMpnjhSLi5XEmBMy3b3XHu+T5nYyLzLxxMpO2fHH41/GpWmOEVrjoT1qP1JSv+ehuXiuMW0rM1833os6jMHCZijfDGh8blWI2nthjOLbr/KQKQhkIqOXKwdkVLY5x4/c78L8dV3eZ647SqurWC/N8kr5r4LvfwIDAQABAoIBABTPHSUHURJzBeVIW5bGDVi3PP5E4Tdpnjl4uJNRM/ytb46jdqcxTyCiBW4EXchIRtZbYelKEHZvANSzfwTaLwnLhh0KNwxrbkyrJF5MIREX9EhDqkjbPEBW0D1UzDfXORsFf5848H8urrg0WF5CG4ZDVd7i3P0HLmPQTMwqgSYo2pLexcj0LtiZZqJ6ta9kxAiJniZyoNshRJnAZMMnFYRhy/eDF+L6sJPHieYgwiQFU5e0CK9UgsLmmOQWCKWtPgvxOhqlbcTz1pJAqkyzOC0wK/ydJpVAh9RUqf46rEDFzL/l90ZOir3AMlYJIHf4PX0TWchXjFW7bbHn5Zvk1xECgYEAzpuGDfaerUl8QziD6F/OoIz1/EZwSumErCH2NXYMBcCyzKu4fBqVqj5tcLsNx42v6kAGaERAQqaC5ZZ9ZNhXiWasHAermQqv8DtlYVCUih4e87dX1/xTF5TzR8RhLwHPADd1rRafCKJMD9X6Qquer5LmSST8ej3mJ4mrflw837cCgYEAzsCoqFenGlCvAZoQrekxS1VmGJDCKBQ7LlbOwQaUkD4I23rjbAHG8J51jmaQQ4epm6lU0JLSma/LKp8dl9oDEP09vcgKj6xuHMZV+EmsA5c181zMrGoH+tSZiWQZjSmJVhd5T147vnbUunTbGKlOQByD0tWM913Dm2dqB3goXnkCgYBZax4dtPr/7KoHPdJ5I939xoQ/5wx6n454IUq54JlbdAbuZfO2Ypsbz2D2RT61ezEDpSogvklBj2dfjj4/AxL/uJwMlZVC60kyI8LA12syS88Bk/xE0kP0FNcl3GxjN9krMtWPUBcMWZGp2OYzLKvFOULJrWRIU7nkqsS6L5l5CQKBgBa/tg8HzfgkRo1LkWhBT041sE0lqGdWioh3vroYakJQwRK9O8bHj0cseEzZ1ifIBo59HDry3L9SS21+Inhx4YJ+CswV9auHUnpSDGWMXaPrgGEtpcuWwxgDSn2GiRUyK81QOeXUvYggdRmq/+x/vH9rY8nP+3nAVGSGBXGa8/4pAoGBAMB7EOk/RnsgQ+SotHbvgv18S0lbJuWsLYGnNp8EcuPxDIxz29fOFH94qzVOwAkk5cbHvAl3/5sl3SelmKM9LXhcOT+1zxoavyAYyVeAGZsrbBmbzj9yeZON0gHtpF3dMWxiguyWuiiHM/pL92gKzlyIXryC3andL/y8/6VpWbtt
|
||||
isConsensus: true
|
||||
signingKey: YpCGjsSuT8O6mkYTOExkdwNRODBaJ20hYJHFO/A/RUFUsUwxIME9X9FIp69VYvKuL6er973p0iG7UVVvLgLjnA==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA2T4/6T5etB9W7qzJ1sNfWFdOTa2koXKcQkaLBUTervApLPZtaVsbNtyVFtqqdsck1qpu+AVif19EFlYqSRtn/dxEN5/2myqVA6lZMm0Bd9mWpfoDQx20KAYwWBwzKSH1EQiTte0bw1zf0RpztxQ3nCOLCU4Y6x2lfk6Ea2XEayPxx0FDmeY3JSqUDOwx33Sz8Imx8R7+Dfjl6Og3DEqGxXoPfZ6hj9LynqNswjRIdmMZPsuEHguKXMbp+cncErGWcyzH417XYSDPoRn/3awpLfQ9F+KSjAe5cUltC7M4veSZW+t3VcJypvfRlU4ayTZMuvMHPlMcl/0jP5w0Q2+2pQIDAQABAoIBAGMvmrqBcXfHv0cluNnHRebtpaCtoTbdPx67WonDUfCJUiNnN7kckaZQu/k9SQsGDXm9QwEWZExHUKzqFlBepPIw+Sx0aoGZxYNwdHsjbcIspC2PoqGoFDMZ8ESqS2mCSYPHaLltUnm2E7JC44Y5QtKVH8vVzma6mG68ppTqV+2aGfGiPDq8cAYeH9/8Ys8/S28IwCp/M7lnXZhJ38bHD3YyPpcgbyGI/Zr5xaPd0hqHH08Z+S9V7QPJUGY0Y21s99DhkUGctb4B17d0/3Nzk/iWY1rp7A/kbdBeWonsHrTc6OnmbdiOcjC8seOIKMJ/WE3JznqnI1oydFb/dp6raNkCgYEA+pn1akGIKnVP0oFh5PZfUpuZtVV9u9xccIXyeFmCAXyFuUz1KYbfwwqZnm9r6kHAO+aBtRtVsCVle5oVWNQq1pdv117hPhRnVrDtvL80z50a5L9gEVu4Yz24Q3vs3RglcVpafSaRuyPbiYHMmQ4Ly+9nbwEbOVDbzK5A3Wrny2cCgYEA3exS3aG7+7mbSnNTYkkTgl7goLXZgEST/0EM2CvayxZ2QUS94Vq5HjGRpWnni3YttLiYlgCLe3CqeiIh6E3n6b9sory8Oy6lik/elj28kcZIuNvPU0xVcqrmGCg/KEnYkXjsGKsBDk6SV9nKH7880oIe0Rh3gc0hHHIl0Z4CshMCgYBifXHLkffPIA4AIKN11jJ+h/LwJqpk0+Vsv+gczqjepq7ztcBA0uZMhHT9pLLX/YFsyVo+8IBL21a4LkWnhLNVZW0qSvrhaCl5E85LuSYrVoaEUoaSK+ca8d3if+kGt/+3PhiESU1LLHuS3nWnzbJrMysGoHuvmgzYs7+AhgyVjwKBgQCoVgrFc1lUqIXTA4fMlgHmcnGRdl91nI9mn8FOeHWOd4tcFvixaE/jR1ZjUuIAN7ST0TJtFhy3lc66tgliXTX9aObOyrs9aTTIpa0B6fKP4QhosNOjK9PlFx1SVbUSqnFMZ50vWQeEArWfTeS0ECviwjD+CsEcBK2JFkz5pBIHYQKBgQD3zcYdYwvGkolLXNN3vbgTVnbNe2YMUBwgp5i1XGzAiG8XpwKTi4vDFIYgCZAG5wsyqUPdTOY2wyLjHwGdUfl7P3tCsHVzVh/xvuSl3nzW3OdCniKaBBdtZS6+s25Ijzdwiwnp21NWE6XU2BptIwTMHrKOc7BpZykgHsORMtptsQ==
|
||||
space:
|
||||
gcTTL: 60
|
||||
syncPeriod: 10
|
||||
storage:
|
||||
path: db
|
||||
metric:
|
||||
addr: ""
|
||||
log:
|
||||
production: false
|
||||
defaultLevel: ""
|
||||
namedLevels: {}
|
||||
|
||||
36
etc/configs/client1.yml
Executable file
36
etc/configs/client1.yml
Executable file
@ -0,0 +1,36 @@
|
||||
anytype:
|
||||
swarmKey: /key/swarm/psk/1.0.0/base16/209992e611c27d5dce8fbd2e7389f6b51da9bee980992ef60739460b536139ec
|
||||
grpcServer:
|
||||
listenAddrs:
|
||||
- 127.0.0.1:4630
|
||||
tls: false
|
||||
account:
|
||||
peerId: 12D3KooWC2SctmKSLWqmzsKCpQBo4iqNzbZhWivM3jbhovB4JFug
|
||||
signingKey: Maen+w6qwWuS79RZyMbuW7wnWAox0+rMinAb/gsOSl8gz2BLCfMlwXjlo8NLKfFFZFNUzl0ANTxbrK45Be7CPw==
|
||||
encryptionKey: MIIEowIBAAKCAQEAonOsG0DzAzGlR7cd0u31DS0xoHihxdfJwut5JMtLKqGwkUC5RM+/eTa96hKYp8ED6B8Q4ZBhmt2gQnOUQJpoAnJ6uU/HgQVVhsJD7uMQcyVWr2KZbRK2GAohxOiW8JaB8pLiIRJbOxaeIu8dGRTrTTxYnh4IbIUgMu5x3iPW1/6YT/LCN1r/CBgHnPLtxMjAdUYzz9+LC13sZJsanUot83MTgl+5unEPh+ogbrSJ6P8FAAWW8HHD5lUSSb2l8NFRafYWP4o3vF9fqtmpt5I2nK6PaNh+4YXB7CX8Nak3AYuSO/aLGUtZMGYv9Qqwewjk/ewEGNWz33D/Hve8+hctXQIDAQABAoIBAQCNY7/XuJ/Jl9wSnv4GJ7Ww0jTvRg8G8tlYHTpDG+1AHZpf0cVubqJoDY0dvTHAT+3miaNXryJEd8CUFaRi1gDQoHLP9u/dC5d0wn/92wLmNQlNfLOsiyyRn7/kccttepF/XvgRcLiWpQjdvt/EhMCHaI54kAsk6Hkt2vqgLPFA66MH/5AMyf+8RmouYvc1m8jPUVmkIZVkoO4/6kh0tZS+rGdjxB65zDaoBx6CcXAMkTWe27Ce87vfGwCRySGVGRg7RuTJQR8VO3oSmsPVIZ8A48fKPQvryrl/5ztvE35lL4i3pdIbd/CJ9zTKIEM4nyPWSmxsaxs1yIllsj3BFpDBAoGBAMzWUEBYm5FH6wG2GXigkou4VSUBAoKCi5XmA2bwCUZx6CaG4uk43cbYpkbLpIRchfLHAeVCiaOYe5VFvYMth6o+OICEKfXWEwGqjtWeHkyIQIZ1Yo+BKk1rbzkYa/n3a7Mw+C6HsweFq1v01eTChmMr/PF6trFQiJJhTGkGKS2/AoGBAMsHKMEmgw1/hRqiEai73AVLSzXGoHSUWsM1vV05EzDyoxkk8Q/+sJR/BOp4HvJidXiM9B0hSOBhkPZjP3TZSQTKXwMGY+Hcs0XhwGxV5Eb9XdbD5rhCT6eVUeQeP9W9J34RdobJauG1Ld9E1U0nKEI+ls6VZf6/k+ixDOa3TaPjAoGADI+7/iYw7Bjf9YvoRfh65CyatBk6wSwmSTwAy2g++V304Z/1/F1rZE1W7RKB9UgDQt8nY5rP/ANW2NGdDJVXM357Uo5IUHYfVkPSXJFExGa6pkQ+lhRStsq22GaCAKNGrId9QMU7mmN9HbeHAm9XdG93JIvk9jy9E1T6LZqeHdsCgYAXsvQ856PwlWwSGcz550PdklZrJo5gTVjy5HkAQsNMuWX0b218MnymONV4ESF7paaUtc9g/xukpX7oY9lqaFqvpnfEwKA0IzEB/UIa40PMTZMAmMl7xLHLnBB9ElLdPkE35A3z2dsSEbYTE9PaN7HpWaj84E+RlwdK6C/bVpZHhQKBgBv8Up6nOfQyW4jiRo5CPOzXPYu+tXfsV0lKbYAjlp3rcczsi/BPXF6tLZ74/f5Cp2NJxx1GIitjqGzZ1mhkB8Eimuw1o+uNRBRh5BcmQTXPTxrrbOsYzjBJNb7n9HcHlGivcmDooxP7TgRJydEiFdpoBhjU+7yGJTJk7YdDLI3I
|
||||
apiServer:
|
||||
port: "8090"
|
||||
nodes:
|
||||
- peerId: 12D3KooWC9DkXiYK8MiQb87ffW51ggZR4FWASadh4UENXdaa16iz
|
||||
address: 127.0.0.1:4430
|
||||
signingKey: yfFJv5klknUeG8rROCNTktCk5rsBvz16aEanYBAl9oYii+Q8XwH8mVXr5hHSiP+HYxEaSSozlMAAXUjdW2vK5w==
|
||||
encryptionKey: MIIEowIBAAKCAQEA5zUOQ42SFUYJyX86llYopUE4Q+RQvbCakTPd9LBKt6pBWyW3PA9sjFisxVFFwYOVwghzF8QDSRrWdkjGmRPPOSRNmNiJFGtk6wb26eihenFECdb4nJyTDZVhvayHpByCKleAl7dHLjHCIsVaaFfn5rntm47IdDSNFgZnNDrNrdS2SchXWHamcfWBJSQirdp+8kSh5RC6/J53LVa+Sff6D49BsF8VsevcjvFcdlpxG6GKhr6kzvnEwCCk8DIqjpF3geUVj/QbT9tGa12bAgDQuckW4DavIN1zT7BAUbZPcbFZ9Bd2bbKzXDFNt2mRXafDPL07KhnXSZ2YAxHf5M4s7QIDAQABAoIBABV5aQy/Lm1JZwlPBtsFv5qxtw8fOpyTtZd88MWURixO5OkZVK6AZD2Y0ts01DzIAvXVoRL5ArEcjATKd5+qJloRVB+5JOo/m0z1BaPuFmlv8bjUPZ0WMdZWJJDgYGzOtQxHukrdHABfYL+oAuCkIYbdiAMlvNqGMwBzscw5FfdqGBRwC0bus+YD103Hhc8pN0REwLZmiOvHR6b4Agwv4ruFsqthg13EwcqDVTnS1/sZyodLZaAGBUXlqUxuFakI/9CqpPuOkDgxelTYdXbS4yhfRF4zwoBGZx1462iJs4XM8TXhDcZpTRwCChM5Qf7jvvgbi7+gYTX9B1dxg7gZUyUCgYEA/cd/NqOyx7bn0twiuMEdq8bCi5Y/GvWLrQ3pf58DPanIydGPJU5/obKZw5Tv5LWbE5rUEeC2YpFleNh01oc0xHCveIR6JNGihN8u0DZPmcx2B1lwEzdYefRJfGcYXYhm/nCpzYn3VH0TfKA6qci+KLarYaeDpUCXAihZMUZxSfcCgYEA6Tr+fSXmHIYoKcewIpwSTvcFOJ6spMRSG+mxQAFit8vUQTw2e/aTESEECo24XJ/SKVK01CSoWXrw3t9eBgziyHI3GaaZ5LaXMZLLZhmGUT5kZiTR7083h+9bHt2+MzRXpaAEEc1FNgV3T2sSl1S+oKDL1MAcR42JaQtC1P2epzsCgYBKDdD9bL9ar/DuAvbO2uuBmLpkaS94+nYLxaeBajFT6RuCaPhQdpuf37Im9GscXjImgmOn497U3ICzxtYxU7r+J7PMgzvxSosWItpSP8bypks60cp2kQvsanCXMK5XfNoxHUcvhzb5HJZ3I3p62O1EjClukadErZhjNMryKhAc+QKBgFwvpUdyI3JC1L0u4L/NUK9FlBq9HSBDOPEvfY/+/DYJquveEOsOmzK6Cg7h1W1G/pq2xiLUGnbD0VFGmLNrhHgWLRFGeK2ePkSp8Rt6G00hjC2TgCdG+HwSb8HTg8pZdgtRJEqlCCZCItaRS9fk9zQmWmrNRGBD4XxTpybo2DzhAoGBAIxRN8WZc9HYVq8t20MieKP3pp5Nrl0wj9Z9EPvC60CwQRdv/FvWzDwF5/9Kg79rvbguZgjD6FNy35BGC5sN/24awWJ/mKYosctRwZVFpogoZ0qAdOwxowfAJXLRC5Chgim8vCFFdKdrMo2a6V+MQuhrTv06QAV1sYAH5P7abfPy
|
||||
- peerId: 12D3KooWC6sZYJXFagZtRjY4Jc4dzBLpEgYsUhJRauYheSAGk26y
|
||||
address: 127.0.0.1:4431
|
||||
signingKey: mLzjMshSbtOkUKZha0bNIHvW9nlqOPX6VM/mvKicx6kh8ebP2mfrkCS0qz5GwlFEqTgtuSnWsHdvGZnuan2Ahg==
|
||||
encryptionKey: MIIEogIBAAKCAQEAuJcCEM4sM5I1Aj2y0HDgR/UrKEVF1iZ1CYWv4jVOt/e1avDn7XjF9ArB7lngq7lOTxpCNeLMQXeBl1gY1SBCPeTrs+tltyAUeSOZStwP9qhjUhI9TntfW3QfVlC2lB17liGa4b2F10x9vW/0f3R7m5xgz8NyqcFOZip0Ehe9UJbNFwPr00by0D4/XptkDT44wAIDlw7lgOmXWR3RpCYAYFonYeE2HK7FFNTIOJucfJ8kbK7wLp5EZRARYfCDUFq7czFu97FIrmQfS4Fyg8ESB+R28+dJIQ6G8U1MicX4Ibf9IkufK+r2fMYPv13F33omrwSGhNIWtX9WjAQ4bjmA6wIDAQABAoIBACHuaEvMimWEd8gMrWURirjPgXpqmXbPJO52K6mqYOkCWM/qrseBTuoYXCPDU8BdVN7Hleov4ZobLLA0WoQ65NJZ1VYCbHUoKXtHJvOS1kBiHbfFcI2PsiyugOAuABHkBYbIcJ8UZpj4D5kWDlyrfdlR+p3WcKpxxUaUgTeeM4evkMg2dg1/S4psgu1SKdGYMtafKBgvxxE0R/fjfP9MRD260/ydcUT0gRE+uUu6WFm92MLV72W3hoKfNqgGnQWCTG8UJGGK3KC/c9lAvLiDygo3GJLEjhnrIGkSbbd0uHtAYD8Uc+gq3z3o5Rger4P/FyWSbJ6Vz20iYHTeYUEDkKECgYEA5KK5/Z6XQHwsEGXSSCXKvUjJ7ZOV5k3D2im0F1dTtQaOjFgwZ9SPW/k7tQfcwfZLeDSm5V98FXSAu9XgT/Zrd+/RrfbgmKLMcNVet+l2OPq1cOeKE7io7wAXlkO5CmiMXMCRVcgqaENutUSTsmadFqd2NE7/gEUjeNIQLGkSsXECgYEAzq6+HtOxhfbTEC8ZUz6Y7+CphmtYiuX7G42lwv70mg+sap7mVlZzOHNNM1p9BOVEo2K1RKNWtXMgXDbt/KakBLCab9sR4R68tS7JX281I8RK/kYOLqlVE0CahujcCJATZAsDLMCpjeN85vwqJ9Cy1errf69thZwo1QI1BvRIahsCgYAkmz1GMycqZvczJOpXLN3aEpZqGHAusJLEEltIRW4clNEr/U66wRi29B+wK3MYBxQsSdnS7cfTM5UM/gBtLRol2NrsjJOHPMGY60DAF3wbQWDdk+TSpYU+xvf/0hYFaZnXm+lpH6RSj0FhenpfXPiX0PYnB+L2qZs1VATM54HbsQKBgG9nVwkMuCpqUXfuuyrYmdzqbtYKdG5h6kj+v7Nsc3G7MwdBYQx2iqKJ27nrc2m5HpcmtGgr1qf1RyMNZJgDRnNUsdnK7kc2pybN8jMjoTQHMRj/r9NM6JN5BhHj3/4pkpohKXPs4TeewAtNLnfJkSum9Yscht82vfeaufRmpcWzAoGAfxcnMvi2EhE6uNjDENqnFH9XD2zAAeKhiQumz2ts3cSUd1QOfPMeytsBML/jdmOMQNaTbMryhWPaqTewHky8P+l/7oVbMTTFnaaaZRZCSOSXe+2R3mJkRQzE+DkVhgfpEku/BVGRHRvltM+ehk3m64j5vHWC97cP52qZ0bkxKHo=
|
||||
- peerId: 12D3KooWFWyDckUJBtHtARzRDTRpo4XzeKAo8oN23MXh3Xwbp2fd
|
||||
address: 127.0.0.1:4432
|
||||
signingKey: YpCGjsSuT8O6mkYTOExkdwNRODBaJ20hYJHFO/A/RUFUsUwxIME9X9FIp69VYvKuL6er973p0iG7UVVvLgLjnA==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA2T4/6T5etB9W7qzJ1sNfWFdOTa2koXKcQkaLBUTervApLPZtaVsbNtyVFtqqdsck1qpu+AVif19EFlYqSRtn/dxEN5/2myqVA6lZMm0Bd9mWpfoDQx20KAYwWBwzKSH1EQiTte0bw1zf0RpztxQ3nCOLCU4Y6x2lfk6Ea2XEayPxx0FDmeY3JSqUDOwx33Sz8Imx8R7+Dfjl6Og3DEqGxXoPfZ6hj9LynqNswjRIdmMZPsuEHguKXMbp+cncErGWcyzH417XYSDPoRn/3awpLfQ9F+KSjAe5cUltC7M4veSZW+t3VcJypvfRlU4ayTZMuvMHPlMcl/0jP5w0Q2+2pQIDAQABAoIBAGMvmrqBcXfHv0cluNnHRebtpaCtoTbdPx67WonDUfCJUiNnN7kckaZQu/k9SQsGDXm9QwEWZExHUKzqFlBepPIw+Sx0aoGZxYNwdHsjbcIspC2PoqGoFDMZ8ESqS2mCSYPHaLltUnm2E7JC44Y5QtKVH8vVzma6mG68ppTqV+2aGfGiPDq8cAYeH9/8Ys8/S28IwCp/M7lnXZhJ38bHD3YyPpcgbyGI/Zr5xaPd0hqHH08Z+S9V7QPJUGY0Y21s99DhkUGctb4B17d0/3Nzk/iWY1rp7A/kbdBeWonsHrTc6OnmbdiOcjC8seOIKMJ/WE3JznqnI1oydFb/dp6raNkCgYEA+pn1akGIKnVP0oFh5PZfUpuZtVV9u9xccIXyeFmCAXyFuUz1KYbfwwqZnm9r6kHAO+aBtRtVsCVle5oVWNQq1pdv117hPhRnVrDtvL80z50a5L9gEVu4Yz24Q3vs3RglcVpafSaRuyPbiYHMmQ4Ly+9nbwEbOVDbzK5A3Wrny2cCgYEA3exS3aG7+7mbSnNTYkkTgl7goLXZgEST/0EM2CvayxZ2QUS94Vq5HjGRpWnni3YttLiYlgCLe3CqeiIh6E3n6b9sory8Oy6lik/elj28kcZIuNvPU0xVcqrmGCg/KEnYkXjsGKsBDk6SV9nKH7880oIe0Rh3gc0hHHIl0Z4CshMCgYBifXHLkffPIA4AIKN11jJ+h/LwJqpk0+Vsv+gczqjepq7ztcBA0uZMhHT9pLLX/YFsyVo+8IBL21a4LkWnhLNVZW0qSvrhaCl5E85LuSYrVoaEUoaSK+ca8d3if+kGt/+3PhiESU1LLHuS3nWnzbJrMysGoHuvmgzYs7+AhgyVjwKBgQCoVgrFc1lUqIXTA4fMlgHmcnGRdl91nI9mn8FOeHWOd4tcFvixaE/jR1ZjUuIAN7ST0TJtFhy3lc66tgliXTX9aObOyrs9aTTIpa0B6fKP4QhosNOjK9PlFx1SVbUSqnFMZ50vWQeEArWfTeS0ECviwjD+CsEcBK2JFkz5pBIHYQKBgQD3zcYdYwvGkolLXNN3vbgTVnbNe2YMUBwgp5i1XGzAiG8XpwKTi4vDFIYgCZAG5wsyqUPdTOY2wyLjHwGdUfl7P3tCsHVzVh/xvuSl3nzW3OdCniKaBBdtZS6+s25Ijzdwiwnp21NWE6XU2BptIwTMHrKOc7BpZykgHsORMtptsQ==
|
||||
space:
|
||||
gcTTL: 60
|
||||
syncPeriod: 10
|
||||
storage:
|
||||
path: db
|
||||
metric:
|
||||
addr: ""
|
||||
log:
|
||||
production: false
|
||||
defaultLevel: ""
|
||||
namedLevels: {}
|
||||
36
etc/configs/client2.yml
Executable file
36
etc/configs/client2.yml
Executable file
@ -0,0 +1,36 @@
|
||||
anytype:
|
||||
swarmKey: /key/swarm/psk/1.0.0/base16/209992e611c27d5dce8fbd2e7389f6b51da9bee980992ef60739460b536139ec
|
||||
grpcServer:
|
||||
listenAddrs:
|
||||
- 127.0.0.1:4631
|
||||
tls: false
|
||||
account:
|
||||
peerId: 12D3KooWEycQPaaTbsZJ2rfZ7cKNFB57o44kKukwKkb7mUCo4Agh
|
||||
signingKey: 2Lxt8Qy52wZHC1T/5zYvT3o4LhZY++4d0Km2gOj5R1hMqMH+Knnt+8cBGONe9r0QdtiXom/AxzWFFf0ol0bBOg==
|
||||
encryptionKey: MIIEpQIBAAKCAQEAwsGthwrb3RDzzmnbgQ4OubKCYEfTWSor0Q3Q9R+atV5llOivw7OGoXZ9c2W51oqlSIfwkWPLb1MPq+sE3pUsLeU09lmpBIBWKVg+MMEMXbBKMV/8qvVjr6HLNCMgKqBf4Nvfpv7Cgy1QoXrE4YjGzRTAlyREJoSQVAGHT9hpy/QDlW0VdwAvHpWrxRcd+Ro8dY87wWFIS2tEhjWMSra9sSFeOOaelSfPwki33beqZog0p22s4pIONrU4EoZvvs/43LrxxaoqWwX15u8+Agh1Z62llDDPke9tul80lW8x+UIiuXjcUkvdaAd0xJ85rrmwCCeLrjQ1yoJmqk5idgysKwIDAQABAoIBAGV+Gxk57nQZBoU2Iz7w/XmGbm0QYTKhSG5Mfe2QB8amp9dfH2GkJ+/y2NOPWrZUUGgo95Q85mJgbdVQx5vbL0fHn78V4H/JBZ3ML7SmlfQpD7EFbZ4F/WokrcnA2F1+cBi1XKshLmq/7boJSZqi9b8gJnFdY+qSwMgWd9aDWDcBTMVmtjpnxdp9AH1vC1pF8IjOM8SG+z3Wln0CX7dKeeB8xMohqNDd5/nWIXgjKyhUNZL7hKz+H27UzGMidF3W5CHi5u6BYqzkAvagQF+1+tVwjgRUp3pZdf/7Nlw9rImACPXi2kA3zpjRxnBNZWnjmPxt+6ISIzi3ZAmmpA5YmbECgYEA0ewToWwF2kHnUFCh/rm1lsH+jKR1McyuNhTM2gx1LO+IJ+GCHd5POMjBzdowbLv0BgTT7ncARwfryznkbJM/SZ+Llf5oDfsuRmf/8AnatLv9Yt/YYg3Uk+s9Wl6FG2I+Hb0WcLLAWBpV0ZhH5JI/dZepsRezoTnWnC4t98g3cpkCgYEA7YFqk4JFiKH7xdZ9UQJS2p2Ho9OWG00Yi9ddwxp+JtuHWRWo2zaRKiHBamXWPFQPmWrNURHB+NtjXMLQahVrxqg88SoKnIiRo7U1m0e6TNBzsSlkmD+2+co0u0ECxe9gxIBJkE56kR6Wl06VKLJ7HwcK6DjeMRN3UrIyBM4qE2MCgYEAhdKctRQ7KudGgfHVQ6C5/XCQSLJyr5uPF5Ts/rhgXpQY1WuyWj4lfMqmmgdVRYwQRWIAhQ3B1IZdMAIo93prJxEZmDZFuVv+JQ4Zn7l4fi01nDmdJO0yLlYRl7GX41wewzCOxKt/aOro+KO+eR0ubVWQ7P9yGP7ZLFlYHpS5nEkCgYEAxWnO9nFP7rQFnHoei9lMmR5bglb67BJ3FrWa3/MDbLUImYmhYyTGIKkSJagkHN0aYkEeDAagnoNs4cukhKjtfqCUlziEvXve4p5awokqV3Lk1xs63DoJkzL6BbOR5IiGfI7Nlr9ErZ8pOPc+kCdao32tGT07ors1cW1gmhHrc1UCgYEAn3pEkmfJL+ufWYZ/t685mrdUqhp/HcwXTByPLSIr+nP6xXod94uusufVTuMXfYzKgnmsIlt8zk1wu2kSJJUcQjL5Q5rK8suYnJB0Z+x5wa2XTwajThPK29DSpjTY4qjOx7ZCgaZuwJNIFzxp0QrV6QA/0y1CmvhpPYiW2wesug0=
|
||||
apiServer:
|
||||
port: "8091"
|
||||
nodes:
|
||||
- peerId: 12D3KooWC9DkXiYK8MiQb87ffW51ggZR4FWASadh4UENXdaa16iz
|
||||
address: 127.0.0.1:4430
|
||||
signingKey: yfFJv5klknUeG8rROCNTktCk5rsBvz16aEanYBAl9oYii+Q8XwH8mVXr5hHSiP+HYxEaSSozlMAAXUjdW2vK5w==
|
||||
encryptionKey: MIIEowIBAAKCAQEA5zUOQ42SFUYJyX86llYopUE4Q+RQvbCakTPd9LBKt6pBWyW3PA9sjFisxVFFwYOVwghzF8QDSRrWdkjGmRPPOSRNmNiJFGtk6wb26eihenFECdb4nJyTDZVhvayHpByCKleAl7dHLjHCIsVaaFfn5rntm47IdDSNFgZnNDrNrdS2SchXWHamcfWBJSQirdp+8kSh5RC6/J53LVa+Sff6D49BsF8VsevcjvFcdlpxG6GKhr6kzvnEwCCk8DIqjpF3geUVj/QbT9tGa12bAgDQuckW4DavIN1zT7BAUbZPcbFZ9Bd2bbKzXDFNt2mRXafDPL07KhnXSZ2YAxHf5M4s7QIDAQABAoIBABV5aQy/Lm1JZwlPBtsFv5qxtw8fOpyTtZd88MWURixO5OkZVK6AZD2Y0ts01DzIAvXVoRL5ArEcjATKd5+qJloRVB+5JOo/m0z1BaPuFmlv8bjUPZ0WMdZWJJDgYGzOtQxHukrdHABfYL+oAuCkIYbdiAMlvNqGMwBzscw5FfdqGBRwC0bus+YD103Hhc8pN0REwLZmiOvHR6b4Agwv4ruFsqthg13EwcqDVTnS1/sZyodLZaAGBUXlqUxuFakI/9CqpPuOkDgxelTYdXbS4yhfRF4zwoBGZx1462iJs4XM8TXhDcZpTRwCChM5Qf7jvvgbi7+gYTX9B1dxg7gZUyUCgYEA/cd/NqOyx7bn0twiuMEdq8bCi5Y/GvWLrQ3pf58DPanIydGPJU5/obKZw5Tv5LWbE5rUEeC2YpFleNh01oc0xHCveIR6JNGihN8u0DZPmcx2B1lwEzdYefRJfGcYXYhm/nCpzYn3VH0TfKA6qci+KLarYaeDpUCXAihZMUZxSfcCgYEA6Tr+fSXmHIYoKcewIpwSTvcFOJ6spMRSG+mxQAFit8vUQTw2e/aTESEECo24XJ/SKVK01CSoWXrw3t9eBgziyHI3GaaZ5LaXMZLLZhmGUT5kZiTR7083h+9bHt2+MzRXpaAEEc1FNgV3T2sSl1S+oKDL1MAcR42JaQtC1P2epzsCgYBKDdD9bL9ar/DuAvbO2uuBmLpkaS94+nYLxaeBajFT6RuCaPhQdpuf37Im9GscXjImgmOn497U3ICzxtYxU7r+J7PMgzvxSosWItpSP8bypks60cp2kQvsanCXMK5XfNoxHUcvhzb5HJZ3I3p62O1EjClukadErZhjNMryKhAc+QKBgFwvpUdyI3JC1L0u4L/NUK9FlBq9HSBDOPEvfY/+/DYJquveEOsOmzK6Cg7h1W1G/pq2xiLUGnbD0VFGmLNrhHgWLRFGeK2ePkSp8Rt6G00hjC2TgCdG+HwSb8HTg8pZdgtRJEqlCCZCItaRS9fk9zQmWmrNRGBD4XxTpybo2DzhAoGBAIxRN8WZc9HYVq8t20MieKP3pp5Nrl0wj9Z9EPvC60CwQRdv/FvWzDwF5/9Kg79rvbguZgjD6FNy35BGC5sN/24awWJ/mKYosctRwZVFpogoZ0qAdOwxowfAJXLRC5Chgim8vCFFdKdrMo2a6V+MQuhrTv06QAV1sYAH5P7abfPy
|
||||
- peerId: 12D3KooWC6sZYJXFagZtRjY4Jc4dzBLpEgYsUhJRauYheSAGk26y
|
||||
address: 127.0.0.1:4431
|
||||
signingKey: mLzjMshSbtOkUKZha0bNIHvW9nlqOPX6VM/mvKicx6kh8ebP2mfrkCS0qz5GwlFEqTgtuSnWsHdvGZnuan2Ahg==
|
||||
encryptionKey: MIIEogIBAAKCAQEAuJcCEM4sM5I1Aj2y0HDgR/UrKEVF1iZ1CYWv4jVOt/e1avDn7XjF9ArB7lngq7lOTxpCNeLMQXeBl1gY1SBCPeTrs+tltyAUeSOZStwP9qhjUhI9TntfW3QfVlC2lB17liGa4b2F10x9vW/0f3R7m5xgz8NyqcFOZip0Ehe9UJbNFwPr00by0D4/XptkDT44wAIDlw7lgOmXWR3RpCYAYFonYeE2HK7FFNTIOJucfJ8kbK7wLp5EZRARYfCDUFq7czFu97FIrmQfS4Fyg8ESB+R28+dJIQ6G8U1MicX4Ibf9IkufK+r2fMYPv13F33omrwSGhNIWtX9WjAQ4bjmA6wIDAQABAoIBACHuaEvMimWEd8gMrWURirjPgXpqmXbPJO52K6mqYOkCWM/qrseBTuoYXCPDU8BdVN7Hleov4ZobLLA0WoQ65NJZ1VYCbHUoKXtHJvOS1kBiHbfFcI2PsiyugOAuABHkBYbIcJ8UZpj4D5kWDlyrfdlR+p3WcKpxxUaUgTeeM4evkMg2dg1/S4psgu1SKdGYMtafKBgvxxE0R/fjfP9MRD260/ydcUT0gRE+uUu6WFm92MLV72W3hoKfNqgGnQWCTG8UJGGK3KC/c9lAvLiDygo3GJLEjhnrIGkSbbd0uHtAYD8Uc+gq3z3o5Rger4P/FyWSbJ6Vz20iYHTeYUEDkKECgYEA5KK5/Z6XQHwsEGXSSCXKvUjJ7ZOV5k3D2im0F1dTtQaOjFgwZ9SPW/k7tQfcwfZLeDSm5V98FXSAu9XgT/Zrd+/RrfbgmKLMcNVet+l2OPq1cOeKE7io7wAXlkO5CmiMXMCRVcgqaENutUSTsmadFqd2NE7/gEUjeNIQLGkSsXECgYEAzq6+HtOxhfbTEC8ZUz6Y7+CphmtYiuX7G42lwv70mg+sap7mVlZzOHNNM1p9BOVEo2K1RKNWtXMgXDbt/KakBLCab9sR4R68tS7JX281I8RK/kYOLqlVE0CahujcCJATZAsDLMCpjeN85vwqJ9Cy1errf69thZwo1QI1BvRIahsCgYAkmz1GMycqZvczJOpXLN3aEpZqGHAusJLEEltIRW4clNEr/U66wRi29B+wK3MYBxQsSdnS7cfTM5UM/gBtLRol2NrsjJOHPMGY60DAF3wbQWDdk+TSpYU+xvf/0hYFaZnXm+lpH6RSj0FhenpfXPiX0PYnB+L2qZs1VATM54HbsQKBgG9nVwkMuCpqUXfuuyrYmdzqbtYKdG5h6kj+v7Nsc3G7MwdBYQx2iqKJ27nrc2m5HpcmtGgr1qf1RyMNZJgDRnNUsdnK7kc2pybN8jMjoTQHMRj/r9NM6JN5BhHj3/4pkpohKXPs4TeewAtNLnfJkSum9Yscht82vfeaufRmpcWzAoGAfxcnMvi2EhE6uNjDENqnFH9XD2zAAeKhiQumz2ts3cSUd1QOfPMeytsBML/jdmOMQNaTbMryhWPaqTewHky8P+l/7oVbMTTFnaaaZRZCSOSXe+2R3mJkRQzE+DkVhgfpEku/BVGRHRvltM+ehk3m64j5vHWC97cP52qZ0bkxKHo=
|
||||
- peerId: 12D3KooWFWyDckUJBtHtARzRDTRpo4XzeKAo8oN23MXh3Xwbp2fd
|
||||
address: 127.0.0.1:4432
|
||||
signingKey: YpCGjsSuT8O6mkYTOExkdwNRODBaJ20hYJHFO/A/RUFUsUwxIME9X9FIp69VYvKuL6er973p0iG7UVVvLgLjnA==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA2T4/6T5etB9W7qzJ1sNfWFdOTa2koXKcQkaLBUTervApLPZtaVsbNtyVFtqqdsck1qpu+AVif19EFlYqSRtn/dxEN5/2myqVA6lZMm0Bd9mWpfoDQx20KAYwWBwzKSH1EQiTte0bw1zf0RpztxQ3nCOLCU4Y6x2lfk6Ea2XEayPxx0FDmeY3JSqUDOwx33Sz8Imx8R7+Dfjl6Og3DEqGxXoPfZ6hj9LynqNswjRIdmMZPsuEHguKXMbp+cncErGWcyzH417XYSDPoRn/3awpLfQ9F+KSjAe5cUltC7M4veSZW+t3VcJypvfRlU4ayTZMuvMHPlMcl/0jP5w0Q2+2pQIDAQABAoIBAGMvmrqBcXfHv0cluNnHRebtpaCtoTbdPx67WonDUfCJUiNnN7kckaZQu/k9SQsGDXm9QwEWZExHUKzqFlBepPIw+Sx0aoGZxYNwdHsjbcIspC2PoqGoFDMZ8ESqS2mCSYPHaLltUnm2E7JC44Y5QtKVH8vVzma6mG68ppTqV+2aGfGiPDq8cAYeH9/8Ys8/S28IwCp/M7lnXZhJ38bHD3YyPpcgbyGI/Zr5xaPd0hqHH08Z+S9V7QPJUGY0Y21s99DhkUGctb4B17d0/3Nzk/iWY1rp7A/kbdBeWonsHrTc6OnmbdiOcjC8seOIKMJ/WE3JznqnI1oydFb/dp6raNkCgYEA+pn1akGIKnVP0oFh5PZfUpuZtVV9u9xccIXyeFmCAXyFuUz1KYbfwwqZnm9r6kHAO+aBtRtVsCVle5oVWNQq1pdv117hPhRnVrDtvL80z50a5L9gEVu4Yz24Q3vs3RglcVpafSaRuyPbiYHMmQ4Ly+9nbwEbOVDbzK5A3Wrny2cCgYEA3exS3aG7+7mbSnNTYkkTgl7goLXZgEST/0EM2CvayxZ2QUS94Vq5HjGRpWnni3YttLiYlgCLe3CqeiIh6E3n6b9sory8Oy6lik/elj28kcZIuNvPU0xVcqrmGCg/KEnYkXjsGKsBDk6SV9nKH7880oIe0Rh3gc0hHHIl0Z4CshMCgYBifXHLkffPIA4AIKN11jJ+h/LwJqpk0+Vsv+gczqjepq7ztcBA0uZMhHT9pLLX/YFsyVo+8IBL21a4LkWnhLNVZW0qSvrhaCl5E85LuSYrVoaEUoaSK+ca8d3if+kGt/+3PhiESU1LLHuS3nWnzbJrMysGoHuvmgzYs7+AhgyVjwKBgQCoVgrFc1lUqIXTA4fMlgHmcnGRdl91nI9mn8FOeHWOd4tcFvixaE/jR1ZjUuIAN7ST0TJtFhy3lc66tgliXTX9aObOyrs9aTTIpa0B6fKP4QhosNOjK9PlFx1SVbUSqnFMZ50vWQeEArWfTeS0ECviwjD+CsEcBK2JFkz5pBIHYQKBgQD3zcYdYwvGkolLXNN3vbgTVnbNe2YMUBwgp5i1XGzAiG8XpwKTi4vDFIYgCZAG5wsyqUPdTOY2wyLjHwGdUfl7P3tCsHVzVh/xvuSl3nzW3OdCniKaBBdtZS6+s25Ijzdwiwnp21NWE6XU2BptIwTMHrKOc7BpZykgHsORMtptsQ==
|
||||
space:
|
||||
gcTTL: 60
|
||||
syncPeriod: 10
|
||||
storage:
|
||||
path: db
|
||||
metric:
|
||||
addr: ""
|
||||
log:
|
||||
production: false
|
||||
defaultLevel: ""
|
||||
namedLevels: {}
|
||||
@ -3,9 +3,9 @@ grpcServer:
|
||||
- 127.0.0.1:4530
|
||||
tls: false
|
||||
account:
|
||||
peerId: 12D3KooWJpE9AtG4RX4Dwm4vhrCGqiUhKj6Mvbqj2V4rV4diyksT
|
||||
signingKey: 6tA9VizrAMtsZlzBXXnsg+LzwSwBLU7oiVP1qOHN4PaFsBslV0nt2aKBXfcfxp17V/bvydNfyYbGu50F6spLCg==
|
||||
encryptionKey: MIIEowIBAAKCAQEAtsYet7J4bNo9zSPFZVFkkInUoAW7os8PtZH6qMUEOKcLAi1PDbkBBCmzHdfuzik8H8DgQl36/0gCqRPM6nhQlbF59mV7brI8/kH3Eiw0rxqWAe0+C6CzDyEqtKC7pJyC3FJe0MZRRtDXiDYlVurHrsW22fA03rJY5++eW6bXiqL7WB44zxMrztkvPljlhDf2XTAcrZWI10oXKjSZMW051Figbhdl06R1ZiW1F1LmUEd3ufiYoevpq8jAHWIToTZrYNX0sfrdNaf/CPCq9ZDSqISf8CZ/bE1VxYRPEnjmX1hZQ132S1KCEQwpBWxpcvePonEMPGp+5F7h4k+46f16vQIDAQABAoIBAEa8np7Rv7HBNTHzqi3wNk+KSHQ2Q8xa/uVyveQbe+rBG42YI4RYGYCW8u+V5qJ7av2PFDwbS00JfZ4aP7BvKCEHMwCdfgv1h42P0iOCYFF0pKHSQ7UUWLh+SZzmqDipKixC5NdAKaySnxfkfMcKzoVhl8b5JD0cITSClHM8Oyc4DR5DeB9MlgrVqV/fcdzR10J6TeEPyJjs7CF+Y4OFUEf8FnNxfx5btWm8dIxRMiFUqdI1SVHmOJo0wO2z36RKZ2f8eHApafpJ/1MWccCCSB34Kry4WjDLn8yfOZ5GavXKDVKnE2won5ZhpZGTaLVHLR8QzvkzuBHDk1j1kSi2RjECgYEAzwjnJc5F8XdOkNNPKpftnUVlijhEx0lSknL/j1wIE7bdqbGvIhW+OlIP3bc6O5h0QGSoB71cAiurzro9rsZnSZ4qqjyeGh55j8I4RoZHGDu8BoUOXzrIL1nw3JWxrsNxu5hV9bcYAOJDG9BOcm7F9g00+f+p2zR7BvZMYm3d0vsCgYEA4gBSbChHTMHs15wppaTqV5iQEbfAU/oweRBnflQTHVdezMDt85BpZv0ik2vTuhMJuiaISMvb5l2fHI+LIKoZgCBfymQ50Yv6dZqOMeY5XwUQiQ8DtVtoetYBwwPIS3hSntTu/a4Q9tZbmmWYG6rZ7X58UrtVHY5DfFMS8MOrO6cCgYEAgDkGV57KKMN4cC+/DyUrL8VEHve8eSSLNFJuvs4D3pnZ7Pgz/Es1Fo+ubeXF9hT0otD0VF7NtjZv4Mft3enZHHoN+IM0c/690PA7xEnzjCmqyOrtPMN+Kf1tNGCtvAwly0aMrnKoNhvr7jTz8OF0T3BciBz0iOOW8nfmVOuwf7MCgYB9va4eDR72XuMWZwVo6uOTTwfBQ9oXHxk/ElhymfZ0mbrd8u2xWQS7z1UgbprDaXo8/tlOn1W+yxIOwvKmft1nQxvosHDW3KnCKva4Xp5G9rtndloa2ju8NDuQtBcJnm1hf5lkvSclHsiik6nYoutTTs9+/El0A0Ya8uGT4Vnw+wKBgDq6yliV5g56J3+gHB4w8yQSoIx4AjHoGkYbaVNiCNLfH02VVIGINnlBk+6xurHUwBg68cAsMSAPWqky3BMvhpAAoyPDBycrWEYKHvKvVsH5R0JRDymVJ3UHJVzCp49+CHIoOElnR+IueVluljtxTrB4JgJj0NOLKOHiTNHW6emJ
|
||||
peerId: 12D3KooWAB7hjh7KWdLz1nxkb8VQ4BU9ZfMwjAFNyBB9NnJCw7AP
|
||||
signingKey: vE+fJjNKXf7y8hW7IXerySK+Fr8b/9WRThM5/tBxww4FUNczjvzd67XXrdvOdZtYQ+QTDfwItNbLwbzLTEMOeA==
|
||||
encryptionKey: MIIEowIBAAKCAQEAtYh4UPVQGLUx9sGYEbItTysmrM/MIpNHnZQaGhEROw6n3Uta5NI6nUCQ7IvqGB9ewNKOsED+7zY2QjZ0RGB/qn7cdRbizxDydx+UxFZy18J2aN4zbK2eoxwn16pGVk6asatzChcfYnI11Is3T9p+5/+gqqfhb2NYA2xU09g4V1nnsyZYWCj4mHcz+AHjhCjFrp53XXp/A8KkBC/gzPH1ic4sRxtjAXG5De/d3YpSD7ejnc/YeifilOJj7wPBo+DkpEZHGu/tRYQgDBWlVIc3oQ+KygXsC/inGODrhg0tLlVSLYFdTsktweKyCA9LKR1y/JNC6F8HbqN9ke/ENsvlSQIDAQABAoIBADmHWyHE7DI4UfIyHeAVyDgbo7EGVVnrtLlicvcpy30cwuPlepOjcAHfsU3VdUVZw6x1zdRbdK8YTg+jtCrrLeo5M+JDc3NNmplXv8yM3O41aVMIf+GEEA7+4D1/b7TwSiPeAqIC++Y17YtC5y9+PdOF9kO+2jlzkTPcg/Fyx0Ae7CIXnfZNZwsZo6fyhstYH6bKe1pJuJeWxQmSMXZO34Nz1qXpTu/E8cevu0iQtAOfyXEzB90i0+JdEe7Ckp3Pv9iCBTMVEZJgNRfXHdyuTr6e0/Tjl5ezUJg3IE7tlP2B251j8cC8nUNuXL34aZ1FPwLKf+OUkTJp+7cGdA8BMwECgYEA1NcKU7/wgT+vfv8i+ENrz75DCRt6MJ1R5agkApjed5T1ExYk7Y/qVBVNOCZeK37z9ehCJ7zft711g4o9XB4FZF8gJFD7TBbK9XzljuIcYartPdRYuugv5T0/xTb3xKQp20xPBmgLO/ZazPrRq83dEISwBXsx3o2t2leQLUm/bmkCgYEA2lg5QTPuZQYplDCeiwmH3C2wo5VMwQQyfT/EfMJ8wkBKoe1ndCLNxPvFramD7gJs6iG4nwynOcdBCpmlxvSm4qQo8AEWNcexRZPVCenw6dgjOvRswfeodZcM++HHByaAy9PtSX6YM70py6GbjV1DKreR9BkFT/C1wyosxKZno+ECgYEAoVr1RVC58AJr9YdO54+VaEUBZSIjnD9oGwdBZYanAVk4AmRDUqZMK7qKdAsCUU9JfB+8J4wUvqMvN63RnshTpihHocCTArg03a72CUB568E9YiZdrjTgOpYYhlaJt9YMtWhAcMbn3WmCpOtxkSHcee1d1In04JfgOSsw7mR+cCECgYBUbu9dDnburA5iFtcITxwxgZ2f9Hkk3rmjg4g48oCKIZB6w7JQz7CgrvfHaxjwbhGuDHI3Vw5Hooy9S6M2p57tX6vQ+6qaC2m6zSsB1WxrEUC2aJSyAVIsfsfvk2SCmFoP+Bj3ZbP3tfu2mfzsEpeJqkkPiqlqO1weZ22+cdb8IQKBgA0hmqgzYG3X7/BifZfrm57xNU7d7B/ffjbQwKHMV3Op7VQiCcGc87Da1IJiKmm/lk7lgWNDTxFnkQhqUEYo1/ty9JmNeq/OClTkomYiUE+4xs1H1f3oZ1kT8iJga03dS3XvxJOux8UDjJymqFfs8xBsbvBP0i1grc/fZNLkEtfa
|
||||
mongo:
|
||||
connect: mongodb://localhost:27017/?w=majority
|
||||
database: consensus
|
||||
|
||||
@ -3,9 +3,9 @@ grpcServer:
|
||||
- 127.0.0.1:4531
|
||||
tls: false
|
||||
account:
|
||||
peerId: 12D3KooWCeSDwgmdmLMweWKf1avCqaBYuzEo5GpMGa8MBBskBmen
|
||||
signingKey: N8fkrWmuf1wVxL72XE4Di8pSyTaQpev/9NV4eznVcfoqB9Z+urz0kg1NKJjWisC/nUGdJP9EB5ZhgPyuQfqIvw==
|
||||
encryptionKey: MIIEowIBAAKCAQEAx9vwNRbEUtOuJ+UxXsvepKC1VY76RNv+SnnUIQE2/fXo/1iUEevydpWWD+V4n0DjxMsCViOv/kIOuXArIntFqr5xyRdIFE1nbiSW20IppRZO2Vw2fZwN+5DOl1Z3MfiZsqD2dbdtVLuUP9On1lqPWgW/ZHzweCcVMz2ZZ/txubSBE889bbSoZcNlgXS0fJSaw/6XApgtL++sZBqxwp2lkf918ZM3SFuAVHYU56tAOnZrCbyHcbDk4OOJ1q7NzrxWg71S02yqesuDSjIW6BzIXbDVjS2yvhKRJrrKXSIYepIczPwHPPCs7/pCPE7XQ6sYB9d8BL9/U+doLTJToAhHwwIDAQABAoIBAEZwU9bCMWtnw8e31ZCtlci8A20mOTqvto4VJhiDzxfu5bGpTHaMjCYTTpJHtB2cxyoCys4FQfAA5COjTvCWNdWZzYysMfFF3qBJMQoR5Y+TrzKYd3QJ3ju9q7JW/SeVkMYOSQ7wGQ52FifwtwSrYj6+K9iE2FPgom4u1bR6QHjMcAf9+eDJMUJk6Jg62SATPmiiN3b3OktNSsqvAf06I2K3ob1xIai0aTVcNsEoLbdDTejgFkkU3BHIzY9IXYkfipHV9+51cpRFb8q/Hl4boolgSPUSfe+pC11sm56QZZ7Gt0CF2ejhWyJKiyV50B1enKeeVN50KIMdtQn3VpTN65ECgYEA4wiKX/72Ca9wld+moywqexXNuh0a0gS/cWX4gFRv27jUScR7KTDM2jSPUxUK7F/hONOBBevfA7DMxsNNoPHoK9U2iwCO5fI9n1oWrUUjq9srJvrvsz2n2RmQ2deqmosLs0Gbb/I13+qEkunS7pfIIdul0LFE28PK5BhCDRdOUe8CgYEA4VvSWswkXQP4eNDTe78+GItQ78TluU26b+HOnkPRQlA2lUyxkUZT3VJQcgIptJJ20K13NZypJazJm6QELZPd/WcUAWKZqTSQxXUBwPVuoW5Aw0glXCfUOEG+LU+Ue8tvNCdqrAJopuYkYniT1LsQAOYMbJvL9PGkJosJfq4X620CgYARmgLoaGL440IuTHWl5vGwM0OM716586ZIC2jVwjYd6dmDkpkd22u2aybFgTckllZmyncRV3Ul2xo1OsUU+kxOwawF4NgzWbGPXjOt4VNfqpFQ51mYIuqVeVbynLbcXnVcw3RinHuyzYLTxQ8WcmwQu+/CG0xEYYykXIEadLkcvwKBgQCB5RovicFf99ztTnjHuCjDnvGs8lHzaDERMheVM8PXNELx9X3YHbBTPpHt1P9S/KUNjR7MQRtiAuFGG9joqHVpDVQDpGCrngfgOJwlK5Jz7AfaR6h5IN/6+TH0Dg2o+U6Ewj+DG/RUVw0b0SJsmNIVooQAyiBadDnImZWEdjaFVQKBgDnrnvtTMZFvJofnDNSQfOsDru5Mc9c/WRfegq58ocf8XaMMJyFCZGw90TLgQgWkxDCjQ4qnigFRWRCJ3sWB9LS8uFW5Gif0GtP6foL9rWlsQpCUqVApJRnVFFqW5f5FC4MZHtDTlZUk5lDQuvZjvQjJ+3vmusxEUIP0IS74Gr5+
|
||||
peerId: 12D3KooWG3ZrWs8Q3kQhQeXp8RWw8FKb2cThTFwD1nbRMMNzf2xW
|
||||
signingKey: P3a0z3Um1QJ2lEwqcaNkVXwMaFz/Xmb2na4RqO79Lw5ch+KZVitiA6jifmRQkPm4z8e1wIf7Eel1VnhuhRuZVw==
|
||||
encryptionKey: MIIEowIBAAKCAQEAmi8Yvv3F9/ddTHj4GscR37pr38/NbbDfOtqoervlG1SE7zJglpnwEI6ThhjiAPaXr9UgzvIne8uyGk3ioQz0zDO7X0Omq8wPc1rPDmy4E8mcJyaLyQD4RiTDIuiOKO9+sfWzOwK8zGfPEmBqnfccGOlRelBuREvm4IZnP6HXKetRxxdIexe+W4ZRZN+AuaD5+k3+CPs1l52cIEuBWJ27piiX8oL8indy5gVdNyFPKoTeysJb6pCDYoMoe2EobovSX7hK/28okyJa5SGAVzJpSZCAzn+VljXu4UDMMiWOntiOElsvHuekySg5dAs/LO3lohDdPo9ITAs54P63MHN5cwIDAQABAoIBABDaEu9VF10p2TWxhxSOK4LzgjTdJovVqCBro7x+auUY0MrAC9SKELYOj0s5zwHh8eRS/BoCV5RtSBMd7iZCH0NuaA1afI4MaKfoBfeCpH/tKjcRPHgEth4ciIN5PYh13Lggra1GeFIzCmvsw9puFtEWN0SSI+stDJf/uKs4yiaXmU8xgKplOx97hpTXYLV007mQ2AAZ9ZB3xvUAfADHTtOI46yeO9HMkjoQP2noHyFtKoPXzvra9HBq9M83ohPEE7bew8FAzgxeuiJ+CNU0MSvrW4JVPVcxQbxqsbWJSY+y4HZ6bqFRx9xz6e4iQqVH/XiQWQkET25/iJ+PPi0PP0kCgYEAzF4pY/F8nFnDmi3H4v3p2g8xlLknJaQmvMP0o2L0elZSFJ6YPvL0iOVM1T/5nFjThDOXtux0lSis3C5CZK7LRGQLut8G/5OC290vkwKr+BqqZZ3KIPjBO+RWsOUD2+MBBjQBGQQBy35oQ1Gv+MEUjar7gXRYRhqOY3epQROp0YUCgYEAwSM1cprDtsyqKRpcAFf72D9K0P5F3i/Q0BuitJmV+FaIBa+y1C2H2FxW1rqqScw2zmKeTYz/L4s8paShM8b3SjkzK5dvJ33BN0tqJGVSW06LffLjkh7GVIFQGhPy8qLPDgVY3goDphrnMH6g3gH3ewqRWispu7jwxW6Xn8YIlJcCgYALg1J5muUWOchXKzUTiJJgAnMcmcGm0TSNdcyWV8DGE47UMosJIM69140Yhl4dfLONwwpM980pif0S+lgrK92voKM4h8/xHfJFSJShh4kAlR/8UYNNkDXylc58cKpi/MrV+qAFNMCVIi3lfPiY3ue1g2hfxpoieOSEnf0e+WibsQKBgQCB4tXM7vvz8Yv1/H4m1QTPlzEPgBEorWt2qT8wyaEr07XCbTiMrNoQzXixC/P9kVLCVVw0tz/ej3sHwsGOep5P0kvxYvQj0NSiBRuqwmEyeo4g87nLyNqEdjqSbxwRxSAOQ9ZR7NYrXShhWqeA5j2zB5Zc125HisaRYCCkGKAonQKBgB5CGTP982bbrlmh7bwJFQjQFD6ufXhEr6X8O90yw15sdktp2+bwr+pd85602kqfyN0Ksdm2w43AeV08OxJBQDDSvI6LspS/v3aLXhWT6LPqEtH/Qq8KH4I5UTUsoa2rT/iyAZZ3zjT5W1D63RbPsMsr2ZMTC0bRrCvaCVKfX8ys
|
||||
mongo:
|
||||
connect: mongodb://localhost:27017/?w=majority
|
||||
database: consensus
|
||||
|
||||
@ -3,9 +3,9 @@ grpcServer:
|
||||
- 127.0.0.1:4532
|
||||
tls: false
|
||||
account:
|
||||
peerId: 12D3KooWGqsXf6No926wTb2eZdauqDcEkoAdKCeYkNzT6yrL3YDE
|
||||
signingKey: fSLDcrMD0v+yzQwHG+KWdCkuZ5HPvx3vIb+5MecREc5oZJZfrN9P2z8gBU8HqZH/noB4aJRjXRVZsy4M5jPcwQ==
|
||||
encryptionKey: MIIEowIBAAKCAQEAtM7k4K2spm+GZa13SkRbDuFpPVAdPmR1+aN8IAtmSAISxw2vb4ET47Ck8vDfNtQ9rAvoAn2c3GxJb5Sb0pL9rofeIYYN/qS08zFVP2+FRM5CfuBbfVbwMZ2WvBJD02LzDrHRm0blc8JZDs3xFi5o+mWfeM2SZXVCJHFSNS+v1TRgVfQzu0uKlTD00CLPNz+uzDG6VntlzzEzkF4jVRA59BmkzqAI2ZgtB0cG5ztMnUhnZCX8I0b9CCb0UHjq9j97Xuot/hMAEGVQhNY3iyJx5gAR0t5PipgQZz5j0EXBGPy9T2+VA1QFLHVsUDmd2iV5fmTZziOWn7988Co+ZVMB4wIDAQABAoIBADbQ5ukLHmXTN/7JiXn1oVmwkzRofoU09eN6Yh5g9mBsaH76si5vBrWoD0osJrA7xnrLnUpsBMt69QSkHF3J/KkWPg0R1FpYWxfD5CF4UQIcOmK26GXmnqmcKl/YdcG3pRLWbELUSqo+yLtJSoc8CM2pU6DPSkwCMcxUouTHEVrkpL+Ic6RNGVFjX7E/HjfX9U/BKH0bzwj9CEPQEm9bqc3Zq+EmcE/CHXfRnHdG1cSp65qNHDfyEBjudR4ddItzwpmxLsW6+2Ywlg2pG/vfvRkGvwtAySkVs05J0vrpwSJlPy0NvKAbHAnmNBnmRH4E/myXf5MFcl/nz55J+yJs6QECgYEA1b6fp4FeIBfhvrRseLJeAepZhvmXkRegT61No5632SpcHymz3WnO+EsrL5O6+Ldpa8Gv/LmiVBQjvQeTvx97kINXKPLxmvdxRo+i7YUCAec8AZH7WEkxa0vvi3FLVoZZ8/P5fjvUscwxBeOvwhXnyXsFB9pJduYu6wzuMJe7HmMCgYEA2I1k0YjcTCqOk2Vp1lvHLtnMcmpm4FDMl9uws0HX4UO8i9tXlLZmWqDvPpvhxZVY+1hXOEid67712q1fiei440AGGNxc/xbq8Htw1GBzKyTd9dCQCVwWGX3VUO8EKAKVXdVIyqW+YUqD5PXUcPA41ll+nJdx5Z/liSNJvpxCJoECgYBv2P5GcuXEOXsBhfw09HFI407R2I29ePWEfBVih02BMC9ghzv9or6RIxSIIu/18lQR9RqYTrNo99jzs6FWo6zPJEtZvDc9djoqSENjsvQn9s5pq/AwdKyNjwDcoP5hWpB7nbFyovBb0ZPdlxWDpF7UCbHKOCm1NCJdETka6GscLQKBgQCGh8CcU5PYVY/hjd0kaDvjpTbX1bY3oLqZlMe/dSYyMayOjiNopbAMmXJHyPuHjfKLoyP8OVCyRh3iTlbODB/gPcQL6cp0Rr6Jy4YayhiCMxMZRQpWZjjseTnuX66LVJ+KfZgNHM6bDnnF4dqqlvIYZ9y6V3NQnfcxLRUBL34BAQKBgElDMZD0rP/u6Xch33udIlzdai30QUNWS9MgSrPBz1s8+u1e0g3UnbfCH7e5q0ofSmd+Ot21i03cLgUgJAFmoVmoJ794aveBo/bPbDrlbolxOUX4dFODvvOKzCcUHeOJzc9JE/Ci3LuHyEcqv49uRIe4BFc8c/ssDpj9h7Cyx+qq
|
||||
peerId: 12D3KooWS6PKUYH6Jedkjsut9ajgWSvn53Qz1LLACoPJX6dUbtCg
|
||||
signingKey: 11vXVlqQr2e/XMKALUPhMgnJEtZ1HKaDerxXvhNvYfXx1ZWt16PoEMpy/+ZHA1gw3ErI9+2/6auhjGC9InHskQ==
|
||||
encryptionKey: MIIEpAIBAAKCAQEAy4PQ8dL0gUmtumZQ3GBmHW7CHsuu/VIMWZSmfEIWgMDqrUDkIQxOZ0+hEDUbtCbAdbklgVmvFWUL/F9frBp14gqyMQG3sG/2l9UsQ3p5Z/jRM/peFCtnUj8Xa4ktsOcKFrjEDuBylqanBCpVXGKMDN5Tx+c8ODaXgdRj4x9vY3BN3w+vxXBXIYDyN6H4SesD988VobW42mveVKl3vaOFDf38LRZUe5T0SUDt4wdeAN/pzpFnH4RR//HYujarhF1yIrs3eVu2ltwrHBQoPTboIW+n13B5eqLVTJcXMAsIM+jA3XNu2ZrgmBLEKn0NZNhAgVvGPwMuUpgFz79rvJvrIwIDAQABAoIBAErRKdZNBGAnUvvMs3tg4Ql+91RU8v7j0/B2yoGx1g39XgjVa0iO+p/WUVLhA09GU8iziQs1ij0mSbK86TIfBClWX03O4NW3Q4Nr9frUop9LhLVEHKPzlOdSlGyPIMIBHd9ei40gjF+/4nSQj5MIE46DiW9bHfNYdnhfOV185/k430Ojm12gi6MMlm9CTysNSdleUlO0udmm5JxkvhosPENLG37Wm8JpbesmPiYZiT+jyu8YOaawAXZeGc8NSDBwovzjAAJ++/yRoKKPcsQUV6EYx47PGibV7aXEwbZ+2133C5tm7KDDfvS7sEQjVBXh9Iea4tmdAu3q/0wn+L5ACpkCgYEA5aIIUDdRUERJly9z0eD+iBA2DRNxi6Lpl/wERMkNWrUhnIVV2wDuKiJK80D5DDbszT/gXvY5oj2diKaakGMkj4UCGyFVRy1/2nvjVUugK5ABf2acWbFrgH00UUuUUwFf4UAjypIsJ4Ue52/l8YTVLAfDWXCw1Bh3h9XznS43gvUCgYEA4uIOAOaZwlLI8OKJcJJsDgJEFfm18tCq3zvC7z1z31CcjG6C30ggE35q5hceznom2gLZBLAMQpwthyLjZoVGESEDBdK6d+qtTN95qz3DBtijVOQ8VuP1q9YLMU2IfFeftlRnaR6eYZpAMh3+/fDXpjKaIYImJQalrivfB4nTVrcCgYEAvheAIkdovLWK5eiWTCuhCSnCVNi/qgRWs0YgkoCM2YYQKO4HwJ/oiGCTAwPKJt5g8RfruTDDTRcMjc69LMGlxlkpASR6380+hbMA4d8U3Hr9gmWDEIzanScIZDPYuU3t/R2Hg221t5Fvn8713xVDEovqnuO2vhzy9jOa04cq1PECgYEAhzuEa0cICQq9GM9+amnsHCF/obWYnOWBo9OEKoNviIEM/qt0OFBORjBI2WKYiyvF8pZV8nRYqm9at7y03Eu96sHJgnQLjySDLVnatJX4pCEGobf0uznfGhBX1YhIPQ0hdlUy2jZU4wpFD1pPvd8LOtXYhvaDc/hVUs51fpHJNVsCgYBUZ9fVCoSni9m/eTlDSsWtk+sL/0LkHT0/ym41wTdeFgefCdZMGFBu91z8Td5ol0yclJjxNr3tGUvINCuSzsM4WRh2f9zSjOka+M841WK31DCUmlhekjmKmYw8Ie147d0P2waVmEIdUs40aCiJW/hcV0ld+H5jg7Od+Yb0rDIWPg==
|
||||
mongo:
|
||||
connect: mongodb://localhost:27017/?w=majority
|
||||
database: consensus
|
||||
|
||||
@ -5,39 +5,24 @@ grpcServer:
|
||||
- 127.0.0.1:4430
|
||||
tls: false
|
||||
account:
|
||||
peerId: 12D3KooWRqbgXAdsP9zzBeKv6qjqmW9qfo7TbQfTi4eYYCcpFBwT
|
||||
signingKey: 4JPubXZ2chIF3SFYiEGHvdTs7/B+IbrdUCHWYkNH/E7uC9nsnBle8q/FaG/7b6pNKjXukTGaXnDrSixZw343/g==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA3xGRPt9EXpes27462scV4Wm71KUZ/mqf6re/x8LW+ZPvuuq1R5bj2AhUYj7oamVvqnpO8N3UxOSQB0N3eKtmi/I4M2OdLhkZHKBdGi/XG+eGRcCaM5kGBdot52dgFkqXunnU1h2khCk8XeWrJL2mnm9eSgSzvxExkQQfx3nCwYLq/ZmgGT+wBHZECxIlzxjpcgGjnCCIthb409YUitF/tnkwkcM9KBZJFJyJxTAmPaISrcpb30xNfxjuI4khst/s55XYsptyqRLzWMvr3fKUg2qN+GUCv4uAEQYLOGde0nVLq7zqofkH3jqXta13q1zi5OBiW75dCXmjtCtdBeMcNwIDAQABAoIBABV/b+wLQF+NZo9W6f0jqqwqsHtx3etzAy5vvv/VezpaU4REEmxv0k2Dn/5H6cY3OGfJmcoE1viSvn60tdLfUeay1U++jetfZ9gmbFKVwbliusIGKdZHLRlrSXk/sTb0wWKrUyO/f5dtEfBKrg/AZ0plmUSw51HGqmw7ZYSn62kSstB3VKEiM0nWQAh2D9R4APMaaBEo3XPJ+l706T+VPK07rD9oBdQmEkhA2Dks1jYzWVGeMY1aNhndPPVKy34BcYJa+z8X41bwUDsE4mNFId2nPVofgaGJiby4A/3adlvLzosBC5kYxj/V9icNH/iEYtwVV2rIjPLXgt54k1L8SQECgYEA5OWewIuAluIIt7RnClmpd6LPQAc24NsfaC+edGj63b1m9VPV1Vyve/+Mp642FUbp1zmFeTfTBOg+577rnrlI2Arfy1vRrHrSRFLEXfyGA6SSpssvDrHmJtJBh/H3kUgLeqsQlX+ov8mtZEelUF2oWSbmP9k5JaoXoN67gGVrAiECgYEA+XtHB2sZOWV8jOCN6ZU4GfjjymNtCRsH2jWs1fBJ5Sfpei9TK/ZemJ7n+vnANiFLycNoQ00EFlOYaTBCCig+vc6/jX+Ecmh4fUb/ZAuYx+GOA1TltcD+OWBrUEqNdrXwICtUWo8/m+As+ntbCmDSZRUIGRny/N549sGEipufA1cCgYEAsA6NlLu4JFWnLuVre+KLHqHzluP1qe3gslouHovAqV1NG9Vn27x2nYFpxm+Q2by5j/mGWD4/6L5Z5BZNVMBe7w0uJVRyaZ/uqu6ea0wYKCUlR3VwtHTQ+XsvPEk4il5Htgptrw+J1DpjS4Zv+OiQ3EG3R9Tkx7uUgP/QaGmZbQECgYAT2xvsGzoGt20SSU0CKj4s0wJOOVuUPfKCC4OWA2neMy8B6oJUHWep/fu4negOZtgBVuwVbyvEGyMmPBEFfe6AbNQSDvQbpvTwA5aP/9xJDEqhOUCPFq0lI+dmnIhlylUyOkCcdIo7fbwWs3qreMlGAkaCuO398jbubLh/z6L4QQKBgQDKUzTECIr75cLiFbUFxcseYFZEc1weYtlp3E28H0rceSD1GakQfu0osi294lLFzWbc4JfZ29F2rFnOAeZ55f4AtFh5xxoY2robre7C5pOklG5zTcHXakvqdWXPtYfi0o2dI/JBRNnS14ZDJqVmROGmMXsdm1et/qARKBI86wORUw==
|
||||
peerId: 12D3KooWC9DkXiYK8MiQb87ffW51ggZR4FWASadh4UENXdaa16iz
|
||||
signingKey: yfFJv5klknUeG8rROCNTktCk5rsBvz16aEanYBAl9oYii+Q8XwH8mVXr5hHSiP+HYxEaSSozlMAAXUjdW2vK5w==
|
||||
encryptionKey: MIIEowIBAAKCAQEA5zUOQ42SFUYJyX86llYopUE4Q+RQvbCakTPd9LBKt6pBWyW3PA9sjFisxVFFwYOVwghzF8QDSRrWdkjGmRPPOSRNmNiJFGtk6wb26eihenFECdb4nJyTDZVhvayHpByCKleAl7dHLjHCIsVaaFfn5rntm47IdDSNFgZnNDrNrdS2SchXWHamcfWBJSQirdp+8kSh5RC6/J53LVa+Sff6D49BsF8VsevcjvFcdlpxG6GKhr6kzvnEwCCk8DIqjpF3geUVj/QbT9tGa12bAgDQuckW4DavIN1zT7BAUbZPcbFZ9Bd2bbKzXDFNt2mRXafDPL07KhnXSZ2YAxHf5M4s7QIDAQABAoIBABV5aQy/Lm1JZwlPBtsFv5qxtw8fOpyTtZd88MWURixO5OkZVK6AZD2Y0ts01DzIAvXVoRL5ArEcjATKd5+qJloRVB+5JOo/m0z1BaPuFmlv8bjUPZ0WMdZWJJDgYGzOtQxHukrdHABfYL+oAuCkIYbdiAMlvNqGMwBzscw5FfdqGBRwC0bus+YD103Hhc8pN0REwLZmiOvHR6b4Agwv4ruFsqthg13EwcqDVTnS1/sZyodLZaAGBUXlqUxuFakI/9CqpPuOkDgxelTYdXbS4yhfRF4zwoBGZx1462iJs4XM8TXhDcZpTRwCChM5Qf7jvvgbi7+gYTX9B1dxg7gZUyUCgYEA/cd/NqOyx7bn0twiuMEdq8bCi5Y/GvWLrQ3pf58DPanIydGPJU5/obKZw5Tv5LWbE5rUEeC2YpFleNh01oc0xHCveIR6JNGihN8u0DZPmcx2B1lwEzdYefRJfGcYXYhm/nCpzYn3VH0TfKA6qci+KLarYaeDpUCXAihZMUZxSfcCgYEA6Tr+fSXmHIYoKcewIpwSTvcFOJ6spMRSG+mxQAFit8vUQTw2e/aTESEECo24XJ/SKVK01CSoWXrw3t9eBgziyHI3GaaZ5LaXMZLLZhmGUT5kZiTR7083h+9bHt2+MzRXpaAEEc1FNgV3T2sSl1S+oKDL1MAcR42JaQtC1P2epzsCgYBKDdD9bL9ar/DuAvbO2uuBmLpkaS94+nYLxaeBajFT6RuCaPhQdpuf37Im9GscXjImgmOn497U3ICzxtYxU7r+J7PMgzvxSosWItpSP8bypks60cp2kQvsanCXMK5XfNoxHUcvhzb5HJZ3I3p62O1EjClukadErZhjNMryKhAc+QKBgFwvpUdyI3JC1L0u4L/NUK9FlBq9HSBDOPEvfY/+/DYJquveEOsOmzK6Cg7h1W1G/pq2xiLUGnbD0VFGmLNrhHgWLRFGeK2ePkSp8Rt6G00hjC2TgCdG+HwSb8HTg8pZdgtRJEqlCCZCItaRS9fk9zQmWmrNRGBD4XxTpybo2DzhAoGBAIxRN8WZc9HYVq8t20MieKP3pp5Nrl0wj9Z9EPvC60CwQRdv/FvWzDwF5/9Kg79rvbguZgjD6FNy35BGC5sN/24awWJ/mKYosctRwZVFpogoZ0qAdOwxowfAJXLRC5Chgim8vCFFdKdrMo2a6V+MQuhrTv06QAV1sYAH5P7abfPy
|
||||
apiServer:
|
||||
port: "8080"
|
||||
nodes:
|
||||
- peerId: 12D3KooWRqbgXAdsP9zzBeKv6qjqmW9qfo7TbQfTi4eYYCcpFBwT
|
||||
- peerId: 12D3KooWC9DkXiYK8MiQb87ffW51ggZR4FWASadh4UENXdaa16iz
|
||||
address: 127.0.0.1:4430
|
||||
signingKey: 4JPubXZ2chIF3SFYiEGHvdTs7/B+IbrdUCHWYkNH/E7uC9nsnBle8q/FaG/7b6pNKjXukTGaXnDrSixZw343/g==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA3xGRPt9EXpes27462scV4Wm71KUZ/mqf6re/x8LW+ZPvuuq1R5bj2AhUYj7oamVvqnpO8N3UxOSQB0N3eKtmi/I4M2OdLhkZHKBdGi/XG+eGRcCaM5kGBdot52dgFkqXunnU1h2khCk8XeWrJL2mnm9eSgSzvxExkQQfx3nCwYLq/ZmgGT+wBHZECxIlzxjpcgGjnCCIthb409YUitF/tnkwkcM9KBZJFJyJxTAmPaISrcpb30xNfxjuI4khst/s55XYsptyqRLzWMvr3fKUg2qN+GUCv4uAEQYLOGde0nVLq7zqofkH3jqXta13q1zi5OBiW75dCXmjtCtdBeMcNwIDAQABAoIBABV/b+wLQF+NZo9W6f0jqqwqsHtx3etzAy5vvv/VezpaU4REEmxv0k2Dn/5H6cY3OGfJmcoE1viSvn60tdLfUeay1U++jetfZ9gmbFKVwbliusIGKdZHLRlrSXk/sTb0wWKrUyO/f5dtEfBKrg/AZ0plmUSw51HGqmw7ZYSn62kSstB3VKEiM0nWQAh2D9R4APMaaBEo3XPJ+l706T+VPK07rD9oBdQmEkhA2Dks1jYzWVGeMY1aNhndPPVKy34BcYJa+z8X41bwUDsE4mNFId2nPVofgaGJiby4A/3adlvLzosBC5kYxj/V9icNH/iEYtwVV2rIjPLXgt54k1L8SQECgYEA5OWewIuAluIIt7RnClmpd6LPQAc24NsfaC+edGj63b1m9VPV1Vyve/+Mp642FUbp1zmFeTfTBOg+577rnrlI2Arfy1vRrHrSRFLEXfyGA6SSpssvDrHmJtJBh/H3kUgLeqsQlX+ov8mtZEelUF2oWSbmP9k5JaoXoN67gGVrAiECgYEA+XtHB2sZOWV8jOCN6ZU4GfjjymNtCRsH2jWs1fBJ5Sfpei9TK/ZemJ7n+vnANiFLycNoQ00EFlOYaTBCCig+vc6/jX+Ecmh4fUb/ZAuYx+GOA1TltcD+OWBrUEqNdrXwICtUWo8/m+As+ntbCmDSZRUIGRny/N549sGEipufA1cCgYEAsA6NlLu4JFWnLuVre+KLHqHzluP1qe3gslouHovAqV1NG9Vn27x2nYFpxm+Q2by5j/mGWD4/6L5Z5BZNVMBe7w0uJVRyaZ/uqu6ea0wYKCUlR3VwtHTQ+XsvPEk4il5Htgptrw+J1DpjS4Zv+OiQ3EG3R9Tkx7uUgP/QaGmZbQECgYAT2xvsGzoGt20SSU0CKj4s0wJOOVuUPfKCC4OWA2neMy8B6oJUHWep/fu4negOZtgBVuwVbyvEGyMmPBEFfe6AbNQSDvQbpvTwA5aP/9xJDEqhOUCPFq0lI+dmnIhlylUyOkCcdIo7fbwWs3qreMlGAkaCuO398jbubLh/z6L4QQKBgQDKUzTECIr75cLiFbUFxcseYFZEc1weYtlp3E28H0rceSD1GakQfu0osi294lLFzWbc4JfZ29F2rFnOAeZ55f4AtFh5xxoY2robre7C5pOklG5zTcHXakvqdWXPtYfi0o2dI/JBRNnS14ZDJqVmROGmMXsdm1et/qARKBI86wORUw==
|
||||
- peerId: 12D3KooWFYTh59WMXGLDqS8EXfTjHvrS9uXrcYJuE6yDyL1hh45R
|
||||
signingKey: yfFJv5klknUeG8rROCNTktCk5rsBvz16aEanYBAl9oYii+Q8XwH8mVXr5hHSiP+HYxEaSSozlMAAXUjdW2vK5w==
|
||||
encryptionKey: MIIEowIBAAKCAQEA5zUOQ42SFUYJyX86llYopUE4Q+RQvbCakTPd9LBKt6pBWyW3PA9sjFisxVFFwYOVwghzF8QDSRrWdkjGmRPPOSRNmNiJFGtk6wb26eihenFECdb4nJyTDZVhvayHpByCKleAl7dHLjHCIsVaaFfn5rntm47IdDSNFgZnNDrNrdS2SchXWHamcfWBJSQirdp+8kSh5RC6/J53LVa+Sff6D49BsF8VsevcjvFcdlpxG6GKhr6kzvnEwCCk8DIqjpF3geUVj/QbT9tGa12bAgDQuckW4DavIN1zT7BAUbZPcbFZ9Bd2bbKzXDFNt2mRXafDPL07KhnXSZ2YAxHf5M4s7QIDAQABAoIBABV5aQy/Lm1JZwlPBtsFv5qxtw8fOpyTtZd88MWURixO5OkZVK6AZD2Y0ts01DzIAvXVoRL5ArEcjATKd5+qJloRVB+5JOo/m0z1BaPuFmlv8bjUPZ0WMdZWJJDgYGzOtQxHukrdHABfYL+oAuCkIYbdiAMlvNqGMwBzscw5FfdqGBRwC0bus+YD103Hhc8pN0REwLZmiOvHR6b4Agwv4ruFsqthg13EwcqDVTnS1/sZyodLZaAGBUXlqUxuFakI/9CqpPuOkDgxelTYdXbS4yhfRF4zwoBGZx1462iJs4XM8TXhDcZpTRwCChM5Qf7jvvgbi7+gYTX9B1dxg7gZUyUCgYEA/cd/NqOyx7bn0twiuMEdq8bCi5Y/GvWLrQ3pf58DPanIydGPJU5/obKZw5Tv5LWbE5rUEeC2YpFleNh01oc0xHCveIR6JNGihN8u0DZPmcx2B1lwEzdYefRJfGcYXYhm/nCpzYn3VH0TfKA6qci+KLarYaeDpUCXAihZMUZxSfcCgYEA6Tr+fSXmHIYoKcewIpwSTvcFOJ6spMRSG+mxQAFit8vUQTw2e/aTESEECo24XJ/SKVK01CSoWXrw3t9eBgziyHI3GaaZ5LaXMZLLZhmGUT5kZiTR7083h+9bHt2+MzRXpaAEEc1FNgV3T2sSl1S+oKDL1MAcR42JaQtC1P2epzsCgYBKDdD9bL9ar/DuAvbO2uuBmLpkaS94+nYLxaeBajFT6RuCaPhQdpuf37Im9GscXjImgmOn497U3ICzxtYxU7r+J7PMgzvxSosWItpSP8bypks60cp2kQvsanCXMK5XfNoxHUcvhzb5HJZ3I3p62O1EjClukadErZhjNMryKhAc+QKBgFwvpUdyI3JC1L0u4L/NUK9FlBq9HSBDOPEvfY/+/DYJquveEOsOmzK6Cg7h1W1G/pq2xiLUGnbD0VFGmLNrhHgWLRFGeK2ePkSp8Rt6G00hjC2TgCdG+HwSb8HTg8pZdgtRJEqlCCZCItaRS9fk9zQmWmrNRGBD4XxTpybo2DzhAoGBAIxRN8WZc9HYVq8t20MieKP3pp5Nrl0wj9Z9EPvC60CwQRdv/FvWzDwF5/9Kg79rvbguZgjD6FNy35BGC5sN/24awWJ/mKYosctRwZVFpogoZ0qAdOwxowfAJXLRC5Chgim8vCFFdKdrMo2a6V+MQuhrTv06QAV1sYAH5P7abfPy
|
||||
- peerId: 12D3KooWC6sZYJXFagZtRjY4Jc4dzBLpEgYsUhJRauYheSAGk26y
|
||||
address: 127.0.0.1:4431
|
||||
signingKey: g673H1+gh/KSbRat4m+E+UBTxEmcbxNJ2ZEwdBnQKiFVExLIU7FUXhx7F7xw2QJOw4CInWK6tNZZRNAzOWcD7A==
|
||||
encryptionKey: MIIEpgIBAAKCAQEAwrKCiqwW7ZGgxfG/t/GgPZ/shmbXEtZjDiZKuLugfSOedERYdsPZ4PmPZkVxo1rIoZjZOnoo7qeC5LWk1A0N33LudQF7Qg50O0QyiV5QTRxkv9IUvAeXyUR5TrxD5oRdFKuCbyDUQYaoAOYCBeqSI1ub5HdFt1fDMqgHXVW/p9kMwHEXpHM7ZaARFf5ri9/FIIodb5+IkduSK3/qBPlvt6dy2MlKlHRkzHef4q8YFKuDyzsyF7fdtjhhHk6p86JBnMaQpP+mi3e+qUxhdWEIY1s7Jo1Yal+GDQ0NtRrZp4GdlpFT7Kgp1Sm5OzSrtEQduluc0GWJFAVpolHg8e7QlQIDAQABAoIBAQCTZjIOalqxYR8mvO84g2WdQgX/erw5NrWncLYBRYsrMlw0Ccovn/bDrCw0cT6nPYPHU8Ch1PpIM+mU3S/8miV2lbySOJzoVakJdYgNF6oTtvtPfezUrarsZTqxsTZ2vp75lx8YovIO6bMnevrtH7mjqydKwEG3nGnbX/qzXsfKeeZgd4kvnjlxGTDUen12Pl0kPLcBgyckZLDJmXYtvxuK1sZTjifyHoeGVYpOOLYi3rRSEoZnVS4z/fM1sG5aUM6eA/7HaXDAe5sT0rgmPt0mu6Mo13dF3rWkP/MCqEVdBLfQLXEfqKp/9QuZ7szdsM0b0WPDXP/YXDLALLvL5/vBAoGBAOPeOrG+JyyS85//wKy+ZRZND5IdxBWoPDfItKnQJtMzOMiYcpwF0J0j3VqdulQlz4zX0Zly0iEYtFtNozVLStDn4IPrqg/vJI+vkikDrY/r1lseVFGR0euVtpRth3BybzhR9llfqK1tuR7cCg7NaxnoIkwtbZDumKDPRoXSQmAvAoGBANq76w8ZMdduxQhroE4Hs4uP5g3Yx9bDlimwGBwX0afGoO82kvgxpol4Z/3sXC7dAKoBqLTTpVDq44AkMhSXgT/CGALsebRxqc45orafe3s+rTFoQsR8eXu9pRw6TxjwATMMxZHjIkV2DeQuKIOTZcvd9E1PVmUB3VSwihje7oZ7AoGBAJGSi1S58jTbvKBetyykhdf1axkhwv9C9xV8N061F9idRI2CNtXOMTPykZsuYLcZYLrNta2eWPej3LTnqHiHnUhQmnIsv/xl/ql8tJdXLi5fsBWODrf9vGoQvw+b2YbQ1JTaZ9M49X22Nymr0REb0mw+jIq2CuUoSIGTaa5cYOMpAoGBAK6tnZUsKKqDsmP8F0PZUKAmpbDvKwAup8/Y6hgdSXfz3vfKHGqKtBVai6mzxRZDtdEOjB0EXCQXwODHhxr8tuIk7aoAEV1x3Apt6qxvBlyw+/zV52Qkh5uzIpU9V4dxu3N6Qpkzy12vXn6YAhC5eHTrZrsKndMCPy/v4Ajml5PbAoGBAKugn3Gh4BLUOW9Tvnc9UIwITp8p8+Dx9yQJugHSDzBFGuAZ1FUciCrK8SGarDCyyzY+XBKVuNZEj7D4P2+JiTKv8nweRVj0DdXYUwIsX6cWgPF5i8dm0Nl5PbsR27L+TxficuO4IQRHMz+Loho5itbSuDY9Y07PvKLKJfu7Cd9l
|
||||
- peerId: 12D3KooWHgeiz7EyY59t5fEZnkdg2gJxk3YvJmxpVibEcX2EtUcp
|
||||
signingKey: mLzjMshSbtOkUKZha0bNIHvW9nlqOPX6VM/mvKicx6kh8ebP2mfrkCS0qz5GwlFEqTgtuSnWsHdvGZnuan2Ahg==
|
||||
encryptionKey: MIIEogIBAAKCAQEAuJcCEM4sM5I1Aj2y0HDgR/UrKEVF1iZ1CYWv4jVOt/e1avDn7XjF9ArB7lngq7lOTxpCNeLMQXeBl1gY1SBCPeTrs+tltyAUeSOZStwP9qhjUhI9TntfW3QfVlC2lB17liGa4b2F10x9vW/0f3R7m5xgz8NyqcFOZip0Ehe9UJbNFwPr00by0D4/XptkDT44wAIDlw7lgOmXWR3RpCYAYFonYeE2HK7FFNTIOJucfJ8kbK7wLp5EZRARYfCDUFq7czFu97FIrmQfS4Fyg8ESB+R28+dJIQ6G8U1MicX4Ibf9IkufK+r2fMYPv13F33omrwSGhNIWtX9WjAQ4bjmA6wIDAQABAoIBACHuaEvMimWEd8gMrWURirjPgXpqmXbPJO52K6mqYOkCWM/qrseBTuoYXCPDU8BdVN7Hleov4ZobLLA0WoQ65NJZ1VYCbHUoKXtHJvOS1kBiHbfFcI2PsiyugOAuABHkBYbIcJ8UZpj4D5kWDlyrfdlR+p3WcKpxxUaUgTeeM4evkMg2dg1/S4psgu1SKdGYMtafKBgvxxE0R/fjfP9MRD260/ydcUT0gRE+uUu6WFm92MLV72W3hoKfNqgGnQWCTG8UJGGK3KC/c9lAvLiDygo3GJLEjhnrIGkSbbd0uHtAYD8Uc+gq3z3o5Rger4P/FyWSbJ6Vz20iYHTeYUEDkKECgYEA5KK5/Z6XQHwsEGXSSCXKvUjJ7ZOV5k3D2im0F1dTtQaOjFgwZ9SPW/k7tQfcwfZLeDSm5V98FXSAu9XgT/Zrd+/RrfbgmKLMcNVet+l2OPq1cOeKE7io7wAXlkO5CmiMXMCRVcgqaENutUSTsmadFqd2NE7/gEUjeNIQLGkSsXECgYEAzq6+HtOxhfbTEC8ZUz6Y7+CphmtYiuX7G42lwv70mg+sap7mVlZzOHNNM1p9BOVEo2K1RKNWtXMgXDbt/KakBLCab9sR4R68tS7JX281I8RK/kYOLqlVE0CahujcCJATZAsDLMCpjeN85vwqJ9Cy1errf69thZwo1QI1BvRIahsCgYAkmz1GMycqZvczJOpXLN3aEpZqGHAusJLEEltIRW4clNEr/U66wRi29B+wK3MYBxQsSdnS7cfTM5UM/gBtLRol2NrsjJOHPMGY60DAF3wbQWDdk+TSpYU+xvf/0hYFaZnXm+lpH6RSj0FhenpfXPiX0PYnB+L2qZs1VATM54HbsQKBgG9nVwkMuCpqUXfuuyrYmdzqbtYKdG5h6kj+v7Nsc3G7MwdBYQx2iqKJ27nrc2m5HpcmtGgr1qf1RyMNZJgDRnNUsdnK7kc2pybN8jMjoTQHMRj/r9NM6JN5BhHj3/4pkpohKXPs4TeewAtNLnfJkSum9Yscht82vfeaufRmpcWzAoGAfxcnMvi2EhE6uNjDENqnFH9XD2zAAeKhiQumz2ts3cSUd1QOfPMeytsBML/jdmOMQNaTbMryhWPaqTewHky8P+l/7oVbMTTFnaaaZRZCSOSXe+2R3mJkRQzE+DkVhgfpEku/BVGRHRvltM+ehk3m64j5vHWC97cP52qZ0bkxKHo=
|
||||
- peerId: 12D3KooWFWyDckUJBtHtARzRDTRpo4XzeKAo8oN23MXh3Xwbp2fd
|
||||
address: 127.0.0.1:4432
|
||||
signingKey: Tr1OaCpnYVkdeuyoBHAETn3DHWbQZELK2x5xuvd5301045GYTnQdWWT/05UB61dmu1NcY4yznm90baj36GrgUQ==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA6FzTxWImBPJL+dhVbCUWqcuxBmbR7npbgHNOTJFh38InqxEkGwrulenCyy7bewIQXLMfzxroxm17GpWWV3hMcAzQUOojUSylJPguhrWOOtsJyxxDXyG7MEleaFX51MF+SNEo9ivBYbbwJiFrGv9tGW6D4dGSMl1Xf8yKyKWCJVBah0Pzc57I8e93qOZjaCHRmsgC7DdzD8FyIPnAuxYxNs8iSaYPP/UjcZT/SA+Ldu0vyNxdnHCSs/+3FwbmPyhYrn+uBOUUidfzraVn9ra/xtcCZQXbf4fhJ6iwfp0wJoaDU5akN40910XGQqbF6FLfqZZx220vIcJkHc3McbtiaQIDAQABAoIBAQDjTLMIOduxKQgzTnE5igpibNQty/T+UQkjXSgx9GGGzlmZmPn1zjrXwUUBF0QyTzGMTNkH8m3UdZJfzga0aAR188Lv9Co6JO8je/efZQjOACjTXEF3VPrU4GCOtdPfUKxlNN3Z+bGBEcBXvIcWcNjbcOVnyGc4B2Eprf/xCR6Hufa289Awnf1ixe33VdlBMsuua7qc+gydRF9BNpvTop7n4bGkrPJkpuNp1063QEh6Gi9Za5gM+bd573FsYMhHdECcSWS1ogtTTNsVyLPo+x/Naj1pC3UTmAFXyiseeVJ82ibMCOBywr13I0WlknNoxGevU/een4sxX4K3CFH0YGZRAoGBAPVz2qhTDSplq0EVnUVEINfvNTEDLgUMBbdrwpO6FeMR/QBohGB+Yzoen4rBNqnLOOSsetaWYN1u2XgyA9RyL6wnO7hOhlpgY9m5+CCKOwKhPwIBGOOsaFwKLzwDcACK8rg5S/EGDRYCT2SfKv2bSdyLxVt4bXjvMZBQ0lt86R8tAoGBAPJY+Yb5vwiyMlQk16spB/KoQ/hZmjuWUt6tIDf/B9/LM/vMfguJJRq+tmBa2JxvYmUj3lIt7Sg5RiFECIiZ9MW3H7rCu+SHRN5HaDjKOkFX8qTTPJJu5LyBcCnHHxQBi4t5bVTAbKfpBXTi7lr5aAhUIztUVc9Poyz9mm410TWtAoGBAPCaOnLZxoQS2UaZW2r0l4VUNL3wsgG8gTYFadzJgn7tuSXXTjwQaFAmiJnJQD48uW5fLKKBEj69VGugC2UK8XQ9mSrXvpeE+RwKUhIDrkirq0nZrX4wGLRwP1ECxZ2ilr7DW4/OMLGsXgryg3/J4yNP14wMhrMPNXST5UBNN2+ZAoGAcfb7aMjbWBiMaFtm/DtwXGFajVh9mhXn5IVfiFWq+0fQq1GP2Jbm1vvmQcuW34HVsKA8dULZqre8TfpzVOGpZKzoA+h9eUtPTIQh88rNuFrGZVJcwrPZZvgrqcnUyJCtcappiphuwEtpYH0y/58XmAsRAl53d+UIZCjiTX+LYYUCgYBWuUASFeKBWp8/jRO6xgcKT7DErnMZr3TRYkduH9miIlqhx4NH+K/hkgkIFk77ov1swj2XrPL/rMMtWDRsn8fvwhRYkU25FCNAdmSg3G2iaW3Pd99d/fsdJtE+VjVQv58R6nxp5aiVH2rX9l/tspdUsupoYdFDDHYDkL+lIu2ZIA==
|
||||
- peerId: 12D3KooWJpE9AtG4RX4Dwm4vhrCGqiUhKj6Mvbqj2V4rV4diyksT
|
||||
address: 127.0.0.1:4530
|
||||
signingKey: 6tA9VizrAMtsZlzBXXnsg+LzwSwBLU7oiVP1qOHN4PaFsBslV0nt2aKBXfcfxp17V/bvydNfyYbGu50F6spLCg==
|
||||
encryptionKey: MIIEowIBAAKCAQEAtsYet7J4bNo9zSPFZVFkkInUoAW7os8PtZH6qMUEOKcLAi1PDbkBBCmzHdfuzik8H8DgQl36/0gCqRPM6nhQlbF59mV7brI8/kH3Eiw0rxqWAe0+C6CzDyEqtKC7pJyC3FJe0MZRRtDXiDYlVurHrsW22fA03rJY5++eW6bXiqL7WB44zxMrztkvPljlhDf2XTAcrZWI10oXKjSZMW051Figbhdl06R1ZiW1F1LmUEd3ufiYoevpq8jAHWIToTZrYNX0sfrdNaf/CPCq9ZDSqISf8CZ/bE1VxYRPEnjmX1hZQ132S1KCEQwpBWxpcvePonEMPGp+5F7h4k+46f16vQIDAQABAoIBAEa8np7Rv7HBNTHzqi3wNk+KSHQ2Q8xa/uVyveQbe+rBG42YI4RYGYCW8u+V5qJ7av2PFDwbS00JfZ4aP7BvKCEHMwCdfgv1h42P0iOCYFF0pKHSQ7UUWLh+SZzmqDipKixC5NdAKaySnxfkfMcKzoVhl8b5JD0cITSClHM8Oyc4DR5DeB9MlgrVqV/fcdzR10J6TeEPyJjs7CF+Y4OFUEf8FnNxfx5btWm8dIxRMiFUqdI1SVHmOJo0wO2z36RKZ2f8eHApafpJ/1MWccCCSB34Kry4WjDLn8yfOZ5GavXKDVKnE2won5ZhpZGTaLVHLR8QzvkzuBHDk1j1kSi2RjECgYEAzwjnJc5F8XdOkNNPKpftnUVlijhEx0lSknL/j1wIE7bdqbGvIhW+OlIP3bc6O5h0QGSoB71cAiurzro9rsZnSZ4qqjyeGh55j8I4RoZHGDu8BoUOXzrIL1nw3JWxrsNxu5hV9bcYAOJDG9BOcm7F9g00+f+p2zR7BvZMYm3d0vsCgYEA4gBSbChHTMHs15wppaTqV5iQEbfAU/oweRBnflQTHVdezMDt85BpZv0ik2vTuhMJuiaISMvb5l2fHI+LIKoZgCBfymQ50Yv6dZqOMeY5XwUQiQ8DtVtoetYBwwPIS3hSntTu/a4Q9tZbmmWYG6rZ7X58UrtVHY5DfFMS8MOrO6cCgYEAgDkGV57KKMN4cC+/DyUrL8VEHve8eSSLNFJuvs4D3pnZ7Pgz/Es1Fo+ubeXF9hT0otD0VF7NtjZv4Mft3enZHHoN+IM0c/690PA7xEnzjCmqyOrtPMN+Kf1tNGCtvAwly0aMrnKoNhvr7jTz8OF0T3BciBz0iOOW8nfmVOuwf7MCgYB9va4eDR72XuMWZwVo6uOTTwfBQ9oXHxk/ElhymfZ0mbrd8u2xWQS7z1UgbprDaXo8/tlOn1W+yxIOwvKmft1nQxvosHDW3KnCKva4Xp5G9rtndloa2ju8NDuQtBcJnm1hf5lkvSclHsiik6nYoutTTs9+/El0A0Ya8uGT4Vnw+wKBgDq6yliV5g56J3+gHB4w8yQSoIx4AjHoGkYbaVNiCNLfH02VVIGINnlBk+6xurHUwBg68cAsMSAPWqky3BMvhpAAoyPDBycrWEYKHvKvVsH5R0JRDymVJ3UHJVzCp49+CHIoOElnR+IueVluljtxTrB4JgJj0NOLKOHiTNHW6emJ
|
||||
isConsensus: true
|
||||
- peerId: 12D3KooWCeSDwgmdmLMweWKf1avCqaBYuzEo5GpMGa8MBBskBmen
|
||||
address: 127.0.0.1:4531
|
||||
signingKey: N8fkrWmuf1wVxL72XE4Di8pSyTaQpev/9NV4eznVcfoqB9Z+urz0kg1NKJjWisC/nUGdJP9EB5ZhgPyuQfqIvw==
|
||||
encryptionKey: MIIEowIBAAKCAQEAx9vwNRbEUtOuJ+UxXsvepKC1VY76RNv+SnnUIQE2/fXo/1iUEevydpWWD+V4n0DjxMsCViOv/kIOuXArIntFqr5xyRdIFE1nbiSW20IppRZO2Vw2fZwN+5DOl1Z3MfiZsqD2dbdtVLuUP9On1lqPWgW/ZHzweCcVMz2ZZ/txubSBE889bbSoZcNlgXS0fJSaw/6XApgtL++sZBqxwp2lkf918ZM3SFuAVHYU56tAOnZrCbyHcbDk4OOJ1q7NzrxWg71S02yqesuDSjIW6BzIXbDVjS2yvhKRJrrKXSIYepIczPwHPPCs7/pCPE7XQ6sYB9d8BL9/U+doLTJToAhHwwIDAQABAoIBAEZwU9bCMWtnw8e31ZCtlci8A20mOTqvto4VJhiDzxfu5bGpTHaMjCYTTpJHtB2cxyoCys4FQfAA5COjTvCWNdWZzYysMfFF3qBJMQoR5Y+TrzKYd3QJ3ju9q7JW/SeVkMYOSQ7wGQ52FifwtwSrYj6+K9iE2FPgom4u1bR6QHjMcAf9+eDJMUJk6Jg62SATPmiiN3b3OktNSsqvAf06I2K3ob1xIai0aTVcNsEoLbdDTejgFkkU3BHIzY9IXYkfipHV9+51cpRFb8q/Hl4boolgSPUSfe+pC11sm56QZZ7Gt0CF2ejhWyJKiyV50B1enKeeVN50KIMdtQn3VpTN65ECgYEA4wiKX/72Ca9wld+moywqexXNuh0a0gS/cWX4gFRv27jUScR7KTDM2jSPUxUK7F/hONOBBevfA7DMxsNNoPHoK9U2iwCO5fI9n1oWrUUjq9srJvrvsz2n2RmQ2deqmosLs0Gbb/I13+qEkunS7pfIIdul0LFE28PK5BhCDRdOUe8CgYEA4VvSWswkXQP4eNDTe78+GItQ78TluU26b+HOnkPRQlA2lUyxkUZT3VJQcgIptJJ20K13NZypJazJm6QELZPd/WcUAWKZqTSQxXUBwPVuoW5Aw0glXCfUOEG+LU+Ue8tvNCdqrAJopuYkYniT1LsQAOYMbJvL9PGkJosJfq4X620CgYARmgLoaGL440IuTHWl5vGwM0OM716586ZIC2jVwjYd6dmDkpkd22u2aybFgTckllZmyncRV3Ul2xo1OsUU+kxOwawF4NgzWbGPXjOt4VNfqpFQ51mYIuqVeVbynLbcXnVcw3RinHuyzYLTxQ8WcmwQu+/CG0xEYYykXIEadLkcvwKBgQCB5RovicFf99ztTnjHuCjDnvGs8lHzaDERMheVM8PXNELx9X3YHbBTPpHt1P9S/KUNjR7MQRtiAuFGG9joqHVpDVQDpGCrngfgOJwlK5Jz7AfaR6h5IN/6+TH0Dg2o+U6Ewj+DG/RUVw0b0SJsmNIVooQAyiBadDnImZWEdjaFVQKBgDnrnvtTMZFvJofnDNSQfOsDru5Mc9c/WRfegq58ocf8XaMMJyFCZGw90TLgQgWkxDCjQ4qnigFRWRCJ3sWB9LS8uFW5Gif0GtP6foL9rWlsQpCUqVApJRnVFFqW5f5FC4MZHtDTlZUk5lDQuvZjvQjJ+3vmusxEUIP0IS74Gr5+
|
||||
isConsensus: true
|
||||
- peerId: 12D3KooWGqsXf6No926wTb2eZdauqDcEkoAdKCeYkNzT6yrL3YDE
|
||||
address: 127.0.0.1:4532
|
||||
signingKey: fSLDcrMD0v+yzQwHG+KWdCkuZ5HPvx3vIb+5MecREc5oZJZfrN9P2z8gBU8HqZH/noB4aJRjXRVZsy4M5jPcwQ==
|
||||
encryptionKey: MIIEowIBAAKCAQEAtM7k4K2spm+GZa13SkRbDuFpPVAdPmR1+aN8IAtmSAISxw2vb4ET47Ck8vDfNtQ9rAvoAn2c3GxJb5Sb0pL9rofeIYYN/qS08zFVP2+FRM5CfuBbfVbwMZ2WvBJD02LzDrHRm0blc8JZDs3xFi5o+mWfeM2SZXVCJHFSNS+v1TRgVfQzu0uKlTD00CLPNz+uzDG6VntlzzEzkF4jVRA59BmkzqAI2ZgtB0cG5ztMnUhnZCX8I0b9CCb0UHjq9j97Xuot/hMAEGVQhNY3iyJx5gAR0t5PipgQZz5j0EXBGPy9T2+VA1QFLHVsUDmd2iV5fmTZziOWn7988Co+ZVMB4wIDAQABAoIBADbQ5ukLHmXTN/7JiXn1oVmwkzRofoU09eN6Yh5g9mBsaH76si5vBrWoD0osJrA7xnrLnUpsBMt69QSkHF3J/KkWPg0R1FpYWxfD5CF4UQIcOmK26GXmnqmcKl/YdcG3pRLWbELUSqo+yLtJSoc8CM2pU6DPSkwCMcxUouTHEVrkpL+Ic6RNGVFjX7E/HjfX9U/BKH0bzwj9CEPQEm9bqc3Zq+EmcE/CHXfRnHdG1cSp65qNHDfyEBjudR4ddItzwpmxLsW6+2Ywlg2pG/vfvRkGvwtAySkVs05J0vrpwSJlPy0NvKAbHAnmNBnmRH4E/myXf5MFcl/nz55J+yJs6QECgYEA1b6fp4FeIBfhvrRseLJeAepZhvmXkRegT61No5632SpcHymz3WnO+EsrL5O6+Ldpa8Gv/LmiVBQjvQeTvx97kINXKPLxmvdxRo+i7YUCAec8AZH7WEkxa0vvi3FLVoZZ8/P5fjvUscwxBeOvwhXnyXsFB9pJduYu6wzuMJe7HmMCgYEA2I1k0YjcTCqOk2Vp1lvHLtnMcmpm4FDMl9uws0HX4UO8i9tXlLZmWqDvPpvhxZVY+1hXOEid67712q1fiei440AGGNxc/xbq8Htw1GBzKyTd9dCQCVwWGX3VUO8EKAKVXdVIyqW+YUqD5PXUcPA41ll+nJdx5Z/liSNJvpxCJoECgYBv2P5GcuXEOXsBhfw09HFI407R2I29ePWEfBVih02BMC9ghzv9or6RIxSIIu/18lQR9RqYTrNo99jzs6FWo6zPJEtZvDc9djoqSENjsvQn9s5pq/AwdKyNjwDcoP5hWpB7nbFyovBb0ZPdlxWDpF7UCbHKOCm1NCJdETka6GscLQKBgQCGh8CcU5PYVY/hjd0kaDvjpTbX1bY3oLqZlMe/dSYyMayOjiNopbAMmXJHyPuHjfKLoyP8OVCyRh3iTlbODB/gPcQL6cp0Rr6Jy4YayhiCMxMZRQpWZjjseTnuX66LVJ+KfZgNHM6bDnnF4dqqlvIYZ9y6V3NQnfcxLRUBL34BAQKBgElDMZD0rP/u6Xch33udIlzdai30QUNWS9MgSrPBz1s8+u1e0g3UnbfCH7e5q0ofSmd+Ot21i03cLgUgJAFmoVmoJ794aveBo/bPbDrlbolxOUX4dFODvvOKzCcUHeOJzc9JE/Ci3LuHyEcqv49uRIe4BFc8c/ssDpj9h7Cyx+qq
|
||||
isConsensus: true
|
||||
signingKey: YpCGjsSuT8O6mkYTOExkdwNRODBaJ20hYJHFO/A/RUFUsUwxIME9X9FIp69VYvKuL6er973p0iG7UVVvLgLjnA==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA2T4/6T5etB9W7qzJ1sNfWFdOTa2koXKcQkaLBUTervApLPZtaVsbNtyVFtqqdsck1qpu+AVif19EFlYqSRtn/dxEN5/2myqVA6lZMm0Bd9mWpfoDQx20KAYwWBwzKSH1EQiTte0bw1zf0RpztxQ3nCOLCU4Y6x2lfk6Ea2XEayPxx0FDmeY3JSqUDOwx33Sz8Imx8R7+Dfjl6Og3DEqGxXoPfZ6hj9LynqNswjRIdmMZPsuEHguKXMbp+cncErGWcyzH417XYSDPoRn/3awpLfQ9F+KSjAe5cUltC7M4veSZW+t3VcJypvfRlU4ayTZMuvMHPlMcl/0jP5w0Q2+2pQIDAQABAoIBAGMvmrqBcXfHv0cluNnHRebtpaCtoTbdPx67WonDUfCJUiNnN7kckaZQu/k9SQsGDXm9QwEWZExHUKzqFlBepPIw+Sx0aoGZxYNwdHsjbcIspC2PoqGoFDMZ8ESqS2mCSYPHaLltUnm2E7JC44Y5QtKVH8vVzma6mG68ppTqV+2aGfGiPDq8cAYeH9/8Ys8/S28IwCp/M7lnXZhJ38bHD3YyPpcgbyGI/Zr5xaPd0hqHH08Z+S9V7QPJUGY0Y21s99DhkUGctb4B17d0/3Nzk/iWY1rp7A/kbdBeWonsHrTc6OnmbdiOcjC8seOIKMJ/WE3JznqnI1oydFb/dp6raNkCgYEA+pn1akGIKnVP0oFh5PZfUpuZtVV9u9xccIXyeFmCAXyFuUz1KYbfwwqZnm9r6kHAO+aBtRtVsCVle5oVWNQq1pdv117hPhRnVrDtvL80z50a5L9gEVu4Yz24Q3vs3RglcVpafSaRuyPbiYHMmQ4Ly+9nbwEbOVDbzK5A3Wrny2cCgYEA3exS3aG7+7mbSnNTYkkTgl7goLXZgEST/0EM2CvayxZ2QUS94Vq5HjGRpWnni3YttLiYlgCLe3CqeiIh6E3n6b9sory8Oy6lik/elj28kcZIuNvPU0xVcqrmGCg/KEnYkXjsGKsBDk6SV9nKH7880oIe0Rh3gc0hHHIl0Z4CshMCgYBifXHLkffPIA4AIKN11jJ+h/LwJqpk0+Vsv+gczqjepq7ztcBA0uZMhHT9pLLX/YFsyVo+8IBL21a4LkWnhLNVZW0qSvrhaCl5E85LuSYrVoaEUoaSK+ca8d3if+kGt/+3PhiESU1LLHuS3nWnzbJrMysGoHuvmgzYs7+AhgyVjwKBgQCoVgrFc1lUqIXTA4fMlgHmcnGRdl91nI9mn8FOeHWOd4tcFvixaE/jR1ZjUuIAN7ST0TJtFhy3lc66tgliXTX9aObOyrs9aTTIpa0B6fKP4QhosNOjK9PlFx1SVbUSqnFMZ50vWQeEArWfTeS0ECviwjD+CsEcBK2JFkz5pBIHYQKBgQD3zcYdYwvGkolLXNN3vbgTVnbNe2YMUBwgp5i1XGzAiG8XpwKTi4vDFIYgCZAG5wsyqUPdTOY2wyLjHwGdUfl7P3tCsHVzVh/xvuSl3nzW3OdCniKaBBdtZS6+s25Ijzdwiwnp21NWE6XU2BptIwTMHrKOc7BpZykgHsORMtptsQ==
|
||||
space:
|
||||
gcTTL: 60
|
||||
syncPeriod: 10
|
||||
|
||||
@ -5,39 +5,24 @@ grpcServer:
|
||||
- 127.0.0.1:4431
|
||||
tls: false
|
||||
account:
|
||||
peerId: 12D3KooWFYTh59WMXGLDqS8EXfTjHvrS9uXrcYJuE6yDyL1hh45R
|
||||
signingKey: g673H1+gh/KSbRat4m+E+UBTxEmcbxNJ2ZEwdBnQKiFVExLIU7FUXhx7F7xw2QJOw4CInWK6tNZZRNAzOWcD7A==
|
||||
encryptionKey: MIIEpgIBAAKCAQEAwrKCiqwW7ZGgxfG/t/GgPZ/shmbXEtZjDiZKuLugfSOedERYdsPZ4PmPZkVxo1rIoZjZOnoo7qeC5LWk1A0N33LudQF7Qg50O0QyiV5QTRxkv9IUvAeXyUR5TrxD5oRdFKuCbyDUQYaoAOYCBeqSI1ub5HdFt1fDMqgHXVW/p9kMwHEXpHM7ZaARFf5ri9/FIIodb5+IkduSK3/qBPlvt6dy2MlKlHRkzHef4q8YFKuDyzsyF7fdtjhhHk6p86JBnMaQpP+mi3e+qUxhdWEIY1s7Jo1Yal+GDQ0NtRrZp4GdlpFT7Kgp1Sm5OzSrtEQduluc0GWJFAVpolHg8e7QlQIDAQABAoIBAQCTZjIOalqxYR8mvO84g2WdQgX/erw5NrWncLYBRYsrMlw0Ccovn/bDrCw0cT6nPYPHU8Ch1PpIM+mU3S/8miV2lbySOJzoVakJdYgNF6oTtvtPfezUrarsZTqxsTZ2vp75lx8YovIO6bMnevrtH7mjqydKwEG3nGnbX/qzXsfKeeZgd4kvnjlxGTDUen12Pl0kPLcBgyckZLDJmXYtvxuK1sZTjifyHoeGVYpOOLYi3rRSEoZnVS4z/fM1sG5aUM6eA/7HaXDAe5sT0rgmPt0mu6Mo13dF3rWkP/MCqEVdBLfQLXEfqKp/9QuZ7szdsM0b0WPDXP/YXDLALLvL5/vBAoGBAOPeOrG+JyyS85//wKy+ZRZND5IdxBWoPDfItKnQJtMzOMiYcpwF0J0j3VqdulQlz4zX0Zly0iEYtFtNozVLStDn4IPrqg/vJI+vkikDrY/r1lseVFGR0euVtpRth3BybzhR9llfqK1tuR7cCg7NaxnoIkwtbZDumKDPRoXSQmAvAoGBANq76w8ZMdduxQhroE4Hs4uP5g3Yx9bDlimwGBwX0afGoO82kvgxpol4Z/3sXC7dAKoBqLTTpVDq44AkMhSXgT/CGALsebRxqc45orafe3s+rTFoQsR8eXu9pRw6TxjwATMMxZHjIkV2DeQuKIOTZcvd9E1PVmUB3VSwihje7oZ7AoGBAJGSi1S58jTbvKBetyykhdf1axkhwv9C9xV8N061F9idRI2CNtXOMTPykZsuYLcZYLrNta2eWPej3LTnqHiHnUhQmnIsv/xl/ql8tJdXLi5fsBWODrf9vGoQvw+b2YbQ1JTaZ9M49X22Nymr0REb0mw+jIq2CuUoSIGTaa5cYOMpAoGBAK6tnZUsKKqDsmP8F0PZUKAmpbDvKwAup8/Y6hgdSXfz3vfKHGqKtBVai6mzxRZDtdEOjB0EXCQXwODHhxr8tuIk7aoAEV1x3Apt6qxvBlyw+/zV52Qkh5uzIpU9V4dxu3N6Qpkzy12vXn6YAhC5eHTrZrsKndMCPy/v4Ajml5PbAoGBAKugn3Gh4BLUOW9Tvnc9UIwITp8p8+Dx9yQJugHSDzBFGuAZ1FUciCrK8SGarDCyyzY+XBKVuNZEj7D4P2+JiTKv8nweRVj0DdXYUwIsX6cWgPF5i8dm0Nl5PbsR27L+TxficuO4IQRHMz+Loho5itbSuDY9Y07PvKLKJfu7Cd9l
|
||||
peerId: 12D3KooWC6sZYJXFagZtRjY4Jc4dzBLpEgYsUhJRauYheSAGk26y
|
||||
signingKey: mLzjMshSbtOkUKZha0bNIHvW9nlqOPX6VM/mvKicx6kh8ebP2mfrkCS0qz5GwlFEqTgtuSnWsHdvGZnuan2Ahg==
|
||||
encryptionKey: MIIEogIBAAKCAQEAuJcCEM4sM5I1Aj2y0HDgR/UrKEVF1iZ1CYWv4jVOt/e1avDn7XjF9ArB7lngq7lOTxpCNeLMQXeBl1gY1SBCPeTrs+tltyAUeSOZStwP9qhjUhI9TntfW3QfVlC2lB17liGa4b2F10x9vW/0f3R7m5xgz8NyqcFOZip0Ehe9UJbNFwPr00by0D4/XptkDT44wAIDlw7lgOmXWR3RpCYAYFonYeE2HK7FFNTIOJucfJ8kbK7wLp5EZRARYfCDUFq7czFu97FIrmQfS4Fyg8ESB+R28+dJIQ6G8U1MicX4Ibf9IkufK+r2fMYPv13F33omrwSGhNIWtX9WjAQ4bjmA6wIDAQABAoIBACHuaEvMimWEd8gMrWURirjPgXpqmXbPJO52K6mqYOkCWM/qrseBTuoYXCPDU8BdVN7Hleov4ZobLLA0WoQ65NJZ1VYCbHUoKXtHJvOS1kBiHbfFcI2PsiyugOAuABHkBYbIcJ8UZpj4D5kWDlyrfdlR+p3WcKpxxUaUgTeeM4evkMg2dg1/S4psgu1SKdGYMtafKBgvxxE0R/fjfP9MRD260/ydcUT0gRE+uUu6WFm92MLV72W3hoKfNqgGnQWCTG8UJGGK3KC/c9lAvLiDygo3GJLEjhnrIGkSbbd0uHtAYD8Uc+gq3z3o5Rger4P/FyWSbJ6Vz20iYHTeYUEDkKECgYEA5KK5/Z6XQHwsEGXSSCXKvUjJ7ZOV5k3D2im0F1dTtQaOjFgwZ9SPW/k7tQfcwfZLeDSm5V98FXSAu9XgT/Zrd+/RrfbgmKLMcNVet+l2OPq1cOeKE7io7wAXlkO5CmiMXMCRVcgqaENutUSTsmadFqd2NE7/gEUjeNIQLGkSsXECgYEAzq6+HtOxhfbTEC8ZUz6Y7+CphmtYiuX7G42lwv70mg+sap7mVlZzOHNNM1p9BOVEo2K1RKNWtXMgXDbt/KakBLCab9sR4R68tS7JX281I8RK/kYOLqlVE0CahujcCJATZAsDLMCpjeN85vwqJ9Cy1errf69thZwo1QI1BvRIahsCgYAkmz1GMycqZvczJOpXLN3aEpZqGHAusJLEEltIRW4clNEr/U66wRi29B+wK3MYBxQsSdnS7cfTM5UM/gBtLRol2NrsjJOHPMGY60DAF3wbQWDdk+TSpYU+xvf/0hYFaZnXm+lpH6RSj0FhenpfXPiX0PYnB+L2qZs1VATM54HbsQKBgG9nVwkMuCpqUXfuuyrYmdzqbtYKdG5h6kj+v7Nsc3G7MwdBYQx2iqKJ27nrc2m5HpcmtGgr1qf1RyMNZJgDRnNUsdnK7kc2pybN8jMjoTQHMRj/r9NM6JN5BhHj3/4pkpohKXPs4TeewAtNLnfJkSum9Yscht82vfeaufRmpcWzAoGAfxcnMvi2EhE6uNjDENqnFH9XD2zAAeKhiQumz2ts3cSUd1QOfPMeytsBML/jdmOMQNaTbMryhWPaqTewHky8P+l/7oVbMTTFnaaaZRZCSOSXe+2R3mJkRQzE+DkVhgfpEku/BVGRHRvltM+ehk3m64j5vHWC97cP52qZ0bkxKHo=
|
||||
apiServer:
|
||||
port: "8081"
|
||||
nodes:
|
||||
- peerId: 12D3KooWRqbgXAdsP9zzBeKv6qjqmW9qfo7TbQfTi4eYYCcpFBwT
|
||||
- peerId: 12D3KooWC9DkXiYK8MiQb87ffW51ggZR4FWASadh4UENXdaa16iz
|
||||
address: 127.0.0.1:4430
|
||||
signingKey: 4JPubXZ2chIF3SFYiEGHvdTs7/B+IbrdUCHWYkNH/E7uC9nsnBle8q/FaG/7b6pNKjXukTGaXnDrSixZw343/g==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA3xGRPt9EXpes27462scV4Wm71KUZ/mqf6re/x8LW+ZPvuuq1R5bj2AhUYj7oamVvqnpO8N3UxOSQB0N3eKtmi/I4M2OdLhkZHKBdGi/XG+eGRcCaM5kGBdot52dgFkqXunnU1h2khCk8XeWrJL2mnm9eSgSzvxExkQQfx3nCwYLq/ZmgGT+wBHZECxIlzxjpcgGjnCCIthb409YUitF/tnkwkcM9KBZJFJyJxTAmPaISrcpb30xNfxjuI4khst/s55XYsptyqRLzWMvr3fKUg2qN+GUCv4uAEQYLOGde0nVLq7zqofkH3jqXta13q1zi5OBiW75dCXmjtCtdBeMcNwIDAQABAoIBABV/b+wLQF+NZo9W6f0jqqwqsHtx3etzAy5vvv/VezpaU4REEmxv0k2Dn/5H6cY3OGfJmcoE1viSvn60tdLfUeay1U++jetfZ9gmbFKVwbliusIGKdZHLRlrSXk/sTb0wWKrUyO/f5dtEfBKrg/AZ0plmUSw51HGqmw7ZYSn62kSstB3VKEiM0nWQAh2D9R4APMaaBEo3XPJ+l706T+VPK07rD9oBdQmEkhA2Dks1jYzWVGeMY1aNhndPPVKy34BcYJa+z8X41bwUDsE4mNFId2nPVofgaGJiby4A/3adlvLzosBC5kYxj/V9icNH/iEYtwVV2rIjPLXgt54k1L8SQECgYEA5OWewIuAluIIt7RnClmpd6LPQAc24NsfaC+edGj63b1m9VPV1Vyve/+Mp642FUbp1zmFeTfTBOg+577rnrlI2Arfy1vRrHrSRFLEXfyGA6SSpssvDrHmJtJBh/H3kUgLeqsQlX+ov8mtZEelUF2oWSbmP9k5JaoXoN67gGVrAiECgYEA+XtHB2sZOWV8jOCN6ZU4GfjjymNtCRsH2jWs1fBJ5Sfpei9TK/ZemJ7n+vnANiFLycNoQ00EFlOYaTBCCig+vc6/jX+Ecmh4fUb/ZAuYx+GOA1TltcD+OWBrUEqNdrXwICtUWo8/m+As+ntbCmDSZRUIGRny/N549sGEipufA1cCgYEAsA6NlLu4JFWnLuVre+KLHqHzluP1qe3gslouHovAqV1NG9Vn27x2nYFpxm+Q2by5j/mGWD4/6L5Z5BZNVMBe7w0uJVRyaZ/uqu6ea0wYKCUlR3VwtHTQ+XsvPEk4il5Htgptrw+J1DpjS4Zv+OiQ3EG3R9Tkx7uUgP/QaGmZbQECgYAT2xvsGzoGt20SSU0CKj4s0wJOOVuUPfKCC4OWA2neMy8B6oJUHWep/fu4negOZtgBVuwVbyvEGyMmPBEFfe6AbNQSDvQbpvTwA5aP/9xJDEqhOUCPFq0lI+dmnIhlylUyOkCcdIo7fbwWs3qreMlGAkaCuO398jbubLh/z6L4QQKBgQDKUzTECIr75cLiFbUFxcseYFZEc1weYtlp3E28H0rceSD1GakQfu0osi294lLFzWbc4JfZ29F2rFnOAeZ55f4AtFh5xxoY2robre7C5pOklG5zTcHXakvqdWXPtYfi0o2dI/JBRNnS14ZDJqVmROGmMXsdm1et/qARKBI86wORUw==
|
||||
- peerId: 12D3KooWFYTh59WMXGLDqS8EXfTjHvrS9uXrcYJuE6yDyL1hh45R
|
||||
signingKey: yfFJv5klknUeG8rROCNTktCk5rsBvz16aEanYBAl9oYii+Q8XwH8mVXr5hHSiP+HYxEaSSozlMAAXUjdW2vK5w==
|
||||
encryptionKey: MIIEowIBAAKCAQEA5zUOQ42SFUYJyX86llYopUE4Q+RQvbCakTPd9LBKt6pBWyW3PA9sjFisxVFFwYOVwghzF8QDSRrWdkjGmRPPOSRNmNiJFGtk6wb26eihenFECdb4nJyTDZVhvayHpByCKleAl7dHLjHCIsVaaFfn5rntm47IdDSNFgZnNDrNrdS2SchXWHamcfWBJSQirdp+8kSh5RC6/J53LVa+Sff6D49BsF8VsevcjvFcdlpxG6GKhr6kzvnEwCCk8DIqjpF3geUVj/QbT9tGa12bAgDQuckW4DavIN1zT7BAUbZPcbFZ9Bd2bbKzXDFNt2mRXafDPL07KhnXSZ2YAxHf5M4s7QIDAQABAoIBABV5aQy/Lm1JZwlPBtsFv5qxtw8fOpyTtZd88MWURixO5OkZVK6AZD2Y0ts01DzIAvXVoRL5ArEcjATKd5+qJloRVB+5JOo/m0z1BaPuFmlv8bjUPZ0WMdZWJJDgYGzOtQxHukrdHABfYL+oAuCkIYbdiAMlvNqGMwBzscw5FfdqGBRwC0bus+YD103Hhc8pN0REwLZmiOvHR6b4Agwv4ruFsqthg13EwcqDVTnS1/sZyodLZaAGBUXlqUxuFakI/9CqpPuOkDgxelTYdXbS4yhfRF4zwoBGZx1462iJs4XM8TXhDcZpTRwCChM5Qf7jvvgbi7+gYTX9B1dxg7gZUyUCgYEA/cd/NqOyx7bn0twiuMEdq8bCi5Y/GvWLrQ3pf58DPanIydGPJU5/obKZw5Tv5LWbE5rUEeC2YpFleNh01oc0xHCveIR6JNGihN8u0DZPmcx2B1lwEzdYefRJfGcYXYhm/nCpzYn3VH0TfKA6qci+KLarYaeDpUCXAihZMUZxSfcCgYEA6Tr+fSXmHIYoKcewIpwSTvcFOJ6spMRSG+mxQAFit8vUQTw2e/aTESEECo24XJ/SKVK01CSoWXrw3t9eBgziyHI3GaaZ5LaXMZLLZhmGUT5kZiTR7083h+9bHt2+MzRXpaAEEc1FNgV3T2sSl1S+oKDL1MAcR42JaQtC1P2epzsCgYBKDdD9bL9ar/DuAvbO2uuBmLpkaS94+nYLxaeBajFT6RuCaPhQdpuf37Im9GscXjImgmOn497U3ICzxtYxU7r+J7PMgzvxSosWItpSP8bypks60cp2kQvsanCXMK5XfNoxHUcvhzb5HJZ3I3p62O1EjClukadErZhjNMryKhAc+QKBgFwvpUdyI3JC1L0u4L/NUK9FlBq9HSBDOPEvfY/+/DYJquveEOsOmzK6Cg7h1W1G/pq2xiLUGnbD0VFGmLNrhHgWLRFGeK2ePkSp8Rt6G00hjC2TgCdG+HwSb8HTg8pZdgtRJEqlCCZCItaRS9fk9zQmWmrNRGBD4XxTpybo2DzhAoGBAIxRN8WZc9HYVq8t20MieKP3pp5Nrl0wj9Z9EPvC60CwQRdv/FvWzDwF5/9Kg79rvbguZgjD6FNy35BGC5sN/24awWJ/mKYosctRwZVFpogoZ0qAdOwxowfAJXLRC5Chgim8vCFFdKdrMo2a6V+MQuhrTv06QAV1sYAH5P7abfPy
|
||||
- peerId: 12D3KooWC6sZYJXFagZtRjY4Jc4dzBLpEgYsUhJRauYheSAGk26y
|
||||
address: 127.0.0.1:4431
|
||||
signingKey: g673H1+gh/KSbRat4m+E+UBTxEmcbxNJ2ZEwdBnQKiFVExLIU7FUXhx7F7xw2QJOw4CInWK6tNZZRNAzOWcD7A==
|
||||
encryptionKey: MIIEpgIBAAKCAQEAwrKCiqwW7ZGgxfG/t/GgPZ/shmbXEtZjDiZKuLugfSOedERYdsPZ4PmPZkVxo1rIoZjZOnoo7qeC5LWk1A0N33LudQF7Qg50O0QyiV5QTRxkv9IUvAeXyUR5TrxD5oRdFKuCbyDUQYaoAOYCBeqSI1ub5HdFt1fDMqgHXVW/p9kMwHEXpHM7ZaARFf5ri9/FIIodb5+IkduSK3/qBPlvt6dy2MlKlHRkzHef4q8YFKuDyzsyF7fdtjhhHk6p86JBnMaQpP+mi3e+qUxhdWEIY1s7Jo1Yal+GDQ0NtRrZp4GdlpFT7Kgp1Sm5OzSrtEQduluc0GWJFAVpolHg8e7QlQIDAQABAoIBAQCTZjIOalqxYR8mvO84g2WdQgX/erw5NrWncLYBRYsrMlw0Ccovn/bDrCw0cT6nPYPHU8Ch1PpIM+mU3S/8miV2lbySOJzoVakJdYgNF6oTtvtPfezUrarsZTqxsTZ2vp75lx8YovIO6bMnevrtH7mjqydKwEG3nGnbX/qzXsfKeeZgd4kvnjlxGTDUen12Pl0kPLcBgyckZLDJmXYtvxuK1sZTjifyHoeGVYpOOLYi3rRSEoZnVS4z/fM1sG5aUM6eA/7HaXDAe5sT0rgmPt0mu6Mo13dF3rWkP/MCqEVdBLfQLXEfqKp/9QuZ7szdsM0b0WPDXP/YXDLALLvL5/vBAoGBAOPeOrG+JyyS85//wKy+ZRZND5IdxBWoPDfItKnQJtMzOMiYcpwF0J0j3VqdulQlz4zX0Zly0iEYtFtNozVLStDn4IPrqg/vJI+vkikDrY/r1lseVFGR0euVtpRth3BybzhR9llfqK1tuR7cCg7NaxnoIkwtbZDumKDPRoXSQmAvAoGBANq76w8ZMdduxQhroE4Hs4uP5g3Yx9bDlimwGBwX0afGoO82kvgxpol4Z/3sXC7dAKoBqLTTpVDq44AkMhSXgT/CGALsebRxqc45orafe3s+rTFoQsR8eXu9pRw6TxjwATMMxZHjIkV2DeQuKIOTZcvd9E1PVmUB3VSwihje7oZ7AoGBAJGSi1S58jTbvKBetyykhdf1axkhwv9C9xV8N061F9idRI2CNtXOMTPykZsuYLcZYLrNta2eWPej3LTnqHiHnUhQmnIsv/xl/ql8tJdXLi5fsBWODrf9vGoQvw+b2YbQ1JTaZ9M49X22Nymr0REb0mw+jIq2CuUoSIGTaa5cYOMpAoGBAK6tnZUsKKqDsmP8F0PZUKAmpbDvKwAup8/Y6hgdSXfz3vfKHGqKtBVai6mzxRZDtdEOjB0EXCQXwODHhxr8tuIk7aoAEV1x3Apt6qxvBlyw+/zV52Qkh5uzIpU9V4dxu3N6Qpkzy12vXn6YAhC5eHTrZrsKndMCPy/v4Ajml5PbAoGBAKugn3Gh4BLUOW9Tvnc9UIwITp8p8+Dx9yQJugHSDzBFGuAZ1FUciCrK8SGarDCyyzY+XBKVuNZEj7D4P2+JiTKv8nweRVj0DdXYUwIsX6cWgPF5i8dm0Nl5PbsR27L+TxficuO4IQRHMz+Loho5itbSuDY9Y07PvKLKJfu7Cd9l
|
||||
- peerId: 12D3KooWHgeiz7EyY59t5fEZnkdg2gJxk3YvJmxpVibEcX2EtUcp
|
||||
signingKey: mLzjMshSbtOkUKZha0bNIHvW9nlqOPX6VM/mvKicx6kh8ebP2mfrkCS0qz5GwlFEqTgtuSnWsHdvGZnuan2Ahg==
|
||||
encryptionKey: MIIEogIBAAKCAQEAuJcCEM4sM5I1Aj2y0HDgR/UrKEVF1iZ1CYWv4jVOt/e1avDn7XjF9ArB7lngq7lOTxpCNeLMQXeBl1gY1SBCPeTrs+tltyAUeSOZStwP9qhjUhI9TntfW3QfVlC2lB17liGa4b2F10x9vW/0f3R7m5xgz8NyqcFOZip0Ehe9UJbNFwPr00by0D4/XptkDT44wAIDlw7lgOmXWR3RpCYAYFonYeE2HK7FFNTIOJucfJ8kbK7wLp5EZRARYfCDUFq7czFu97FIrmQfS4Fyg8ESB+R28+dJIQ6G8U1MicX4Ibf9IkufK+r2fMYPv13F33omrwSGhNIWtX9WjAQ4bjmA6wIDAQABAoIBACHuaEvMimWEd8gMrWURirjPgXpqmXbPJO52K6mqYOkCWM/qrseBTuoYXCPDU8BdVN7Hleov4ZobLLA0WoQ65NJZ1VYCbHUoKXtHJvOS1kBiHbfFcI2PsiyugOAuABHkBYbIcJ8UZpj4D5kWDlyrfdlR+p3WcKpxxUaUgTeeM4evkMg2dg1/S4psgu1SKdGYMtafKBgvxxE0R/fjfP9MRD260/ydcUT0gRE+uUu6WFm92MLV72W3hoKfNqgGnQWCTG8UJGGK3KC/c9lAvLiDygo3GJLEjhnrIGkSbbd0uHtAYD8Uc+gq3z3o5Rger4P/FyWSbJ6Vz20iYHTeYUEDkKECgYEA5KK5/Z6XQHwsEGXSSCXKvUjJ7ZOV5k3D2im0F1dTtQaOjFgwZ9SPW/k7tQfcwfZLeDSm5V98FXSAu9XgT/Zrd+/RrfbgmKLMcNVet+l2OPq1cOeKE7io7wAXlkO5CmiMXMCRVcgqaENutUSTsmadFqd2NE7/gEUjeNIQLGkSsXECgYEAzq6+HtOxhfbTEC8ZUz6Y7+CphmtYiuX7G42lwv70mg+sap7mVlZzOHNNM1p9BOVEo2K1RKNWtXMgXDbt/KakBLCab9sR4R68tS7JX281I8RK/kYOLqlVE0CahujcCJATZAsDLMCpjeN85vwqJ9Cy1errf69thZwo1QI1BvRIahsCgYAkmz1GMycqZvczJOpXLN3aEpZqGHAusJLEEltIRW4clNEr/U66wRi29B+wK3MYBxQsSdnS7cfTM5UM/gBtLRol2NrsjJOHPMGY60DAF3wbQWDdk+TSpYU+xvf/0hYFaZnXm+lpH6RSj0FhenpfXPiX0PYnB+L2qZs1VATM54HbsQKBgG9nVwkMuCpqUXfuuyrYmdzqbtYKdG5h6kj+v7Nsc3G7MwdBYQx2iqKJ27nrc2m5HpcmtGgr1qf1RyMNZJgDRnNUsdnK7kc2pybN8jMjoTQHMRj/r9NM6JN5BhHj3/4pkpohKXPs4TeewAtNLnfJkSum9Yscht82vfeaufRmpcWzAoGAfxcnMvi2EhE6uNjDENqnFH9XD2zAAeKhiQumz2ts3cSUd1QOfPMeytsBML/jdmOMQNaTbMryhWPaqTewHky8P+l/7oVbMTTFnaaaZRZCSOSXe+2R3mJkRQzE+DkVhgfpEku/BVGRHRvltM+ehk3m64j5vHWC97cP52qZ0bkxKHo=
|
||||
- peerId: 12D3KooWFWyDckUJBtHtARzRDTRpo4XzeKAo8oN23MXh3Xwbp2fd
|
||||
address: 127.0.0.1:4432
|
||||
signingKey: Tr1OaCpnYVkdeuyoBHAETn3DHWbQZELK2x5xuvd5301045GYTnQdWWT/05UB61dmu1NcY4yznm90baj36GrgUQ==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA6FzTxWImBPJL+dhVbCUWqcuxBmbR7npbgHNOTJFh38InqxEkGwrulenCyy7bewIQXLMfzxroxm17GpWWV3hMcAzQUOojUSylJPguhrWOOtsJyxxDXyG7MEleaFX51MF+SNEo9ivBYbbwJiFrGv9tGW6D4dGSMl1Xf8yKyKWCJVBah0Pzc57I8e93qOZjaCHRmsgC7DdzD8FyIPnAuxYxNs8iSaYPP/UjcZT/SA+Ldu0vyNxdnHCSs/+3FwbmPyhYrn+uBOUUidfzraVn9ra/xtcCZQXbf4fhJ6iwfp0wJoaDU5akN40910XGQqbF6FLfqZZx220vIcJkHc3McbtiaQIDAQABAoIBAQDjTLMIOduxKQgzTnE5igpibNQty/T+UQkjXSgx9GGGzlmZmPn1zjrXwUUBF0QyTzGMTNkH8m3UdZJfzga0aAR188Lv9Co6JO8je/efZQjOACjTXEF3VPrU4GCOtdPfUKxlNN3Z+bGBEcBXvIcWcNjbcOVnyGc4B2Eprf/xCR6Hufa289Awnf1ixe33VdlBMsuua7qc+gydRF9BNpvTop7n4bGkrPJkpuNp1063QEh6Gi9Za5gM+bd573FsYMhHdECcSWS1ogtTTNsVyLPo+x/Naj1pC3UTmAFXyiseeVJ82ibMCOBywr13I0WlknNoxGevU/een4sxX4K3CFH0YGZRAoGBAPVz2qhTDSplq0EVnUVEINfvNTEDLgUMBbdrwpO6FeMR/QBohGB+Yzoen4rBNqnLOOSsetaWYN1u2XgyA9RyL6wnO7hOhlpgY9m5+CCKOwKhPwIBGOOsaFwKLzwDcACK8rg5S/EGDRYCT2SfKv2bSdyLxVt4bXjvMZBQ0lt86R8tAoGBAPJY+Yb5vwiyMlQk16spB/KoQ/hZmjuWUt6tIDf/B9/LM/vMfguJJRq+tmBa2JxvYmUj3lIt7Sg5RiFECIiZ9MW3H7rCu+SHRN5HaDjKOkFX8qTTPJJu5LyBcCnHHxQBi4t5bVTAbKfpBXTi7lr5aAhUIztUVc9Poyz9mm410TWtAoGBAPCaOnLZxoQS2UaZW2r0l4VUNL3wsgG8gTYFadzJgn7tuSXXTjwQaFAmiJnJQD48uW5fLKKBEj69VGugC2UK8XQ9mSrXvpeE+RwKUhIDrkirq0nZrX4wGLRwP1ECxZ2ilr7DW4/OMLGsXgryg3/J4yNP14wMhrMPNXST5UBNN2+ZAoGAcfb7aMjbWBiMaFtm/DtwXGFajVh9mhXn5IVfiFWq+0fQq1GP2Jbm1vvmQcuW34HVsKA8dULZqre8TfpzVOGpZKzoA+h9eUtPTIQh88rNuFrGZVJcwrPZZvgrqcnUyJCtcappiphuwEtpYH0y/58XmAsRAl53d+UIZCjiTX+LYYUCgYBWuUASFeKBWp8/jRO6xgcKT7DErnMZr3TRYkduH9miIlqhx4NH+K/hkgkIFk77ov1swj2XrPL/rMMtWDRsn8fvwhRYkU25FCNAdmSg3G2iaW3Pd99d/fsdJtE+VjVQv58R6nxp5aiVH2rX9l/tspdUsupoYdFDDHYDkL+lIu2ZIA==
|
||||
- peerId: 12D3KooWJpE9AtG4RX4Dwm4vhrCGqiUhKj6Mvbqj2V4rV4diyksT
|
||||
address: 127.0.0.1:4530
|
||||
signingKey: 6tA9VizrAMtsZlzBXXnsg+LzwSwBLU7oiVP1qOHN4PaFsBslV0nt2aKBXfcfxp17V/bvydNfyYbGu50F6spLCg==
|
||||
encryptionKey: MIIEowIBAAKCAQEAtsYet7J4bNo9zSPFZVFkkInUoAW7os8PtZH6qMUEOKcLAi1PDbkBBCmzHdfuzik8H8DgQl36/0gCqRPM6nhQlbF59mV7brI8/kH3Eiw0rxqWAe0+C6CzDyEqtKC7pJyC3FJe0MZRRtDXiDYlVurHrsW22fA03rJY5++eW6bXiqL7WB44zxMrztkvPljlhDf2XTAcrZWI10oXKjSZMW051Figbhdl06R1ZiW1F1LmUEd3ufiYoevpq8jAHWIToTZrYNX0sfrdNaf/CPCq9ZDSqISf8CZ/bE1VxYRPEnjmX1hZQ132S1KCEQwpBWxpcvePonEMPGp+5F7h4k+46f16vQIDAQABAoIBAEa8np7Rv7HBNTHzqi3wNk+KSHQ2Q8xa/uVyveQbe+rBG42YI4RYGYCW8u+V5qJ7av2PFDwbS00JfZ4aP7BvKCEHMwCdfgv1h42P0iOCYFF0pKHSQ7UUWLh+SZzmqDipKixC5NdAKaySnxfkfMcKzoVhl8b5JD0cITSClHM8Oyc4DR5DeB9MlgrVqV/fcdzR10J6TeEPyJjs7CF+Y4OFUEf8FnNxfx5btWm8dIxRMiFUqdI1SVHmOJo0wO2z36RKZ2f8eHApafpJ/1MWccCCSB34Kry4WjDLn8yfOZ5GavXKDVKnE2won5ZhpZGTaLVHLR8QzvkzuBHDk1j1kSi2RjECgYEAzwjnJc5F8XdOkNNPKpftnUVlijhEx0lSknL/j1wIE7bdqbGvIhW+OlIP3bc6O5h0QGSoB71cAiurzro9rsZnSZ4qqjyeGh55j8I4RoZHGDu8BoUOXzrIL1nw3JWxrsNxu5hV9bcYAOJDG9BOcm7F9g00+f+p2zR7BvZMYm3d0vsCgYEA4gBSbChHTMHs15wppaTqV5iQEbfAU/oweRBnflQTHVdezMDt85BpZv0ik2vTuhMJuiaISMvb5l2fHI+LIKoZgCBfymQ50Yv6dZqOMeY5XwUQiQ8DtVtoetYBwwPIS3hSntTu/a4Q9tZbmmWYG6rZ7X58UrtVHY5DfFMS8MOrO6cCgYEAgDkGV57KKMN4cC+/DyUrL8VEHve8eSSLNFJuvs4D3pnZ7Pgz/Es1Fo+ubeXF9hT0otD0VF7NtjZv4Mft3enZHHoN+IM0c/690PA7xEnzjCmqyOrtPMN+Kf1tNGCtvAwly0aMrnKoNhvr7jTz8OF0T3BciBz0iOOW8nfmVOuwf7MCgYB9va4eDR72XuMWZwVo6uOTTwfBQ9oXHxk/ElhymfZ0mbrd8u2xWQS7z1UgbprDaXo8/tlOn1W+yxIOwvKmft1nQxvosHDW3KnCKva4Xp5G9rtndloa2ju8NDuQtBcJnm1hf5lkvSclHsiik6nYoutTTs9+/El0A0Ya8uGT4Vnw+wKBgDq6yliV5g56J3+gHB4w8yQSoIx4AjHoGkYbaVNiCNLfH02VVIGINnlBk+6xurHUwBg68cAsMSAPWqky3BMvhpAAoyPDBycrWEYKHvKvVsH5R0JRDymVJ3UHJVzCp49+CHIoOElnR+IueVluljtxTrB4JgJj0NOLKOHiTNHW6emJ
|
||||
isConsensus: true
|
||||
- peerId: 12D3KooWCeSDwgmdmLMweWKf1avCqaBYuzEo5GpMGa8MBBskBmen
|
||||
address: 127.0.0.1:4531
|
||||
signingKey: N8fkrWmuf1wVxL72XE4Di8pSyTaQpev/9NV4eznVcfoqB9Z+urz0kg1NKJjWisC/nUGdJP9EB5ZhgPyuQfqIvw==
|
||||
encryptionKey: MIIEowIBAAKCAQEAx9vwNRbEUtOuJ+UxXsvepKC1VY76RNv+SnnUIQE2/fXo/1iUEevydpWWD+V4n0DjxMsCViOv/kIOuXArIntFqr5xyRdIFE1nbiSW20IppRZO2Vw2fZwN+5DOl1Z3MfiZsqD2dbdtVLuUP9On1lqPWgW/ZHzweCcVMz2ZZ/txubSBE889bbSoZcNlgXS0fJSaw/6XApgtL++sZBqxwp2lkf918ZM3SFuAVHYU56tAOnZrCbyHcbDk4OOJ1q7NzrxWg71S02yqesuDSjIW6BzIXbDVjS2yvhKRJrrKXSIYepIczPwHPPCs7/pCPE7XQ6sYB9d8BL9/U+doLTJToAhHwwIDAQABAoIBAEZwU9bCMWtnw8e31ZCtlci8A20mOTqvto4VJhiDzxfu5bGpTHaMjCYTTpJHtB2cxyoCys4FQfAA5COjTvCWNdWZzYysMfFF3qBJMQoR5Y+TrzKYd3QJ3ju9q7JW/SeVkMYOSQ7wGQ52FifwtwSrYj6+K9iE2FPgom4u1bR6QHjMcAf9+eDJMUJk6Jg62SATPmiiN3b3OktNSsqvAf06I2K3ob1xIai0aTVcNsEoLbdDTejgFkkU3BHIzY9IXYkfipHV9+51cpRFb8q/Hl4boolgSPUSfe+pC11sm56QZZ7Gt0CF2ejhWyJKiyV50B1enKeeVN50KIMdtQn3VpTN65ECgYEA4wiKX/72Ca9wld+moywqexXNuh0a0gS/cWX4gFRv27jUScR7KTDM2jSPUxUK7F/hONOBBevfA7DMxsNNoPHoK9U2iwCO5fI9n1oWrUUjq9srJvrvsz2n2RmQ2deqmosLs0Gbb/I13+qEkunS7pfIIdul0LFE28PK5BhCDRdOUe8CgYEA4VvSWswkXQP4eNDTe78+GItQ78TluU26b+HOnkPRQlA2lUyxkUZT3VJQcgIptJJ20K13NZypJazJm6QELZPd/WcUAWKZqTSQxXUBwPVuoW5Aw0glXCfUOEG+LU+Ue8tvNCdqrAJopuYkYniT1LsQAOYMbJvL9PGkJosJfq4X620CgYARmgLoaGL440IuTHWl5vGwM0OM716586ZIC2jVwjYd6dmDkpkd22u2aybFgTckllZmyncRV3Ul2xo1OsUU+kxOwawF4NgzWbGPXjOt4VNfqpFQ51mYIuqVeVbynLbcXnVcw3RinHuyzYLTxQ8WcmwQu+/CG0xEYYykXIEadLkcvwKBgQCB5RovicFf99ztTnjHuCjDnvGs8lHzaDERMheVM8PXNELx9X3YHbBTPpHt1P9S/KUNjR7MQRtiAuFGG9joqHVpDVQDpGCrngfgOJwlK5Jz7AfaR6h5IN/6+TH0Dg2o+U6Ewj+DG/RUVw0b0SJsmNIVooQAyiBadDnImZWEdjaFVQKBgDnrnvtTMZFvJofnDNSQfOsDru5Mc9c/WRfegq58ocf8XaMMJyFCZGw90TLgQgWkxDCjQ4qnigFRWRCJ3sWB9LS8uFW5Gif0GtP6foL9rWlsQpCUqVApJRnVFFqW5f5FC4MZHtDTlZUk5lDQuvZjvQjJ+3vmusxEUIP0IS74Gr5+
|
||||
isConsensus: true
|
||||
- peerId: 12D3KooWGqsXf6No926wTb2eZdauqDcEkoAdKCeYkNzT6yrL3YDE
|
||||
address: 127.0.0.1:4532
|
||||
signingKey: fSLDcrMD0v+yzQwHG+KWdCkuZ5HPvx3vIb+5MecREc5oZJZfrN9P2z8gBU8HqZH/noB4aJRjXRVZsy4M5jPcwQ==
|
||||
encryptionKey: MIIEowIBAAKCAQEAtM7k4K2spm+GZa13SkRbDuFpPVAdPmR1+aN8IAtmSAISxw2vb4ET47Ck8vDfNtQ9rAvoAn2c3GxJb5Sb0pL9rofeIYYN/qS08zFVP2+FRM5CfuBbfVbwMZ2WvBJD02LzDrHRm0blc8JZDs3xFi5o+mWfeM2SZXVCJHFSNS+v1TRgVfQzu0uKlTD00CLPNz+uzDG6VntlzzEzkF4jVRA59BmkzqAI2ZgtB0cG5ztMnUhnZCX8I0b9CCb0UHjq9j97Xuot/hMAEGVQhNY3iyJx5gAR0t5PipgQZz5j0EXBGPy9T2+VA1QFLHVsUDmd2iV5fmTZziOWn7988Co+ZVMB4wIDAQABAoIBADbQ5ukLHmXTN/7JiXn1oVmwkzRofoU09eN6Yh5g9mBsaH76si5vBrWoD0osJrA7xnrLnUpsBMt69QSkHF3J/KkWPg0R1FpYWxfD5CF4UQIcOmK26GXmnqmcKl/YdcG3pRLWbELUSqo+yLtJSoc8CM2pU6DPSkwCMcxUouTHEVrkpL+Ic6RNGVFjX7E/HjfX9U/BKH0bzwj9CEPQEm9bqc3Zq+EmcE/CHXfRnHdG1cSp65qNHDfyEBjudR4ddItzwpmxLsW6+2Ywlg2pG/vfvRkGvwtAySkVs05J0vrpwSJlPy0NvKAbHAnmNBnmRH4E/myXf5MFcl/nz55J+yJs6QECgYEA1b6fp4FeIBfhvrRseLJeAepZhvmXkRegT61No5632SpcHymz3WnO+EsrL5O6+Ldpa8Gv/LmiVBQjvQeTvx97kINXKPLxmvdxRo+i7YUCAec8AZH7WEkxa0vvi3FLVoZZ8/P5fjvUscwxBeOvwhXnyXsFB9pJduYu6wzuMJe7HmMCgYEA2I1k0YjcTCqOk2Vp1lvHLtnMcmpm4FDMl9uws0HX4UO8i9tXlLZmWqDvPpvhxZVY+1hXOEid67712q1fiei440AGGNxc/xbq8Htw1GBzKyTd9dCQCVwWGX3VUO8EKAKVXdVIyqW+YUqD5PXUcPA41ll+nJdx5Z/liSNJvpxCJoECgYBv2P5GcuXEOXsBhfw09HFI407R2I29ePWEfBVih02BMC9ghzv9or6RIxSIIu/18lQR9RqYTrNo99jzs6FWo6zPJEtZvDc9djoqSENjsvQn9s5pq/AwdKyNjwDcoP5hWpB7nbFyovBb0ZPdlxWDpF7UCbHKOCm1NCJdETka6GscLQKBgQCGh8CcU5PYVY/hjd0kaDvjpTbX1bY3oLqZlMe/dSYyMayOjiNopbAMmXJHyPuHjfKLoyP8OVCyRh3iTlbODB/gPcQL6cp0Rr6Jy4YayhiCMxMZRQpWZjjseTnuX66LVJ+KfZgNHM6bDnnF4dqqlvIYZ9y6V3NQnfcxLRUBL34BAQKBgElDMZD0rP/u6Xch33udIlzdai30QUNWS9MgSrPBz1s8+u1e0g3UnbfCH7e5q0ofSmd+Ot21i03cLgUgJAFmoVmoJ794aveBo/bPbDrlbolxOUX4dFODvvOKzCcUHeOJzc9JE/Ci3LuHyEcqv49uRIe4BFc8c/ssDpj9h7Cyx+qq
|
||||
isConsensus: true
|
||||
signingKey: YpCGjsSuT8O6mkYTOExkdwNRODBaJ20hYJHFO/A/RUFUsUwxIME9X9FIp69VYvKuL6er973p0iG7UVVvLgLjnA==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA2T4/6T5etB9W7qzJ1sNfWFdOTa2koXKcQkaLBUTervApLPZtaVsbNtyVFtqqdsck1qpu+AVif19EFlYqSRtn/dxEN5/2myqVA6lZMm0Bd9mWpfoDQx20KAYwWBwzKSH1EQiTte0bw1zf0RpztxQ3nCOLCU4Y6x2lfk6Ea2XEayPxx0FDmeY3JSqUDOwx33Sz8Imx8R7+Dfjl6Og3DEqGxXoPfZ6hj9LynqNswjRIdmMZPsuEHguKXMbp+cncErGWcyzH417XYSDPoRn/3awpLfQ9F+KSjAe5cUltC7M4veSZW+t3VcJypvfRlU4ayTZMuvMHPlMcl/0jP5w0Q2+2pQIDAQABAoIBAGMvmrqBcXfHv0cluNnHRebtpaCtoTbdPx67WonDUfCJUiNnN7kckaZQu/k9SQsGDXm9QwEWZExHUKzqFlBepPIw+Sx0aoGZxYNwdHsjbcIspC2PoqGoFDMZ8ESqS2mCSYPHaLltUnm2E7JC44Y5QtKVH8vVzma6mG68ppTqV+2aGfGiPDq8cAYeH9/8Ys8/S28IwCp/M7lnXZhJ38bHD3YyPpcgbyGI/Zr5xaPd0hqHH08Z+S9V7QPJUGY0Y21s99DhkUGctb4B17d0/3Nzk/iWY1rp7A/kbdBeWonsHrTc6OnmbdiOcjC8seOIKMJ/WE3JznqnI1oydFb/dp6raNkCgYEA+pn1akGIKnVP0oFh5PZfUpuZtVV9u9xccIXyeFmCAXyFuUz1KYbfwwqZnm9r6kHAO+aBtRtVsCVle5oVWNQq1pdv117hPhRnVrDtvL80z50a5L9gEVu4Yz24Q3vs3RglcVpafSaRuyPbiYHMmQ4Ly+9nbwEbOVDbzK5A3Wrny2cCgYEA3exS3aG7+7mbSnNTYkkTgl7goLXZgEST/0EM2CvayxZ2QUS94Vq5HjGRpWnni3YttLiYlgCLe3CqeiIh6E3n6b9sory8Oy6lik/elj28kcZIuNvPU0xVcqrmGCg/KEnYkXjsGKsBDk6SV9nKH7880oIe0Rh3gc0hHHIl0Z4CshMCgYBifXHLkffPIA4AIKN11jJ+h/LwJqpk0+Vsv+gczqjepq7ztcBA0uZMhHT9pLLX/YFsyVo+8IBL21a4LkWnhLNVZW0qSvrhaCl5E85LuSYrVoaEUoaSK+ca8d3if+kGt/+3PhiESU1LLHuS3nWnzbJrMysGoHuvmgzYs7+AhgyVjwKBgQCoVgrFc1lUqIXTA4fMlgHmcnGRdl91nI9mn8FOeHWOd4tcFvixaE/jR1ZjUuIAN7ST0TJtFhy3lc66tgliXTX9aObOyrs9aTTIpa0B6fKP4QhosNOjK9PlFx1SVbUSqnFMZ50vWQeEArWfTeS0ECviwjD+CsEcBK2JFkz5pBIHYQKBgQD3zcYdYwvGkolLXNN3vbgTVnbNe2YMUBwgp5i1XGzAiG8XpwKTi4vDFIYgCZAG5wsyqUPdTOY2wyLjHwGdUfl7P3tCsHVzVh/xvuSl3nzW3OdCniKaBBdtZS6+s25Ijzdwiwnp21NWE6XU2BptIwTMHrKOc7BpZykgHsORMtptsQ==
|
||||
space:
|
||||
gcTTL: 60
|
||||
syncPeriod: 10
|
||||
|
||||
@ -5,39 +5,24 @@ grpcServer:
|
||||
- 127.0.0.1:4432
|
||||
tls: false
|
||||
account:
|
||||
peerId: 12D3KooWHgeiz7EyY59t5fEZnkdg2gJxk3YvJmxpVibEcX2EtUcp
|
||||
signingKey: Tr1OaCpnYVkdeuyoBHAETn3DHWbQZELK2x5xuvd5301045GYTnQdWWT/05UB61dmu1NcY4yznm90baj36GrgUQ==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA6FzTxWImBPJL+dhVbCUWqcuxBmbR7npbgHNOTJFh38InqxEkGwrulenCyy7bewIQXLMfzxroxm17GpWWV3hMcAzQUOojUSylJPguhrWOOtsJyxxDXyG7MEleaFX51MF+SNEo9ivBYbbwJiFrGv9tGW6D4dGSMl1Xf8yKyKWCJVBah0Pzc57I8e93qOZjaCHRmsgC7DdzD8FyIPnAuxYxNs8iSaYPP/UjcZT/SA+Ldu0vyNxdnHCSs/+3FwbmPyhYrn+uBOUUidfzraVn9ra/xtcCZQXbf4fhJ6iwfp0wJoaDU5akN40910XGQqbF6FLfqZZx220vIcJkHc3McbtiaQIDAQABAoIBAQDjTLMIOduxKQgzTnE5igpibNQty/T+UQkjXSgx9GGGzlmZmPn1zjrXwUUBF0QyTzGMTNkH8m3UdZJfzga0aAR188Lv9Co6JO8je/efZQjOACjTXEF3VPrU4GCOtdPfUKxlNN3Z+bGBEcBXvIcWcNjbcOVnyGc4B2Eprf/xCR6Hufa289Awnf1ixe33VdlBMsuua7qc+gydRF9BNpvTop7n4bGkrPJkpuNp1063QEh6Gi9Za5gM+bd573FsYMhHdECcSWS1ogtTTNsVyLPo+x/Naj1pC3UTmAFXyiseeVJ82ibMCOBywr13I0WlknNoxGevU/een4sxX4K3CFH0YGZRAoGBAPVz2qhTDSplq0EVnUVEINfvNTEDLgUMBbdrwpO6FeMR/QBohGB+Yzoen4rBNqnLOOSsetaWYN1u2XgyA9RyL6wnO7hOhlpgY9m5+CCKOwKhPwIBGOOsaFwKLzwDcACK8rg5S/EGDRYCT2SfKv2bSdyLxVt4bXjvMZBQ0lt86R8tAoGBAPJY+Yb5vwiyMlQk16spB/KoQ/hZmjuWUt6tIDf/B9/LM/vMfguJJRq+tmBa2JxvYmUj3lIt7Sg5RiFECIiZ9MW3H7rCu+SHRN5HaDjKOkFX8qTTPJJu5LyBcCnHHxQBi4t5bVTAbKfpBXTi7lr5aAhUIztUVc9Poyz9mm410TWtAoGBAPCaOnLZxoQS2UaZW2r0l4VUNL3wsgG8gTYFadzJgn7tuSXXTjwQaFAmiJnJQD48uW5fLKKBEj69VGugC2UK8XQ9mSrXvpeE+RwKUhIDrkirq0nZrX4wGLRwP1ECxZ2ilr7DW4/OMLGsXgryg3/J4yNP14wMhrMPNXST5UBNN2+ZAoGAcfb7aMjbWBiMaFtm/DtwXGFajVh9mhXn5IVfiFWq+0fQq1GP2Jbm1vvmQcuW34HVsKA8dULZqre8TfpzVOGpZKzoA+h9eUtPTIQh88rNuFrGZVJcwrPZZvgrqcnUyJCtcappiphuwEtpYH0y/58XmAsRAl53d+UIZCjiTX+LYYUCgYBWuUASFeKBWp8/jRO6xgcKT7DErnMZr3TRYkduH9miIlqhx4NH+K/hkgkIFk77ov1swj2XrPL/rMMtWDRsn8fvwhRYkU25FCNAdmSg3G2iaW3Pd99d/fsdJtE+VjVQv58R6nxp5aiVH2rX9l/tspdUsupoYdFDDHYDkL+lIu2ZIA==
|
||||
peerId: 12D3KooWFWyDckUJBtHtARzRDTRpo4XzeKAo8oN23MXh3Xwbp2fd
|
||||
signingKey: YpCGjsSuT8O6mkYTOExkdwNRODBaJ20hYJHFO/A/RUFUsUwxIME9X9FIp69VYvKuL6er973p0iG7UVVvLgLjnA==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA2T4/6T5etB9W7qzJ1sNfWFdOTa2koXKcQkaLBUTervApLPZtaVsbNtyVFtqqdsck1qpu+AVif19EFlYqSRtn/dxEN5/2myqVA6lZMm0Bd9mWpfoDQx20KAYwWBwzKSH1EQiTte0bw1zf0RpztxQ3nCOLCU4Y6x2lfk6Ea2XEayPxx0FDmeY3JSqUDOwx33Sz8Imx8R7+Dfjl6Og3DEqGxXoPfZ6hj9LynqNswjRIdmMZPsuEHguKXMbp+cncErGWcyzH417XYSDPoRn/3awpLfQ9F+KSjAe5cUltC7M4veSZW+t3VcJypvfRlU4ayTZMuvMHPlMcl/0jP5w0Q2+2pQIDAQABAoIBAGMvmrqBcXfHv0cluNnHRebtpaCtoTbdPx67WonDUfCJUiNnN7kckaZQu/k9SQsGDXm9QwEWZExHUKzqFlBepPIw+Sx0aoGZxYNwdHsjbcIspC2PoqGoFDMZ8ESqS2mCSYPHaLltUnm2E7JC44Y5QtKVH8vVzma6mG68ppTqV+2aGfGiPDq8cAYeH9/8Ys8/S28IwCp/M7lnXZhJ38bHD3YyPpcgbyGI/Zr5xaPd0hqHH08Z+S9V7QPJUGY0Y21s99DhkUGctb4B17d0/3Nzk/iWY1rp7A/kbdBeWonsHrTc6OnmbdiOcjC8seOIKMJ/WE3JznqnI1oydFb/dp6raNkCgYEA+pn1akGIKnVP0oFh5PZfUpuZtVV9u9xccIXyeFmCAXyFuUz1KYbfwwqZnm9r6kHAO+aBtRtVsCVle5oVWNQq1pdv117hPhRnVrDtvL80z50a5L9gEVu4Yz24Q3vs3RglcVpafSaRuyPbiYHMmQ4Ly+9nbwEbOVDbzK5A3Wrny2cCgYEA3exS3aG7+7mbSnNTYkkTgl7goLXZgEST/0EM2CvayxZ2QUS94Vq5HjGRpWnni3YttLiYlgCLe3CqeiIh6E3n6b9sory8Oy6lik/elj28kcZIuNvPU0xVcqrmGCg/KEnYkXjsGKsBDk6SV9nKH7880oIe0Rh3gc0hHHIl0Z4CshMCgYBifXHLkffPIA4AIKN11jJ+h/LwJqpk0+Vsv+gczqjepq7ztcBA0uZMhHT9pLLX/YFsyVo+8IBL21a4LkWnhLNVZW0qSvrhaCl5E85LuSYrVoaEUoaSK+ca8d3if+kGt/+3PhiESU1LLHuS3nWnzbJrMysGoHuvmgzYs7+AhgyVjwKBgQCoVgrFc1lUqIXTA4fMlgHmcnGRdl91nI9mn8FOeHWOd4tcFvixaE/jR1ZjUuIAN7ST0TJtFhy3lc66tgliXTX9aObOyrs9aTTIpa0B6fKP4QhosNOjK9PlFx1SVbUSqnFMZ50vWQeEArWfTeS0ECviwjD+CsEcBK2JFkz5pBIHYQKBgQD3zcYdYwvGkolLXNN3vbgTVnbNe2YMUBwgp5i1XGzAiG8XpwKTi4vDFIYgCZAG5wsyqUPdTOY2wyLjHwGdUfl7P3tCsHVzVh/xvuSl3nzW3OdCniKaBBdtZS6+s25Ijzdwiwnp21NWE6XU2BptIwTMHrKOc7BpZykgHsORMtptsQ==
|
||||
apiServer:
|
||||
port: "8082"
|
||||
nodes:
|
||||
- peerId: 12D3KooWRqbgXAdsP9zzBeKv6qjqmW9qfo7TbQfTi4eYYCcpFBwT
|
||||
- peerId: 12D3KooWC9DkXiYK8MiQb87ffW51ggZR4FWASadh4UENXdaa16iz
|
||||
address: 127.0.0.1:4430
|
||||
signingKey: 4JPubXZ2chIF3SFYiEGHvdTs7/B+IbrdUCHWYkNH/E7uC9nsnBle8q/FaG/7b6pNKjXukTGaXnDrSixZw343/g==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA3xGRPt9EXpes27462scV4Wm71KUZ/mqf6re/x8LW+ZPvuuq1R5bj2AhUYj7oamVvqnpO8N3UxOSQB0N3eKtmi/I4M2OdLhkZHKBdGi/XG+eGRcCaM5kGBdot52dgFkqXunnU1h2khCk8XeWrJL2mnm9eSgSzvxExkQQfx3nCwYLq/ZmgGT+wBHZECxIlzxjpcgGjnCCIthb409YUitF/tnkwkcM9KBZJFJyJxTAmPaISrcpb30xNfxjuI4khst/s55XYsptyqRLzWMvr3fKUg2qN+GUCv4uAEQYLOGde0nVLq7zqofkH3jqXta13q1zi5OBiW75dCXmjtCtdBeMcNwIDAQABAoIBABV/b+wLQF+NZo9W6f0jqqwqsHtx3etzAy5vvv/VezpaU4REEmxv0k2Dn/5H6cY3OGfJmcoE1viSvn60tdLfUeay1U++jetfZ9gmbFKVwbliusIGKdZHLRlrSXk/sTb0wWKrUyO/f5dtEfBKrg/AZ0plmUSw51HGqmw7ZYSn62kSstB3VKEiM0nWQAh2D9R4APMaaBEo3XPJ+l706T+VPK07rD9oBdQmEkhA2Dks1jYzWVGeMY1aNhndPPVKy34BcYJa+z8X41bwUDsE4mNFId2nPVofgaGJiby4A/3adlvLzosBC5kYxj/V9icNH/iEYtwVV2rIjPLXgt54k1L8SQECgYEA5OWewIuAluIIt7RnClmpd6LPQAc24NsfaC+edGj63b1m9VPV1Vyve/+Mp642FUbp1zmFeTfTBOg+577rnrlI2Arfy1vRrHrSRFLEXfyGA6SSpssvDrHmJtJBh/H3kUgLeqsQlX+ov8mtZEelUF2oWSbmP9k5JaoXoN67gGVrAiECgYEA+XtHB2sZOWV8jOCN6ZU4GfjjymNtCRsH2jWs1fBJ5Sfpei9TK/ZemJ7n+vnANiFLycNoQ00EFlOYaTBCCig+vc6/jX+Ecmh4fUb/ZAuYx+GOA1TltcD+OWBrUEqNdrXwICtUWo8/m+As+ntbCmDSZRUIGRny/N549sGEipufA1cCgYEAsA6NlLu4JFWnLuVre+KLHqHzluP1qe3gslouHovAqV1NG9Vn27x2nYFpxm+Q2by5j/mGWD4/6L5Z5BZNVMBe7w0uJVRyaZ/uqu6ea0wYKCUlR3VwtHTQ+XsvPEk4il5Htgptrw+J1DpjS4Zv+OiQ3EG3R9Tkx7uUgP/QaGmZbQECgYAT2xvsGzoGt20SSU0CKj4s0wJOOVuUPfKCC4OWA2neMy8B6oJUHWep/fu4negOZtgBVuwVbyvEGyMmPBEFfe6AbNQSDvQbpvTwA5aP/9xJDEqhOUCPFq0lI+dmnIhlylUyOkCcdIo7fbwWs3qreMlGAkaCuO398jbubLh/z6L4QQKBgQDKUzTECIr75cLiFbUFxcseYFZEc1weYtlp3E28H0rceSD1GakQfu0osi294lLFzWbc4JfZ29F2rFnOAeZ55f4AtFh5xxoY2robre7C5pOklG5zTcHXakvqdWXPtYfi0o2dI/JBRNnS14ZDJqVmROGmMXsdm1et/qARKBI86wORUw==
|
||||
- peerId: 12D3KooWFYTh59WMXGLDqS8EXfTjHvrS9uXrcYJuE6yDyL1hh45R
|
||||
signingKey: yfFJv5klknUeG8rROCNTktCk5rsBvz16aEanYBAl9oYii+Q8XwH8mVXr5hHSiP+HYxEaSSozlMAAXUjdW2vK5w==
|
||||
encryptionKey: MIIEowIBAAKCAQEA5zUOQ42SFUYJyX86llYopUE4Q+RQvbCakTPd9LBKt6pBWyW3PA9sjFisxVFFwYOVwghzF8QDSRrWdkjGmRPPOSRNmNiJFGtk6wb26eihenFECdb4nJyTDZVhvayHpByCKleAl7dHLjHCIsVaaFfn5rntm47IdDSNFgZnNDrNrdS2SchXWHamcfWBJSQirdp+8kSh5RC6/J53LVa+Sff6D49BsF8VsevcjvFcdlpxG6GKhr6kzvnEwCCk8DIqjpF3geUVj/QbT9tGa12bAgDQuckW4DavIN1zT7BAUbZPcbFZ9Bd2bbKzXDFNt2mRXafDPL07KhnXSZ2YAxHf5M4s7QIDAQABAoIBABV5aQy/Lm1JZwlPBtsFv5qxtw8fOpyTtZd88MWURixO5OkZVK6AZD2Y0ts01DzIAvXVoRL5ArEcjATKd5+qJloRVB+5JOo/m0z1BaPuFmlv8bjUPZ0WMdZWJJDgYGzOtQxHukrdHABfYL+oAuCkIYbdiAMlvNqGMwBzscw5FfdqGBRwC0bus+YD103Hhc8pN0REwLZmiOvHR6b4Agwv4ruFsqthg13EwcqDVTnS1/sZyodLZaAGBUXlqUxuFakI/9CqpPuOkDgxelTYdXbS4yhfRF4zwoBGZx1462iJs4XM8TXhDcZpTRwCChM5Qf7jvvgbi7+gYTX9B1dxg7gZUyUCgYEA/cd/NqOyx7bn0twiuMEdq8bCi5Y/GvWLrQ3pf58DPanIydGPJU5/obKZw5Tv5LWbE5rUEeC2YpFleNh01oc0xHCveIR6JNGihN8u0DZPmcx2B1lwEzdYefRJfGcYXYhm/nCpzYn3VH0TfKA6qci+KLarYaeDpUCXAihZMUZxSfcCgYEA6Tr+fSXmHIYoKcewIpwSTvcFOJ6spMRSG+mxQAFit8vUQTw2e/aTESEECo24XJ/SKVK01CSoWXrw3t9eBgziyHI3GaaZ5LaXMZLLZhmGUT5kZiTR7083h+9bHt2+MzRXpaAEEc1FNgV3T2sSl1S+oKDL1MAcR42JaQtC1P2epzsCgYBKDdD9bL9ar/DuAvbO2uuBmLpkaS94+nYLxaeBajFT6RuCaPhQdpuf37Im9GscXjImgmOn497U3ICzxtYxU7r+J7PMgzvxSosWItpSP8bypks60cp2kQvsanCXMK5XfNoxHUcvhzb5HJZ3I3p62O1EjClukadErZhjNMryKhAc+QKBgFwvpUdyI3JC1L0u4L/NUK9FlBq9HSBDOPEvfY/+/DYJquveEOsOmzK6Cg7h1W1G/pq2xiLUGnbD0VFGmLNrhHgWLRFGeK2ePkSp8Rt6G00hjC2TgCdG+HwSb8HTg8pZdgtRJEqlCCZCItaRS9fk9zQmWmrNRGBD4XxTpybo2DzhAoGBAIxRN8WZc9HYVq8t20MieKP3pp5Nrl0wj9Z9EPvC60CwQRdv/FvWzDwF5/9Kg79rvbguZgjD6FNy35BGC5sN/24awWJ/mKYosctRwZVFpogoZ0qAdOwxowfAJXLRC5Chgim8vCFFdKdrMo2a6V+MQuhrTv06QAV1sYAH5P7abfPy
|
||||
- peerId: 12D3KooWC6sZYJXFagZtRjY4Jc4dzBLpEgYsUhJRauYheSAGk26y
|
||||
address: 127.0.0.1:4431
|
||||
signingKey: g673H1+gh/KSbRat4m+E+UBTxEmcbxNJ2ZEwdBnQKiFVExLIU7FUXhx7F7xw2QJOw4CInWK6tNZZRNAzOWcD7A==
|
||||
encryptionKey: MIIEpgIBAAKCAQEAwrKCiqwW7ZGgxfG/t/GgPZ/shmbXEtZjDiZKuLugfSOedERYdsPZ4PmPZkVxo1rIoZjZOnoo7qeC5LWk1A0N33LudQF7Qg50O0QyiV5QTRxkv9IUvAeXyUR5TrxD5oRdFKuCbyDUQYaoAOYCBeqSI1ub5HdFt1fDMqgHXVW/p9kMwHEXpHM7ZaARFf5ri9/FIIodb5+IkduSK3/qBPlvt6dy2MlKlHRkzHef4q8YFKuDyzsyF7fdtjhhHk6p86JBnMaQpP+mi3e+qUxhdWEIY1s7Jo1Yal+GDQ0NtRrZp4GdlpFT7Kgp1Sm5OzSrtEQduluc0GWJFAVpolHg8e7QlQIDAQABAoIBAQCTZjIOalqxYR8mvO84g2WdQgX/erw5NrWncLYBRYsrMlw0Ccovn/bDrCw0cT6nPYPHU8Ch1PpIM+mU3S/8miV2lbySOJzoVakJdYgNF6oTtvtPfezUrarsZTqxsTZ2vp75lx8YovIO6bMnevrtH7mjqydKwEG3nGnbX/qzXsfKeeZgd4kvnjlxGTDUen12Pl0kPLcBgyckZLDJmXYtvxuK1sZTjifyHoeGVYpOOLYi3rRSEoZnVS4z/fM1sG5aUM6eA/7HaXDAe5sT0rgmPt0mu6Mo13dF3rWkP/MCqEVdBLfQLXEfqKp/9QuZ7szdsM0b0WPDXP/YXDLALLvL5/vBAoGBAOPeOrG+JyyS85//wKy+ZRZND5IdxBWoPDfItKnQJtMzOMiYcpwF0J0j3VqdulQlz4zX0Zly0iEYtFtNozVLStDn4IPrqg/vJI+vkikDrY/r1lseVFGR0euVtpRth3BybzhR9llfqK1tuR7cCg7NaxnoIkwtbZDumKDPRoXSQmAvAoGBANq76w8ZMdduxQhroE4Hs4uP5g3Yx9bDlimwGBwX0afGoO82kvgxpol4Z/3sXC7dAKoBqLTTpVDq44AkMhSXgT/CGALsebRxqc45orafe3s+rTFoQsR8eXu9pRw6TxjwATMMxZHjIkV2DeQuKIOTZcvd9E1PVmUB3VSwihje7oZ7AoGBAJGSi1S58jTbvKBetyykhdf1axkhwv9C9xV8N061F9idRI2CNtXOMTPykZsuYLcZYLrNta2eWPej3LTnqHiHnUhQmnIsv/xl/ql8tJdXLi5fsBWODrf9vGoQvw+b2YbQ1JTaZ9M49X22Nymr0REb0mw+jIq2CuUoSIGTaa5cYOMpAoGBAK6tnZUsKKqDsmP8F0PZUKAmpbDvKwAup8/Y6hgdSXfz3vfKHGqKtBVai6mzxRZDtdEOjB0EXCQXwODHhxr8tuIk7aoAEV1x3Apt6qxvBlyw+/zV52Qkh5uzIpU9V4dxu3N6Qpkzy12vXn6YAhC5eHTrZrsKndMCPy/v4Ajml5PbAoGBAKugn3Gh4BLUOW9Tvnc9UIwITp8p8+Dx9yQJugHSDzBFGuAZ1FUciCrK8SGarDCyyzY+XBKVuNZEj7D4P2+JiTKv8nweRVj0DdXYUwIsX6cWgPF5i8dm0Nl5PbsR27L+TxficuO4IQRHMz+Loho5itbSuDY9Y07PvKLKJfu7Cd9l
|
||||
- peerId: 12D3KooWHgeiz7EyY59t5fEZnkdg2gJxk3YvJmxpVibEcX2EtUcp
|
||||
signingKey: mLzjMshSbtOkUKZha0bNIHvW9nlqOPX6VM/mvKicx6kh8ebP2mfrkCS0qz5GwlFEqTgtuSnWsHdvGZnuan2Ahg==
|
||||
encryptionKey: MIIEogIBAAKCAQEAuJcCEM4sM5I1Aj2y0HDgR/UrKEVF1iZ1CYWv4jVOt/e1avDn7XjF9ArB7lngq7lOTxpCNeLMQXeBl1gY1SBCPeTrs+tltyAUeSOZStwP9qhjUhI9TntfW3QfVlC2lB17liGa4b2F10x9vW/0f3R7m5xgz8NyqcFOZip0Ehe9UJbNFwPr00by0D4/XptkDT44wAIDlw7lgOmXWR3RpCYAYFonYeE2HK7FFNTIOJucfJ8kbK7wLp5EZRARYfCDUFq7czFu97FIrmQfS4Fyg8ESB+R28+dJIQ6G8U1MicX4Ibf9IkufK+r2fMYPv13F33omrwSGhNIWtX9WjAQ4bjmA6wIDAQABAoIBACHuaEvMimWEd8gMrWURirjPgXpqmXbPJO52K6mqYOkCWM/qrseBTuoYXCPDU8BdVN7Hleov4ZobLLA0WoQ65NJZ1VYCbHUoKXtHJvOS1kBiHbfFcI2PsiyugOAuABHkBYbIcJ8UZpj4D5kWDlyrfdlR+p3WcKpxxUaUgTeeM4evkMg2dg1/S4psgu1SKdGYMtafKBgvxxE0R/fjfP9MRD260/ydcUT0gRE+uUu6WFm92MLV72W3hoKfNqgGnQWCTG8UJGGK3KC/c9lAvLiDygo3GJLEjhnrIGkSbbd0uHtAYD8Uc+gq3z3o5Rger4P/FyWSbJ6Vz20iYHTeYUEDkKECgYEA5KK5/Z6XQHwsEGXSSCXKvUjJ7ZOV5k3D2im0F1dTtQaOjFgwZ9SPW/k7tQfcwfZLeDSm5V98FXSAu9XgT/Zrd+/RrfbgmKLMcNVet+l2OPq1cOeKE7io7wAXlkO5CmiMXMCRVcgqaENutUSTsmadFqd2NE7/gEUjeNIQLGkSsXECgYEAzq6+HtOxhfbTEC8ZUz6Y7+CphmtYiuX7G42lwv70mg+sap7mVlZzOHNNM1p9BOVEo2K1RKNWtXMgXDbt/KakBLCab9sR4R68tS7JX281I8RK/kYOLqlVE0CahujcCJATZAsDLMCpjeN85vwqJ9Cy1errf69thZwo1QI1BvRIahsCgYAkmz1GMycqZvczJOpXLN3aEpZqGHAusJLEEltIRW4clNEr/U66wRi29B+wK3MYBxQsSdnS7cfTM5UM/gBtLRol2NrsjJOHPMGY60DAF3wbQWDdk+TSpYU+xvf/0hYFaZnXm+lpH6RSj0FhenpfXPiX0PYnB+L2qZs1VATM54HbsQKBgG9nVwkMuCpqUXfuuyrYmdzqbtYKdG5h6kj+v7Nsc3G7MwdBYQx2iqKJ27nrc2m5HpcmtGgr1qf1RyMNZJgDRnNUsdnK7kc2pybN8jMjoTQHMRj/r9NM6JN5BhHj3/4pkpohKXPs4TeewAtNLnfJkSum9Yscht82vfeaufRmpcWzAoGAfxcnMvi2EhE6uNjDENqnFH9XD2zAAeKhiQumz2ts3cSUd1QOfPMeytsBML/jdmOMQNaTbMryhWPaqTewHky8P+l/7oVbMTTFnaaaZRZCSOSXe+2R3mJkRQzE+DkVhgfpEku/BVGRHRvltM+ehk3m64j5vHWC97cP52qZ0bkxKHo=
|
||||
- peerId: 12D3KooWFWyDckUJBtHtARzRDTRpo4XzeKAo8oN23MXh3Xwbp2fd
|
||||
address: 127.0.0.1:4432
|
||||
signingKey: Tr1OaCpnYVkdeuyoBHAETn3DHWbQZELK2x5xuvd5301045GYTnQdWWT/05UB61dmu1NcY4yznm90baj36GrgUQ==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA6FzTxWImBPJL+dhVbCUWqcuxBmbR7npbgHNOTJFh38InqxEkGwrulenCyy7bewIQXLMfzxroxm17GpWWV3hMcAzQUOojUSylJPguhrWOOtsJyxxDXyG7MEleaFX51MF+SNEo9ivBYbbwJiFrGv9tGW6D4dGSMl1Xf8yKyKWCJVBah0Pzc57I8e93qOZjaCHRmsgC7DdzD8FyIPnAuxYxNs8iSaYPP/UjcZT/SA+Ldu0vyNxdnHCSs/+3FwbmPyhYrn+uBOUUidfzraVn9ra/xtcCZQXbf4fhJ6iwfp0wJoaDU5akN40910XGQqbF6FLfqZZx220vIcJkHc3McbtiaQIDAQABAoIBAQDjTLMIOduxKQgzTnE5igpibNQty/T+UQkjXSgx9GGGzlmZmPn1zjrXwUUBF0QyTzGMTNkH8m3UdZJfzga0aAR188Lv9Co6JO8je/efZQjOACjTXEF3VPrU4GCOtdPfUKxlNN3Z+bGBEcBXvIcWcNjbcOVnyGc4B2Eprf/xCR6Hufa289Awnf1ixe33VdlBMsuua7qc+gydRF9BNpvTop7n4bGkrPJkpuNp1063QEh6Gi9Za5gM+bd573FsYMhHdECcSWS1ogtTTNsVyLPo+x/Naj1pC3UTmAFXyiseeVJ82ibMCOBywr13I0WlknNoxGevU/een4sxX4K3CFH0YGZRAoGBAPVz2qhTDSplq0EVnUVEINfvNTEDLgUMBbdrwpO6FeMR/QBohGB+Yzoen4rBNqnLOOSsetaWYN1u2XgyA9RyL6wnO7hOhlpgY9m5+CCKOwKhPwIBGOOsaFwKLzwDcACK8rg5S/EGDRYCT2SfKv2bSdyLxVt4bXjvMZBQ0lt86R8tAoGBAPJY+Yb5vwiyMlQk16spB/KoQ/hZmjuWUt6tIDf/B9/LM/vMfguJJRq+tmBa2JxvYmUj3lIt7Sg5RiFECIiZ9MW3H7rCu+SHRN5HaDjKOkFX8qTTPJJu5LyBcCnHHxQBi4t5bVTAbKfpBXTi7lr5aAhUIztUVc9Poyz9mm410TWtAoGBAPCaOnLZxoQS2UaZW2r0l4VUNL3wsgG8gTYFadzJgn7tuSXXTjwQaFAmiJnJQD48uW5fLKKBEj69VGugC2UK8XQ9mSrXvpeE+RwKUhIDrkirq0nZrX4wGLRwP1ECxZ2ilr7DW4/OMLGsXgryg3/J4yNP14wMhrMPNXST5UBNN2+ZAoGAcfb7aMjbWBiMaFtm/DtwXGFajVh9mhXn5IVfiFWq+0fQq1GP2Jbm1vvmQcuW34HVsKA8dULZqre8TfpzVOGpZKzoA+h9eUtPTIQh88rNuFrGZVJcwrPZZvgrqcnUyJCtcappiphuwEtpYH0y/58XmAsRAl53d+UIZCjiTX+LYYUCgYBWuUASFeKBWp8/jRO6xgcKT7DErnMZr3TRYkduH9miIlqhx4NH+K/hkgkIFk77ov1swj2XrPL/rMMtWDRsn8fvwhRYkU25FCNAdmSg3G2iaW3Pd99d/fsdJtE+VjVQv58R6nxp5aiVH2rX9l/tspdUsupoYdFDDHYDkL+lIu2ZIA==
|
||||
- peerId: 12D3KooWJpE9AtG4RX4Dwm4vhrCGqiUhKj6Mvbqj2V4rV4diyksT
|
||||
address: 127.0.0.1:4530
|
||||
signingKey: 6tA9VizrAMtsZlzBXXnsg+LzwSwBLU7oiVP1qOHN4PaFsBslV0nt2aKBXfcfxp17V/bvydNfyYbGu50F6spLCg==
|
||||
encryptionKey: MIIEowIBAAKCAQEAtsYet7J4bNo9zSPFZVFkkInUoAW7os8PtZH6qMUEOKcLAi1PDbkBBCmzHdfuzik8H8DgQl36/0gCqRPM6nhQlbF59mV7brI8/kH3Eiw0rxqWAe0+C6CzDyEqtKC7pJyC3FJe0MZRRtDXiDYlVurHrsW22fA03rJY5++eW6bXiqL7WB44zxMrztkvPljlhDf2XTAcrZWI10oXKjSZMW051Figbhdl06R1ZiW1F1LmUEd3ufiYoevpq8jAHWIToTZrYNX0sfrdNaf/CPCq9ZDSqISf8CZ/bE1VxYRPEnjmX1hZQ132S1KCEQwpBWxpcvePonEMPGp+5F7h4k+46f16vQIDAQABAoIBAEa8np7Rv7HBNTHzqi3wNk+KSHQ2Q8xa/uVyveQbe+rBG42YI4RYGYCW8u+V5qJ7av2PFDwbS00JfZ4aP7BvKCEHMwCdfgv1h42P0iOCYFF0pKHSQ7UUWLh+SZzmqDipKixC5NdAKaySnxfkfMcKzoVhl8b5JD0cITSClHM8Oyc4DR5DeB9MlgrVqV/fcdzR10J6TeEPyJjs7CF+Y4OFUEf8FnNxfx5btWm8dIxRMiFUqdI1SVHmOJo0wO2z36RKZ2f8eHApafpJ/1MWccCCSB34Kry4WjDLn8yfOZ5GavXKDVKnE2won5ZhpZGTaLVHLR8QzvkzuBHDk1j1kSi2RjECgYEAzwjnJc5F8XdOkNNPKpftnUVlijhEx0lSknL/j1wIE7bdqbGvIhW+OlIP3bc6O5h0QGSoB71cAiurzro9rsZnSZ4qqjyeGh55j8I4RoZHGDu8BoUOXzrIL1nw3JWxrsNxu5hV9bcYAOJDG9BOcm7F9g00+f+p2zR7BvZMYm3d0vsCgYEA4gBSbChHTMHs15wppaTqV5iQEbfAU/oweRBnflQTHVdezMDt85BpZv0ik2vTuhMJuiaISMvb5l2fHI+LIKoZgCBfymQ50Yv6dZqOMeY5XwUQiQ8DtVtoetYBwwPIS3hSntTu/a4Q9tZbmmWYG6rZ7X58UrtVHY5DfFMS8MOrO6cCgYEAgDkGV57KKMN4cC+/DyUrL8VEHve8eSSLNFJuvs4D3pnZ7Pgz/Es1Fo+ubeXF9hT0otD0VF7NtjZv4Mft3enZHHoN+IM0c/690PA7xEnzjCmqyOrtPMN+Kf1tNGCtvAwly0aMrnKoNhvr7jTz8OF0T3BciBz0iOOW8nfmVOuwf7MCgYB9va4eDR72XuMWZwVo6uOTTwfBQ9oXHxk/ElhymfZ0mbrd8u2xWQS7z1UgbprDaXo8/tlOn1W+yxIOwvKmft1nQxvosHDW3KnCKva4Xp5G9rtndloa2ju8NDuQtBcJnm1hf5lkvSclHsiik6nYoutTTs9+/El0A0Ya8uGT4Vnw+wKBgDq6yliV5g56J3+gHB4w8yQSoIx4AjHoGkYbaVNiCNLfH02VVIGINnlBk+6xurHUwBg68cAsMSAPWqky3BMvhpAAoyPDBycrWEYKHvKvVsH5R0JRDymVJ3UHJVzCp49+CHIoOElnR+IueVluljtxTrB4JgJj0NOLKOHiTNHW6emJ
|
||||
isConsensus: true
|
||||
- peerId: 12D3KooWCeSDwgmdmLMweWKf1avCqaBYuzEo5GpMGa8MBBskBmen
|
||||
address: 127.0.0.1:4531
|
||||
signingKey: N8fkrWmuf1wVxL72XE4Di8pSyTaQpev/9NV4eznVcfoqB9Z+urz0kg1NKJjWisC/nUGdJP9EB5ZhgPyuQfqIvw==
|
||||
encryptionKey: MIIEowIBAAKCAQEAx9vwNRbEUtOuJ+UxXsvepKC1VY76RNv+SnnUIQE2/fXo/1iUEevydpWWD+V4n0DjxMsCViOv/kIOuXArIntFqr5xyRdIFE1nbiSW20IppRZO2Vw2fZwN+5DOl1Z3MfiZsqD2dbdtVLuUP9On1lqPWgW/ZHzweCcVMz2ZZ/txubSBE889bbSoZcNlgXS0fJSaw/6XApgtL++sZBqxwp2lkf918ZM3SFuAVHYU56tAOnZrCbyHcbDk4OOJ1q7NzrxWg71S02yqesuDSjIW6BzIXbDVjS2yvhKRJrrKXSIYepIczPwHPPCs7/pCPE7XQ6sYB9d8BL9/U+doLTJToAhHwwIDAQABAoIBAEZwU9bCMWtnw8e31ZCtlci8A20mOTqvto4VJhiDzxfu5bGpTHaMjCYTTpJHtB2cxyoCys4FQfAA5COjTvCWNdWZzYysMfFF3qBJMQoR5Y+TrzKYd3QJ3ju9q7JW/SeVkMYOSQ7wGQ52FifwtwSrYj6+K9iE2FPgom4u1bR6QHjMcAf9+eDJMUJk6Jg62SATPmiiN3b3OktNSsqvAf06I2K3ob1xIai0aTVcNsEoLbdDTejgFkkU3BHIzY9IXYkfipHV9+51cpRFb8q/Hl4boolgSPUSfe+pC11sm56QZZ7Gt0CF2ejhWyJKiyV50B1enKeeVN50KIMdtQn3VpTN65ECgYEA4wiKX/72Ca9wld+moywqexXNuh0a0gS/cWX4gFRv27jUScR7KTDM2jSPUxUK7F/hONOBBevfA7DMxsNNoPHoK9U2iwCO5fI9n1oWrUUjq9srJvrvsz2n2RmQ2deqmosLs0Gbb/I13+qEkunS7pfIIdul0LFE28PK5BhCDRdOUe8CgYEA4VvSWswkXQP4eNDTe78+GItQ78TluU26b+HOnkPRQlA2lUyxkUZT3VJQcgIptJJ20K13NZypJazJm6QELZPd/WcUAWKZqTSQxXUBwPVuoW5Aw0glXCfUOEG+LU+Ue8tvNCdqrAJopuYkYniT1LsQAOYMbJvL9PGkJosJfq4X620CgYARmgLoaGL440IuTHWl5vGwM0OM716586ZIC2jVwjYd6dmDkpkd22u2aybFgTckllZmyncRV3Ul2xo1OsUU+kxOwawF4NgzWbGPXjOt4VNfqpFQ51mYIuqVeVbynLbcXnVcw3RinHuyzYLTxQ8WcmwQu+/CG0xEYYykXIEadLkcvwKBgQCB5RovicFf99ztTnjHuCjDnvGs8lHzaDERMheVM8PXNELx9X3YHbBTPpHt1P9S/KUNjR7MQRtiAuFGG9joqHVpDVQDpGCrngfgOJwlK5Jz7AfaR6h5IN/6+TH0Dg2o+U6Ewj+DG/RUVw0b0SJsmNIVooQAyiBadDnImZWEdjaFVQKBgDnrnvtTMZFvJofnDNSQfOsDru5Mc9c/WRfegq58ocf8XaMMJyFCZGw90TLgQgWkxDCjQ4qnigFRWRCJ3sWB9LS8uFW5Gif0GtP6foL9rWlsQpCUqVApJRnVFFqW5f5FC4MZHtDTlZUk5lDQuvZjvQjJ+3vmusxEUIP0IS74Gr5+
|
||||
isConsensus: true
|
||||
- peerId: 12D3KooWGqsXf6No926wTb2eZdauqDcEkoAdKCeYkNzT6yrL3YDE
|
||||
address: 127.0.0.1:4532
|
||||
signingKey: fSLDcrMD0v+yzQwHG+KWdCkuZ5HPvx3vIb+5MecREc5oZJZfrN9P2z8gBU8HqZH/noB4aJRjXRVZsy4M5jPcwQ==
|
||||
encryptionKey: MIIEowIBAAKCAQEAtM7k4K2spm+GZa13SkRbDuFpPVAdPmR1+aN8IAtmSAISxw2vb4ET47Ck8vDfNtQ9rAvoAn2c3GxJb5Sb0pL9rofeIYYN/qS08zFVP2+FRM5CfuBbfVbwMZ2WvBJD02LzDrHRm0blc8JZDs3xFi5o+mWfeM2SZXVCJHFSNS+v1TRgVfQzu0uKlTD00CLPNz+uzDG6VntlzzEzkF4jVRA59BmkzqAI2ZgtB0cG5ztMnUhnZCX8I0b9CCb0UHjq9j97Xuot/hMAEGVQhNY3iyJx5gAR0t5PipgQZz5j0EXBGPy9T2+VA1QFLHVsUDmd2iV5fmTZziOWn7988Co+ZVMB4wIDAQABAoIBADbQ5ukLHmXTN/7JiXn1oVmwkzRofoU09eN6Yh5g9mBsaH76si5vBrWoD0osJrA7xnrLnUpsBMt69QSkHF3J/KkWPg0R1FpYWxfD5CF4UQIcOmK26GXmnqmcKl/YdcG3pRLWbELUSqo+yLtJSoc8CM2pU6DPSkwCMcxUouTHEVrkpL+Ic6RNGVFjX7E/HjfX9U/BKH0bzwj9CEPQEm9bqc3Zq+EmcE/CHXfRnHdG1cSp65qNHDfyEBjudR4ddItzwpmxLsW6+2Ywlg2pG/vfvRkGvwtAySkVs05J0vrpwSJlPy0NvKAbHAnmNBnmRH4E/myXf5MFcl/nz55J+yJs6QECgYEA1b6fp4FeIBfhvrRseLJeAepZhvmXkRegT61No5632SpcHymz3WnO+EsrL5O6+Ldpa8Gv/LmiVBQjvQeTvx97kINXKPLxmvdxRo+i7YUCAec8AZH7WEkxa0vvi3FLVoZZ8/P5fjvUscwxBeOvwhXnyXsFB9pJduYu6wzuMJe7HmMCgYEA2I1k0YjcTCqOk2Vp1lvHLtnMcmpm4FDMl9uws0HX4UO8i9tXlLZmWqDvPpvhxZVY+1hXOEid67712q1fiei440AGGNxc/xbq8Htw1GBzKyTd9dCQCVwWGX3VUO8EKAKVXdVIyqW+YUqD5PXUcPA41ll+nJdx5Z/liSNJvpxCJoECgYBv2P5GcuXEOXsBhfw09HFI407R2I29ePWEfBVih02BMC9ghzv9or6RIxSIIu/18lQR9RqYTrNo99jzs6FWo6zPJEtZvDc9djoqSENjsvQn9s5pq/AwdKyNjwDcoP5hWpB7nbFyovBb0ZPdlxWDpF7UCbHKOCm1NCJdETka6GscLQKBgQCGh8CcU5PYVY/hjd0kaDvjpTbX1bY3oLqZlMe/dSYyMayOjiNopbAMmXJHyPuHjfKLoyP8OVCyRh3iTlbODB/gPcQL6cp0Rr6Jy4YayhiCMxMZRQpWZjjseTnuX66LVJ+KfZgNHM6bDnnF4dqqlvIYZ9y6V3NQnfcxLRUBL34BAQKBgElDMZD0rP/u6Xch33udIlzdai30QUNWS9MgSrPBz1s8+u1e0g3UnbfCH7e5q0ofSmd+Ot21i03cLgUgJAFmoVmoJ794aveBo/bPbDrlbolxOUX4dFODvvOKzCcUHeOJzc9JE/Ci3LuHyEcqv49uRIe4BFc8c/ssDpj9h7Cyx+qq
|
||||
isConsensus: true
|
||||
signingKey: YpCGjsSuT8O6mkYTOExkdwNRODBaJ20hYJHFO/A/RUFUsUwxIME9X9FIp69VYvKuL6er973p0iG7UVVvLgLjnA==
|
||||
encryptionKey: MIIEpAIBAAKCAQEA2T4/6T5etB9W7qzJ1sNfWFdOTa2koXKcQkaLBUTervApLPZtaVsbNtyVFtqqdsck1qpu+AVif19EFlYqSRtn/dxEN5/2myqVA6lZMm0Bd9mWpfoDQx20KAYwWBwzKSH1EQiTte0bw1zf0RpztxQ3nCOLCU4Y6x2lfk6Ea2XEayPxx0FDmeY3JSqUDOwx33Sz8Imx8R7+Dfjl6Og3DEqGxXoPfZ6hj9LynqNswjRIdmMZPsuEHguKXMbp+cncErGWcyzH417XYSDPoRn/3awpLfQ9F+KSjAe5cUltC7M4veSZW+t3VcJypvfRlU4ayTZMuvMHPlMcl/0jP5w0Q2+2pQIDAQABAoIBAGMvmrqBcXfHv0cluNnHRebtpaCtoTbdPx67WonDUfCJUiNnN7kckaZQu/k9SQsGDXm9QwEWZExHUKzqFlBepPIw+Sx0aoGZxYNwdHsjbcIspC2PoqGoFDMZ8ESqS2mCSYPHaLltUnm2E7JC44Y5QtKVH8vVzma6mG68ppTqV+2aGfGiPDq8cAYeH9/8Ys8/S28IwCp/M7lnXZhJ38bHD3YyPpcgbyGI/Zr5xaPd0hqHH08Z+S9V7QPJUGY0Y21s99DhkUGctb4B17d0/3Nzk/iWY1rp7A/kbdBeWonsHrTc6OnmbdiOcjC8seOIKMJ/WE3JznqnI1oydFb/dp6raNkCgYEA+pn1akGIKnVP0oFh5PZfUpuZtVV9u9xccIXyeFmCAXyFuUz1KYbfwwqZnm9r6kHAO+aBtRtVsCVle5oVWNQq1pdv117hPhRnVrDtvL80z50a5L9gEVu4Yz24Q3vs3RglcVpafSaRuyPbiYHMmQ4Ly+9nbwEbOVDbzK5A3Wrny2cCgYEA3exS3aG7+7mbSnNTYkkTgl7goLXZgEST/0EM2CvayxZ2QUS94Vq5HjGRpWnni3YttLiYlgCLe3CqeiIh6E3n6b9sory8Oy6lik/elj28kcZIuNvPU0xVcqrmGCg/KEnYkXjsGKsBDk6SV9nKH7880oIe0Rh3gc0hHHIl0Z4CshMCgYBifXHLkffPIA4AIKN11jJ+h/LwJqpk0+Vsv+gczqjepq7ztcBA0uZMhHT9pLLX/YFsyVo+8IBL21a4LkWnhLNVZW0qSvrhaCl5E85LuSYrVoaEUoaSK+ca8d3if+kGt/+3PhiESU1LLHuS3nWnzbJrMysGoHuvmgzYs7+AhgyVjwKBgQCoVgrFc1lUqIXTA4fMlgHmcnGRdl91nI9mn8FOeHWOd4tcFvixaE/jR1ZjUuIAN7ST0TJtFhy3lc66tgliXTX9aObOyrs9aTTIpa0B6fKP4QhosNOjK9PlFx1SVbUSqnFMZ50vWQeEArWfTeS0ECviwjD+CsEcBK2JFkz5pBIHYQKBgQD3zcYdYwvGkolLXNN3vbgTVnbNe2YMUBwgp5i1XGzAiG8XpwKTi4vDFIYgCZAG5wsyqUPdTOY2wyLjHwGdUfl7P3tCsHVzVh/xvuSl3nzW3OdCniKaBBdtZS6+s25Ijzdwiwnp21NWE6XU2BptIwTMHrKOc7BpZykgHsORMtptsQ==
|
||||
space:
|
||||
gcTTL: 60
|
||||
syncPeriod: 10
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/config"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/metric"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/dialer"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/server"
|
||||
@ -91,6 +92,7 @@ func main() {
|
||||
|
||||
func Bootstrap(a *app.App) {
|
||||
a.Register(account.New()).
|
||||
Register(metric.New()).
|
||||
Register(storage.New()).
|
||||
Register(nodecache.New(200)).
|
||||
Register(nodeconf.New()).
|
||||
@ -100,10 +102,4 @@ func Bootstrap(a *app.App) {
|
||||
Register(nodespace.New()).
|
||||
Register(commonspace.New()).
|
||||
Register(server.New())
|
||||
|
||||
//Register(document.New()).
|
||||
//Register(message.New()).
|
||||
//Register(requesthandler.New()).
|
||||
//Register(treecache.New()).
|
||||
//Register(api.New())
|
||||
}
|
||||
|
||||
@ -5,7 +5,8 @@ import (
|
||||
"errors"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ocache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/node/nodespace"
|
||||
"time"
|
||||
@ -24,7 +25,7 @@ type treeCache struct {
|
||||
nodeService nodespace.Service
|
||||
}
|
||||
|
||||
func New(ttl int) cache.TreeCache {
|
||||
func New(ttl int) treegetter.TreeGetter {
|
||||
return &treeCache{
|
||||
gcttl: ttl,
|
||||
}
|
||||
@ -52,34 +53,20 @@ func (c *treeCache) Init(a *app.App) (err error) {
|
||||
ocache.WithLogger(log.Sugar()),
|
||||
ocache.WithGCPeriod(time.Minute),
|
||||
ocache.WithTTL(time.Duration(c.gcttl)*time.Second),
|
||||
ocache.WithRefCounter(false),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *treeCache) Name() (name string) {
|
||||
return cache.CName
|
||||
return treegetter.CName
|
||||
}
|
||||
|
||||
func (c *treeCache) GetTree(ctx context.Context, spaceId, id string) (res cache.TreeResult, err error) {
|
||||
var cacheRes ocache.Object
|
||||
func (c *treeCache) GetTree(ctx context.Context, spaceId, id string) (tr tree.ObjectTree, err error) {
|
||||
ctx = context.WithValue(ctx, spaceKey, spaceId)
|
||||
cacheRes, err = c.cache.Get(ctx, id)
|
||||
value, err := c.cache.Get(ctx, id)
|
||||
if err != nil {
|
||||
return cache.TreeResult{}, err
|
||||
}
|
||||
|
||||
treeContainer, ok := cacheRes.(cache.TreeContainer)
|
||||
if !ok {
|
||||
err = ErrCacheObjectWithoutTree
|
||||
return
|
||||
}
|
||||
|
||||
res = cache.TreeResult{
|
||||
Release: func() {
|
||||
c.cache.Release(id)
|
||||
},
|
||||
TreeContainer: treeContainer,
|
||||
}
|
||||
tr = value.(tree.ObjectTree)
|
||||
return
|
||||
}
|
||||
|
||||
@ -2,9 +2,9 @@ package nodespace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||
)
|
||||
|
||||
type rpcHandler struct {
|
||||
@ -17,16 +17,19 @@ func (r *rpcHandler) PushSpace(ctx context.Context, req *spacesyncproto.PushSpac
|
||||
err = spacesyncproto.ErrSpaceExists
|
||||
return
|
||||
}
|
||||
if err != cache.ErrSpaceNotFound {
|
||||
if err != storage.ErrSpaceStorageMissing {
|
||||
err = spacesyncproto.ErrUnexpected
|
||||
return
|
||||
}
|
||||
|
||||
payload := storage.SpaceStorageCreatePayload{
|
||||
RecWithId: req.AclRoot,
|
||||
RecWithId: &aclrecordproto.RawACLRecordWithId{
|
||||
Payload: req.AclPayload,
|
||||
Id: req.AclPayloadId,
|
||||
},
|
||||
SpaceHeaderWithId: req.SpaceHeader,
|
||||
}
|
||||
_, err = r.s.spaceStorageProvider.CreateSpaceStorage(payload)
|
||||
st, err := r.s.spaceStorageProvider.CreateSpaceStorage(payload)
|
||||
if err != nil {
|
||||
err = spacesyncproto.ErrUnexpected
|
||||
if err == storage.ErrSpaceStorageExists {
|
||||
@ -34,6 +37,7 @@ func (r *rpcHandler) PushSpace(ctx context.Context, req *spacesyncproto.PushSpac
|
||||
}
|
||||
return
|
||||
}
|
||||
st.Close()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -44,7 +44,6 @@ func (s *service) Init(a *app.App) (err error) {
|
||||
ocache.WithLogger(log.Sugar()),
|
||||
ocache.WithGCPeriod(time.Minute),
|
||||
ocache.WithTTL(time.Duration(s.conf.GCTTL)*time.Second),
|
||||
ocache.WithRefCounter(false),
|
||||
)
|
||||
return spacesyncproto.DRPCRegisterSpace(a.MustComponent(server.CName).(server.DRPCServer), &rpcHandler{s})
|
||||
}
|
||||
@ -54,10 +53,6 @@ func (s *service) Name() (name string) {
|
||||
}
|
||||
|
||||
func (s *service) Run(ctx context.Context) (err error) {
|
||||
go func() {
|
||||
time.Sleep(time.Second * 5)
|
||||
_, _ = s.GetSpace(ctx, "testDSpace")
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -62,5 +62,5 @@ func (s spaceKeys) HeaderKey() []byte {
|
||||
}
|
||||
|
||||
func isRootIdKey(key string) bool {
|
||||
return strings.HasPrefix(key, "t/") && strings.HasSuffix(key, "rootId")
|
||||
return strings.HasPrefix(key, "t/") && strings.HasSuffix(key, "heads")
|
||||
}
|
||||
|
||||
@ -2,9 +2,11 @@ package storage
|
||||
|
||||
import (
|
||||
"github.com/akrylysov/pogreb"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
"go.uber.org/zap"
|
||||
"path"
|
||||
"sync"
|
||||
"time"
|
||||
@ -14,6 +16,8 @@ var defPogrebOptions = &pogreb.Options{
|
||||
BackgroundCompactionInterval: time.Minute * 5,
|
||||
}
|
||||
|
||||
var log = logger.NewNamed("storage.spacestorage")
|
||||
|
||||
type spaceStorage struct {
|
||||
spaceId string
|
||||
objDb *pogreb.DB
|
||||
@ -24,6 +28,7 @@ type spaceStorage struct {
|
||||
}
|
||||
|
||||
func newSpaceStorage(rootPath string, spaceId string) (store spacestorage.SpaceStorage, err error) {
|
||||
log.With(zap.String("id", spaceId)).Debug("space storage opening with new")
|
||||
dbPath := path.Join(rootPath, spaceId)
|
||||
objDb, err := pogreb.Open(dbPath, defPogrebOptions)
|
||||
if err != nil {
|
||||
@ -32,6 +37,7 @@ func newSpaceStorage(rootPath string, spaceId string) (store spacestorage.SpaceS
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.With(zap.String("id", spaceId), zap.Error(err)).Warn("failed to open storage")
|
||||
objDb.Close()
|
||||
}
|
||||
}()
|
||||
@ -74,6 +80,7 @@ func newSpaceStorage(rootPath string, spaceId string) (store spacestorage.SpaceS
|
||||
}
|
||||
|
||||
func createSpaceStorage(rootPath string, payload spacestorage.SpaceStorageCreatePayload) (store spacestorage.SpaceStorage, err error) {
|
||||
log.With(zap.String("id", payload.SpaceHeaderWithId.Id)).Debug("space storage creating")
|
||||
dbPath := path.Join(rootPath, payload.SpaceHeaderWithId.Id)
|
||||
db, err := pogreb.Open(dbPath, defPogrebOptions)
|
||||
if err != nil {
|
||||
@ -81,6 +88,7 @@ func createSpaceStorage(rootPath string, payload spacestorage.SpaceStorageCreate
|
||||
}
|
||||
|
||||
defer func() {
|
||||
log.With(zap.String("id", payload.SpaceHeaderWithId.Id), zap.Error(err)).Warn("failed to create storage")
|
||||
if err != nil {
|
||||
db.Close()
|
||||
}
|
||||
@ -165,5 +173,6 @@ func (s *spaceStorage) StoredIds() (ids []string, err error) {
|
||||
}
|
||||
|
||||
func (s *spaceStorage) Close() (err error) {
|
||||
log.With(zap.String("id", s.spaceId)).Debug("space storage closed")
|
||||
return s.objDb.Close()
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ func (t *treeStorage) Heads() (heads []string, err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if heads == nil {
|
||||
if headsBytes == nil {
|
||||
err = storage2.ErrUnknownTreeId
|
||||
return
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
flagNodeMap = flag.String("n", "cmd/nodesgen/nodemap.yml", "path to nodes map file")
|
||||
flagNodeMap = flag.String("n", "util/cmd/nodesgen/nodemap.yml", "path to nodes map file")
|
||||
flagEtcPath = flag.String("e", "etc", "path to etc directory")
|
||||
)
|
||||
|
||||
@ -27,6 +27,10 @@ type NodesMap struct {
|
||||
Consensus []struct {
|
||||
Addresses []string `yaml:"grpcAddresses"`
|
||||
}
|
||||
Clients []struct {
|
||||
Addresses []string `yaml:"grpcAddresses"`
|
||||
APIPort string `yaml:"apiPort"`
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
@ -60,6 +64,15 @@ func main() {
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
|
||||
var clientConfigs []config2.Config
|
||||
for _, c := range nodesMap.Clients {
|
||||
cfg, err := genClientConfig(c.Addresses, c.APIPort)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("could not generate the config file: %s", err.Error()))
|
||||
}
|
||||
clientConfigs = append(clientConfigs, cfg)
|
||||
}
|
||||
|
||||
var consConfigs []cconfig.Config
|
||||
for _, n := range nodesMap.Consensus {
|
||||
cfg, err := genConsensusConfig(n.Addresses)
|
||||
@ -67,19 +80,13 @@ func main() {
|
||||
panic(fmt.Sprintf("could not generate the config file: %s", err.Error()))
|
||||
}
|
||||
consConfigs = append(consConfigs, cfg)
|
||||
|
||||
node := config2.Node{
|
||||
PeerId: cfg.Account.PeerId,
|
||||
Address: cfg.GrpcServer.ListenAddrs[0],
|
||||
SigningKey: cfg.Account.SigningKey,
|
||||
EncryptionKey: cfg.Account.EncryptionKey,
|
||||
IsConsensus: true,
|
||||
}
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
for idx := range configs {
|
||||
configs[idx].Nodes = nodes
|
||||
}
|
||||
for idx := range clientConfigs {
|
||||
clientConfigs[idx].Nodes = nodes
|
||||
}
|
||||
|
||||
// saving configs
|
||||
configsPath := fmt.Sprintf("%s/configs", *flagEtcPath)
|
||||
@ -110,6 +117,18 @@ func main() {
|
||||
panic(fmt.Sprintf("could not write the config to file: %v", err))
|
||||
}
|
||||
}
|
||||
for idx, cfg := range clientConfigs {
|
||||
path := fmt.Sprintf("%s/client%d.yml", configsPath, idx+1)
|
||||
bytes, err := yaml.Marshal(cfg)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("could not marshal the keys: %v", err))
|
||||
}
|
||||
|
||||
err = os.WriteFile(path, bytes, os.ModePerm)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("could not write the config to file: %v", err))
|
||||
}
|
||||
}
|
||||
for idx, cfg := range consConfigs {
|
||||
path := fmt.Sprintf("%s/cons%d.yml", configsPath, idx+1)
|
||||
bytes, err := yaml.Marshal(cfg)
|
||||
@ -172,6 +191,54 @@ func genNodeConfig(addresses []string, apiPort string) (config2.Config, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func genClientConfig(addresses []string, apiPort string) (config2.Config, error) {
|
||||
encKey, _, err := encryptionkey.GenerateRandomRSAKeyPair(2048)
|
||||
if err != nil {
|
||||
return config2.Config{}, err
|
||||
}
|
||||
|
||||
signKey, _, err := signingkey.GenerateRandomEd25519KeyPair()
|
||||
if err != nil {
|
||||
return config2.Config{}, err
|
||||
}
|
||||
|
||||
encEncKey, err := keys.EncodeKeyToString(encKey)
|
||||
if err != nil {
|
||||
return config2.Config{}, err
|
||||
}
|
||||
|
||||
encSignKey, err := keys.EncodeKeyToString(signKey)
|
||||
if err != nil {
|
||||
return config2.Config{}, err
|
||||
}
|
||||
|
||||
peerID, err := peer.IDFromSigningPubKey(signKey.GetPublic())
|
||||
if err != nil {
|
||||
return config2.Config{}, err
|
||||
}
|
||||
|
||||
return config2.Config{
|
||||
Anytype: config2.Anytype{SwarmKey: "/key/swarm/psk/1.0.0/base16/209992e611c27d5dce8fbd2e7389f6b51da9bee980992ef60739460b536139ec"},
|
||||
GrpcServer: config2.GrpcServer{
|
||||
ListenAddrs: addresses,
|
||||
TLS: false,
|
||||
},
|
||||
Storage: config2.Storage{Path: "db"},
|
||||
Account: config2.Account{
|
||||
PeerId: peerID.String(),
|
||||
SigningKey: encSignKey,
|
||||
EncryptionKey: encEncKey,
|
||||
},
|
||||
APIServer: config2.APIServer{
|
||||
Port: apiPort,
|
||||
},
|
||||
Space: config2.Space{
|
||||
GCTTL: 60,
|
||||
SyncPeriod: 10,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func genConsensusConfig(addresses []string) (cconfig.Config, error) {
|
||||
encKey, _, err := encryptionkey.GenerateRandomRSAKeyPair(2048)
|
||||
if err != nil {
|
||||
|
||||
@ -15,3 +15,10 @@ consensus:
|
||||
- "127.0.0.1:4531"
|
||||
- grpcAddresses:
|
||||
- "127.0.0.1:4532"
|
||||
clients:
|
||||
- grpcAddresses:
|
||||
- "127.0.0.1:4630"
|
||||
apiPort: "8090"
|
||||
- grpcAddresses:
|
||||
- "127.0.0.1:4631"
|
||||
apiPort: "8091"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user