Merge pull request #14 from anytypeio/add-client-functionality

This commit is contained in:
Mikhail Rakhmanov 2022-10-24 14:46:48 +02:00 committed by GitHub
commit 8263bbfde2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
87 changed files with 4624 additions and 3350 deletions

7
.gitignore vendored
View File

@ -8,12 +8,19 @@
# Test binary, built with `go test -c` # Test binary, built with `go test -c`
*.test *.test
# Output of the go coverage tool, specifically when used with LiteIDE # Output of the go coverage tool, specifically when used with LiteIDE
*.out *.out
# Golang vendor folder # Golang vendor folder
vendor vendor
# database
db
# artefacts for Intelli-J fleet
.fleet
# Intelli-J files # Intelli-J files
.idea .idea

View File

@ -1,20 +1,125 @@
package api 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 { type Controller interface {
// DeriveSpace derives the space from current account // DeriveSpace derives the space from current account
DeriveSpace() (id string, err error) DeriveSpace() (id string, err error)
// CreateSpace creates new space with random data // CreateSpace creates new space with random data
CreateSpace() (id string, err error) 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 asks node to load a particular space
LoadSpace(id string) (err error) LoadSpace(id string) (err error)
// CreateDocument creates new document in space
CreateDocument(spaceId string) (id string, err error) CreateDocument(spaceId string) (id string, err error)
GetAllDocumentIds(spaceId string) (ids []string, err error) // AllDocumentIds gets all ids of documents in space
AddText(documentId, text string) (err error) AllDocumentIds(spaceId string) (ids []string, err error)
DumpDocumentTree(documentId 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) GenerateInvite(spaceId string) (invite string, err error)
JoinSpace(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
View 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))
}
}

View File

@ -18,6 +18,10 @@ type service struct {
db *badger.DB db *badger.DB
} }
func New() BadgerProvider {
return &service{}
}
func (s *service) Init(a *app.App) (err error) { func (s *service) Init(a *app.App) (err error) {
cfg := a.MustComponent(config.CName).(*config.Config) cfg := a.MustComponent(config.CName).(*config.Config)
s.db, err = badger.Open(badger.DefaultOptions(cfg.Storage.Path)) s.db, err = badger.Open(badger.DefaultOptions(cfg.Storage.Path))

View File

@ -3,11 +3,15 @@ package clientcache
import ( import (
"context" "context"
"errors" "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"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "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/treegetter"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache" "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/common/pkg/ocache"
"go.uber.org/zap"
"time" "time"
) )
@ -21,10 +25,33 @@ const spaceKey ctxKey = 0
type treeCache struct { type treeCache struct {
gcttl int gcttl int
cache ocache.OCache cache ocache.OCache
account account.Service
clientService clientspace.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{ return &treeCache{
gcttl: ttl, gcttl: ttl,
} }
@ -40,6 +67,7 @@ func (c *treeCache) Close(ctx context.Context) (err error) {
func (c *treeCache) Init(a *app.App) (err error) { func (c *treeCache) Init(a *app.App) (err error) {
c.clientService = a.MustComponent(clientspace.CName).(clientspace.Service) c.clientService = a.MustComponent(clientspace.CName).(clientspace.Service)
c.account = a.MustComponent(account.CName).(account.Service)
c.cache = ocache.New( c.cache = ocache.New(
func(ctx context.Context, id string) (value ocache.Object, err error) { func(ctx context.Context, id string) (value ocache.Object, err error) {
spaceId := ctx.Value(spaceKey).(string) spaceId := ctx.Value(spaceKey).(string)
@ -47,39 +75,34 @@ func (c *treeCache) Init(a *app.App) (err error) {
if err != nil { if err != nil {
return return
} }
return space.BuildTree(ctx, id, nil) return textdocument.NewTextDocument(context.Background(), space, id, &updateListener{}, c.account)
}, },
ocache.WithLogger(log.Sugar()), ocache.WithLogger(log.Sugar()),
ocache.WithGCPeriod(time.Minute), ocache.WithGCPeriod(time.Minute),
ocache.WithTTL(time.Duration(c.gcttl)*time.Second), ocache.WithTTL(time.Duration(c.gcttl)*time.Second),
ocache.WithRefCounter(false),
) )
return nil return nil
} }
func (c *treeCache) Name() (name string) { 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) { func (c *treeCache) GetDocument(ctx context.Context, spaceId, id string) (doc textdocument.TextDocument, err error) {
var cacheRes ocache.Object
ctx = context.WithValue(ctx, spaceKey, spaceId) ctx = context.WithValue(ctx, spaceKey, spaceId)
cacheRes, err = c.cache.Get(ctx, id) v, err := c.cache.Get(ctx, id)
if err != nil { if err != nil {
return cache.TreeResult{}, err
}
treeContainer, ok := cacheRes.(cache.TreeContainer)
if !ok {
err = ErrCacheObjectWithoutTree
return return
} }
doc = v.(textdocument.TextDocument)
res = cache.TreeResult{ return
Release: func() { }
c.cache.Release(id)
}, func (c *treeCache) GetTree(ctx context.Context, spaceId, id string) (tr tree.ObjectTree, err error) {
TreeContainer: treeContainer, doc, err := c.GetDocument(ctx, spaceId, id)
} if err != nil {
return
}
tr = doc.Tree()
return return
} }

View File

@ -2,9 +2,10 @@ package clientspace
import ( import (
"context" "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/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "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 { type rpcHandler struct {
@ -17,16 +18,19 @@ func (r *rpcHandler) PushSpace(ctx context.Context, req *spacesyncproto.PushSpac
err = spacesyncproto.ErrSpaceExists err = spacesyncproto.ErrSpaceExists
return return
} }
if err != cache.ErrSpaceNotFound { if err != treegetter.ErrSpaceNotFound {
err = spacesyncproto.ErrUnexpected err = spacesyncproto.ErrUnexpected
return return
} }
payload := storage.SpaceStorageCreatePayload{ payload := storage.SpaceStorageCreatePayload{
RecWithId: req.AclRoot, RecWithId: &aclrecordproto.RawACLRecordWithId{
Payload: req.AclPayload,
Id: req.AclPayloadId,
},
SpaceHeaderWithId: req.SpaceHeader, SpaceHeaderWithId: req.SpaceHeader,
} }
_, err = r.s.spaceStorageProvider.CreateSpaceStorage(payload) st, err := r.s.spaceStorageProvider.CreateSpaceStorage(payload)
if err != nil { if err != nil {
err = spacesyncproto.ErrUnexpected err = spacesyncproto.ErrUnexpected
if err == storage.ErrSpaceStorageExists { if err == storage.ErrSpaceStorageExists {
@ -34,6 +38,7 @@ func (r *rpcHandler) PushSpace(ctx context.Context, req *spacesyncproto.PushSpac
} }
return return
} }
st.Close()
return return
} }

View File

@ -46,7 +46,6 @@ func (s *service) Init(a *app.App) (err error) {
ocache.WithLogger(log.Sugar()), ocache.WithLogger(log.Sugar()),
ocache.WithGCPeriod(time.Minute), ocache.WithGCPeriod(time.Minute),
ocache.WithTTL(time.Duration(s.conf.GCTTL)*time.Second), ocache.WithTTL(time.Duration(s.conf.GCTTL)*time.Second),
ocache.WithRefCounter(false),
) )
return spacesyncproto.DRPCRegisterSpace(a.MustComponent(server.CName).(server.DRPCServer), &rpcHandler{s}) 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) { func (s *service) Run(ctx context.Context) (err error) {
go func() {
time.Sleep(time.Second * 5)
_, _ = s.GetSpace(ctx, "testDSpace")
}()
return 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) id, err := s.commonSpace.CreateSpace(ctx, payload)
if err != nil { if err != nil {
return return
} }
obj, err := s.commonSpace.GetSpace(ctx, id) obj, err := s.spaceCache.Get(ctx, id)
if err != nil { if err != nil {
return return
} }
return obj.(commonspace.Space), nil 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) id, err := s.commonSpace.DeriveSpace(ctx, payload)
if err != nil { if err != nil {
return return
} }
obj, err := s.commonSpace.GetSpace(ctx, id) obj, err := s.spaceCache.Get(ctx, id)
if err != nil { if err != nil {
return return
} }
return obj.(commonspace.Space), nil 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) v, err := s.spaceCache.Get(ctx, id)
if err != nil { if err != nil {
return nil, err return
} }
return v.(commonspace.Space), nil return v.(commonspace.Space), nil
} }

112
client/cmd/client.go Normal file
View 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())
}

View File

@ -1,13 +1,83 @@
package document 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 { type Service interface {
app.Component app.Component
CreateDocument(spaceId string) (id string, err error) CreateDocument(spaceId string) (id string, err error)
GetAllDocumentIds(spaceId string) (ids []string, err error) AllDocumentIds(spaceId string) (ids []string, err error)
AddText(documentId, text string) (err error) AddText(spaceId, documentId, text string) (err error)
DumpDocumentTree(documentId string) (err error) DumpDocumentTree(spaceId, documentId string) (dump string, err error)
} }
const CName = "client.document" 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()
}

View 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
}

View File

@ -2,10 +2,70 @@ module github.com/anytypeio/go-anytype-infrastructure-experiments/client
replace github.com/anytypeio/go-anytype-infrastructure-experiments/common => ../common replace github.com/anytypeio/go-anytype-infrastructure-experiments/common => ../common
go 1.19 go 1.19
require ( require (
github.com/anytypeio/go-anytype-infrastructure-experiments/common v0.0.0-00010101000000-000000000000 github.com/anytypeio/go-anytype-infrastructure-experiments/common v0.0.0-00010101000000-000000000000
github.com/dgraph-io/badger/v3 v3.2103.3 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
) )

View File

@ -65,7 +65,7 @@ type spaceKeys struct {
func newSpaceKeys(spaceId string) spaceKeys { func newSpaceKeys(spaceId string) spaceKeys {
return spaceKeys{ return spaceKeys{
headerKey: storage.JoinStringsToBytes("space", spaceId), headerKey: storage.JoinStringsToBytes("space", "header", spaceId),
treePrefixKey: storage.JoinStringsToBytes("space", spaceId, "t", "rootId"), treePrefixKey: storage.JoinStringsToBytes("space", spaceId, "t", "rootId"),
} }
} }
@ -77,3 +77,15 @@ func (s spaceKeys) HeaderKey() []byte {
func (s spaceKeys) TreeRootPrefix() []byte { func (s spaceKeys) TreeRootPrefix() []byte {
return s.treePrefixKey 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
}

View File

@ -37,7 +37,7 @@ func newListStorage(spaceId string, db *badger.DB, txn *badger.Txn) (ls storage.
ls = &listStorage{ ls = &listStorage{
db: db, db: db,
keys: aclKeys{}, keys: newACLKeys(spaceId),
id: stringId, id: stringId,
root: rootWithId, root: rootWithId,
} }
@ -70,7 +70,7 @@ func createListStorage(spaceId string, db *badger.DB, txn *badger.Txn, root *acl
ls = &listStorage{ ls = &listStorage{
db: db, db: db,
keys: aclKeys{}, keys: newACLKeys(spaceId),
id: root.Id, id: root.Id,
root: root, root: root,
} }

View File

@ -125,5 +125,5 @@ func (s *spaceStorage) StoredIds() (ids []string, err error) {
} }
func (s *spaceStorage) Close() (err error) { func (s *spaceStorage) Close() (err error) {
return s.objDb.Close() return nil
} }

View File

@ -1,23 +1,32 @@
package storage package storage
import ( 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/client/badgerprovider"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/dgraph-io/badger/v3" "github.com/dgraph-io/badger/v3"
) )
type storageService struct { 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{} return &storageService{}
} }
func (s *storageService) Init(a *app.App) (err error) { func (s *storageService) Init(a *app.App) (err error) {
provider := a.MustComponent(badgerprovider.CName).(badgerprovider.BadgerProvider) provider := a.MustComponent(badgerprovider.CName).(badgerprovider.BadgerProvider)
s.db = provider.Badger() s.db = provider.Badger()
s.keys = newStorageServiceKeys()
return return
} }
@ -32,3 +41,34 @@ func (s *storageService) SpaceStorage(id string) (storage.SpaceStorage, error) {
func (s *storageService) CreateSpaceStorage(payload storage.SpaceStorageCreatePayload) (storage.SpaceStorage, error) { func (s *storageService) CreateSpaceStorage(payload storage.SpaceStorageCreatePayload) (storage.SpaceStorage, error) {
return createSpaceStorage(s.db, payload) 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()
}

View File

@ -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)
}

View 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
}

View File

@ -3,10 +3,10 @@ package diffservice
import ( import (
"context" "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/remotediff"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "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/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/nodeconf"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff"
"go.uber.org/zap" "go.uber.org/zap"
@ -14,9 +14,10 @@ import (
) )
type DiffService interface { type DiffService interface {
HeadNotifiable
HandleRangeRequest(ctx context.Context, req *spacesyncproto.HeadSyncRequest) (resp *spacesyncproto.HeadSyncResponse, err error) HandleRangeRequest(ctx context.Context, req *spacesyncproto.HeadSyncRequest) (resp *spacesyncproto.HeadSyncResponse, err error)
UpdateHeads(id string, heads []string)
RemoveObject(id string) RemoveObject(id string)
AllIds() []string
Init(objectIds []string) Init(objectIds []string)
Close() (err error) Close() (err error)
@ -37,7 +38,7 @@ func NewDiffService(
syncPeriod int, syncPeriod int,
storage storage.SpaceStorage, storage storage.SpaceStorage,
confConnector nodeconf.ConfConnector, confConnector nodeconf.ConfConnector,
cache cache.TreeCache, cache treegetter.TreeGetter,
log *zap.Logger) DiffService { log *zap.Logger) DiffService {
diff := ldiff.New(16, 16) 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) { func (d *diffService) RemoveObject(id string) {
// TODO: add space document to remove ids // TODO: add space document to remove ids
d.diff.RemoveId(id) d.diff.RemoveId(id)

View File

@ -2,10 +2,10 @@ package diffservice
import ( import (
"context" "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/remotediff"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "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/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/peer"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr" "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/nodeconf"
@ -22,7 +22,7 @@ func newDiffSyncer(
spaceId string, spaceId string,
diff ldiff.Diff, diff ldiff.Diff,
confConnector nodeconf.ConfConnector, confConnector nodeconf.ConfConnector,
cache cache.TreeCache, cache treegetter.TreeGetter,
storage storage.SpaceStorage, storage storage.SpaceStorage,
clientFactory spacesyncproto.ClientFactory, clientFactory spacesyncproto.ClientFactory,
log *zap.Logger) DiffSyncer { log *zap.Logger) DiffSyncer {
@ -41,7 +41,7 @@ type diffSyncer struct {
spaceId string spaceId string
diff ldiff.Diff diff ldiff.Diff
confConnector nodeconf.ConfConnector confConnector nodeconf.ConfConnector
cache cache.TreeCache cache treegetter.TreeGetter
storage storage.SpaceStorage storage storage.SpaceStorage
clientFactory spacesyncproto.ClientFactory clientFactory spacesyncproto.ClientFactory
log *zap.Logger 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, newIds)
d.pingTreesInCache(ctx, changedIds) d.pingTreesInCache(ctx, changedIds)
d.pingTreesInCache(ctx, removedIds)
d.log.Info("sync done:", zap.Int("newIds", len(newIds)), d.log.Info("sync done:", zap.Int("newIds", len(newIds)),
zap.Int("changedIds", len(changedIds)), zap.Int("changedIds", len(changedIds)),
@ -107,8 +108,9 @@ func (d *diffSyncer) sendPushSpaceRequest(ctx context.Context, cl spacesyncproto
} }
_, err = cl.PushSpace(ctx, &spacesyncproto.PushSpaceRequest{ _, err = cl.PushSpace(ctx, &spacesyncproto.PushSpaceRequest{
SpaceHeader: header, SpaceHeader: header,
AclRoot: root, AclPayload: root.Payload,
AclPayloadId: root.Id,
}) })
return return
} }

View File

@ -4,12 +4,11 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "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/remotediff"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "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/spacesyncproto/mock_spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage" "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/net/peer"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf/mock_nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf/mock_nodeconf"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
@ -24,7 +23,7 @@ import (
type pushSpaceRequestMatcher struct { type pushSpaceRequestMatcher struct {
spaceId string spaceId string
aclRoot *aclrecordproto.RawACLRecordWithId aclRootId string
spaceHeader *spacesyncproto.RawSpaceHeaderWithId spaceHeader *spacesyncproto.RawSpaceHeaderWithId
} }
@ -34,7 +33,7 @@ func (p pushSpaceRequestMatcher) Matches(x interface{}) bool {
return false 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 { func (p pushSpaceRequestMatcher) String() string {
@ -72,11 +71,11 @@ func (m mockPeer) NewStream(ctx context.Context, rpc string, enc drpc.Encoding)
func newPushSpaceRequestMatcher( func newPushSpaceRequestMatcher(
spaceId string, spaceId string,
aclRoot *aclrecordproto.RawACLRecordWithId, aclRootId string,
spaceHeader *spacesyncproto.RawSpaceHeaderWithId) *pushSpaceRequestMatcher { spaceHeader *spacesyncproto.RawSpaceHeaderWithId) *pushSpaceRequestMatcher {
return &pushSpaceRequestMatcher{ return &pushSpaceRequestMatcher{
spaceId: spaceId, spaceId: spaceId,
aclRoot: aclRoot, aclRootId: aclRootId,
spaceHeader: spaceHeader, spaceHeader: spaceHeader,
} }
} }
@ -89,13 +88,14 @@ func TestDiffSyncer_Sync(t *testing.T) {
diffMock := mock_ldiff.NewMockDiff(ctrl) diffMock := mock_ldiff.NewMockDiff(ctrl)
connectorMock := mock_nodeconf.NewMockConfConnector(ctrl) connectorMock := mock_nodeconf.NewMockConfConnector(ctrl)
cacheMock := mock_cache.NewMockTreeCache(ctrl) cacheMock := mock_treegetter.NewMockTreeGetter(ctrl)
stMock := mock_storage.NewMockSpaceStorage(ctrl) stMock := mock_storage.NewMockSpaceStorage(ctrl)
clientMock := mock_spacesyncproto.NewMockDRPCSpaceClient(ctrl) clientMock := mock_spacesyncproto.NewMockDRPCSpaceClient(ctrl)
factory := spacesyncproto.ClientFactoryFunc(func(cc drpc.Conn) spacesyncproto.DRPCSpaceClient { factory := spacesyncproto.ClientFactoryFunc(func(cc drpc.Conn) spacesyncproto.DRPCSpaceClient {
return clientMock return clientMock
}) })
spaceId := "spaceId" spaceId := "spaceId"
aclRootId := "aclRootId"
l := logger.NewNamed(spaceId) l := logger.NewNamed(spaceId)
diffSyncer := newDiffSyncer(spaceId, diffMock, connectorMock, cacheMock, stMock, factory, l) 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"} { for _, arg := range []string{"new", "changed"} {
cacheMock.EXPECT(). cacheMock.EXPECT().
GetTree(gomock.Any(), spaceId, arg). GetTree(gomock.Any(), spaceId, arg).
Return(cache.TreeResult{}, nil) Return(nil, nil)
} }
require.NoError(t, diffSyncer.Sync(ctx)) 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) { t.Run("diff syncer sync space missing", func(t *testing.T) {
aclStorageMock := mock_aclstorage.NewMockListStorage(ctrl) aclStorageMock := mock_aclstorage.NewMockListStorage(ctrl)
aclRoot := &aclrecordproto.RawACLRecordWithId{} aclRoot := &aclrecordproto.RawACLRecordWithId{
Id: aclRootId,
}
spaceHeader := &spacesyncproto.RawSpaceHeaderWithId{} spaceHeader := &spacesyncproto.RawSpaceHeaderWithId{}
connectorMock.EXPECT(). connectorMock.EXPECT().
@ -143,7 +145,7 @@ func TestDiffSyncer_Sync(t *testing.T) {
Root(). Root().
Return(aclRoot, nil) Return(aclRoot, nil)
clientMock.EXPECT(). clientMock.EXPECT().
PushSpace(gomock.Any(), newPushSpaceRequestMatcher(spaceId, aclRoot, spaceHeader)). PushSpace(gomock.Any(), newPushSpaceRequestMatcher(spaceId, aclRootId, spaceHeader)).
Return(nil, nil) Return(nil, nil)
require.NoError(t, diffSyncer.Sync(ctx)) require.NoError(t, diffSyncer.Sync(ctx))

View File

@ -0,0 +1,5 @@
package diffservice
type HeadNotifiable interface {
UpdateHeads(id string, heads []string)
}

View 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)
}

View File

@ -19,5 +19,5 @@ func (r *rpcHandler) HeadSync(ctx context.Context, req *spacesyncproto.HeadSyncR
} }
func (r *rpcHandler) Stream(stream spacesyncproto.DRPCSpace_StreamStream) (err error) { func (r *rpcHandler) Stream(stream spacesyncproto.DRPCSpace_StreamStream) (err error) {
return r.s.SyncService().SyncClient().AddAndReadStreamSync(stream) return r.s.SyncService().StreamPool().AddAndReadStreamSync(stream)
} }

View File

@ -2,12 +2,13 @@ package commonspace
import ( import (
"context" "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"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "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/diffservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "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"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
config2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/config" 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/net/pool"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
@ -30,17 +31,19 @@ type Service interface {
type service struct { type service struct {
config config2.Space config config2.Space
account account.Service
configurationService nodeconf.Service configurationService nodeconf.Service
storageProvider storage.SpaceStorageProvider storageProvider storage.SpaceStorageProvider
cache cache.TreeCache treeGetter treegetter.TreeGetter
pool pool.Pool pool pool.Pool
} }
func (s *service) Init(a *app.App) (err error) { func (s *service) Init(a *app.App) (err error) {
s.config = a.MustComponent(config2.CName).(*config2.Config).Space 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.storageProvider = a.MustComponent(storage.CName).(storage.SpaceStorageProvider)
s.configurationService = a.MustComponent(nodeconf.CName).(nodeconf.Service) 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) s.pool = a.MustComponent(pool.CName).(pool.Pool)
return nil return nil
} }
@ -84,16 +87,19 @@ func (s *service) GetSpace(ctx context.Context, id string) (Space, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
lastConfiguration := s.configurationService.GetLast() lastConfiguration := s.configurationService.GetLast()
confConnector := nodeconf.NewConfConnector(lastConfiguration, s.pool) confConnector := nodeconf.NewConfConnector(lastConfiguration, s.pool)
diffService := diffservice.NewDiffService(id, s.config.SyncPeriod, st, confConnector, s.cache, log) diffService := diffservice.NewDiffService(id, s.config.SyncPeriod, st, confConnector, s.treeGetter, log)
syncService := syncservice.NewSyncService(id, diffService, s.cache, lastConfiguration, confConnector) syncService := syncservice.NewSyncService(id, confConnector)
sp := &space{ sp := &space{
id: id, id: id,
syncService: syncService, syncService: syncService,
diffService: diffService, diffService: diffService,
cache: s.cache, cache: s.treeGetter,
storage: st, account: s.account,
configuration: lastConfiguration,
storage: st,
} }
if err := sp.Init(ctx); err != nil { if err := sp.Init(ctx); err != nil {
return nil, err return nil, err

View File

@ -2,22 +2,29 @@ package commonspace
import ( import (
"context" "context"
"errors"
"fmt" "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/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/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/syncservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree" "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/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" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list"
storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" tree "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
tree2 "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/encryptionkey"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey"
"go.uber.org/zap"
"sync" "sync"
"sync/atomic"
"time"
) )
var ErrSpaceClosed = errors.New("space is closed")
type SpaceCreatePayload struct { type SpaceCreatePayload struct {
// SigningKey is the signing key of the owner // SigningKey is the signing key of the owner
SigningKey signingkey.PrivKey SigningKey signingkey.PrivKey
@ -44,12 +51,13 @@ func NewSpaceId(id string, repKey uint64) string {
type Space interface { type Space interface {
Id() string Id() string
StoredIds() []string
SpaceSyncRpc() RpcHandler SpaceSyncRpc() RpcHandler
DeriveTree(ctx context.Context, payload tree2.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree2.ObjectTree, error) DeriveTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error)
CreateTree(ctx context.Context, payload tree2.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree2.ObjectTree, error) CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error)
BuildTree(ctx context.Context, id string, listener updatelistener.UpdateListener) (tree2.ObjectTree, error) BuildTree(ctx context.Context, id string, listener updatelistener.UpdateListener) (tree.ObjectTree, error)
Close() error Close() error
} }
@ -60,11 +68,19 @@ type space struct {
rpc *rpcHandler rpc *rpcHandler
syncService syncservice.SyncService syncService syncservice.SyncService
diffService diffservice.DiffService diffService diffservice.DiffService
storage storage.SpaceStorage storage storage.SpaceStorage
cache cache.TreeCache cache treegetter.TreeGetter
aclList list.ACLList 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 { func (s *space) Id() string {
@ -77,8 +93,18 @@ func (s *space) Init(ctx context.Context) (err error) {
if err != nil { if err != nil {
return 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.diffService.Init(initialIds)
s.syncService.Init()
return nil return nil
} }
@ -94,62 +120,69 @@ func (s *space) DiffService() diffservice.DiffService {
return s.diffService return s.diffService
} }
func (s *space) DeriveTree(ctx context.Context, payload tree2.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree2.ObjectTree, error) { func (s *space) StoredIds() []string {
return synctree.DeriveSyncTree(ctx, payload, s.syncService.SyncClient(), listener, s.aclList, s.storage.CreateTreeStorage) return s.diffService.AllIds()
} }
func (s *space) CreateTree(ctx context.Context, payload tree2.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree2.ObjectTree, error) { func (s *space) DeriveTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tr tree.ObjectTree, err error) {
return synctree.CreateSyncTree(ctx, payload, s.syncService.SyncClient(), listener, s.aclList, s.storage.CreateTreeStorage) if s.isClosed.Load() {
} err = ErrSpaceClosed
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 {
return return
} }
deps := synctree.CreateDeps{
if err == storage2.ErrUnknownTreeId { SpaceId: s.id,
var resp *spacesyncproto.ObjectSyncMessage Payload: payload,
resp, err = getTreeRemote() StreamPool: s.syncService.StreamPool(),
if err != nil { Configuration: s.configuration,
return HeadNotifiable: s.diffService,
} Listener: listener,
fullSyncResp := resp.GetContent().GetFullSyncResponse() AclList: s.aclList,
CreateStorage: s.storage.CreateTreeStorage,
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
}
} }
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 { 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.diffService.Close()
s.syncService.Close() s.syncService.Close()
return s.storage.Close() return s.storage.Close()

View File

@ -2,8 +2,6 @@ syntax = "proto3";
package anySpace; package anySpace;
option go_package = "commonspace/spacesyncproto"; option go_package = "commonspace/spacesyncproto";
import "pkg/acl/treechangeproto/protos/treechange.proto";
import "pkg/acl/aclrecordproto/protos/aclrecord.proto";
enum ErrCodes { enum ErrCodes {
Unexpected = 0; Unexpected = 0;
@ -55,55 +53,18 @@ message HeadSyncResponse {
// ObjectSyncMessage is a message sent on object sync // ObjectSyncMessage is a message sent on object sync
message ObjectSyncMessage { message ObjectSyncMessage {
string spaceId = 1; string spaceId = 1;
ObjectSyncContentValue content = 2; string replyId = 2;
treechange.RawTreeChangeWithId rootChange = 3; bytes payload = 3;
string treeId = 4; string objectId = 4;
string trackingId = 5;
// string identity = 5; // string identity = 5;
// string peerSignature = 6; // 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 // PushSpaceRequest is a request to add space on a node containing only one acl record
message PushSpaceRequest { message PushSpaceRequest {
RawSpaceHeaderWithId spaceHeader = 2; RawSpaceHeaderWithId spaceHeader = 1;
aclrecord.RawACLRecordWithId aclRoot = 3; bytes aclPayload = 2;
string aclPayloadId = 3;
} }
// PushSpaceResponse is an empty response // PushSpaceResponse is an empty response

View File

@ -2,7 +2,6 @@
package spacesyncproto package spacesyncproto
import ( import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
"storj.io/drpc" "storj.io/drpc"
) )
@ -17,43 +16,3 @@ func (c ClientFactoryFunc) Client(cc drpc.Conn) DRPCSpaceClient {
type ClientFactory interface { type ClientFactory interface {
Client(cc drpc.Conn) DRPCSpaceClient 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

View File

@ -5,12 +5,12 @@
package mock_storage package mock_storage
import ( import (
storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
reflect "reflect" reflect "reflect"
app "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app" app "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" 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" gomock "github.com/golang/mock/gomock"
) )
@ -119,10 +119,10 @@ func (m *MockSpaceStorage) EXPECT() *MockSpaceStorageMockRecorder {
} }
// ACLStorage mocks base method. // ACLStorage mocks base method.
func (m *MockSpaceStorage) ACLStorage() (storage2.ListStorage, error) { func (m *MockSpaceStorage) ACLStorage() (storage0.ListStorage, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ACLStorage") ret := m.ctrl.Call(m, "ACLStorage")
ret0, _ := ret[0].(storage2.ListStorage) ret0, _ := ret[0].(storage0.ListStorage)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@ -148,10 +148,10 @@ func (mr *MockSpaceStorageMockRecorder) Close() *gomock.Call {
} }
// CreateTreeStorage mocks base method. // 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() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreateTreeStorage", arg0) ret := m.ctrl.Call(m, "CreateTreeStorage", arg0)
ret0, _ := ret[0].(storage2.TreeStorage) ret0, _ := ret[0].(storage0.TreeStorage)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@ -208,10 +208,10 @@ func (mr *MockSpaceStorageMockRecorder) StoredIds() *gomock.Call {
} }
// TreeStorage mocks base method. // 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() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "TreeStorage", arg0) ret := m.ctrl.Call(m, "TreeStorage", arg0)
ret0, _ := ret[0].(storage2.TreeStorage) ret0, _ := ret[0].(storage0.TreeStorage)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }

View 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,
}
}

View File

@ -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)
}

View File

@ -5,30 +5,34 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "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" "github.com/libp2p/go-libp2p/core/sec"
"storj.io/drpc/drpcctx" "storj.io/drpc/drpcctx"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time"
) )
var ErrEmptyPeer = errors.New("don't have such a peer") var ErrEmptyPeer = errors.New("don't have such a peer")
var ErrStreamClosed = errors.New("stream is already closed") 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 // StreamPool can be made generic to work with different streams
type StreamPool interface { type StreamPool interface {
Sender ocache.ObjectLastUsage
AddAndReadStreamSync(stream spacesyncproto.SpaceStream) (err error) AddAndReadStreamSync(stream spacesyncproto.SpaceStream) (err error)
AddAndReadStreamAsync(stream spacesyncproto.SpaceStream) 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) SendSync(peerId string, message *spacesyncproto.ObjectSyncMessage) (reply *spacesyncproto.ObjectSyncMessage, err error)
SendAsync(peers []string, message *spacesyncproto.ObjectSyncMessage) (err error) SendAsync(peers []string, message *spacesyncproto.ObjectSyncMessage) (err error)
BroadcastAsync(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) type MessageHandler func(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error)
@ -44,15 +48,23 @@ type streamPool struct {
wg *sync.WaitGroup wg *sync.WaitGroup
waiters map[string]responseWaiter waiters map[string]responseWaiter
waitersMx sync.Mutex waitersMx sync.Mutex
counter uint64 counter atomic.Uint64
lastUsage atomic.Int64
} }
func newStreamPool(messageHandler MessageHandler) StreamPool { func newStreamPool(messageHandler MessageHandler) StreamPool {
return &streamPool{ s := &streamPool{
peerStreams: make(map[string]spacesyncproto.SpaceStream), peerStreams: make(map[string]spacesyncproto.SpaceStream),
messageHandler: messageHandler, messageHandler: messageHandler,
waiters: make(map[string]responseWaiter),
wg: &sync.WaitGroup{}, 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) { func (s *streamPool) HasActiveStream(peerId string) (res bool) {
@ -65,26 +77,39 @@ func (s *streamPool) HasActiveStream(peerId string) (res bool) {
func (s *streamPool) SendSync( func (s *streamPool) SendSync(
peerId string, peerId string,
msg *spacesyncproto.ObjectSyncMessage) (reply *spacesyncproto.ObjectSyncMessage, err error) { msg *spacesyncproto.ObjectSyncMessage) (reply *spacesyncproto.ObjectSyncMessage, err error) {
newCounter := atomic.AddUint64(&s.counter, 1) newCounter := s.counter.Add(1)
msg.TrackingId = genStreamPoolKey(peerId, msg.TreeId, newCounter) msg.ReplyId = genStreamPoolKey(peerId, msg.ObjectId, newCounter)
s.waitersMx.Lock() s.waitersMx.Lock()
waiter := responseWaiter{ 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() s.waitersMx.Unlock()
err = s.SendAsync([]string{peerId}, msg) err = s.SendAsync([]string{peerId}, msg)
if err != nil { if err != nil {
return 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 return
} }
func (s *streamPool) SendAsync(peers []string, message *spacesyncproto.ObjectSyncMessage) (err error) { func (s *streamPool) SendAsync(peers []string, message *spacesyncproto.ObjectSyncMessage) (err error) {
s.lastUsage.Store(time.Now().Unix())
getStreams := func() (streams []spacesyncproto.SpaceStream) { getStreams := func() (streams []spacesyncproto.SpaceStream) {
for _, pId := range peers { for _, pId := range peers {
stream, err := s.getOrDeleteStream(pId) stream, err := s.getOrDeleteStream(pId)
@ -100,10 +125,13 @@ func (s *streamPool) SendAsync(peers []string, message *spacesyncproto.ObjectSyn
streams := getStreams() streams := getStreams()
s.Unlock() s.Unlock()
log.With("objectId", message.ObjectId).
Debugf("sending message to %d peers", len(streams))
for _, s := range 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 return err
} }
@ -145,6 +173,8 @@ Loop:
func (s *streamPool) BroadcastAsync(message *spacesyncproto.ObjectSyncMessage) (err error) { func (s *streamPool) BroadcastAsync(message *spacesyncproto.ObjectSyncMessage) (err error) {
streams := s.getAllStreams() streams := s.getAllStreams()
log.With("objectId", message.ObjectId).
Debugf("broadcasting message to %d peers", len(streams))
for _, stream := range streams { for _, stream := range streams {
if err = stream.Send(message); err != nil { if err = stream.Send(message); err != nil {
// TODO: add logging // TODO: add logging
@ -191,21 +221,24 @@ func (s *streamPool) readPeerLoop(peerId string, stream spacesyncproto.SpaceStre
} }
process := func(msg *spacesyncproto.ObjectSyncMessage) { process := func(msg *spacesyncproto.ObjectSyncMessage) {
if msg.TrackingId == "" { s.lastUsage.Store(time.Now().Unix())
if msg.ReplyId == "" {
s.messageHandler(stream.Context(), peerId, msg) s.messageHandler(stream.Context(), peerId, msg)
return return
} }
log.With("replyId", msg.ReplyId).Debug("getting message with reply id")
s.waitersMx.Lock() s.waitersMx.Lock()
waiter, exists := s.waiters[msg.TrackingId] waiter, exists := s.waiters[msg.ReplyId]
if !exists { if !exists {
log.With("replyId", msg.ReplyId).Debug("reply id not exists")
s.waitersMx.Unlock() s.waitersMx.Unlock()
s.messageHandler(stream.Context(), peerId, msg) s.messageHandler(stream.Context(), peerId, msg)
return return
} }
log.With("replyId", msg.ReplyId).Debug("reply id exists")
delete(s.waiters, msg.TrackingId) delete(s.waiters, msg.ReplyId)
s.waitersMx.Unlock() s.waitersMx.Unlock()
waiter.ch <- msg waiter.ch <- msg
} }
@ -213,6 +246,7 @@ func (s *streamPool) readPeerLoop(peerId string, stream spacesyncproto.SpaceStre
Loop: Loop:
for { for {
msg, err := stream.Recv() msg, err := stream.Recv()
s.lastUsage.Store(time.Now().Unix())
if err != nil { if err != nil {
break break
} }

View File

@ -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)
}
}

View File

@ -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...)
}

View 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)
}

View File

@ -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 package syncservice
import ( import (
"context" "context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "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/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/net/rpc/rpcerr"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ocache"
"time" "time"
) )
var log = logger.NewNamed("syncservice").Sugar() var log = logger.NewNamed("syncservice").Sugar()
type SyncService interface { type SyncService interface {
SyncClient() SyncClient ocache.ObjectLastUsage
synchandler.SyncHandler
StreamPool() StreamPool
Init() Init(getter objectgetter.ObjectGetter)
Close() (err error) Close() (err error)
} }
type HeadNotifiable interface {
UpdateHeads(id string, heads []string)
}
const respPeersStreamCheckInterval = time.Second * 10 const respPeersStreamCheckInterval = time.Second * 10
type syncService struct { type syncService struct {
spaceId string spaceId string
syncClient SyncClient streamPool StreamPool
clientFactory spacesyncproto.ClientFactory clientFactory spacesyncproto.ClientFactory
objectGetter objectgetter.ObjectGetter
streamLoopCtx context.Context streamLoopCtx context.Context
stopStreamLoop context.CancelFunc stopStreamLoop context.CancelFunc
@ -40,31 +40,25 @@ type syncService struct {
func NewSyncService( func NewSyncService(
spaceId string, spaceId string,
headNotifiable HeadNotifiable, confConnector nodeconf.ConfConnector) (syncService SyncService) {
cache cache.TreeCache,
configuration nodeconf.Configuration,
confConnector nodeconf.ConfConnector) SyncService {
var syncHandler SyncHandler
streamPool := newStreamPool(func(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) { 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() syncService = newSyncService(
syncClient := newSyncClient(spaceId, streamPool, headNotifiable, factory, configuration)
syncHandler = newSyncHandler(spaceId, cache, syncClient)
return newSyncService(
spaceId, spaceId,
syncClient, streamPool,
spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient), spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient),
confConnector) confConnector)
return
} }
func newSyncService( func newSyncService(
spaceId string, spaceId string,
syncClient SyncClient, streamPool StreamPool,
clientFactory spacesyncproto.ClientFactory, clientFactory spacesyncproto.ClientFactory,
connector nodeconf.ConfConnector) *syncService { connector nodeconf.ConfConnector) *syncService {
return &syncService{ return &syncService{
syncClient: syncClient, streamPool: streamPool,
connector: connector, connector: connector,
clientFactory: clientFactory, clientFactory: clientFactory,
spaceId: spaceId, 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()) s.streamLoopCtx, s.stopStreamLoop = context.WithCancel(context.Background())
go s.responsibleStreamCheckLoop(s.streamLoopCtx) go s.responsibleStreamCheckLoop(s.streamLoopCtx)
} }
@ -80,7 +75,19 @@ func (s *syncService) Init() {
func (s *syncService) Close() (err error) { func (s *syncService) Close() (err error) {
s.stopStreamLoop() s.stopStreamLoop()
<-s.streamLoopDone <-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) { func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) {
@ -91,7 +98,7 @@ func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) {
return return
} }
for _, peer := range respPeers { for _, peer := range respPeers {
if s.syncClient.HasActiveStream(peer.Id()) { if s.streamPool.HasActiveStream(peer.Id()) {
continue continue
} }
stream, err := s.clientFactory.Client(peer).Stream(ctx) 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) log.With("spaceId", s.spaceId).Errorf("failed to send first message to stream: %v", err)
continue 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 { func (s *syncService) StreamPool() StreamPool {
return s.syncClient return s.streamPool
} }

View 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)
}

View File

@ -1,40 +1,41 @@
package syncservice package synctree
import ( import (
"fmt" "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/tree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/slice" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/slice"
) )
type RequestFactory interface { type RequestFactory interface {
CreateHeadUpdate(t tree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *spacesyncproto.ObjectSyncMessage) CreateHeadUpdate(t tree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *treechangeproto.TreeSyncMessage)
CreateNewTreeRequest(id string) (msg *spacesyncproto.ObjectSyncMessage) CreateNewTreeRequest() (msg *treechangeproto.TreeSyncMessage)
CreateFullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (req *spacesyncproto.ObjectSyncMessage, err error) CreateFullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string) (req *treechangeproto.TreeSyncMessage, err error)
CreateFullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (*spacesyncproto.ObjectSyncMessage, error) CreateFullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string) (*treechangeproto.TreeSyncMessage, error)
} }
func newRequestFactory() RequestFactory { var sharedFactory = &requestFactory{}
return &requestFactory{}
func GetRequestFactory() RequestFactory {
return sharedFactory
} }
type requestFactory struct{} type requestFactory struct{}
func (r *requestFactory) CreateHeadUpdate(t tree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *spacesyncproto.ObjectSyncMessage) { func (r *requestFactory) CreateHeadUpdate(t tree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *treechangeproto.TreeSyncMessage) {
return spacesyncproto.WrapHeadUpdate(&spacesyncproto.ObjectHeadUpdate{ return treechangeproto.WrapHeadUpdate(&treechangeproto.TreeHeadUpdate{
Heads: t.Heads(), Heads: t.Heads(),
Changes: added, Changes: added,
SnapshotPath: t.SnapshotPath(), SnapshotPath: t.SnapshotPath(),
}, t.Header(), t.ID(), "") }, t.Header())
} }
func (r *requestFactory) CreateNewTreeRequest(id string) (msg *spacesyncproto.ObjectSyncMessage) { func (r *requestFactory) CreateNewTreeRequest() (msg *treechangeproto.TreeSyncMessage) {
return spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{}, nil, id, "") return treechangeproto.WrapFullRequest(&treechangeproto.TreeFullSyncRequest{}, nil)
} }
func (r *requestFactory) CreateFullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (msg *spacesyncproto.ObjectSyncMessage, err error) { func (r *requestFactory) CreateFullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string) (msg *treechangeproto.TreeSyncMessage, err error) {
req := &spacesyncproto.ObjectFullSyncRequest{} req := &treechangeproto.TreeFullSyncRequest{}
if t == nil { if t == nil {
return nil, fmt.Errorf("tree should not be empty") 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 req.Changes = changesAfterSnapshot
msg = spacesyncproto.WrapFullRequest(req, t.Header(), t.ID(), trackingId) msg = treechangeproto.WrapFullRequest(req, t.Header())
return return
} }
func (r *requestFactory) CreateFullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (msg *spacesyncproto.ObjectSyncMessage, err error) { func (r *requestFactory) CreateFullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string) (msg *treechangeproto.TreeSyncMessage, err error) {
resp := &spacesyncproto.ObjectFullSyncResponse{ resp := &treechangeproto.TreeFullSyncResponse{
Heads: t.Heads(), Heads: t.Heads(),
SnapshotPath: t.SnapshotPath(), SnapshotPath: t.SnapshotPath(),
} }
if slice.UnsortedEquals(theirHeads, t.Heads()) { if slice.UnsortedEquals(theirHeads, t.Heads()) {
msg = spacesyncproto.WrapFullResponse(resp, t.Header(), t.ID(), trackingId) msg = treechangeproto.WrapFullResponse(resp, t.Header())
return return
} }
@ -68,6 +69,6 @@ func (r *requestFactory) CreateFullSyncResponse(t tree.ObjectTree, theirHeads, t
return return
} }
resp.Changes = ourChanges resp.Changes = ourChanges
msg = spacesyncproto.WrapFullResponse(resp, t.Header(), t.ID(), trackingId) msg = treechangeproto.WrapFullResponse(resp, t.Header())
return return
} }

View 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
}

View File

@ -2,41 +2,84 @@ package synctree
import ( import (
"context" "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"
"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/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/list"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" "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/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 // SyncTree sends head updates to sync service and also sends new changes to update listener
type SyncTree struct { type SyncTree struct {
tree2.ObjectTree tree.ObjectTree
syncClient syncservice.SyncClient synchandler.SyncHandler
syncClient SyncClient
listener updatelistener.UpdateListener listener updatelistener.UpdateListener
isClosed bool
} }
var createDerivedObjectTree = tree2.CreateDerivedObjectTree var log = logger.NewNamed("commonspace.synctree").Sugar()
var createObjectTree = tree2.CreateObjectTree
var buildObjectTree = tree2.BuildObjectTree 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( func DeriveSyncTree(
ctx context.Context, ctx context.Context,
payload tree2.ObjectTreeCreatePayload, deps CreateDeps) (t tree.ObjectTree, err error) {
syncClient syncservice.SyncClient, t, err = createDerivedObjectTree(deps.Payload, deps.AclList, deps.CreateStorage)
listener updatelistener.UpdateListener,
aclList list.ACLList,
createStorage storage.TreeStorageCreatorFunc) (t tree2.ObjectTree, err error) {
t, err = createDerivedObjectTree(payload, aclList, createStorage)
if err != nil { if err != nil {
return return
} }
t = &SyncTree{ syncClient := createSyncClient(
deps.SpaceId,
deps.StreamPool,
deps.HeadNotifiable,
sharedFactory,
deps.Configuration)
syncTree := &SyncTree{
ObjectTree: t, ObjectTree: t,
syncClient: syncClient, syncClient: syncClient,
listener: listener, listener: deps.Listener,
} }
syncHandler := newSyncTreeHandler(syncTree, syncClient)
syncTree.SyncHandler = syncHandler
t = syncTree
headUpdate := syncClient.CreateHeadUpdate(t, nil) headUpdate := syncClient.CreateHeadUpdate(t, nil)
err = syncClient.BroadcastAsync(headUpdate) err = syncClient.BroadcastAsync(headUpdate)
@ -45,58 +88,134 @@ func DeriveSyncTree(
func CreateSyncTree( func CreateSyncTree(
ctx context.Context, ctx context.Context,
payload tree2.ObjectTreeCreatePayload, deps CreateDeps) (t tree.ObjectTree, err error) {
syncClient syncservice.SyncClient, t, err = createObjectTree(deps.Payload, deps.AclList, deps.CreateStorage)
listener updatelistener.UpdateListener,
aclList list.ACLList,
createStorage storage.TreeStorageCreatorFunc) (t tree2.ObjectTree, err error) {
t, err = createObjectTree(payload, aclList, createStorage)
if err != nil { if err != nil {
return return
} }
t = &SyncTree{ syncClient := createSyncClient(
deps.SpaceId,
deps.StreamPool,
deps.HeadNotifiable,
GetRequestFactory(),
deps.Configuration)
syncTree := &SyncTree{
ObjectTree: t, ObjectTree: t,
syncClient: syncClient, syncClient: syncClient,
listener: listener, listener: deps.Listener,
} }
syncHandler := newSyncTreeHandler(syncTree, syncClient)
syncTree.SyncHandler = syncHandler
t = syncTree
headUpdate := syncClient.CreateHeadUpdate(t, nil) headUpdate := syncClient.CreateHeadUpdate(t, nil)
err = syncClient.BroadcastAsync(headUpdate) err = syncClient.BroadcastAsync(headUpdate)
return return
} }
func BuildSyncTree( func BuildSyncTreeOrGetRemote(ctx context.Context, id string, deps BuildDeps) (t tree.ObjectTree, err error) {
ctx context.Context, getTreeRemote := func() (msg *treechangeproto.TreeSyncMessage, err error) {
syncClient syncservice.SyncClient, // TODO: add empty context handling (when this is not happening due to head update)
treeStorage storage.TreeStorage, peerId, err := syncservice.GetPeerIdFromStreamContext(ctx)
listener updatelistener.UpdateListener, if err != nil {
aclList list.ACLList) (t tree2.ObjectTree, err error) { return
return buildSyncTree(ctx, syncClient, treeStorage, listener, aclList) }
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( func buildSyncTree(
ctx context.Context, ctx context.Context,
syncClient syncservice.SyncClient, isFirstBuild bool,
treeStorage storage.TreeStorage, deps BuildDeps) (t tree.ObjectTree, err error) {
listener updatelistener.UpdateListener,
aclList list.ACLList) (t tree2.ObjectTree, err error) { t, err = buildObjectTree(deps.TreeStorage, deps.AclList)
t, err = buildObjectTree(treeStorage, aclList)
if err != nil { if err != nil {
return return
} }
t = &SyncTree{ syncClient := createSyncClient(
deps.SpaceId,
deps.StreamPool,
deps.HeadNotifiable,
GetRequestFactory(),
deps.Configuration)
syncTree := &SyncTree{
ObjectTree: t, ObjectTree: t,
syncClient: syncClient, 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 // 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 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) res, err = s.ObjectTree.AddContent(ctx, content)
if err != nil { if err != nil {
return return
@ -106,25 +225,41 @@ func (s *SyncTree) AddContent(ctx context.Context, content tree2.SignableChangeC
return 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...) res, err = s.ObjectTree.AddRawChanges(ctx, changes...)
if err != nil { if err != nil {
return return
} }
switch res.Mode { if s.listener != nil {
case tree2.Nothing: switch res.Mode {
return case tree.Nothing:
case tree2.Append: return
s.listener.Update(s) case tree.Append:
case tree2.Rebuild: s.listener.Update(s)
s.listener.Rebuild(s) case tree.Rebuild:
s.listener.Rebuild(s)
}
} }
//if res.Mode != tree.Nothing {
headUpdate := s.syncClient.CreateHeadUpdate(s, res.Added) headUpdate := s.syncClient.CreateHeadUpdate(s, res.Added)
err = s.syncClient.BroadcastAsync(headUpdate) err = s.syncClient.BroadcastAsync(headUpdate)
//}
return return
} }
func (s *SyncTree) Tree() tree2.ObjectTree { func (s *SyncTree) Close() (err error) {
return s 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
} }

View File

@ -2,16 +2,16 @@ package synctree
import ( import (
"context" "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"
"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"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener/mock_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"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list/mock_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" 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" tree "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
tree2 "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/tree/mock_objecttree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
@ -20,8 +20,8 @@ import (
) )
type syncTreeMatcher struct { type syncTreeMatcher struct {
objTree tree2.ObjectTree objTree tree.ObjectTree
client syncservice.SyncClient client SyncClient
listener updatelistener.UpdateListener listener updatelistener.UpdateListener
} }
@ -43,21 +43,25 @@ func Test_DeriveSyncTree(t *testing.T) {
defer ctrl.Finish() defer ctrl.Finish()
updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl) updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl)
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl) syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
aclListMock := mock_list.NewMockACLList(ctrl) aclListMock := mock_list.NewMockACLList(ctrl)
createStorage := storage2.TreeStorageCreatorFunc(func(payload storage2.TreeStorageCreatePayload) (storage2.TreeStorage, error) {
return nil, nil
})
objTreeMock := mock_tree.NewMockObjectTree(ctrl) 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, l, aclListMock)
require.Equal(t, expectedPayload, payload)
return objTreeMock, nil 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().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate)
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil) 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) require.NoError(t, err)
} }
@ -67,21 +71,25 @@ func Test_CreateSyncTree(t *testing.T) {
defer ctrl.Finish() defer ctrl.Finish()
updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl) updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl)
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl) syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
aclListMock := mock_list.NewMockACLList(ctrl) aclListMock := mock_list.NewMockACLList(ctrl)
createStorage := storage2.TreeStorageCreatorFunc(func(payload storage2.TreeStorageCreatePayload) (storage2.TreeStorage, error) {
return nil, nil
})
objTreeMock := mock_tree.NewMockObjectTree(ctrl) 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, l, aclListMock)
require.Equal(t, expectedPayload, payload)
return objTreeMock, nil 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().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate)
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil) 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) require.NoError(t, err)
} }
@ -91,27 +99,22 @@ func Test_BuildSyncTree(t *testing.T) {
defer ctrl.Finish() defer ctrl.Finish()
updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl) updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl)
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl) syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
aclListMock := mock_list.NewMockACLList(ctrl)
storageMock := mock_storage.NewMockTreeStorage(ctrl)
objTreeMock := mock_tree.NewMockObjectTree(ctrl) objTreeMock := mock_tree.NewMockObjectTree(ctrl)
buildObjectTree = func(store storage2.TreeStorage, l list.ACLList) (objTree tree2.ObjectTree, err error) { tr := &SyncTree{
require.Equal(t, aclListMock, l) ObjectTree: objTreeMock,
require.Equal(t, store, storageMock) SyncHandler: nil,
return objTreeMock, 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) { t.Run("AddRawChanges update", func(t *testing.T) {
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}} changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
expectedRes := tree2.AddResult{ expectedRes := tree.AddResult{
Added: changes, Added: changes,
Mode: tree2.Append, Mode: tree.Append,
} }
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)). objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)).
Return(expectedRes, nil) Return(expectedRes, nil)
@ -126,9 +129,9 @@ func Test_BuildSyncTree(t *testing.T) {
t.Run("AddRawChanges rebuild", func(t *testing.T) { t.Run("AddRawChanges rebuild", func(t *testing.T) {
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}} changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
expectedRes := tree2.AddResult{ expectedRes := tree.AddResult{
Added: changes, Added: changes,
Mode: tree2.Rebuild, Mode: tree.Rebuild,
} }
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)). objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)).
Return(expectedRes, nil) Return(expectedRes, nil)
@ -143,9 +146,9 @@ func Test_BuildSyncTree(t *testing.T) {
t.Run("AddRawChanges nothing", func(t *testing.T) { t.Run("AddRawChanges nothing", func(t *testing.T) {
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}} changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
expectedRes := tree2.AddResult{ expectedRes := tree.AddResult{
Added: changes, Added: changes,
Mode: tree2.Nothing, Mode: tree.Nothing,
} }
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)). objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)).
Return(expectedRes, nil) Return(expectedRes, nil)
@ -157,11 +160,11 @@ func Test_BuildSyncTree(t *testing.T) {
t.Run("AddContent", func(t *testing.T) { t.Run("AddContent", func(t *testing.T) {
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}} changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
content := tree2.SignableChangeContent{ content := tree.SignableChangeContent{
Data: []byte("abcde"), Data: []byte("abcde"),
} }
expectedRes := tree2.AddResult{ expectedRes := tree.AddResult{
Mode: tree2.Append, Mode: tree.Append,
Added: changes, Added: changes,
} }
objTreeMock.EXPECT().AddContent(gomock.Any(), gomock.Eq(content)). objTreeMock.EXPECT().AddContent(gomock.Any(), gomock.Eq(content)).

View 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...)
}

View File

@ -1,29 +1,19 @@
package syncservice package synctree
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/mock_synctree"
"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/pkg/acl/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/tree/mock_objecttree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/zap"
"sync" "sync"
"testing" "testing"
) )
type treeContainer struct {
objTree tree.ObjectTree
}
func (t treeContainer) Tree() tree.ObjectTree {
return t.objTree
}
type testObjTreeMock struct { type testObjTreeMock struct {
*mock_tree.MockObjectTree *mock_tree.MockObjectTree
m sync.Mutex m sync.Mutex
@ -48,28 +38,26 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
defer ctrl.Finish() defer ctrl.Finish()
ctx := context.Background() ctx := context.Background()
spaceId := "spaceId" syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
cacheMock := mock_cache.NewMockTreeCache(ctrl)
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(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) { t.Run("head update non empty all heads added", func(t *testing.T) {
treeId := "treeId" treeId := "treeId"
senderId := "senderId" senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{} chWithId := &treechangeproto.RawTreeChangeWithId{}
headUpdate := &spacesyncproto.ObjectHeadUpdate{ headUpdate := &treechangeproto.TreeHeadUpdate{
Heads: []string{"h1"}, Heads: []string{"h1"},
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId}, Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
SnapshotPath: []string{"h1"}, SnapshotPath: []string{"h1"},
} }
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "") treeMsg := treechangeproto.WrapHeadUpdate(headUpdate, chWithId)
cacheMock.EXPECT(). objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{ objectTreeMock.EXPECT().
Release: func() {}, ID().AnyTimes().Return(treeId)
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT(). objectTreeMock.EXPECT().
Heads(). Heads().
Return([]string{"h2"}) Return([]string{"h2"})
@ -86,7 +74,7 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
HasChanges(gomock.Eq([]string{"h1"})). HasChanges(gomock.Eq([]string{"h1"})).
Return(true) Return(true)
err := syncHandler.HandleMessage(ctx, senderId, msg) err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err) require.NoError(t, err)
}) })
@ -94,19 +82,17 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
treeId := "treeId" treeId := "treeId"
senderId := "senderId" senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{} chWithId := &treechangeproto.RawTreeChangeWithId{}
headUpdate := &spacesyncproto.ObjectHeadUpdate{ headUpdate := &treechangeproto.TreeHeadUpdate{
Heads: []string{"h1"}, Heads: []string{"h1"},
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId}, Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
SnapshotPath: []string{"h1"}, SnapshotPath: []string{"h1"},
} }
fullRequest := &spacesyncproto.ObjectSyncMessage{} treeMsg := treechangeproto.WrapHeadUpdate(headUpdate, chWithId)
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "") objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
cacheMock.EXPECT(). fullRequest := &treechangeproto.TreeSyncMessage{}
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{ objectTreeMock.EXPECT().
Release: func() {}, ID().AnyTimes().Return(treeId)
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT(). objectTreeMock.EXPECT().
Heads(). Heads().
Return([]string{"h2"}) Return([]string{"h2"})
@ -123,11 +109,15 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
HasChanges(gomock.Eq([]string{"h1"})). HasChanges(gomock.Eq([]string{"h1"})).
Return(false) Return(false)
syncClientMock.EXPECT(). 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) Return(fullRequest, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest)) syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Eq(fullRequest), gomock.Eq(""))
err := syncHandler.HandleMessage(ctx, senderId, msg)
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err) require.NoError(t, err)
}) })
@ -135,23 +125,21 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
treeId := "treeId" treeId := "treeId"
senderId := "senderId" senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{} chWithId := &treechangeproto.RawTreeChangeWithId{}
headUpdate := &spacesyncproto.ObjectHeadUpdate{ headUpdate := &treechangeproto.TreeHeadUpdate{
Heads: []string{"h1"}, Heads: []string{"h1"},
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId}, Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
SnapshotPath: []string{"h1"}, SnapshotPath: []string{"h1"},
} }
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "") treeMsg := treechangeproto.WrapHeadUpdate(headUpdate, chWithId)
cacheMock.EXPECT(). objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{ objectTreeMock.EXPECT().
Release: func() {}, ID().AnyTimes().Return(treeId)
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT(). objectTreeMock.EXPECT().
Heads(). Heads().
Return([]string{"h1"}) Return([]string{"h1"})
err := syncHandler.HandleMessage(ctx, senderId, msg) err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err) require.NoError(t, err)
}) })
@ -159,28 +147,30 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
treeId := "treeId" treeId := "treeId"
senderId := "senderId" senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{} chWithId := &treechangeproto.RawTreeChangeWithId{}
headUpdate := &spacesyncproto.ObjectHeadUpdate{ headUpdate := &treechangeproto.TreeHeadUpdate{
Heads: []string{"h1"}, Heads: []string{"h1"},
Changes: nil, Changes: nil,
SnapshotPath: []string{"h1"}, SnapshotPath: []string{"h1"},
} }
fullRequest := &spacesyncproto.ObjectSyncMessage{} treeMsg := treechangeproto.WrapHeadUpdate(headUpdate, chWithId)
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "") objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
cacheMock.EXPECT(). fullRequest := &treechangeproto.TreeSyncMessage{}
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{ objectTreeMock.EXPECT().
Release: func() {}, ID().AnyTimes().Return(treeId)
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT(). objectTreeMock.EXPECT().
Heads(). Heads().
Return([]string{"h2"}) Return([]string{"h2"})
syncClientMock.EXPECT(). 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) Return(fullRequest, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest)) syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Eq(fullRequest), gomock.Eq(""))
err := syncHandler.HandleMessage(ctx, senderId, msg)
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err) require.NoError(t, err)
}) })
@ -188,24 +178,21 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
treeId := "treeId" treeId := "treeId"
senderId := "senderId" senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{} chWithId := &treechangeproto.RawTreeChangeWithId{}
headUpdate := &spacesyncproto.ObjectHeadUpdate{ headUpdate := &treechangeproto.TreeHeadUpdate{
Heads: []string{"h1"}, Heads: []string{"h1"},
Changes: nil, Changes: nil,
SnapshotPath: []string{"h1"}, SnapshotPath: []string{"h1"},
} }
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "") treeMsg := treechangeproto.WrapHeadUpdate(headUpdate, chWithId)
cacheMock.EXPECT(). objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
GetTree(gomock.Any(), spaceId, treeId).
Return(cache.TreeResult{
Release: func() {},
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT().
ID().AnyTimes().Return(treeId)
objectTreeMock.EXPECT(). objectTreeMock.EXPECT().
Heads(). Heads().
Return([]string{"h1"}) Return([]string{"h1"})
err := syncHandler.HandleMessage(ctx, senderId, msg) err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err) require.NoError(t, err)
}) })
} }
@ -215,29 +202,26 @@ func TestSyncHandler_HandleFullSyncRequest(t *testing.T) {
defer ctrl.Finish() defer ctrl.Finish()
ctx := context.Background() ctx := context.Background()
spaceId := "spaceId" syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
cacheMock := mock_cache.NewMockTreeCache(ctrl)
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(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) { t.Run("full sync request with change", func(t *testing.T) {
treeId := "treeId" treeId := "treeId"
senderId := "senderId" senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{} chWithId := &treechangeproto.RawTreeChangeWithId{}
msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{ fullSyncRequest := &treechangeproto.TreeFullSyncRequest{
Heads: []string{"h1"}, Heads: []string{"h1"},
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId}, Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
SnapshotPath: []string{"h1"}, SnapshotPath: []string{"h1"},
}, chWithId, treeId, "") }
fullRequest := &spacesyncproto.ObjectSyncMessage{} treeMsg := treechangeproto.WrapFullRequest(fullSyncRequest, chWithId)
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
cacheMock.EXPECT(). fullResponse := &treechangeproto.TreeSyncMessage{}
GetTree(gomock.Any(), spaceId, treeId). objectTreeMock.EXPECT().
Return(cache.TreeResult{ ID().AnyTimes().Return(treeId)
Release: func() {}, objectTreeMock.EXPECT().Header().Return(nil)
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT(). objectTreeMock.EXPECT().
Heads(). Heads().
Return([]string{"h2"}) Return([]string{"h2"})
@ -248,11 +232,10 @@ func TestSyncHandler_HandleFullSyncRequest(t *testing.T) {
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})). AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
Return(tree.AddResult{}, nil) Return(tree.AddResult{}, nil)
syncClientMock.EXPECT(). syncClientMock.EXPECT().
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")). CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
Return(fullRequest, nil) Return(fullResponse, nil)
syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Eq(fullResponse), gomock.Eq(""))
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest)) err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
err := syncHandler.HandleMessage(ctx, senderId, msg)
require.NoError(t, err) require.NoError(t, err)
}) })
@ -260,72 +243,76 @@ func TestSyncHandler_HandleFullSyncRequest(t *testing.T) {
treeId := "treeId" treeId := "treeId"
senderId := "senderId" senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{} chWithId := &treechangeproto.RawTreeChangeWithId{}
msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{ fullSyncRequest := &treechangeproto.TreeFullSyncRequest{
Heads: []string{"h2"}, Heads: []string{"h1"},
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId}, Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
SnapshotPath: []string{"h2"}, SnapshotPath: []string{"h1"},
}, chWithId, treeId, "") }
fullRequest := &spacesyncproto.ObjectSyncMessage{} 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(). t.Run("full sync request without change but with reply id", func(t *testing.T) {
GetTree(gomock.Any(), spaceId, treeId). treeId := "treeId"
Return(cache.TreeResult{ senderId := "senderId"
Release: func() {}, replyId := "replyId"
TreeContainer: treeContainer{objectTreeMock}, chWithId := &treechangeproto.RawTreeChangeWithId{}
}, nil) 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(). objectTreeMock.EXPECT().
Heads(). Heads().
Return([]string{"h2"}) Return([]string{"h2"})
syncClientMock.EXPECT(). objectTreeMock.EXPECT().
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h2"}), gomock.Eq([]string{"h2"}), gomock.Eq("")). HasChanges(gomock.Eq([]string{"h1"})).
Return(fullRequest, nil) Return(false)
objectTreeMock.EXPECT().
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest)) AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
err := syncHandler.HandleMessage(ctx, senderId, msg) Return(tree.AddResult{}, fmt.Errorf(""))
require.NoError(t, err) syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Any(), gomock.Eq(""))
}) err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
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)
require.Error(t, err) require.Error(t, err)
}) })
} }
@ -335,28 +322,25 @@ func TestSyncHandler_HandleFullSyncResponse(t *testing.T) {
defer ctrl.Finish() defer ctrl.Finish()
ctx := context.Background() ctx := context.Background()
spaceId := "spaceId" syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
cacheMock := mock_cache.NewMockTreeCache(ctrl)
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(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) { t.Run("full sync response with change", func(t *testing.T) {
treeId := "treeId" treeId := "treeId"
senderId := "senderId" senderId := "senderId"
replyId := "replyId"
chWithId := &treechangeproto.RawTreeChangeWithId{} chWithId := &treechangeproto.RawTreeChangeWithId{}
msg := spacesyncproto.WrapFullResponse(&spacesyncproto.ObjectFullSyncResponse{ fullSyncResponse := &treechangeproto.TreeFullSyncResponse{
Heads: []string{"h1"}, Heads: []string{"h1"},
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId}, Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
SnapshotPath: []string{"h1"}, SnapshotPath: []string{"h1"},
}, chWithId, treeId, "") }
treeMsg := treechangeproto.WrapFullResponse(fullSyncResponse, chWithId)
cacheMock.EXPECT(). objectMsg, _ := marshallTreeMessage(treeMsg, treeId, replyId)
GetTree(gomock.Any(), spaceId, treeId). objectTreeMock.EXPECT().ID().AnyTimes().Return(treeId)
Return(cache.TreeResult{
Release: func() {},
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT(). objectTreeMock.EXPECT().
Heads(). Heads().
Return([]string{"h2"}) Return([]string{"h2"})
@ -367,31 +351,28 @@ func TestSyncHandler_HandleFullSyncResponse(t *testing.T) {
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})). AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
Return(tree.AddResult{}, nil) Return(tree.AddResult{}, nil)
err := syncHandler.HandleMessage(ctx, senderId, msg) err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err) 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" treeId := "treeId"
senderId := "senderId" senderId := "senderId"
replyId := "replyId"
chWithId := &treechangeproto.RawTreeChangeWithId{} chWithId := &treechangeproto.RawTreeChangeWithId{}
msg := spacesyncproto.WrapFullResponse(&spacesyncproto.ObjectFullSyncResponse{ fullSyncResponse := &treechangeproto.TreeFullSyncResponse{
Heads: []string{"h1"}, Heads: []string{"h1"},
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId}, Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
SnapshotPath: []string{"h1"}, SnapshotPath: []string{"h1"},
}, chWithId, treeId, "") }
treeMsg := treechangeproto.WrapFullResponse(fullSyncResponse, chWithId)
cacheMock.EXPECT(). objectMsg, _ := marshallTreeMessage(treeMsg, treeId, replyId)
GetTree(gomock.Any(), spaceId, treeId). objectTreeMock.EXPECT().ID().AnyTimes().Return(treeId)
Return(cache.TreeResult{
Release: func() {},
TreeContainer: treeContainer{objectTreeMock},
}, nil)
objectTreeMock.EXPECT(). objectTreeMock.EXPECT().
Heads(). Heads().
Return([]string{"h1"}) Return([]string{"h1"})
err := syncHandler.HandleMessage(ctx, senderId, msg) err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err) require.NoError(t, err)
}) })
} }

View File

@ -5,9 +5,9 @@
package mock_updatelistener package mock_updatelistener
import ( import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
reflect "reflect" reflect "reflect"
tree "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
) )

View File

@ -1,43 +1,43 @@
// Code generated by MockGen. DO NOT EDIT. // 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_treegetter is a generated GoMock package.
package mock_cache package mock_treegetter
import ( import (
context "context" context "context"
reflect "reflect" reflect "reflect"
app "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app" 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" gomock "github.com/golang/mock/gomock"
) )
// MockTreeCache is a mock of TreeCache interface. // MockTreeGetter is a mock of TreeGetter interface.
type MockTreeCache struct { type MockTreeGetter struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockTreeCacheMockRecorder recorder *MockTreeGetterMockRecorder
} }
// MockTreeCacheMockRecorder is the mock recorder for MockTreeCache. // MockTreeGetterMockRecorder is the mock recorder for MockTreeGetter.
type MockTreeCacheMockRecorder struct { type MockTreeGetterMockRecorder struct {
mock *MockTreeCache mock *MockTreeGetter
} }
// NewMockTreeCache creates a new mock instance. // NewMockTreeGetter creates a new mock instance.
func NewMockTreeCache(ctrl *gomock.Controller) *MockTreeCache { func NewMockTreeGetter(ctrl *gomock.Controller) *MockTreeGetter {
mock := &MockTreeCache{ctrl: ctrl} mock := &MockTreeGetter{ctrl: ctrl}
mock.recorder = &MockTreeCacheMockRecorder{mock} mock.recorder = &MockTreeGetterMockRecorder{mock}
return mock return mock
} }
// EXPECT returns an object that allows the caller to indicate expected use. // 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 return m.recorder
} }
// Close mocks base method. // Close mocks base method.
func (m *MockTreeCache) Close(arg0 context.Context) error { func (m *MockTreeGetter) Close(arg0 context.Context) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Close", arg0) ret := m.ctrl.Call(m, "Close", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
@ -45,28 +45,28 @@ func (m *MockTreeCache) Close(arg0 context.Context) error {
} }
// Close indicates an expected call of Close. // 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() 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. // 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() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetTree", arg0, arg1, arg2) ret := m.ctrl.Call(m, "GetTree", arg0, arg1, arg2)
ret0, _ := ret[0].(cache.TreeResult) ret0, _ := ret[0].(tree.ObjectTree)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// GetTree indicates an expected call of GetTree. // 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() 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. // Init mocks base method.
func (m *MockTreeCache) Init(arg0 *app.App) error { func (m *MockTreeGetter) Init(arg0 *app.App) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Init", arg0) ret := m.ctrl.Call(m, "Init", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
@ -74,13 +74,13 @@ func (m *MockTreeCache) Init(arg0 *app.App) error {
} }
// Init indicates an expected call of Init. // 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() 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. // Name mocks base method.
func (m *MockTreeCache) Name() string { func (m *MockTreeGetter) Name() string {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Name") ret := m.ctrl.Call(m, "Name")
ret0, _ := ret[0].(string) ret0, _ := ret[0].(string)
@ -88,13 +88,13 @@ func (m *MockTreeCache) Name() string {
} }
// Name indicates an expected call of Name. // Name indicates an expected call of Name.
func (mr *MockTreeCacheMockRecorder) Name() *gomock.Call { func (mr *MockTreeGetterMockRecorder) Name() *gomock.Call {
mr.mock.ctrl.T.Helper() 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. // Run mocks base method.
func (m *MockTreeCache) Run(arg0 context.Context) error { func (m *MockTreeGetter) Run(arg0 context.Context) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Run", arg0) ret := m.ctrl.Call(m, "Run", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
@ -102,7 +102,7 @@ func (m *MockTreeCache) Run(arg0 context.Context) error {
} }
// Run indicates an expected call of Run. // 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() 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)
} }

View 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)
}

View File

@ -54,3 +54,7 @@ func (c Config) GetGRPCServer() GrpcServer {
func (c Config) GetAccount() Account { func (c Config) GetAccount() Account {
return c.Account return c.Account
} }
func (c Config) GetMetric() Metric {
return c.Metric
}

View File

@ -54,7 +54,6 @@ func (p *pool) Init(a *app.App) (err error) {
ocache.WithLogger(log.Sugar()), ocache.WithLogger(log.Sugar()),
ocache.WithGCPeriod(time.Minute), ocache.WithGCPeriod(time.Minute),
ocache.WithTTL(time.Minute*5), ocache.WithTTL(time.Minute*5),
ocache.WithRefCounter(false),
) )
return nil return nil
} }

View File

@ -63,20 +63,17 @@ message ACLUserAdd {
ACLUserPermissions permissions = 4; ACLUserPermissions permissions = 4;
} }
// signing accept key
// rsa encryption key -> read keys
// accept key, encrypt key, invite id // accept key, encrypt key, invite id
// GetSpace(id) -> ... (space header + acl root) -> diff // GetSpace(id) -> ... (space header + acl root) -> diff
// Join(ACLJoinRecord) -> Ok // Join(ACLJoinRecord) -> Ok
//
message ACLUserInvite { message ACLUserInvite {
bytes acceptPublicKey = 1; bytes acceptPublicKey = 1;
// TODO: change to read key
bytes encryptPublicKey = 2; bytes encryptPublicKey = 2;
repeated bytes encryptedReadKeys = 3; repeated bytes encryptedReadKeys = 3;
ACLUserPermissions permissions = 4; 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; string inviteId = 5;
} }

View File

@ -5,10 +5,10 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "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/pkg/acl/common"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/encryptionkey" "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/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/symmetric"
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
"go.uber.org/zap" "go.uber.org/zap"
@ -30,17 +30,17 @@ var ErrIncorrectRoot = errors.New("incorrect root")
type UserPermissionPair struct { type UserPermissionPair struct {
Identity string Identity string
Permission aclrecordproto2.ACLUserPermissions Permission aclrecordproto.ACLUserPermissions
} }
type ACLState struct { type ACLState struct {
id string id string
currentReadKeyHash uint64 currentReadKeyHash uint64
userReadKeys map[uint64]*symmetric.Key userReadKeys map[uint64]*symmetric.Key
userStates map[string]*aclrecordproto2.ACLUserState userStates map[string]*aclrecordproto.ACLUserState
userInvites map[string]*aclrecordproto2.ACLUserInvite userInvites map[string]*aclrecordproto.ACLUserInvite
encryptionKey encryptionkey.PrivKey encryptionKey encryptionkey.PrivKey
signingKey signingkey2.PrivKey signingKey signingkey.PrivKey
identity string identity string
permissionsAtRecord map[string][]UserPermissionPair permissionsAtRecord map[string][]UserPermissionPair
@ -50,9 +50,9 @@ type ACLState struct {
func newACLStateWithKeys( func newACLStateWithKeys(
id string, id string,
signingKey signingkey2.PrivKey, signingKey signingkey.PrivKey,
encryptionKey encryptionkey.PrivKey) (*ACLState, error) { encryptionKey encryptionkey.PrivKey) (*ACLState, error) {
identity, err := signingKey.Raw() identity, err := signingKey.GetPublic().Raw()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -62,8 +62,8 @@ func newACLStateWithKeys(
signingKey: signingKey, signingKey: signingKey,
encryptionKey: encryptionKey, encryptionKey: encryptionKey,
userReadKeys: make(map[uint64]*symmetric.Key), userReadKeys: make(map[uint64]*symmetric.Key),
userStates: make(map[string]*aclrecordproto2.ACLUserState), userStates: make(map[string]*aclrecordproto.ACLUserState),
userInvites: make(map[string]*aclrecordproto2.ACLUserInvite), userInvites: make(map[string]*aclrecordproto.ACLUserInvite),
permissionsAtRecord: make(map[string][]UserPermissionPair), permissionsAtRecord: make(map[string][]UserPermissionPair),
}, nil }, nil
} }
@ -72,8 +72,8 @@ func newACLState(id string) *ACLState {
return &ACLState{ return &ACLState{
id: id, id: id,
userReadKeys: make(map[uint64]*symmetric.Key), userReadKeys: make(map[uint64]*symmetric.Key),
userStates: make(map[string]*aclrecordproto2.ACLUserState), userStates: make(map[string]*aclrecordproto.ACLUserState),
userInvites: make(map[string]*aclrecordproto2.ACLUserInvite), userInvites: make(map[string]*aclrecordproto.ACLUserInvite),
permissionsAtRecord: make(map[string][]UserPermissionPair), 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) { func (st *ACLState) applyRecord(record *ACLRecord) (err error) {
if record.Id == st.id { if record.Id == st.id {
root, ok := record.Model.(*aclrecordproto2.ACLRoot) root, ok := record.Model.(*aclrecordproto.ACLRoot)
if !ok { if !ok {
return ErrIncorrectRoot return ErrIncorrectRoot
} }
st.permissionsAtRecord[record.Id] = []UserPermissionPair{
{Identity: string(root.Identity), Permission: aclrecordproto.ACLUserPermissions_Admin},
}
return st.applyRoot(root) return st.applyRoot(root)
} }
aclData := &aclrecordproto2.ACLData{} aclData := &aclrecordproto.ACLData{}
if record.Model != nil { if record.Model != nil {
aclData = record.Model.(*aclrecordproto2.ACLData) aclData = record.Model.(*aclrecordproto.ACLData)
} else { } else {
err = proto.Unmarshal(record.Data, aclData) err = proto.Unmarshal(record.Data, aclData)
if err != nil { if err != nil {
@ -148,8 +151,8 @@ func (st *ACLState) applyRecord(record *ACLRecord) (err error) {
return nil return nil
} }
func (st *ACLState) applyRoot(root *aclrecordproto2.ACLRoot) (err error) { func (st *ACLState) applyRoot(root *aclrecordproto.ACLRoot) (err error) {
if st.signingKey != nil && st.encryptionKey != nil { if st.signingKey != nil && st.encryptionKey != nil && st.identity == string(root.Identity) {
err = st.saveReadKeyFromRoot(root) err = st.saveReadKeyFromRoot(root)
if err != nil { if err != nil {
return return
@ -157,16 +160,16 @@ func (st *ACLState) applyRoot(root *aclrecordproto2.ACLRoot) (err error) {
} }
// adding user to the list // adding user to the list
userState := &aclrecordproto2.ACLUserState{ userState := &aclrecordproto.ACLUserState{
Identity: root.Identity, Identity: root.Identity,
EncryptionKey: root.EncryptionKey, EncryptionKey: root.EncryptionKey,
Permissions: aclrecordproto2.ACLUserPermissions_Admin, Permissions: aclrecordproto.ACLUserPermissions_Admin,
} }
st.userStates[string(root.Identity)] = userState st.userStates[string(root.Identity)] = userState
return return
} }
func (st *ACLState) saveReadKeyFromRoot(root *aclrecordproto2.ACLRoot) (err error) { func (st *ACLState) saveReadKeyFromRoot(root *aclrecordproto.ACLRoot) (err error) {
var readKey *symmetric.Key var readKey *symmetric.Key
if len(root.GetDerivationScheme()) != 0 { if len(root.GetDerivationScheme()) != 0 {
var encPubKey []byte var encPubKey []byte
@ -175,7 +178,7 @@ func (st *ACLState) saveReadKeyFromRoot(root *aclrecordproto2.ACLRoot) (err erro
return return
} }
readKey, err = aclrecordproto2.ACLReadKeyDerive([]byte(st.identity), encPubKey) readKey, err = aclrecordproto.ACLReadKeyDerive([]byte(st.identity), encPubKey)
if err != nil { if err != nil {
return return
} }
@ -199,7 +202,7 @@ func (st *ACLState) saveReadKeyFromRoot(root *aclrecordproto2.ACLRoot) (err erro
return 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() { defer func() {
if err != nil { if err != nil {
return return
@ -214,7 +217,7 @@ func (st *ACLState) applyChangeData(changeData *aclrecordproto2.ACLData, hash ui
return 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) err = fmt.Errorf("user %s must have admin permissions", identity)
return return
} }
@ -230,7 +233,7 @@ func (st *ACLState) applyChangeData(changeData *aclrecordproto2.ACLData, hash ui
return nil return nil
} }
func (st *ACLState) applyChangeContent(ch *aclrecordproto2.ACLContentValue) error { func (st *ACLState) applyChangeContent(ch *aclrecordproto.ACLContentValue) error {
switch { switch {
case ch.GetUserPermissionChange() != nil: case ch.GetUserPermissionChange() != nil:
return st.applyUserPermissionChange(ch.GetUserPermissionChange()) 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) chIdentity := string(ch.Identity)
state, exists := st.userStates[chIdentity] state, exists := st.userStates[chIdentity]
if !exists { if !exists {
@ -258,12 +261,12 @@ func (st *ACLState) applyUserPermissionChange(ch *aclrecordproto2.ACLUserPermiss
return nil return nil
} }
func (st *ACLState) applyUserInvite(ch *aclrecordproto2.ACLUserInvite) error { func (st *ACLState) applyUserInvite(ch *aclrecordproto.ACLUserInvite) error {
st.userInvites[ch.InviteId] = ch st.userInvites[ch.InviteId] = ch
return nil return nil
} }
func (st *ACLState) applyUserJoin(ch *aclrecordproto2.ACLUserJoin) error { func (st *ACLState) applyUserJoin(ch *aclrecordproto.ACLUserJoin) error {
invite, exists := st.userInvites[ch.InviteId] invite, exists := st.userInvites[ch.InviteId]
if !exists { if !exists {
return fmt.Errorf("no such invite with id %s", ch.InviteId) 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 // validating signature
signature := ch.GetAcceptSignature() signature := ch.GetAcceptSignature()
verificationKey, err := signingkey2.NewSigningEd25519PubKeyFromBytes(invite.AcceptPublicKey) verificationKey, err := signingkey.NewSigningEd25519PubKeyFromBytes(invite.AcceptPublicKey)
if err != nil { if err != nil {
return fmt.Errorf("public key verifying invite accepts is given in incorrect format: %v", err) 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 { if err != nil {
return fmt.Errorf("verification returned error: %w", err) 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 // adding user to the list
userState := &aclrecordproto2.ACLUserState{ userState := &aclrecordproto.ACLUserState{
Identity: ch.Identity, Identity: ch.Identity,
EncryptionKey: ch.EncryptionKey, EncryptionKey: ch.EncryptionKey,
Permissions: invite.Permissions, Permissions: invite.Permissions,
@ -311,13 +314,13 @@ func (st *ACLState) applyUserJoin(ch *aclrecordproto2.ACLUserJoin) error {
return nil return nil
} }
func (st *ACLState) applyUserAdd(ch *aclrecordproto2.ACLUserAdd) error { func (st *ACLState) applyUserAdd(ch *aclrecordproto.ACLUserAdd) error {
chIdentity := string(ch.Identity) chIdentity := string(ch.Identity)
if _, exists := st.userStates[chIdentity]; exists { if _, exists := st.userStates[chIdentity]; exists {
return ErrUserAlreadyExists return ErrUserAlreadyExists
} }
st.userStates[chIdentity] = &aclrecordproto2.ACLUserState{ st.userStates[chIdentity] = &aclrecordproto.ACLUserState{
Identity: ch.Identity, Identity: ch.Identity,
EncryptionKey: ch.EncryptionKey, EncryptionKey: ch.EncryptionKey,
Permissions: ch.Permissions, Permissions: ch.Permissions,
@ -337,7 +340,7 @@ func (st *ACLState) applyUserAdd(ch *aclrecordproto2.ACLUserAdd) error {
return nil return nil
} }
func (st *ACLState) applyUserRemove(ch *aclrecordproto2.ACLUserRemove) error { func (st *ACLState) applyUserRemove(ch *aclrecordproto.ACLUserRemove) error {
chIdentity := string(ch.Identity) chIdentity := string(ch.Identity)
if chIdentity == st.identity { if chIdentity == st.identity {
return ErrDocumentForbidden return ErrDocumentForbidden
@ -381,7 +384,7 @@ func (st *ACLState) decryptReadKeyAndHash(msg []byte) (*symmetric.Key, uint64, e
return key, hasher.Sum64(), nil 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)] state, exists := st.userStates[string(identity)]
if !exists { if !exists {
return false return false
@ -390,17 +393,17 @@ func (st *ACLState) hasPermission(identity []byte, permission aclrecordproto2.AC
return state.Permissions == permission 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 // if we have a UserJoin, then it should always be the first one applied
return data.GetAclContent() != nil && data.GetAclContent()[0].GetUserJoin() != nil 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 // if we have a UserAdd, then it should always be the first one applied
userAdd := data.GetAclContent()[0].GetUserAdd() userAdd := data.GetAclContent()[0].GetUserAdd()
return data.GetAclContent() != nil && userAdd != nil && bytes.Compare(userAdd.GetIdentity(), identity) == 0 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 return st.userStates
} }

View File

@ -5,10 +5,10 @@
package mock_list package mock_list
import ( 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" 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" gomock "github.com/golang/mock/gomock"
) )
@ -36,10 +36,10 @@ func (m *MockACLList) EXPECT() *MockACLListMockRecorder {
} }
// ACLState mocks base method. // ACLState mocks base method.
func (m *MockACLList) ACLState() *list2.ACLState { func (m *MockACLList) ACLState() *list.ACLState {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ACLState") ret := m.ctrl.Call(m, "ACLState")
ret0, _ := ret[0].(*list2.ACLState) ret0, _ := ret[0].(*list.ACLState)
return ret0 return ret0
} }
@ -64,10 +64,10 @@ func (mr *MockACLListMockRecorder) Close() *gomock.Call {
} }
// Get mocks base method. // 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() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Get", arg0) ret := m.ctrl.Call(m, "Get", arg0)
ret0, _ := ret[0].(*list2.ACLRecord) ret0, _ := ret[0].(*list.ACLRecord)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@ -79,10 +79,10 @@ func (mr *MockACLListMockRecorder) Get(arg0 interface{}) *gomock.Call {
} }
// Head mocks base method. // Head mocks base method.
func (m *MockACLList) Head() *list2.ACLRecord { func (m *MockACLList) Head() *list.ACLRecord {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Head") ret := m.ctrl.Call(m, "Head")
ret0, _ := ret[0].(*list2.ACLRecord) ret0, _ := ret[0].(*list.ACLRecord)
return ret0 return ret0
} }
@ -122,7 +122,7 @@ func (mr *MockACLListMockRecorder) IsAfter(arg0, arg1 interface{}) *gomock.Call
} }
// Iterate mocks base method. // 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.T.Helper()
m.ctrl.Call(m, "Iterate", arg0) m.ctrl.Call(m, "Iterate", arg0)
} }
@ -134,7 +134,7 @@ func (mr *MockACLListMockRecorder) Iterate(arg0 interface{}) *gomock.Call {
} }
// IterateFrom mocks base method. // 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.T.Helper()
m.ctrl.Call(m, "IterateFrom", arg0, arg1) m.ctrl.Call(m, "IterateFrom", arg0, arg1)
} }
@ -182,10 +182,10 @@ func (mr *MockACLListMockRecorder) RUnlock() *gomock.Call {
} }
// Records mocks base method. // Records mocks base method.
func (m *MockACLList) Records() []*list2.ACLRecord { func (m *MockACLList) Records() []*list.ACLRecord {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Records") ret := m.ctrl.Call(m, "Records")
ret0, _ := ret[0].([]*list2.ACLRecord) ret0, _ := ret[0].([]*list.ACLRecord)
return ret0 return ret0
} }

View File

@ -6,10 +6,10 @@ package mock_storage
import ( import (
context "context" 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" 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" gomock "github.com/golang/mock/gomock"
) )

View File

@ -22,61 +22,25 @@ var _ = math.Inf
// proto package needs to be updated. // proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type PlainTextChange struct { type TextContent 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 {
// Types that are valid to be assigned to Value: // Types that are valid to be assigned to Value:
// //
// *PlainTextChange_Content_TextAppend // *TextContent_TextAppend
Value isPlainTextChange_Content_Value `protobuf_oneof:"value"` Value isTextContent_Value `protobuf_oneof:"value"`
} }
func (m *PlainTextChange_Content) Reset() { *m = PlainTextChange_Content{} } func (m *TextContent) Reset() { *m = TextContent{} }
func (m *PlainTextChange_Content) String() string { return proto.CompactTextString(m) } func (m *TextContent) String() string { return proto.CompactTextString(m) }
func (*PlainTextChange_Content) ProtoMessage() {} func (*TextContent) ProtoMessage() {}
func (*PlainTextChange_Content) Descriptor() ([]byte, []int) { func (*TextContent) Descriptor() ([]byte, []int) {
return fileDescriptor_37f33c266ada4318, []int{0, 0} 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) 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 { if deterministic {
return xxx_messageInfo_PlainTextChange_Content.Marshal(b, m, deterministic) return xxx_messageInfo_TextContent.Marshal(b, m, deterministic)
} else { } else {
b = b[:cap(b)] b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(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 return b[:n], nil
} }
} }
func (m *PlainTextChange_Content) XXX_Merge(src proto.Message) { func (m *TextContent) XXX_Merge(src proto.Message) {
xxx_messageInfo_PlainTextChange_Content.Merge(m, src) xxx_messageInfo_TextContent.Merge(m, src)
} }
func (m *PlainTextChange_Content) XXX_Size() int { func (m *TextContent) XXX_Size() int {
return m.Size() return m.Size()
} }
func (m *PlainTextChange_Content) XXX_DiscardUnknown() { func (m *TextContent) XXX_DiscardUnknown() {
xxx_messageInfo_PlainTextChange_Content.DiscardUnknown(m) xxx_messageInfo_TextContent.DiscardUnknown(m)
} }
var xxx_messageInfo_PlainTextChange_Content proto.InternalMessageInfo var xxx_messageInfo_TextContent proto.InternalMessageInfo
type isPlainTextChange_Content_Value interface { type isTextContent_Value interface {
isPlainTextChange_Content_Value() isTextContent_Value()
MarshalTo([]byte) (int, error) MarshalTo([]byte) (int, error)
Size() int Size() int
} }
type PlainTextChange_Content_TextAppend struct { type TextContent_TextAppend struct {
TextAppend *PlainTextChange_TextAppend `protobuf:"bytes,1,opt,name=textAppend,proto3,oneof" json:"textAppend,omitempty"` 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 { if m != nil {
return m.Value return m.Value
} }
return nil return nil
} }
func (m *PlainTextChange_Content) GetTextAppend() *PlainTextChange_TextAppend { func (m *TextContent) GetTextAppend() *TextAppend {
if x, ok := m.GetValue().(*PlainTextChange_Content_TextAppend); ok { if x, ok := m.GetValue().(*TextContent_TextAppend); ok {
return x.TextAppend return x.TextAppend
} }
return nil return nil
} }
// XXX_OneofWrappers is for the internal use of the proto package. // XXX_OneofWrappers is for the internal use of the proto package.
func (*PlainTextChange_Content) XXX_OneofWrappers() []interface{} { func (*TextContent) XXX_OneofWrappers() []interface{} {
return []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"` Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"`
} }
func (m *PlainTextChange_TextAppend) Reset() { *m = PlainTextChange_TextAppend{} } func (m *TextAppend) Reset() { *m = TextAppend{} }
func (m *PlainTextChange_TextAppend) String() string { return proto.CompactTextString(m) } func (m *TextAppend) String() string { return proto.CompactTextString(m) }
func (*PlainTextChange_TextAppend) ProtoMessage() {} func (*TextAppend) ProtoMessage() {}
func (*PlainTextChange_TextAppend) Descriptor() ([]byte, []int) { func (*TextAppend) Descriptor() ([]byte, []int) {
return fileDescriptor_37f33c266ada4318, []int{0, 1} 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) 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 { if deterministic {
return xxx_messageInfo_PlainTextChange_TextAppend.Marshal(b, m, deterministic) return xxx_messageInfo_TextAppend.Marshal(b, m, deterministic)
} else { } else {
b = b[:cap(b)] b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b) n, err := m.MarshalToSizedBuffer(b)
@ -156,41 +120,41 @@ func (m *PlainTextChange_TextAppend) XXX_Marshal(b []byte, deterministic bool) (
return b[:n], nil return b[:n], nil
} }
} }
func (m *PlainTextChange_TextAppend) XXX_Merge(src proto.Message) { func (m *TextAppend) XXX_Merge(src proto.Message) {
xxx_messageInfo_PlainTextChange_TextAppend.Merge(m, src) xxx_messageInfo_TextAppend.Merge(m, src)
} }
func (m *PlainTextChange_TextAppend) XXX_Size() int { func (m *TextAppend) XXX_Size() int {
return m.Size() return m.Size()
} }
func (m *PlainTextChange_TextAppend) XXX_DiscardUnknown() { func (m *TextAppend) XXX_DiscardUnknown() {
xxx_messageInfo_PlainTextChange_TextAppend.DiscardUnknown(m) 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 { if m != nil {
return m.Text return m.Text
} }
return "" return ""
} }
type PlainTextChange_Snapshot struct { type TextSnapshot struct {
Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"`
} }
func (m *PlainTextChange_Snapshot) Reset() { *m = PlainTextChange_Snapshot{} } func (m *TextSnapshot) Reset() { *m = TextSnapshot{} }
func (m *PlainTextChange_Snapshot) String() string { return proto.CompactTextString(m) } func (m *TextSnapshot) String() string { return proto.CompactTextString(m) }
func (*PlainTextChange_Snapshot) ProtoMessage() {} func (*TextSnapshot) ProtoMessage() {}
func (*PlainTextChange_Snapshot) Descriptor() ([]byte, []int) { func (*TextSnapshot) Descriptor() ([]byte, []int) {
return fileDescriptor_37f33c266ada4318, []int{0, 2} 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) 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 { if deterministic {
return xxx_messageInfo_PlainTextChange_Snapshot.Marshal(b, m, deterministic) return xxx_messageInfo_TextSnapshot.Marshal(b, m, deterministic)
} else { } else {
b = b[:cap(b)] b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b) n, err := m.MarshalToSizedBuffer(b)
@ -200,42 +164,42 @@ func (m *PlainTextChange_Snapshot) XXX_Marshal(b []byte, deterministic bool) ([]
return b[:n], nil return b[:n], nil
} }
} }
func (m *PlainTextChange_Snapshot) XXX_Merge(src proto.Message) { func (m *TextSnapshot) XXX_Merge(src proto.Message) {
xxx_messageInfo_PlainTextChange_Snapshot.Merge(m, src) xxx_messageInfo_TextSnapshot.Merge(m, src)
} }
func (m *PlainTextChange_Snapshot) XXX_Size() int { func (m *TextSnapshot) XXX_Size() int {
return m.Size() return m.Size()
} }
func (m *PlainTextChange_Snapshot) XXX_DiscardUnknown() { func (m *TextSnapshot) XXX_DiscardUnknown() {
xxx_messageInfo_PlainTextChange_Snapshot.DiscardUnknown(m) 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 { if m != nil {
return m.Text return m.Text
} }
return "" return ""
} }
type PlainTextChange_Data struct { type TextData struct {
Content []*PlainTextChange_Content `protobuf:"bytes,1,rep,name=content,proto3" json:"content,omitempty"` Content []*TextContent `protobuf:"bytes,1,rep,name=content,proto3" json:"content,omitempty"`
Snapshot *PlainTextChange_Snapshot `protobuf:"bytes,2,opt,name=snapshot,proto3" json:"snapshot,omitempty"` Snapshot *TextSnapshot `protobuf:"bytes,2,opt,name=snapshot,proto3" json:"snapshot,omitempty"`
} }
func (m *PlainTextChange_Data) Reset() { *m = PlainTextChange_Data{} } func (m *TextData) Reset() { *m = TextData{} }
func (m *PlainTextChange_Data) String() string { return proto.CompactTextString(m) } func (m *TextData) String() string { return proto.CompactTextString(m) }
func (*PlainTextChange_Data) ProtoMessage() {} func (*TextData) ProtoMessage() {}
func (*PlainTextChange_Data) Descriptor() ([]byte, []int) { func (*TextData) Descriptor() ([]byte, []int) {
return fileDescriptor_37f33c266ada4318, []int{0, 3} 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) 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 { if deterministic {
return xxx_messageInfo_PlainTextChange_Data.Marshal(b, m, deterministic) return xxx_messageInfo_TextData.Marshal(b, m, deterministic)
} else { } else {
b = b[:cap(b)] b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(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 return b[:n], nil
} }
} }
func (m *PlainTextChange_Data) XXX_Merge(src proto.Message) { func (m *TextData) XXX_Merge(src proto.Message) {
xxx_messageInfo_PlainTextChange_Data.Merge(m, src) xxx_messageInfo_TextData.Merge(m, src)
} }
func (m *PlainTextChange_Data) XXX_Size() int { func (m *TextData) XXX_Size() int {
return m.Size() return m.Size()
} }
func (m *PlainTextChange_Data) XXX_DiscardUnknown() { func (m *TextData) XXX_DiscardUnknown() {
xxx_messageInfo_PlainTextChange_Data.DiscardUnknown(m) 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 { if m != nil {
return m.Content return m.Content
} }
return nil return nil
} }
func (m *PlainTextChange_Data) GetSnapshot() *PlainTextChange_Snapshot { func (m *TextData) GetSnapshot() *TextSnapshot {
if m != nil { if m != nil {
return m.Snapshot return m.Snapshot
} }
@ -272,11 +236,10 @@ func (m *PlainTextChange_Data) GetSnapshot() *PlainTextChange_Snapshot {
} }
func init() { func init() {
proto.RegisterType((*PlainTextChange)(nil), "anytype.PlainTextChange") proto.RegisterType((*TextContent)(nil), "anytype.TextContent")
proto.RegisterType((*PlainTextChange_Content)(nil), "anytype.PlainTextChange.Content") proto.RegisterType((*TextAppend)(nil), "anytype.TextAppend")
proto.RegisterType((*PlainTextChange_TextAppend)(nil), "anytype.PlainTextChange.TextAppend") proto.RegisterType((*TextSnapshot)(nil), "anytype.TextSnapshot")
proto.RegisterType((*PlainTextChange_Snapshot)(nil), "anytype.PlainTextChange.Snapshot") proto.RegisterType((*TextData)(nil), "anytype.TextData")
proto.RegisterType((*PlainTextChange_Data)(nil), "anytype.PlainTextChange.Data")
} }
func init() { func init() {
@ -284,27 +247,26 @@ func init() {
} }
var fileDescriptor_37f33c266ada4318 = []byte{ 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, 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, 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, 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, 0xa6, 0x10, 0x7b, 0x62, 0x5e, 0x65, 0x49, 0x65, 0x41, 0xaa, 0x92, 0x2f, 0x17, 0x77, 0x48, 0x6a,
0x9c, 0xc4, 0xcc, 0xbc, 0x90, 0xd4, 0x8a, 0x12, 0x67, 0xb0, 0x72, 0xa9, 0x48, 0x2e, 0x76, 0xe7, 0x45, 0x89, 0x73, 0x7e, 0x5e, 0x49, 0x6a, 0x5e, 0x89, 0x90, 0x29, 0x17, 0x57, 0x49, 0x6a, 0x45,
0xfc, 0xbc, 0x92, 0xd4, 0xbc, 0x12, 0x21, 0x57, 0x2e, 0xae, 0x92, 0xd4, 0x8a, 0x12, 0xc7, 0x82, 0x89, 0x63, 0x41, 0x41, 0x6a, 0x5e, 0x8a, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xb7, 0x91, 0xb0, 0x1e,
0x82, 0xd4, 0xbc, 0x14, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x6e, 0x23, 0x65, 0x3d, 0xa8, 0x66, 0x3d, 0x54, 0xb1, 0x5e, 0x08, 0x5c, 0xca, 0x83, 0x21, 0x08, 0x49, 0xa1, 0x13, 0x3b, 0x17, 0x6b, 0x59,
0x34, 0x8d, 0x7a, 0x21, 0x70, 0xa5, 0x1e, 0x0c, 0x41, 0x48, 0x1a, 0x9d, 0xd8, 0xb9, 0x58, 0xcb, 0x62, 0x4e, 0x69, 0xaa, 0x92, 0x02, 0x17, 0x17, 0x42, 0x91, 0x90, 0x10, 0x17, 0x0b, 0x48, 0x11,
0x12, 0x73, 0x4a, 0x53, 0xa5, 0x14, 0xb8, 0xb8, 0x10, 0x8a, 0x84, 0x84, 0xb8, 0x58, 0x40, 0x8a, 0xd8, 0x1c, 0xce, 0x20, 0x30, 0x5b, 0x49, 0x89, 0x8b, 0x07, 0xa4, 0x22, 0x38, 0x2f, 0xb1, 0xa0,
0xc0, 0xe6, 0x72, 0x06, 0x81, 0xd9, 0x52, 0x72, 0x5c, 0x1c, 0xc1, 0x79, 0x89, 0x05, 0xc5, 0x19, 0x38, 0x23, 0xbf, 0x04, 0xab, 0x9a, 0x5c, 0x2e, 0x0e, 0x90, 0x1a, 0x97, 0xc4, 0x92, 0x44, 0x21,
0xf9, 0x25, 0x58, 0xe5, 0x1b, 0x19, 0xb9, 0x58, 0x5c, 0x12, 0x4b, 0x12, 0x85, 0xac, 0xb8, 0xd8, 0x3d, 0x2e, 0xf6, 0x64, 0x88, 0xe3, 0x24, 0x18, 0x15, 0x98, 0x35, 0xb8, 0x8d, 0x44, 0x50, 0x9c,
0x93, 0x21, 0xae, 0x94, 0x60, 0x54, 0x60, 0xd6, 0xe0, 0x36, 0x52, 0xc0, 0xe9, 0x2e, 0xa8, 0x6f, 0x03, 0x75, 0x78, 0x10, 0x4c, 0x91, 0x90, 0x21, 0x17, 0x47, 0x31, 0xd4, 0x6c, 0x09, 0x26, 0xb0,
0x82, 0x60, 0x1a, 0x84, 0x6c, 0xb9, 0x38, 0x8a, 0xa1, 0x96, 0x48, 0x30, 0x81, 0x3d, 0xa5, 0x88, 0xfb, 0x45, 0x51, 0x34, 0xc0, 0x2c, 0x0e, 0x82, 0x2b, 0x73, 0x52, 0x3d, 0xf1, 0x48, 0x8e, 0xf1,
0x53, 0x33, 0xcc, 0x35, 0x41, 0x70, 0x2d, 0x4e, 0xaa, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e,
0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0x6e, 0xa4, 0x40, 0x4c, 0x62, 0x03, 0x07, 0x9d, 0x31, 0x20,
0x2c, 0xc7, 0x10, 0xc5, 0x8d, 0x14, 0xea, 0x49, 0x6c, 0xe0, 0xb0, 0x36, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, 0xbf, 0x78, 0xe5, 0x6c, 0x01, 0x00, 0x00,
0xff, 0xff, 0xf8, 0x8c, 0x6a, 0x1d, 0x9d, 0x01, 0x00, 0x00,
} }
func (m *PlainTextChange) Marshal() (dAtA []byte, err error) { func (m *TextContent) Marshal() (dAtA []byte, err error) {
size := m.Size() size := m.Size()
dAtA = make([]byte, size) dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size]) n, err := m.MarshalToSizedBuffer(dAtA[:size])
@ -314,35 +276,12 @@ func (m *PlainTextChange) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil return dAtA[:n], nil
} }
func (m *PlainTextChange) MarshalTo(dAtA []byte) (int, error) { func (m *TextContent) MarshalTo(dAtA []byte) (int, error) {
size := m.Size() size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size]) return m.MarshalToSizedBuffer(dAtA[:size])
} }
func (m *PlainTextChange) MarshalToSizedBuffer(dAtA []byte) (int, error) { func (m *TextContent) 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) {
i := len(dAtA) i := len(dAtA)
_ = i _ = i
var l int var l int
@ -359,12 +298,12 @@ func (m *PlainTextChange_Content) MarshalToSizedBuffer(dAtA []byte) (int, error)
return len(dAtA) - i, nil 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() size := m.Size()
return m.MarshalToSizedBuffer(dAtA[: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) i := len(dAtA)
if m.TextAppend != nil { if m.TextAppend != nil {
{ {
@ -380,7 +319,7 @@ func (m *PlainTextChange_Content_TextAppend) MarshalToSizedBuffer(dAtA []byte) (
} }
return len(dAtA) - i, nil 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() size := m.Size()
dAtA = make([]byte, size) dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size]) n, err := m.MarshalToSizedBuffer(dAtA[:size])
@ -390,12 +329,12 @@ func (m *PlainTextChange_TextAppend) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil return dAtA[:n], nil
} }
func (m *PlainTextChange_TextAppend) MarshalTo(dAtA []byte) (int, error) { func (m *TextAppend) MarshalTo(dAtA []byte) (int, error) {
size := m.Size() size := m.Size()
return m.MarshalToSizedBuffer(dAtA[: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 := len(dAtA)
_ = i _ = i
var l int var l int
@ -410,7 +349,7 @@ func (m *PlainTextChange_TextAppend) MarshalToSizedBuffer(dAtA []byte) (int, err
return len(dAtA) - i, nil 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() size := m.Size()
dAtA = make([]byte, size) dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size]) n, err := m.MarshalToSizedBuffer(dAtA[:size])
@ -420,12 +359,12 @@ func (m *PlainTextChange_Snapshot) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil return dAtA[:n], nil
} }
func (m *PlainTextChange_Snapshot) MarshalTo(dAtA []byte) (int, error) { func (m *TextSnapshot) MarshalTo(dAtA []byte) (int, error) {
size := m.Size() size := m.Size()
return m.MarshalToSizedBuffer(dAtA[: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 := len(dAtA)
_ = i _ = i
var l int var l int
@ -440,7 +379,7 @@ func (m *PlainTextChange_Snapshot) MarshalToSizedBuffer(dAtA []byte) (int, error
return len(dAtA) - i, nil 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() size := m.Size()
dAtA = make([]byte, size) dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size]) n, err := m.MarshalToSizedBuffer(dAtA[:size])
@ -450,12 +389,12 @@ func (m *PlainTextChange_Data) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil return dAtA[:n], nil
} }
func (m *PlainTextChange_Data) MarshalTo(dAtA []byte) (int, error) { func (m *TextData) MarshalTo(dAtA []byte) (int, error) {
size := m.Size() size := m.Size()
return m.MarshalToSizedBuffer(dAtA[: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 := len(dAtA)
_ = i _ = i
var l int var l int
@ -500,16 +439,7 @@ func encodeVarintTest(dAtA []byte, offset int, v uint64) int {
dAtA[offset] = uint8(v) dAtA[offset] = uint8(v)
return base return base
} }
func (m *PlainTextChange) Size() (n int) { func (m *TextContent) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
return n
}
func (m *PlainTextChange_Content) Size() (n int) {
if m == nil { if m == nil {
return 0 return 0
} }
@ -521,7 +451,7 @@ func (m *PlainTextChange_Content) Size() (n int) {
return n return n
} }
func (m *PlainTextChange_Content_TextAppend) Size() (n int) { func (m *TextContent_TextAppend) Size() (n int) {
if m == nil { if m == nil {
return 0 return 0
} }
@ -533,7 +463,7 @@ func (m *PlainTextChange_Content_TextAppend) Size() (n int) {
} }
return n return n
} }
func (m *PlainTextChange_TextAppend) Size() (n int) { func (m *TextAppend) Size() (n int) {
if m == nil { if m == nil {
return 0 return 0
} }
@ -546,7 +476,7 @@ func (m *PlainTextChange_TextAppend) Size() (n int) {
return n return n
} }
func (m *PlainTextChange_Snapshot) Size() (n int) { func (m *TextSnapshot) Size() (n int) {
if m == nil { if m == nil {
return 0 return 0
} }
@ -559,7 +489,7 @@ func (m *PlainTextChange_Snapshot) Size() (n int) {
return n return n
} }
func (m *PlainTextChange_Data) Size() (n int) { func (m *TextData) Size() (n int) {
if m == nil { if m == nil {
return 0 return 0
} }
@ -584,7 +514,7 @@ func sovTest(x uint64) (n int) {
func sozTest(x uint64) (n int) { func sozTest(x uint64) (n int) {
return sovTest(uint64((x << 1) ^ uint64((int64(x) >> 63)))) 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) l := len(dAtA)
iNdEx := 0 iNdEx := 0
for iNdEx < l { for iNdEx < l {
@ -607,60 +537,10 @@ func (m *PlainTextChange) Unmarshal(dAtA []byte) error {
fieldNum := int32(wire >> 3) fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7) wireType := int(wire & 0x7)
if wireType == 4 { 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 { if fieldNum <= 0 {
return fmt.Errorf("proto: PlainTextChange: illegal tag %d (wire type %d)", fieldNum, wire) return fmt.Errorf("proto: TextContent: 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)
} }
switch fieldNum { switch fieldNum {
case 1: case 1:
@ -692,11 +572,11 @@ func (m *PlainTextChange_Content) Unmarshal(dAtA []byte) error {
if postIndex > l { if postIndex > l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
} }
v := &PlainTextChange_TextAppend{} v := &TextAppend{}
if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err return err
} }
m.Value = &PlainTextChange_Content_TextAppend{v} m.Value = &TextContent_TextAppend{v}
iNdEx = postIndex iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
@ -719,7 +599,7 @@ func (m *PlainTextChange_Content) Unmarshal(dAtA []byte) error {
} }
return nil return nil
} }
func (m *PlainTextChange_TextAppend) Unmarshal(dAtA []byte) error { func (m *TextAppend) Unmarshal(dAtA []byte) error {
l := len(dAtA) l := len(dAtA)
iNdEx := 0 iNdEx := 0
for iNdEx < l { for iNdEx < l {
@ -801,7 +681,7 @@ func (m *PlainTextChange_TextAppend) Unmarshal(dAtA []byte) error {
} }
return nil return nil
} }
func (m *PlainTextChange_Snapshot) Unmarshal(dAtA []byte) error { func (m *TextSnapshot) Unmarshal(dAtA []byte) error {
l := len(dAtA) l := len(dAtA)
iNdEx := 0 iNdEx := 0
for iNdEx < l { for iNdEx < l {
@ -824,10 +704,10 @@ func (m *PlainTextChange_Snapshot) Unmarshal(dAtA []byte) error {
fieldNum := int32(wire >> 3) fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7) wireType := int(wire & 0x7)
if wireType == 4 { 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 { 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 { switch fieldNum {
case 1: case 1:
@ -883,7 +763,7 @@ func (m *PlainTextChange_Snapshot) Unmarshal(dAtA []byte) error {
} }
return nil return nil
} }
func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error { func (m *TextData) Unmarshal(dAtA []byte) error {
l := len(dAtA) l := len(dAtA)
iNdEx := 0 iNdEx := 0
for iNdEx < l { for iNdEx < l {
@ -906,10 +786,10 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
fieldNum := int32(wire >> 3) fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7) wireType := int(wire & 0x7)
if wireType == 4 { 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 { 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 { switch fieldNum {
case 1: case 1:
@ -941,7 +821,7 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
if postIndex > l { if postIndex > l {
return io.ErrUnexpectedEOF 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 { if err := m.Content[len(m.Content)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err return err
} }
@ -976,7 +856,7 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
} }
if m.Snapshot == nil { if m.Snapshot == nil {
m.Snapshot = &PlainTextChange_Snapshot{} m.Snapshot = &TextSnapshot{}
} }
if err := m.Snapshot.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { if err := m.Snapshot.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err return err

View File

@ -2,23 +2,21 @@ syntax = "proto3";
package anytype; package anytype;
option go_package = "testchanges"; option go_package = "testchanges";
message PlainTextChange { message TextContent {
message Content { oneof value {
oneof value { TextAppend textAppend = 1;
TextAppend textAppend = 1;
}
} }
}
message TextAppend { message TextAppend {
string text = 1; string text = 1;
} }
message Snapshot { message TextSnapshot {
string text = 1; string text = 1;
} }
message Data { message TextData {
repeated Content content = 1; repeated TextContent content = 1;
Snapshot snapshot = 2; TextSnapshot snapshot = 2;
} }
}

View File

@ -71,6 +71,10 @@ func (c *changeBuilder) ConvertFromRaw(rawIdChange *treechangeproto.RawTreeChang
if err != nil { if err != nil {
return return
} }
ch, err = c.unmarshallRawChange(raw, rawIdChange.Id)
if err != nil {
return
}
if verify { if verify {
var identityKey signingkey.PubKey var identityKey signingkey.PubKey
@ -90,8 +94,7 @@ func (c *changeBuilder) ConvertFromRaw(rawIdChange *treechangeproto.RawTreeChang
return return
} }
} }
return
return c.unmarshallRawChange(raw, rawIdChange.Id)
} }
func (c *changeBuilder) SetRootRawChange(rawIdChange *treechangeproto.RawTreeChangeWithId) { func (c *changeBuilder) SetRootRawChange(rawIdChange *treechangeproto.RawTreeChangeWithId) {

View File

@ -53,6 +53,10 @@ func (v *objectTreeValidator) validateChange(tree *Tree, aclList list2.ACLList,
return return
} }
if c.Id == tree.RootId() {
return
}
// checking if the change refers to later acl heads than its previous ids // checking if the change refers to later acl heads than its previous ids
for _, id := range c.PreviousIds { for _, id := range c.PreviousIds {
prevChange := tree.attached[id] prevChange := tree.attached[id]

View File

@ -6,11 +6,11 @@ package mock_tree
import ( import (
context "context" 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" 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" gomock "github.com/golang/mock/gomock"
) )
@ -38,10 +38,10 @@ func (m *MockObjectTree) EXPECT() *MockObjectTreeMockRecorder {
} }
// AddContent mocks base method. // 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() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddContent", arg0, arg1) ret := m.ctrl.Call(m, "AddContent", arg0, arg1)
ret0, _ := ret[0].(tree2.AddResult) ret0, _ := ret[0].(tree.AddResult)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@ -53,14 +53,14 @@ func (mr *MockObjectTreeMockRecorder) AddContent(arg0, arg1 interface{}) *gomock
} }
// AddRawChanges mocks base method. // 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() m.ctrl.T.Helper()
varargs := []interface{}{arg0} varargs := []interface{}{arg0}
for _, a := range arg1 { for _, a := range arg1 {
varargs = append(varargs, a) varargs = append(varargs, a)
} }
ret := m.ctrl.Call(m, "AddRawChanges", varargs...) ret := m.ctrl.Call(m, "AddRawChanges", varargs...)
ret0, _ := ret[0].(tree2.AddResult) ret0, _ := ret[0].(tree.AddResult)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@ -177,7 +177,7 @@ func (mr *MockObjectTreeMockRecorder) ID() *gomock.Call {
} }
// Iterate mocks base method. // 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() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Iterate", arg0, arg1) ret := m.ctrl.Call(m, "Iterate", arg0, arg1)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
@ -191,7 +191,7 @@ func (mr *MockObjectTreeMockRecorder) Iterate(arg0, arg1 interface{}) *gomock.Ca
} }
// IterateFrom mocks base method. // 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() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IterateFrom", arg0, arg1, arg2) ret := m.ctrl.Call(m, "IterateFrom", arg0, arg1, arg2)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
@ -241,10 +241,10 @@ func (mr *MockObjectTreeMockRecorder) RUnlock() *gomock.Call {
} }
// Root mocks base method. // Root mocks base method.
func (m *MockObjectTree) Root() *tree2.Change { func (m *MockObjectTree) Root() *tree.Change {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Root") ret := m.ctrl.Call(m, "Root")
ret0, _ := ret[0].(*tree2.Change) ret0, _ := ret[0].(*tree.Change)
return ret0 return ret0
} }

View File

@ -177,6 +177,8 @@ func (ot *objectTree) AddContent(ctx context.Context, content SignableChangeCont
Added: []*treechangeproto.RawTreeChangeWithId{rawChange}, Added: []*treechangeproto.RawTreeChangeWithId{rawChange},
Mode: Append, Mode: Append,
} }
log.With("treeId", ot.id).With("head", objChange.Id).
Debug("finished adding content")
return return
} }

View File

@ -1,6 +1,7 @@
package tree package tree
import ( import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/common"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list"
storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
@ -54,10 +55,7 @@ func createObjectTree(
aclList list.ACLList, aclList list.ACLList,
createStorage storage2.TreeStorageCreatorFunc) (objTree ObjectTree, err error) { createStorage storage2.TreeStorageCreatorFunc) (objTree ObjectTree, err error) {
aclList.RLock() aclList.RLock()
var ( aclHeadId := aclList.Head().Id
deps = defaultObjectTreeDeps(nil, nil, aclList)
aclHeadId = aclList.Head().Id
)
aclList.RUnlock() aclList.RUnlock()
if err != nil { if err != nil {
@ -73,11 +71,10 @@ func createObjectTree(
Seed: seed, Seed: seed,
} }
_, raw, err := deps.changeBuilder.BuildInitialContent(cnt) _, raw, err := newChangeBuilder(common.NewKeychain(), nil).BuildInitialContent(cnt)
if err != nil { if err != nil {
return return
} }
deps.changeBuilder.SetRootRawChange(raw)
// create storage // create storage
st, err := createStorage(storage2.TreeStorageCreatePayload{ st, err := createStorage(storage2.TreeStorageCreatePayload{
@ -90,8 +87,7 @@ func createObjectTree(
return return
} }
deps.treeStorage = st return BuildObjectTree(st, aclList)
return buildObjectTree(deps)
} }
func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) { func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {

View File

@ -73,7 +73,9 @@ func (r *rawChangeLoader) LoadFromTree(t *Tree, breakpoints []string) ([]*treech
// now starting from breakpoints // now starting from breakpoints
stack = stack[:0] stack = stack[:0]
for _, h := range breakpoints { 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 // doing another dfs to get all changes before breakpoints, we need to exclude them from results

View File

@ -53,3 +53,44 @@ message RawTreeChangeWithId {
// Id is a cid made from rawChange payload // Id is a cid made from rawChange payload
string id = 2; 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;
}

View 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

View File

@ -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. // 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. // 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 package ldiff
import ( import (
@ -84,6 +85,10 @@ type Diff interface {
RemoveId(id string) error RemoveId(id string) error
// Diff makes diff with remote container // Diff makes diff with remote container
Diff(ctx context.Context, dl Remote) (newIds, changedIds, removedIds []string, err error) 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 // 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 // RemoveId removes element by id
func (d *diff) RemoveId(id string) error { func (d *diff) RemoveId(id string) error {
d.mu.Lock() 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) { func (d *diff) Ranges(ctx context.Context, ranges []Range, resBuf []RangeResult) (results []RangeResult, err error) {
d.mu.RLock() d.mu.RLock()
defer d.mu.RUnlock() defer d.mu.RUnlock()
results = resBuf[:0] results = resBuf[:0]
for _, r := range ranges { for _, r := range ranges {
results = append(results, d.getRange(r)) results = append(results, d.getRange(r))
@ -200,9 +236,6 @@ var errMismatched = errors.New("query and results mismatched")
// Diff makes diff with remote container // Diff makes diff with remote container
func (d *diff) Diff(ctx context.Context, dl Remote) (newIds, changedIds, removedIds []string, err error) { 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 := &diffCtx{}
dctx.toSend = append(dctx.toSend, Range{ dctx.toSend = append(dctx.toSend, Range{
From: 0, From: 0,
@ -216,10 +249,10 @@ func (d *diff) Diff(ctx context.Context, dl Remote) (newIds, changedIds, removed
return return
default: 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 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 return
} }
if len(dctx.otherRes) != len(dctx.toSend) || len(dctx.myRes) != len(dctx.toSend) { if len(dctx.otherRes) != len(dctx.toSend) || len(dctx.myRes) != len(dctx.toSend) {

View File

@ -6,9 +6,9 @@ package mock_ldiff
import ( import (
context "context" context "context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff"
reflect "reflect" reflect "reflect"
ldiff "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff"
gomock "github.com/golang/mock/gomock" 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) 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. // Ranges mocks base method.
func (m *MockDiff) Ranges(arg0 context.Context, arg1 []ldiff.Range, arg2 []ldiff.RangeResult) ([]ldiff.RangeResult, error) { func (m *MockDiff) Ranges(arg0 context.Context, arg1 []ldiff.Range, arg2 []ldiff.RangeResult) ([]ldiff.RangeResult, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()

View File

@ -46,7 +46,7 @@ var WithGCPeriod = func(gcPeriod time.Duration) Option {
var WithRefCounter = func(enable bool) Option { var WithRefCounter = func(enable bool) Option {
return func(cache *oCache) { return func(cache *oCache) {
cache.noRefCounter = !enable cache.refCounter = enable
} }
} }
@ -131,17 +131,17 @@ type OCache interface {
} }
type oCache struct { type oCache struct {
mu sync.Mutex mu sync.Mutex
data map[string]*entry data map[string]*entry
loadFunc LoadFunc loadFunc LoadFunc
timeNow func() time.Time timeNow func() time.Time
ttl time.Duration ttl time.Duration
gc time.Duration gc time.Duration
closed bool closed bool
closeCh chan struct{} closeCh chan struct{}
log *zap.SugaredLogger log *zap.SugaredLogger
metrics *metrics metrics *metrics
noRefCounter bool refCounter bool
} }
func (c *oCache) Get(ctx context.Context, id string) (value Object, err error) { func (c *oCache) Get(ctx context.Context, id string) (value Object, err error) {
@ -167,7 +167,7 @@ Load:
closing := e.isClosing closing := e.isClosing
if !e.isClosing { if !e.isClosing {
e.lastUsage = c.timeNow() e.lastUsage = c.timeNow()
if !c.noRefCounter { if c.refCounter {
e.refCount++ e.refCount++
} }
} }
@ -237,7 +237,7 @@ func (c *oCache) Release(id string) bool {
return false return false
} }
if e, ok := c.data[id]; ok { if e, ok := c.data[id]; ok {
if !c.noRefCounter && e.refCount > 0 { if c.refCounter && e.refCount > 0 {
e.refCount-- e.refCount--
return true return true
} }

View File

@ -119,7 +119,7 @@ func TestOCache_GC(t *testing.T) {
t.Run("test without close wait", func(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) { c := New(func(ctx context.Context, id string) (value Object, err error) {
return &testObject{name: id}, nil return &testObject{name: id}, nil
}, WithTTL(time.Millisecond*10)) }, WithTTL(time.Millisecond*10), WithRefCounter(true))
val, err := c.Get(context.TODO(), "id") val, err := c.Get(context.TODO(), "id")
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, val) 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) { c := New(func(ctx context.Context, id string) (value Object, err error) {
return NewTestObject(id, closeCh), nil return NewTestObject(id, closeCh), nil
}, WithTTL(time.Millisecond*10)) }, WithTTL(time.Millisecond*10), WithRefCounter(true))
val, err := c.Get(context.TODO(), "id") val, err := c.Get(context.TODO(), "id")
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, val) require.NotNil(t, val)

View File

@ -48,10 +48,8 @@ type service struct {
func (s *service) Init(a *app.App) (err error) { func (s *service) Init(a *app.App) (err error) {
s.db = a.MustComponent(db.CName).(db.Service) s.db = a.MustComponent(db.CName).(db.Service)
cacheOpts := []ocache.Option{ cacheOpts := []ocache.Option{
ocache.WithTTL(cacheTTL), ocache.WithTTL(cacheTTL),
ocache.WithRefCounter(false),
ocache.WithLogger(log.Named("cache").Sugar()), ocache.WithLogger(log.Named("cache").Sugar()),
} }
if ms := a.Component(metric.CName); ms != nil { if ms := a.Component(metric.CName); ms != nil {

36
etc/client.yml Normal file
View 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: {}

View File

@ -5,41 +5,32 @@ grpcServer:
- 127.0.0.1:4430 - 127.0.0.1:4430
tls: false tls: false
account: account:
peerId: 12D3KooWNGRznbh4RCYY1hDnG1RLCtWviWwVnZGjKHtsXVgPckNk peerId: 12D3KooWC9DkXiYK8MiQb87ffW51ggZR4FWASadh4UENXdaa16iz
signingKey: buHKTg4VF6lskoFWDdjtjWNj2c/fz0zAxKrOW05pRRu4+aw/tClrubW5wpeCOJxPSMHJBTj/8bJ8icwKfe7yMQ== signingKey: yfFJv5klknUeG8rROCNTktCk5rsBvz16aEanYBAl9oYii+Q8XwH8mVXr5hHSiP+HYxEaSSozlMAAXUjdW2vK5w==
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== 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: apiServer:
port: "8080" port: "8080"
nodes: nodes:
- peerId: 12D3KooWNGRznbh4RCYY1hDnG1RLCtWviWwVnZGjKHtsXVgPckNk - peerId: 12D3KooWC9DkXiYK8MiQb87ffW51ggZR4FWASadh4UENXdaa16iz
address: 127.0.0.1:4430 address: 127.0.0.1:4430
signingKey: buHKTg4VF6lskoFWDdjtjWNj2c/fz0zAxKrOW05pRRu4+aw/tClrubW5wpeCOJxPSMHJBTj/8bJ8icwKfe7yMQ== signingKey: yfFJv5klknUeG8rROCNTktCk5rsBvz16aEanYBAl9oYii+Q8XwH8mVXr5hHSiP+HYxEaSSozlMAAXUjdW2vK5w==
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== 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: 12D3KooWKtsepiMYrDtok7AU4itPcmHQaLuwzzfYYyjEW1KoLeXp - peerId: 12D3KooWC6sZYJXFagZtRjY4Jc4dzBLpEgYsUhJRauYheSAGk26y
address: 127.0.0.1:4431 address: 127.0.0.1:4431
signingKey: bqnCY+BB93A2nTM59zyP1CGZg5seSIeoGM/ATCOMy4+VvIfB1kwEK2VM5QVx3ub8zV/kqND8xuuQCC2NIrAFxw== signingKey: mLzjMshSbtOkUKZha0bNIHvW9nlqOPX6VM/mvKicx6kh8ebP2mfrkCS0qz5GwlFEqTgtuSnWsHdvGZnuan2Ahg==
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 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: 12D3KooWJ2259GQZxf1PBkLBR8J37QN4PMiLedBU9h5PNbUwfaXE - peerId: 12D3KooWFWyDckUJBtHtARzRDTRpo4XzeKAo8oN23MXh3Xwbp2fd
address: 127.0.0.1:4432 address: 127.0.0.1:4432
signingKey: RHl/cHYoPtAGXgJl7F3upI2OAnD4hd9aJztiqo08w/V52b3qKvFr2TWnpbNvBlXSxeyXpo4WB1jH+pMslW0irQ== signingKey: YpCGjsSuT8O6mkYTOExkdwNRODBaJ20hYJHFO/A/RUFUsUwxIME9X9FIp69VYvKuL6er973p0iG7UVVvLgLjnA==
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== 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==
- 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
space: space:
gcTTL: 60 gcTTL: 60
syncPeriod: 10 syncPeriod: 10
storage: storage:
path: db path: db
metric:
addr: ""
log:
production: false
defaultLevel: ""
namedLevels: {}

36
etc/configs/client1.yml Executable file
View 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
View 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: {}

View File

@ -3,9 +3,9 @@ grpcServer:
- 127.0.0.1:4530 - 127.0.0.1:4530
tls: false tls: false
account: account:
peerId: 12D3KooWJpE9AtG4RX4Dwm4vhrCGqiUhKj6Mvbqj2V4rV4diyksT peerId: 12D3KooWAB7hjh7KWdLz1nxkb8VQ4BU9ZfMwjAFNyBB9NnJCw7AP
signingKey: 6tA9VizrAMtsZlzBXXnsg+LzwSwBLU7oiVP1qOHN4PaFsBslV0nt2aKBXfcfxp17V/bvydNfyYbGu50F6spLCg== signingKey: vE+fJjNKXf7y8hW7IXerySK+Fr8b/9WRThM5/tBxww4FUNczjvzd67XXrdvOdZtYQ+QTDfwItNbLwbzLTEMOeA==
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 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: mongo:
connect: mongodb://localhost:27017/?w=majority connect: mongodb://localhost:27017/?w=majority
database: consensus database: consensus

View File

@ -3,9 +3,9 @@ grpcServer:
- 127.0.0.1:4531 - 127.0.0.1:4531
tls: false tls: false
account: account:
peerId: 12D3KooWCeSDwgmdmLMweWKf1avCqaBYuzEo5GpMGa8MBBskBmen peerId: 12D3KooWG3ZrWs8Q3kQhQeXp8RWw8FKb2cThTFwD1nbRMMNzf2xW
signingKey: N8fkrWmuf1wVxL72XE4Di8pSyTaQpev/9NV4eznVcfoqB9Z+urz0kg1NKJjWisC/nUGdJP9EB5ZhgPyuQfqIvw== signingKey: P3a0z3Um1QJ2lEwqcaNkVXwMaFz/Xmb2na4RqO79Lw5ch+KZVitiA6jifmRQkPm4z8e1wIf7Eel1VnhuhRuZVw==
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+ 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: mongo:
connect: mongodb://localhost:27017/?w=majority connect: mongodb://localhost:27017/?w=majority
database: consensus database: consensus

View File

@ -3,9 +3,9 @@ grpcServer:
- 127.0.0.1:4532 - 127.0.0.1:4532
tls: false tls: false
account: account:
peerId: 12D3KooWGqsXf6No926wTb2eZdauqDcEkoAdKCeYkNzT6yrL3YDE peerId: 12D3KooWS6PKUYH6Jedkjsut9ajgWSvn53Qz1LLACoPJX6dUbtCg
signingKey: fSLDcrMD0v+yzQwHG+KWdCkuZ5HPvx3vIb+5MecREc5oZJZfrN9P2z8gBU8HqZH/noB4aJRjXRVZsy4M5jPcwQ== signingKey: 11vXVlqQr2e/XMKALUPhMgnJEtZ1HKaDerxXvhNvYfXx1ZWt16PoEMpy/+ZHA1gw3ErI9+2/6auhjGC9InHskQ==
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 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: mongo:
connect: mongodb://localhost:27017/?w=majority connect: mongodb://localhost:27017/?w=majority
database: consensus database: consensus

View File

@ -5,39 +5,24 @@ grpcServer:
- 127.0.0.1:4430 - 127.0.0.1:4430
tls: false tls: false
account: account:
peerId: 12D3KooWRqbgXAdsP9zzBeKv6qjqmW9qfo7TbQfTi4eYYCcpFBwT peerId: 12D3KooWC9DkXiYK8MiQb87ffW51ggZR4FWASadh4UENXdaa16iz
signingKey: 4JPubXZ2chIF3SFYiEGHvdTs7/B+IbrdUCHWYkNH/E7uC9nsnBle8q/FaG/7b6pNKjXukTGaXnDrSixZw343/g== signingKey: yfFJv5klknUeG8rROCNTktCk5rsBvz16aEanYBAl9oYii+Q8XwH8mVXr5hHSiP+HYxEaSSozlMAAXUjdW2vK5w==
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== 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: apiServer:
port: "8080" port: "8080"
nodes: nodes:
- peerId: 12D3KooWRqbgXAdsP9zzBeKv6qjqmW9qfo7TbQfTi4eYYCcpFBwT - peerId: 12D3KooWC9DkXiYK8MiQb87ffW51ggZR4FWASadh4UENXdaa16iz
address: 127.0.0.1:4430 address: 127.0.0.1:4430
signingKey: 4JPubXZ2chIF3SFYiEGHvdTs7/B+IbrdUCHWYkNH/E7uC9nsnBle8q/FaG/7b6pNKjXukTGaXnDrSixZw343/g== signingKey: yfFJv5klknUeG8rROCNTktCk5rsBvz16aEanYBAl9oYii+Q8XwH8mVXr5hHSiP+HYxEaSSozlMAAXUjdW2vK5w==
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== 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: 12D3KooWFYTh59WMXGLDqS8EXfTjHvrS9uXrcYJuE6yDyL1hh45R - peerId: 12D3KooWC6sZYJXFagZtRjY4Jc4dzBLpEgYsUhJRauYheSAGk26y
address: 127.0.0.1:4431 address: 127.0.0.1:4431
signingKey: g673H1+gh/KSbRat4m+E+UBTxEmcbxNJ2ZEwdBnQKiFVExLIU7FUXhx7F7xw2QJOw4CInWK6tNZZRNAzOWcD7A== signingKey: mLzjMshSbtOkUKZha0bNIHvW9nlqOPX6VM/mvKicx6kh8ebP2mfrkCS0qz5GwlFEqTgtuSnWsHdvGZnuan2Ahg==
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 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: 12D3KooWHgeiz7EyY59t5fEZnkdg2gJxk3YvJmxpVibEcX2EtUcp - peerId: 12D3KooWFWyDckUJBtHtARzRDTRpo4XzeKAo8oN23MXh3Xwbp2fd
address: 127.0.0.1:4432 address: 127.0.0.1:4432
signingKey: Tr1OaCpnYVkdeuyoBHAETn3DHWbQZELK2x5xuvd5301045GYTnQdWWT/05UB61dmu1NcY4yznm90baj36GrgUQ== signingKey: YpCGjsSuT8O6mkYTOExkdwNRODBaJ20hYJHFO/A/RUFUsUwxIME9X9FIp69VYvKuL6er973p0iG7UVVvLgLjnA==
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== 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==
- 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
space: space:
gcTTL: 60 gcTTL: 60
syncPeriod: 10 syncPeriod: 10

View File

@ -5,39 +5,24 @@ grpcServer:
- 127.0.0.1:4431 - 127.0.0.1:4431
tls: false tls: false
account: account:
peerId: 12D3KooWFYTh59WMXGLDqS8EXfTjHvrS9uXrcYJuE6yDyL1hh45R peerId: 12D3KooWC6sZYJXFagZtRjY4Jc4dzBLpEgYsUhJRauYheSAGk26y
signingKey: g673H1+gh/KSbRat4m+E+UBTxEmcbxNJ2ZEwdBnQKiFVExLIU7FUXhx7F7xw2QJOw4CInWK6tNZZRNAzOWcD7A== signingKey: mLzjMshSbtOkUKZha0bNIHvW9nlqOPX6VM/mvKicx6kh8ebP2mfrkCS0qz5GwlFEqTgtuSnWsHdvGZnuan2Ahg==
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 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: apiServer:
port: "8081" port: "8081"
nodes: nodes:
- peerId: 12D3KooWRqbgXAdsP9zzBeKv6qjqmW9qfo7TbQfTi4eYYCcpFBwT - peerId: 12D3KooWC9DkXiYK8MiQb87ffW51ggZR4FWASadh4UENXdaa16iz
address: 127.0.0.1:4430 address: 127.0.0.1:4430
signingKey: 4JPubXZ2chIF3SFYiEGHvdTs7/B+IbrdUCHWYkNH/E7uC9nsnBle8q/FaG/7b6pNKjXukTGaXnDrSixZw343/g== signingKey: yfFJv5klknUeG8rROCNTktCk5rsBvz16aEanYBAl9oYii+Q8XwH8mVXr5hHSiP+HYxEaSSozlMAAXUjdW2vK5w==
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== 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: 12D3KooWFYTh59WMXGLDqS8EXfTjHvrS9uXrcYJuE6yDyL1hh45R - peerId: 12D3KooWC6sZYJXFagZtRjY4Jc4dzBLpEgYsUhJRauYheSAGk26y
address: 127.0.0.1:4431 address: 127.0.0.1:4431
signingKey: g673H1+gh/KSbRat4m+E+UBTxEmcbxNJ2ZEwdBnQKiFVExLIU7FUXhx7F7xw2QJOw4CInWK6tNZZRNAzOWcD7A== signingKey: mLzjMshSbtOkUKZha0bNIHvW9nlqOPX6VM/mvKicx6kh8ebP2mfrkCS0qz5GwlFEqTgtuSnWsHdvGZnuan2Ahg==
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 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: 12D3KooWHgeiz7EyY59t5fEZnkdg2gJxk3YvJmxpVibEcX2EtUcp - peerId: 12D3KooWFWyDckUJBtHtARzRDTRpo4XzeKAo8oN23MXh3Xwbp2fd
address: 127.0.0.1:4432 address: 127.0.0.1:4432
signingKey: Tr1OaCpnYVkdeuyoBHAETn3DHWbQZELK2x5xuvd5301045GYTnQdWWT/05UB61dmu1NcY4yznm90baj36GrgUQ== signingKey: YpCGjsSuT8O6mkYTOExkdwNRODBaJ20hYJHFO/A/RUFUsUwxIME9X9FIp69VYvKuL6er973p0iG7UVVvLgLjnA==
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== 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==
- 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
space: space:
gcTTL: 60 gcTTL: 60
syncPeriod: 10 syncPeriod: 10

View File

@ -5,39 +5,24 @@ grpcServer:
- 127.0.0.1:4432 - 127.0.0.1:4432
tls: false tls: false
account: account:
peerId: 12D3KooWHgeiz7EyY59t5fEZnkdg2gJxk3YvJmxpVibEcX2EtUcp peerId: 12D3KooWFWyDckUJBtHtARzRDTRpo4XzeKAo8oN23MXh3Xwbp2fd
signingKey: Tr1OaCpnYVkdeuyoBHAETn3DHWbQZELK2x5xuvd5301045GYTnQdWWT/05UB61dmu1NcY4yznm90baj36GrgUQ== signingKey: YpCGjsSuT8O6mkYTOExkdwNRODBaJ20hYJHFO/A/RUFUsUwxIME9X9FIp69VYvKuL6er973p0iG7UVVvLgLjnA==
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== 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: apiServer:
port: "8082" port: "8082"
nodes: nodes:
- peerId: 12D3KooWRqbgXAdsP9zzBeKv6qjqmW9qfo7TbQfTi4eYYCcpFBwT - peerId: 12D3KooWC9DkXiYK8MiQb87ffW51ggZR4FWASadh4UENXdaa16iz
address: 127.0.0.1:4430 address: 127.0.0.1:4430
signingKey: 4JPubXZ2chIF3SFYiEGHvdTs7/B+IbrdUCHWYkNH/E7uC9nsnBle8q/FaG/7b6pNKjXukTGaXnDrSixZw343/g== signingKey: yfFJv5klknUeG8rROCNTktCk5rsBvz16aEanYBAl9oYii+Q8XwH8mVXr5hHSiP+HYxEaSSozlMAAXUjdW2vK5w==
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== 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: 12D3KooWFYTh59WMXGLDqS8EXfTjHvrS9uXrcYJuE6yDyL1hh45R - peerId: 12D3KooWC6sZYJXFagZtRjY4Jc4dzBLpEgYsUhJRauYheSAGk26y
address: 127.0.0.1:4431 address: 127.0.0.1:4431
signingKey: g673H1+gh/KSbRat4m+E+UBTxEmcbxNJ2ZEwdBnQKiFVExLIU7FUXhx7F7xw2QJOw4CInWK6tNZZRNAzOWcD7A== signingKey: mLzjMshSbtOkUKZha0bNIHvW9nlqOPX6VM/mvKicx6kh8ebP2mfrkCS0qz5GwlFEqTgtuSnWsHdvGZnuan2Ahg==
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 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: 12D3KooWHgeiz7EyY59t5fEZnkdg2gJxk3YvJmxpVibEcX2EtUcp - peerId: 12D3KooWFWyDckUJBtHtARzRDTRpo4XzeKAo8oN23MXh3Xwbp2fd
address: 127.0.0.1:4432 address: 127.0.0.1:4432
signingKey: Tr1OaCpnYVkdeuyoBHAETn3DHWbQZELK2x5xuvd5301045GYTnQdWWT/05UB61dmu1NcY4yznm90baj36GrgUQ== signingKey: YpCGjsSuT8O6mkYTOExkdwNRODBaJ20hYJHFO/A/RUFUsUwxIME9X9FIp69VYvKuL6er973p0iG7UVVvLgLjnA==
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== 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==
- 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
space: space:
gcTTL: 60 gcTTL: 60
syncPeriod: 10 syncPeriod: 10

View File

@ -8,6 +8,7 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "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/commonspace"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/config" "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/dialer"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool" "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/rpc/server"
@ -91,6 +92,7 @@ func main() {
func Bootstrap(a *app.App) { func Bootstrap(a *app.App) {
a.Register(account.New()). a.Register(account.New()).
Register(metric.New()).
Register(storage.New()). Register(storage.New()).
Register(nodecache.New(200)). Register(nodecache.New(200)).
Register(nodeconf.New()). Register(nodeconf.New()).
@ -100,10 +102,4 @@ func Bootstrap(a *app.App) {
Register(nodespace.New()). Register(nodespace.New()).
Register(commonspace.New()). Register(commonspace.New()).
Register(server.New()) Register(server.New())
//Register(document.New()).
//Register(message.New()).
//Register(requesthandler.New()).
//Register(treecache.New()).
//Register(api.New())
} }

View File

@ -5,7 +5,8 @@ import (
"errors" "errors"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app" "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/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/common/pkg/ocache"
"github.com/anytypeio/go-anytype-infrastructure-experiments/node/nodespace" "github.com/anytypeio/go-anytype-infrastructure-experiments/node/nodespace"
"time" "time"
@ -24,7 +25,7 @@ type treeCache struct {
nodeService nodespace.Service nodeService nodespace.Service
} }
func New(ttl int) cache.TreeCache { func New(ttl int) treegetter.TreeGetter {
return &treeCache{ return &treeCache{
gcttl: ttl, gcttl: ttl,
} }
@ -52,34 +53,20 @@ func (c *treeCache) Init(a *app.App) (err error) {
ocache.WithLogger(log.Sugar()), ocache.WithLogger(log.Sugar()),
ocache.WithGCPeriod(time.Minute), ocache.WithGCPeriod(time.Minute),
ocache.WithTTL(time.Duration(c.gcttl)*time.Second), ocache.WithTTL(time.Duration(c.gcttl)*time.Second),
ocache.WithRefCounter(false),
) )
return nil return nil
} }
func (c *treeCache) Name() (name string) { 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) { func (c *treeCache) GetTree(ctx context.Context, spaceId, id string) (tr tree.ObjectTree, err error) {
var cacheRes ocache.Object
ctx = context.WithValue(ctx, spaceKey, spaceId) ctx = context.WithValue(ctx, spaceKey, spaceId)
cacheRes, err = c.cache.Get(ctx, id) value, err := c.cache.Get(ctx, id)
if err != nil { if err != nil {
return cache.TreeResult{}, err
}
treeContainer, ok := cacheRes.(cache.TreeContainer)
if !ok {
err = ErrCacheObjectWithoutTree
return return
} }
tr = value.(tree.ObjectTree)
res = cache.TreeResult{
Release: func() {
c.cache.Release(id)
},
TreeContainer: treeContainer,
}
return return
} }

View File

@ -2,9 +2,9 @@ package nodespace
import ( import (
"context" "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/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
) )
type rpcHandler struct { type rpcHandler struct {
@ -17,16 +17,19 @@ func (r *rpcHandler) PushSpace(ctx context.Context, req *spacesyncproto.PushSpac
err = spacesyncproto.ErrSpaceExists err = spacesyncproto.ErrSpaceExists
return return
} }
if err != cache.ErrSpaceNotFound { if err != storage.ErrSpaceStorageMissing {
err = spacesyncproto.ErrUnexpected err = spacesyncproto.ErrUnexpected
return return
} }
payload := storage.SpaceStorageCreatePayload{ payload := storage.SpaceStorageCreatePayload{
RecWithId: req.AclRoot, RecWithId: &aclrecordproto.RawACLRecordWithId{
Payload: req.AclPayload,
Id: req.AclPayloadId,
},
SpaceHeaderWithId: req.SpaceHeader, SpaceHeaderWithId: req.SpaceHeader,
} }
_, err = r.s.spaceStorageProvider.CreateSpaceStorage(payload) st, err := r.s.spaceStorageProvider.CreateSpaceStorage(payload)
if err != nil { if err != nil {
err = spacesyncproto.ErrUnexpected err = spacesyncproto.ErrUnexpected
if err == storage.ErrSpaceStorageExists { if err == storage.ErrSpaceStorageExists {
@ -34,6 +37,7 @@ func (r *rpcHandler) PushSpace(ctx context.Context, req *spacesyncproto.PushSpac
} }
return return
} }
st.Close()
return return
} }

View File

@ -44,7 +44,6 @@ func (s *service) Init(a *app.App) (err error) {
ocache.WithLogger(log.Sugar()), ocache.WithLogger(log.Sugar()),
ocache.WithGCPeriod(time.Minute), ocache.WithGCPeriod(time.Minute),
ocache.WithTTL(time.Duration(s.conf.GCTTL)*time.Second), ocache.WithTTL(time.Duration(s.conf.GCTTL)*time.Second),
ocache.WithRefCounter(false),
) )
return spacesyncproto.DRPCRegisterSpace(a.MustComponent(server.CName).(server.DRPCServer), &rpcHandler{s}) 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) { func (s *service) Run(ctx context.Context) (err error) {
go func() {
time.Sleep(time.Second * 5)
_, _ = s.GetSpace(ctx, "testDSpace")
}()
return return
} }

View File

@ -62,5 +62,5 @@ func (s spaceKeys) HeaderKey() []byte {
} }
func isRootIdKey(key string) bool { func isRootIdKey(key string) bool {
return strings.HasPrefix(key, "t/") && strings.HasSuffix(key, "rootId") return strings.HasPrefix(key, "t/") && strings.HasSuffix(key, "heads")
} }

View File

@ -2,9 +2,11 @@ package storage
import ( import (
"github.com/akrylysov/pogreb" "github.com/akrylysov/pogreb"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
"go.uber.org/zap"
"path" "path"
"sync" "sync"
"time" "time"
@ -14,6 +16,8 @@ var defPogrebOptions = &pogreb.Options{
BackgroundCompactionInterval: time.Minute * 5, BackgroundCompactionInterval: time.Minute * 5,
} }
var log = logger.NewNamed("storage.spacestorage")
type spaceStorage struct { type spaceStorage struct {
spaceId string spaceId string
objDb *pogreb.DB objDb *pogreb.DB
@ -24,6 +28,7 @@ type spaceStorage struct {
} }
func newSpaceStorage(rootPath string, spaceId string) (store spacestorage.SpaceStorage, err error) { 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) dbPath := path.Join(rootPath, spaceId)
objDb, err := pogreb.Open(dbPath, defPogrebOptions) objDb, err := pogreb.Open(dbPath, defPogrebOptions)
if err != nil { if err != nil {
@ -32,6 +37,7 @@ func newSpaceStorage(rootPath string, spaceId string) (store spacestorage.SpaceS
defer func() { defer func() {
if err != nil { if err != nil {
log.With(zap.String("id", spaceId), zap.Error(err)).Warn("failed to open storage")
objDb.Close() 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) { 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) dbPath := path.Join(rootPath, payload.SpaceHeaderWithId.Id)
db, err := pogreb.Open(dbPath, defPogrebOptions) db, err := pogreb.Open(dbPath, defPogrebOptions)
if err != nil { if err != nil {
@ -81,6 +88,7 @@ func createSpaceStorage(rootPath string, payload spacestorage.SpaceStorageCreate
} }
defer func() { defer func() {
log.With(zap.String("id", payload.SpaceHeaderWithId.Id), zap.Error(err)).Warn("failed to create storage")
if err != nil { if err != nil {
db.Close() db.Close()
} }
@ -165,5 +173,6 @@ func (s *spaceStorage) StoredIds() (ids []string, err error) {
} }
func (s *spaceStorage) Close() (err error) { func (s *spaceStorage) Close() (err error) {
log.With(zap.String("id", s.spaceId)).Debug("space storage closed")
return s.objDb.Close() return s.objDb.Close()
} }

View File

@ -99,7 +99,7 @@ func (t *treeStorage) Heads() (heads []string, err error) {
if err != nil { if err != nil {
return return
} }
if heads == nil { if headsBytes == nil {
err = storage2.ErrUnknownTreeId err = storage2.ErrUnknownTreeId
return return
} }

View File

@ -15,7 +15,7 @@ import (
) )
var ( 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") flagEtcPath = flag.String("e", "etc", "path to etc directory")
) )
@ -27,6 +27,10 @@ type NodesMap struct {
Consensus []struct { Consensus []struct {
Addresses []string `yaml:"grpcAddresses"` Addresses []string `yaml:"grpcAddresses"`
} }
Clients []struct {
Addresses []string `yaml:"grpcAddresses"`
APIPort string `yaml:"apiPort"`
}
} }
func main() { func main() {
@ -60,6 +64,15 @@ func main() {
nodes = append(nodes, node) 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 var consConfigs []cconfig.Config
for _, n := range nodesMap.Consensus { for _, n := range nodesMap.Consensus {
cfg, err := genConsensusConfig(n.Addresses) cfg, err := genConsensusConfig(n.Addresses)
@ -67,19 +80,13 @@ func main() {
panic(fmt.Sprintf("could not generate the config file: %s", err.Error())) panic(fmt.Sprintf("could not generate the config file: %s", err.Error()))
} }
consConfigs = append(consConfigs, cfg) 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 { for idx := range configs {
configs[idx].Nodes = nodes configs[idx].Nodes = nodes
} }
for idx := range clientConfigs {
clientConfigs[idx].Nodes = nodes
}
// saving configs // saving configs
configsPath := fmt.Sprintf("%s/configs", *flagEtcPath) configsPath := fmt.Sprintf("%s/configs", *flagEtcPath)
@ -110,6 +117,18 @@ func main() {
panic(fmt.Sprintf("could not write the config to file: %v", err)) 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 { for idx, cfg := range consConfigs {
path := fmt.Sprintf("%s/cons%d.yml", configsPath, idx+1) path := fmt.Sprintf("%s/cons%d.yml", configsPath, idx+1)
bytes, err := yaml.Marshal(cfg) bytes, err := yaml.Marshal(cfg)
@ -172,6 +191,54 @@ func genNodeConfig(addresses []string, apiPort string) (config2.Config, error) {
}, nil }, 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) { func genConsensusConfig(addresses []string) (cconfig.Config, error) {
encKey, _, err := encryptionkey.GenerateRandomRSAKeyPair(2048) encKey, _, err := encryptionkey.GenerateRandomRSAKeyPair(2048)
if err != nil { if err != nil {

View File

@ -15,3 +15,10 @@ consensus:
- "127.0.0.1:4531" - "127.0.0.1:4531"
- grpcAddresses: - grpcAddresses:
- "127.0.0.1:4532" - "127.0.0.1:4532"
clients:
- grpcAddresses:
- "127.0.0.1:4630"
apiPort: "8090"
- grpcAddresses:
- "127.0.0.1:4631"
apiPort: "8091"