Merge pull request #19 from anytypeio/sync-fixes

This commit is contained in:
Mikhail Rakhmanov 2022-12-17 14:50:26 +01:00 committed by GitHub
commit 4eba413631
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 1398 additions and 615 deletions

View File

@ -54,13 +54,16 @@ func (s *service) Name() (name string) {
}
func (s *service) Run(ctx context.Context) (err error) {
err = s.BaseDrpcServer.Run(
ctx,
s.cfg.APIServer.ListenAddrs,
func(handler drpc.Handler) drpc.Handler {
params := server.Params{
BufferSizeMb: s.cfg.Stream.MaxMsgSizeMb,
TimeoutMillis: s.cfg.Stream.TimeoutMilliseconds,
ListenAddrs: s.cfg.APIServer.ListenAddrs,
Wrapper: func(handler drpc.Handler) drpc.Handler {
return handler
},
s.transport.BasicListener)
Converter: s.transport.BasicListener,
}
err = s.BaseDrpcServer.Run(ctx, params)
if err != nil {
return
}

View File

@ -13,6 +13,7 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/periodicsync"
"go.uber.org/zap"
"strings"
"time"
)
type TreeHeads struct {
@ -54,7 +55,7 @@ func NewDiffService(
l := log.With(zap.String("spaceId", spaceId))
factory := spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient)
syncer := newDiffSyncer(spaceId, diff, confConnector, cache, storage, factory, l)
periodicSync := periodicsync.NewPeriodicSync(syncPeriod, syncer.Sync, l)
periodicSync := periodicsync.NewPeriodicSync(syncPeriod, time.Minute, syncer.Sync, l)
return &diffService{
spaceId: spaceId,

View File

@ -19,5 +19,6 @@ func (r *rpcHandler) HeadSync(ctx context.Context, req *spacesyncproto.HeadSyncR
}
func (r *rpcHandler) Stream(stream spacesyncproto.DRPCSpace_StreamStream) (err error) {
// TODO: if needed we can launch full sync here
return r.s.SyncService().StreamPool().AddAndReadStreamSync(stream)
}

View File

@ -109,7 +109,7 @@ func (s *service) NewSpace(ctx context.Context, id string) (Space, error) {
lastConfiguration := s.configurationService.GetLast()
confConnector := nodeconf.NewConfConnector(lastConfiguration, s.pool)
diffService := diffservice.NewDiffService(id, s.config.SyncPeriod, st, confConnector, s.treeGetter, log)
syncService := syncservice.NewSyncService(id, confConnector)
syncService := syncservice.NewSyncService(id, confConnector, s.config.SyncPeriod)
sp := &space{
id: id,
syncService: syncService,

View File

@ -218,7 +218,7 @@ func (s *space) DeriveTree(ctx context.Context, payload tree.ObjectTreeCreatePay
deps := synctree.CreateDeps{
SpaceId: s.id,
Payload: payload,
StreamPool: s.syncService.StreamPool(),
SyncService: s.syncService,
Configuration: s.configuration,
AclList: s.aclList,
SpaceStorage: s.storage,
@ -234,7 +234,7 @@ func (s *space) CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePay
deps := synctree.CreateDeps{
SpaceId: s.id,
Payload: payload,
StreamPool: s.syncService.StreamPool(),
SyncService: s.syncService,
Configuration: s.configuration,
AclList: s.aclList,
SpaceStorage: s.storage,
@ -249,7 +249,7 @@ func (s *space) BuildTree(ctx context.Context, id string, listener updatelistene
}
deps := synctree.BuildDeps{
SpaceId: s.id,
StreamPool: s.syncService.StreamPool(),
SyncService: s.syncService,
Configuration: s.configuration,
HeadNotifiable: s.diffService,
Listener: listener,

View File

@ -0,0 +1,87 @@
package syncservice
import (
"context"
"github.com/cheggaaa/mb/v3"
"go.uber.org/zap"
)
type ActionFunc func() error
type ActionQueue interface {
Send(action ActionFunc) (err error)
Run()
Close()
}
type actionQueue struct {
batcher *mb.MB[ActionFunc]
ctx context.Context
cancel context.CancelFunc
queueDone chan struct{}
}
func NewActionQueue() ActionQueue {
return &actionQueue{
batcher: mb.New[ActionFunc](0),
ctx: nil,
cancel: nil,
queueDone: make(chan struct{}),
}
}
func (q *actionQueue) Send(action ActionFunc) (err error) {
log.Debug("adding action to batcher")
return q.batcher.Add(q.ctx, action)
}
func (q *actionQueue) Run() {
log.Debug("running the queue")
q.ctx, q.cancel = context.WithCancel(context.Background())
go q.read()
}
func (q *actionQueue) read() {
limiter := make(chan struct{}, maxSimultaneousOperationsPerStream)
for i := 0; i < maxSimultaneousOperationsPerStream; i++ {
limiter <- struct{}{}
}
defer func() {
// wait until all operations are done
for i := 0; i < maxSimultaneousOperationsPerStream; i++ {
<-limiter
}
close(q.queueDone)
}()
doSendActions := func() {
actions, err := q.batcher.Wait(q.ctx)
log.Debug("reading from batcher")
if err != nil {
log.With(zap.Error(err)).Error("queue finished")
return
}
for _, msg := range actions {
<-limiter
go func(action ActionFunc) {
err = action()
if err != nil {
log.With(zap.Error(err)).Debug("action errored out")
}
limiter <- struct{}{}
}(msg)
}
}
for {
select {
case <-q.ctx.Done():
return
default:
doSendActions()
}
}
}
func (q *actionQueue) Close() {
q.cancel()
<-q.queueDone
}

View File

@ -0,0 +1,73 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice (interfaces: ActionQueue)
// Package mock_syncservice is a generated GoMock package.
package mock_syncservice
import (
reflect "reflect"
syncservice "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
gomock "github.com/golang/mock/gomock"
)
// MockActionQueue is a mock of ActionQueue interface.
type MockActionQueue struct {
ctrl *gomock.Controller
recorder *MockActionQueueMockRecorder
}
// MockActionQueueMockRecorder is the mock recorder for MockActionQueue.
type MockActionQueueMockRecorder struct {
mock *MockActionQueue
}
// NewMockActionQueue creates a new mock instance.
func NewMockActionQueue(ctrl *gomock.Controller) *MockActionQueue {
mock := &MockActionQueue{ctrl: ctrl}
mock.recorder = &MockActionQueueMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockActionQueue) EXPECT() *MockActionQueueMockRecorder {
return m.recorder
}
// Close mocks base method.
func (m *MockActionQueue) Close() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Close")
}
// Close indicates an expected call of Close.
func (mr *MockActionQueueMockRecorder) Close() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockActionQueue)(nil).Close))
}
// Run mocks base method.
func (m *MockActionQueue) Run() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Run")
}
// Run indicates an expected call of Run.
func (mr *MockActionQueueMockRecorder) Run() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockActionQueue)(nil).Run))
}
// Send mocks base method.
func (m *MockActionQueue) Send(arg0 syncservice.ActionFunc) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Send", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// Send indicates an expected call of Send.
func (mr *MockActionQueueMockRecorder) Send(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockActionQueue)(nil).Send), arg0)
}

View File

@ -0,0 +1,98 @@
package syncservice
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
"go.uber.org/atomic"
"go.uber.org/zap"
"time"
)
type StreamChecker interface {
CheckResponsiblePeers()
}
type streamChecker struct {
spaceId string
connector nodeconf.ConfConnector
streamPool StreamPool
clientFactory spacesyncproto.ClientFactory
log *zap.Logger
syncCtx context.Context
lastCheck *atomic.Time
}
const streamCheckerInterval = time.Second * 10
func NewStreamChecker(
spaceId string,
connector nodeconf.ConfConnector,
streamPool StreamPool,
clientFactory spacesyncproto.ClientFactory,
syncCtx context.Context,
log *zap.Logger) StreamChecker {
return &streamChecker{
spaceId: spaceId,
connector: connector,
streamPool: streamPool,
clientFactory: clientFactory,
log: log,
syncCtx: syncCtx,
lastCheck: atomic.NewTime(time.Time{}),
}
}
func (s *streamChecker) CheckResponsiblePeers() {
lastCheck := s.lastCheck.Load()
now := time.Now()
if lastCheck.Add(streamCheckerInterval).After(now) {
return
}
s.lastCheck.Store(now)
var (
activeNodeIds []string
configuration = s.connector.Configuration()
)
nodeIds := configuration.NodeIds(s.spaceId)
for _, nodeId := range nodeIds {
if s.streamPool.HasActiveStream(nodeId) {
s.log.Debug("has active stream for", zap.String("id", nodeId))
activeNodeIds = append(activeNodeIds, nodeId)
continue
}
}
s.log.Debug("total streams", zap.Int("total", len(activeNodeIds)))
newPeers, err := s.connector.DialInactiveResponsiblePeers(s.syncCtx, s.spaceId, activeNodeIds)
if err != nil {
s.log.Error("failed to dial peers", zap.Error(err))
return
}
for _, p := range newPeers {
stream, err := s.clientFactory.Client(p).Stream(s.syncCtx)
if err != nil {
err = rpcerr.Unwrap(err)
s.log.Error("failed to open stream", zap.Error(err))
// so here probably the request is failed because there is no such space,
// but diffService should handle such cases by sending pushSpace
continue
}
// sending empty message for the server to understand from which space is it coming
err = stream.Send(&spacesyncproto.ObjectSyncMessage{SpaceId: s.spaceId})
if err != nil {
err = rpcerr.Unwrap(err)
s.log.Error("failed to send first message to stream", zap.Error(err))
continue
}
err = s.streamPool.AddAndReadStreamAsync(stream)
if err != nil {
s.log.Error("failed to read from stream async", zap.Error(err))
continue
}
s.log.Debug("reading stream for", zap.String("id", p.Id()))
}
return
}

View File

@ -7,6 +7,7 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ocache"
"go.uber.org/zap"
"sync"
"sync/atomic"
"time"
@ -24,7 +25,7 @@ var ErrSyncTimeout = errors.New("too long wait on sync receive")
type StreamPool interface {
ocache.ObjectLastUsage
AddAndReadStreamSync(stream spacesyncproto.SpaceStream) (err error)
AddAndReadStreamAsync(stream spacesyncproto.SpaceStream)
AddAndReadStreamAsync(stream spacesyncproto.SpaceStream) (err error)
SendSync(peerId string, message *spacesyncproto.ObjectSyncMessage) (reply *spacesyncproto.ObjectSyncMessage, err error)
SendAsync(peers []string, message *spacesyncproto.ObjectSyncMessage) (err error)
@ -97,7 +98,7 @@ func (s *streamPool) SendSync(
delete(s.waiters, msg.ReplyId)
s.waitersMx.Unlock()
log.With("replyId", msg.ReplyId).Error("time elapsed when waiting")
log.With(zap.String("replyId", msg.ReplyId)).Error("time elapsed when waiting")
err = ErrSyncTimeout
case reply = <-waiter.ch:
if !delay.Stop() {
@ -124,10 +125,13 @@ func (s *streamPool) SendAsync(peers []string, message *spacesyncproto.ObjectSyn
streams := getStreams()
s.Unlock()
log.With("objectId", message.ObjectId).
Debugf("sending message to %d peers", len(streams))
for _, s := range streams {
err = s.Send(message)
log.With(zap.String("objectId", message.ObjectId), zap.Int("peers", len(streams))).
Debug("sending message to peers")
for _, stream := range streams {
err = stream.Send(message)
if err != nil {
log.Debug("error sending message to stream", zap.Error(err))
}
}
if len(peers) != 1 {
err = nil
@ -164,6 +168,7 @@ Loop:
default:
break
}
log.With(zap.String("id", id)).Debug("getting peer stream")
streams = append(streams, stream)
}
@ -172,40 +177,68 @@ Loop:
func (s *streamPool) BroadcastAsync(message *spacesyncproto.ObjectSyncMessage) (err error) {
streams := s.getAllStreams()
log.With("objectId", message.ObjectId).
Debugf("broadcasting message to %d peers", len(streams))
log.With(zap.String("objectId", message.ObjectId), zap.Int("peers", len(streams))).
Debug("broadcasting message to peers")
for _, stream := range streams {
if err = stream.Send(message); err != nil {
// TODO: add logging
log.Debug("error sending message to stream", zap.Error(err))
}
}
return nil
}
func (s *streamPool) AddAndReadStreamAsync(stream spacesyncproto.SpaceStream) {
go s.AddAndReadStreamSync(stream)
func (s *streamPool) AddAndReadStreamAsync(stream spacesyncproto.SpaceStream) (err error) {
peerId, err := s.addStream(stream)
if err != nil {
return
}
go s.readPeerLoop(peerId, stream)
return
}
func (s *streamPool) AddAndReadStreamSync(stream spacesyncproto.SpaceStream) (err error) {
peerId, err := s.addStream(stream)
if err != nil {
return
}
return s.readPeerLoop(peerId, stream)
}
func (s *streamPool) addStream(stream spacesyncproto.SpaceStream) (peerId string, err error) {
s.Lock()
peerId, err := peer.CtxPeerId(stream.Context())
peerId, err = peer.CtxPeerId(stream.Context())
if err != nil {
s.Unlock()
return
}
log.With(zap.String("peer id", peerId)).Debug("adding stream")
if oldStream, ok := s.peerStreams[peerId]; ok {
s.Unlock()
oldStream.Close()
s.Lock()
log.With(zap.String("peer id", peerId)).Debug("closed old stream before adding")
}
s.peerStreams[peerId] = stream
s.wg.Add(1)
s.Unlock()
log.With("peerId", peerId).Debug("reading stream from peer")
return s.readPeerLoop(peerId, stream)
return
}
func (s *streamPool) Close() (err error) {
s.Lock()
wg := s.wg
s.Unlock()
streams := s.getAllStreams()
log.Debug("closing streams on lock")
for _, stream := range streams {
stream.Close()
}
log.Debug("closed streams")
if wg != nil {
wg.Wait()
}
@ -213,6 +246,7 @@ func (s *streamPool) Close() (err error) {
}
func (s *streamPool) readPeerLoop(peerId string, stream spacesyncproto.SpaceStream) (err error) {
log.With(zap.String("replyId", peerId)).Debug("reading stream from peer")
defer s.wg.Done()
limiter := make(chan struct{}, maxSimultaneousOperationsPerStream)
for i := 0; i < maxSimultaneousOperationsPerStream; i++ {
@ -221,21 +255,22 @@ func (s *streamPool) readPeerLoop(peerId string, stream spacesyncproto.SpaceStre
process := func(msg *spacesyncproto.ObjectSyncMessage) {
s.lastUsage.Store(time.Now().Unix())
log.With(zap.String("replyId", msg.ReplyId), zap.String("object id", msg.ObjectId)).
Debug("getting message with reply id")
if msg.ReplyId == "" {
s.messageHandler(stream.Context(), peerId, msg)
return
}
log.With("replyId", msg.ReplyId).Debug("getting message with reply id")
s.waitersMx.Lock()
waiter, exists := s.waiters[msg.ReplyId]
if !exists {
log.With("replyId", msg.ReplyId).Debug("reply id not exists")
log.With(zap.String("replyId", msg.ReplyId)).Debug("reply id not exists")
s.waitersMx.Unlock()
s.messageHandler(stream.Context(), peerId, msg)
return
}
log.With("replyId", msg.ReplyId).Debug("reply id exists")
log.With(zap.String("replyId", msg.ReplyId)).Debug("reply id exists")
delete(s.waiters, msg.ReplyId)
s.waitersMx.Unlock()
@ -253,6 +288,7 @@ Loop:
select {
case <-limiter:
case <-stream.Context().Done():
log.Debug("stream context done")
break Loop
}
go func() {
@ -260,19 +296,23 @@ Loop:
limiter <- struct{}{}
}()
}
log.With("peerId", peerId).Debug("stopped reading stream from peer")
s.removePeer(peerId)
log.With(zap.String("peerId", peerId)).Debug("stopped reading stream from peer")
s.removePeer(peerId, stream)
return
}
func (s *streamPool) removePeer(peerId string) (err error) {
func (s *streamPool) removePeer(peerId string, stream spacesyncproto.SpaceStream) (err error) {
s.Lock()
defer s.Unlock()
_, ok := s.peerStreams[peerId]
mapStream, ok := s.peerStreams[peerId]
if !ok {
return ErrEmptyPeer
}
delete(s.peerStreams, peerId)
// it can be the case that the stream was already replaced
if mapStream == stream {
delete(s.peerStreams, peerId)
}
return
}

View File

@ -122,39 +122,16 @@ func TestStreamPool_AddAndReadStreamAsync(t *testing.T) {
func TestStreamPool_Close(t *testing.T) {
remId := "remoteId"
t.Run("client close", func(t *testing.T) {
t.Run("close", func(t *testing.T) {
fx := newFixture(t, "", remId, nil)
fx.run(t)
var events []string
recvChan := make(chan struct{})
go func() {
fx.pool.Close()
events = append(events, "pool_close")
recvChan <- struct{}{}
}()
time.Sleep(50 * time.Millisecond) //err = <-waitCh
events = append(events, "stream_close")
err := fx.clientStream.Close()
require.NoError(t, err)
<-recvChan
require.Equal(t, []string{"stream_close", "pool_close"}, events)
})
t.Run("server close", func(t *testing.T) {
fx := newFixture(t, "", remId, nil)
fx.run(t)
var events []string
recvChan := make(chan struct{})
go func() {
fx.pool.Close()
events = append(events, "pool_close")
recvChan <- struct{}{}
}()
time.Sleep(50 * time.Millisecond) //err = <-waitCh
events = append(events, "stream_close")
err := fx.clientStream.Close()
require.NoError(t, err)
<-recvChan
require.Equal(t, []string{"stream_close", "pool_close"}, events)
fx.pool.Close()
select {
case <-fx.clientStream.Context().Done():
break
case <-time.After(time.Millisecond * 100):
t.Fatal("context should be closed")
}
})
}

View File

@ -1,3 +1,4 @@
//go:generate mockgen -destination mock_syncservice/mock_syncservice.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice ActionQueue
package syncservice
import (
@ -6,78 +7,99 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/objectgetter"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/synchandler"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ocache"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/periodicsync"
"go.uber.org/zap"
"time"
)
var log = logger.NewNamed("syncservice").Sugar()
var log = logger.NewNamed("commonspace.syncservice")
type SyncService interface {
ocache.ObjectLastUsage
synchandler.SyncHandler
StreamPool() StreamPool
StreamChecker() StreamChecker
ActionQueue() ActionQueue
Init(getter objectgetter.ObjectGetter)
Close() (err error)
}
const respPeersStreamCheckInterval = time.Second * 10
type syncService struct {
spaceId string
streamPool StreamPool
clientFactory spacesyncproto.ClientFactory
objectGetter objectgetter.ObjectGetter
streamPool StreamPool
checker StreamChecker
periodicSync periodicsync.PeriodicSync
objectGetter objectgetter.ObjectGetter
actionQueue ActionQueue
streamLoopCtx context.Context
stopStreamLoop context.CancelFunc
connector nodeconf.ConfConnector
streamLoopDone chan struct{}
log *zap.SugaredLogger // TODO: change to logger
syncCtx context.Context
cancelSync context.CancelFunc
}
func NewSyncService(
spaceId string,
confConnector nodeconf.ConfConnector) (syncService SyncService) {
confConnector nodeconf.ConfConnector,
periodicSeconds int) (syncService SyncService) {
streamPool := newStreamPool(func(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) {
return syncService.HandleMessage(ctx, senderId, message)
})
clientFactory := spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient)
syncLog := log.With(zap.String("id", spaceId))
syncCtx, cancel := context.WithCancel(context.Background())
checker := NewStreamChecker(
spaceId,
confConnector,
streamPool,
clientFactory,
syncCtx,
syncLog)
periodicSync := periodicsync.NewPeriodicSync(periodicSeconds, 0, func(ctx context.Context) error {
checker.CheckResponsiblePeers()
return nil
}, syncLog)
syncService = newSyncService(
spaceId,
streamPool,
spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient),
confConnector)
periodicSync,
checker,
syncCtx,
cancel)
return
}
func newSyncService(
spaceId string,
streamPool StreamPool,
clientFactory spacesyncproto.ClientFactory,
connector nodeconf.ConfConnector) *syncService {
periodicSync periodicsync.PeriodicSync,
checker StreamChecker,
syncCtx context.Context,
cancel context.CancelFunc,
) *syncService {
return &syncService{
streamPool: streamPool,
connector: connector,
clientFactory: clientFactory,
spaceId: spaceId,
log: log.With(zap.String("id", spaceId)),
streamLoopDone: make(chan struct{}),
periodicSync: periodicSync,
streamPool: streamPool,
spaceId: spaceId,
checker: checker,
syncCtx: syncCtx,
cancelSync: cancel,
actionQueue: NewActionQueue(),
}
}
func (s *syncService) Init(objectGetter objectgetter.ObjectGetter) {
s.objectGetter = objectGetter
s.streamLoopCtx, s.stopStreamLoop = context.WithCancel(context.Background())
go s.responsibleStreamCheckLoop(s.streamLoopCtx)
s.actionQueue.Run()
s.periodicSync.Run()
}
func (s *syncService) Close() (err error) {
s.stopStreamLoop()
<-s.streamLoopDone
s.actionQueue.Close()
s.periodicSync.Close()
s.cancelSync()
return s.streamPool.Close()
}
@ -86,7 +108,7 @@ func (s *syncService) LastUsage() time.Time {
}
func (s *syncService) HandleMessage(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) {
s.log.With(zap.String("peerId", senderId), zap.String("objectId", message.ObjectId)).Debug("handling message")
log.With(zap.String("peerId", senderId), zap.String("objectId", message.ObjectId)).Debug("handling message")
obj, err := s.objectGetter.GetObject(ctx, message.ObjectId)
if err != nil {
return
@ -94,60 +116,14 @@ func (s *syncService) HandleMessage(ctx context.Context, senderId string, messag
return obj.HandleMessage(ctx, senderId, message)
}
func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) {
defer close(s.streamLoopDone)
checkResponsiblePeers := func() {
var (
activeNodeIds []string
configuration = s.connector.Configuration()
)
for _, nodeId := range configuration.NodeIds(s.spaceId) {
if s.streamPool.HasActiveStream(nodeId) {
s.log.Debug("has active stream for", zap.String("id", nodeId))
activeNodeIds = append(activeNodeIds, nodeId)
continue
}
}
newPeers, err := s.connector.DialInactiveResponsiblePeers(ctx, s.spaceId, activeNodeIds)
if err != nil {
s.log.Error("failed to dial peers", zap.Error(err))
return
}
for _, p := range newPeers {
stream, err := s.clientFactory.Client(p).Stream(ctx)
if err != nil {
err = rpcerr.Unwrap(err)
s.log.Errorf("failed to open stream: %v", err)
// so here probably the request is failed because there is no such space,
// but diffService should handle such cases by sending pushSpace
continue
}
// sending empty message for the server to understand from which space is it coming
err = stream.Send(&spacesyncproto.ObjectSyncMessage{SpaceId: s.spaceId})
if err != nil {
err = rpcerr.Unwrap(err)
s.log.Errorf("failed to send first message to stream: %v", err)
continue
}
s.log.Debug("reading stream for", zap.String("id", p.Id()))
s.streamPool.AddAndReadStreamAsync(stream)
}
}
checkResponsiblePeers()
ticker := time.NewTicker(respPeersStreamCheckInterval)
defer ticker.Stop()
for {
select {
case <-s.streamLoopCtx.Done():
return
case <-ticker.C:
checkResponsiblePeers()
}
}
}
func (s *syncService) StreamPool() StreamPool {
return s.streamPool
}
func (s *syncService) StreamChecker() StreamChecker {
return s.checker
}
func (s *syncService) ActionQueue() ActionQueue {
return s.actionQueue
}

View File

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree (interfaces: SyncClient,SyncTree)
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree (interfaces: SyncClient,SyncTree,ReceiveQueue)
// Package mock_synctree is a generated GoMock package.
package mock_synctree
@ -177,23 +177,18 @@ func (mr *MockSyncTreeMockRecorder) AddContent(arg0, arg1 interface{}) *gomock.C
}
// AddRawChanges mocks base method.
func (m *MockSyncTree) AddRawChanges(arg0 context.Context, arg1 ...*treechangeproto.RawTreeChangeWithId) (tree.AddResult, error) {
func (m *MockSyncTree) AddRawChanges(arg0 context.Context, arg1 tree.RawChangesPayload) (tree.AddResult, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0}
for _, a := range arg1 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "AddRawChanges", varargs...)
ret := m.ctrl.Call(m, "AddRawChanges", arg0, arg1)
ret0, _ := ret[0].(tree.AddResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AddRawChanges indicates an expected call of AddRawChanges.
func (mr *MockSyncTreeMockRecorder) AddRawChanges(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
func (mr *MockSyncTreeMockRecorder) AddRawChanges(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChanges", reflect.TypeOf((*MockSyncTree)(nil).AddRawChanges), varargs...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChanges", reflect.TypeOf((*MockSyncTree)(nil).AddRawChanges), arg0, arg1)
}
// ChangesAfterCommonSnapshot mocks base method.
@ -459,3 +454,68 @@ func (mr *MockSyncTreeMockRecorder) Unlock() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unlock", reflect.TypeOf((*MockSyncTree)(nil).Unlock))
}
// MockReceiveQueue is a mock of ReceiveQueue interface.
type MockReceiveQueue struct {
ctrl *gomock.Controller
recorder *MockReceiveQueueMockRecorder
}
// MockReceiveQueueMockRecorder is the mock recorder for MockReceiveQueue.
type MockReceiveQueueMockRecorder struct {
mock *MockReceiveQueue
}
// NewMockReceiveQueue creates a new mock instance.
func NewMockReceiveQueue(ctrl *gomock.Controller) *MockReceiveQueue {
mock := &MockReceiveQueue{ctrl: ctrl}
mock.recorder = &MockReceiveQueueMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockReceiveQueue) EXPECT() *MockReceiveQueueMockRecorder {
return m.recorder
}
// AddMessage mocks base method.
func (m *MockReceiveQueue) AddMessage(arg0 string, arg1 *treechangeproto.TreeSyncMessage, arg2 string) bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddMessage", arg0, arg1, arg2)
ret0, _ := ret[0].(bool)
return ret0
}
// AddMessage indicates an expected call of AddMessage.
func (mr *MockReceiveQueueMockRecorder) AddMessage(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMessage", reflect.TypeOf((*MockReceiveQueue)(nil).AddMessage), arg0, arg1, arg2)
}
// ClearQueue mocks base method.
func (m *MockReceiveQueue) ClearQueue(arg0 string) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "ClearQueue", arg0)
}
// ClearQueue indicates an expected call of ClearQueue.
func (mr *MockReceiveQueueMockRecorder) ClearQueue(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClearQueue", reflect.TypeOf((*MockReceiveQueue)(nil).ClearQueue), arg0)
}
// GetMessage mocks base method.
func (m *MockReceiveQueue) GetMessage(arg0 string) (*treechangeproto.TreeSyncMessage, string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetMessage", arg0)
ret0, _ := ret[0].(*treechangeproto.TreeSyncMessage)
ret1, _ := ret[1].(string)
ret2, _ := ret[2].(error)
return ret0, ret1, ret2
}
// GetMessage indicates an expected call of GetMessage.
func (mr *MockReceiveQueueMockRecorder) GetMessage(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMessage", reflect.TypeOf((*MockReceiveQueue)(nil).GetMessage), arg0)
}

View File

@ -0,0 +1,36 @@
package synctree
import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
)
type queuedClient struct {
SyncClient
queue syncservice.ActionQueue
}
func newQueuedClient(client SyncClient, queue syncservice.ActionQueue) SyncClient {
return &queuedClient{
SyncClient: client,
queue: queue,
}
}
func (q *queuedClient) BroadcastAsync(message *treechangeproto.TreeSyncMessage) (err error) {
return q.queue.Send(func() error {
return q.SyncClient.BroadcastAsync(message)
})
}
func (q *queuedClient) SendAsync(peerId string, message *treechangeproto.TreeSyncMessage, replyId string) (err error) {
return q.queue.Send(func() error {
return q.SyncClient.SendAsync(peerId, message, replyId)
})
}
func (q *queuedClient) BroadcastAsyncOrSendResponsible(message *treechangeproto.TreeSyncMessage) (err error) {
return q.queue.Send(func() error {
return q.SyncClient.BroadcastAsyncOrSendResponsible(message)
})
}

View File

@ -0,0 +1,74 @@
package synctree
import (
"errors"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
"sync"
)
type ReceiveQueue interface {
AddMessage(senderId string, msg *treechangeproto.TreeSyncMessage, replyId string) (queueFull bool)
GetMessage(senderId string) (msg *treechangeproto.TreeSyncMessage, replyId string, err error)
ClearQueue(senderId string)
}
type queueMsg struct {
replyId string
syncMessage *treechangeproto.TreeSyncMessage
}
type receiveQueue struct {
sync.Mutex
handlerMap map[string][]queueMsg
maxSize int
}
func newReceiveQueue(maxSize int) ReceiveQueue {
return &receiveQueue{
Mutex: sync.Mutex{},
handlerMap: map[string][]queueMsg{},
maxSize: maxSize,
}
}
var errEmptyQueue = errors.New("the queue is empty")
func (q *receiveQueue) AddMessage(senderId string, msg *treechangeproto.TreeSyncMessage, replyId string) (queueFull bool) {
q.Lock()
defer q.Unlock()
queue := q.handlerMap[senderId]
queueFull = len(queue) >= maxQueueSize
queue = append(queue, queueMsg{replyId, msg})
q.handlerMap[senderId] = queue
return
}
func (q *receiveQueue) GetMessage(senderId string) (msg *treechangeproto.TreeSyncMessage, replyId string, err error) {
q.Lock()
defer q.Unlock()
if len(q.handlerMap) == 0 {
err = errEmptyQueue
return
}
qMsg := q.handlerMap[senderId][0]
msg = qMsg.syncMessage
replyId = qMsg.replyId
return
}
func (q *receiveQueue) ClearQueue(senderId string) {
q.Lock()
defer q.Unlock()
queue := q.handlerMap[senderId]
excessLen := len(queue) - q.maxSize + 1
if excessLen <= 0 {
excessLen = 1
}
queue = queue[excessLen:]
q.handlerMap[senderId] = queue
}

View File

@ -1,4 +1,4 @@
//go:generate mockgen -destination mock_synctree/mock_synctree.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree SyncClient,SyncTree
//go:generate mockgen -destination mock_synctree/mock_synctree.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree SyncClient,SyncTree,ReceiveQueue
package synctree
import (
@ -19,18 +19,23 @@ type syncClient struct {
syncservice.StreamPool
RequestFactory
spaceId string
connector nodeconf.ConfConnector
configuration nodeconf.Configuration
checker syncservice.StreamChecker
}
func newSyncClient(
spaceId string,
pool syncservice.StreamPool,
factory RequestFactory,
configuration nodeconf.Configuration) SyncClient {
configuration nodeconf.Configuration,
checker syncservice.StreamChecker) SyncClient {
return &syncClient{
StreamPool: pool,
RequestFactory: factory,
configuration: configuration,
checker: checker,
spaceId: spaceId,
}
}
@ -40,6 +45,7 @@ func (s *syncClient) BroadcastAsync(message *treechangeproto.TreeSyncMessage) (e
if err != nil {
return
}
s.checker.CheckResponsiblePeers()
return s.StreamPool.BroadcastAsync(objMsg)
}
@ -57,6 +63,7 @@ func (s *syncClient) BroadcastAsyncOrSendResponsible(message *treechangeproto.Tr
return
}
if s.configuration.IsResponsible(s.spaceId) {
s.checker.CheckResponsiblePeers()
return s.StreamPool.SendAsync(s.configuration.NodeIds(s.spaceId), objMsg)
}
return s.BroadcastAsync(message)

View File

@ -52,20 +52,20 @@ var log = logger.NewNamed("commonspace.synctree").Sugar()
var createDerivedObjectTree = tree.CreateDerivedObjectTree
var createObjectTree = tree.CreateObjectTree
var buildObjectTree = tree.BuildObjectTree
var createSyncClient = newSyncClient
var createSyncClient = newWrappedSyncClient
type CreateDeps struct {
SpaceId string
Payload tree.ObjectTreeCreatePayload
Configuration nodeconf.Configuration
StreamPool syncservice.StreamPool
SyncService syncservice.SyncService
AclList list.ACLList
SpaceStorage spacestorage.SpaceStorage
}
type BuildDeps struct {
SpaceId string
StreamPool syncservice.StreamPool
SyncService syncservice.SyncService
Configuration nodeconf.Configuration
HeadNotifiable HeadNotifiable
Listener updatelistener.UpdateListener
@ -75,6 +75,11 @@ type BuildDeps struct {
TreeUsage *atomic.Int32
}
func newWrappedSyncClient(spaceId string, factory RequestFactory, syncService syncservice.SyncService, configuration nodeconf.Configuration) SyncClient {
syncClient := newSyncClient(spaceId, syncService.StreamPool(), factory, configuration, syncService.StreamChecker())
return newQueuedClient(syncClient, syncService.ActionQueue())
}
func DeriveSyncTree(ctx context.Context, deps CreateDeps) (id string, err error) {
objTree, err := createDerivedObjectTree(deps.Payload, deps.AclList, deps.SpaceStorage.CreateTreeStorage)
if err != nil {
@ -83,8 +88,8 @@ func DeriveSyncTree(ctx context.Context, deps CreateDeps) (id string, err error)
syncClient := createSyncClient(
deps.SpaceId,
deps.StreamPool,
sharedFactory,
deps.SyncService,
deps.Configuration)
headUpdate := syncClient.CreateHeadUpdate(objTree, nil)
@ -100,8 +105,8 @@ func CreateSyncTree(ctx context.Context, deps CreateDeps) (id string, err error)
}
syncClient := createSyncClient(
deps.SpaceId,
deps.StreamPool,
GetRequestFactory(),
sharedFactory,
deps.SyncService,
deps.Configuration)
headUpdate := syncClient.CreateHeadUpdate(objTree, nil)
@ -122,7 +127,7 @@ func BuildSyncTreeOrGetRemote(ctx context.Context, id string, deps BuildDeps) (t
return
}
resp, err := deps.StreamPool.SendSync(peerId, objMsg)
resp, err := deps.SyncService.StreamPool().SendSync(peerId, objMsg)
if err != nil {
return
}
@ -186,8 +191,8 @@ func buildSyncTree(ctx context.Context, isFirstBuild bool, deps BuildDeps) (t Sy
}
syncClient := createSyncClient(
deps.SpaceId,
deps.StreamPool,
GetRequestFactory(),
sharedFactory,
deps.SyncService,
deps.Configuration)
syncTree := &syncTree{
ObjectTree: objTree,
@ -200,12 +205,11 @@ func buildSyncTree(ctx context.Context, isFirstBuild bool, deps BuildDeps) (t Sy
syncTree.SyncHandler = syncHandler
t = syncTree
syncTree.Lock()
defer syncTree.Unlock()
syncTree.afterBuild()
syncTree.Unlock()
headUpdate := syncTree.syncClient.CreateHeadUpdate(t, nil)
// here we will have different behaviour based on who is sending this update
if isFirstBuild {
headUpdate := syncTree.syncClient.CreateHeadUpdate(t, nil)
// send to everybody, because everybody should know that the node or client got new tree
err = syncTree.syncClient.BroadcastAsync(headUpdate)
}
@ -242,11 +246,11 @@ func (s *syncTree) AddContent(ctx context.Context, content tree.SignableChangeCo
return
}
func (s *syncTree) AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (res tree.AddResult, err error) {
func (s *syncTree) AddRawChanges(ctx context.Context, changesPayload tree.RawChangesPayload) (res tree.AddResult, err error) {
if err = s.checkAlive(); err != nil {
return
}
res, err = s.ObjectTree.AddRawChanges(ctx, changes...)
res, err = s.ObjectTree.AddRawChanges(ctx, changesPayload)
if err != nil {
return
}
@ -308,6 +312,8 @@ func (s *syncTree) checkAlive() (err error) {
}
func (s *syncTree) Ping() (err error) {
s.Lock()
defer s.Unlock()
headUpdate := s.syncClient.CreateHeadUpdate(s, nil)
return s.syncClient.BroadcastAsyncOrSendResponsible(headUpdate)
}

View File

@ -37,6 +37,12 @@ func (s syncTreeMatcher) String() string {
return ""
}
func syncClientFuncCreator(client SyncClient) func(spaceId string, factory RequestFactory, syncService syncservice.SyncService, configuration nodeconf.Configuration) SyncClient {
return func(spaceId string, factory RequestFactory, syncService syncservice.SyncService, configuration nodeconf.Configuration) SyncClient {
return client
}
}
func Test_DeriveSyncTree(t *testing.T) {
ctx := context.Background()
ctrl := gomock.NewController(t)
@ -53,9 +59,7 @@ func Test_DeriveSyncTree(t *testing.T) {
require.Equal(t, expectedPayload, payload)
return objTreeMock, nil
}
createSyncClient = func(spaceId string, pool syncservice.StreamPool, factory RequestFactory, configuration nodeconf.Configuration) SyncClient {
return syncClientMock
}
createSyncClient = syncClientFuncCreator(syncClientMock)
headUpdate := &treechangeproto.TreeSyncMessage{}
syncClientMock.EXPECT().CreateHeadUpdate(gomock.Any(), gomock.Nil()).Return(headUpdate)
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
@ -65,6 +69,7 @@ func Test_DeriveSyncTree(t *testing.T) {
Payload: expectedPayload,
SpaceStorage: spaceStorageMock,
}
objTreeMock.EXPECT().ID().Return("id")
_, err := DeriveSyncTree(ctx, deps)
require.NoError(t, err)
@ -86,12 +91,12 @@ func Test_CreateSyncTree(t *testing.T) {
require.Equal(t, expectedPayload, payload)
return objTreeMock, nil
}
createSyncClient = func(spaceId string, pool syncservice.StreamPool, factory RequestFactory, configuration nodeconf.Configuration) SyncClient {
return syncClientMock
}
createSyncClient = syncClientFuncCreator(syncClientMock)
headUpdate := &treechangeproto.TreeSyncMessage{}
syncClientMock.EXPECT().CreateHeadUpdate(gomock.Any(), gomock.Nil()).Return(headUpdate)
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
objTreeMock.EXPECT().ID().Return("id")
deps := CreateDeps{
AclList: aclListMock,
SpaceId: spaceId,
@ -122,48 +127,61 @@ func Test_BuildSyncTree(t *testing.T) {
headUpdate := &treechangeproto.TreeSyncMessage{}
t.Run("AddRawChanges update", func(t *testing.T) {
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
payload := tree.RawChangesPayload{
NewHeads: nil,
RawChanges: changes,
}
expectedRes := tree.AddResult{
Added: changes,
Mode: tree.Append,
}
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)).
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(payload)).
Return(expectedRes, nil)
updateListenerMock.EXPECT().Update(tr)
syncClientMock.EXPECT().CreateHeadUpdate(gomock.Eq(tr), gomock.Eq(changes)).Return(headUpdate)
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
res, err := tr.AddRawChanges(ctx, changes...)
res, err := tr.AddRawChanges(ctx, payload)
require.NoError(t, err)
require.Equal(t, expectedRes, res)
})
t.Run("AddRawChanges rebuild", func(t *testing.T) {
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
payload := tree.RawChangesPayload{
NewHeads: nil,
RawChanges: changes,
}
expectedRes := tree.AddResult{
Added: changes,
Mode: tree.Rebuild,
}
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)).
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(payload)).
Return(expectedRes, nil)
updateListenerMock.EXPECT().Rebuild(tr)
syncClientMock.EXPECT().CreateHeadUpdate(gomock.Eq(tr), gomock.Eq(changes)).Return(headUpdate)
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
res, err := tr.AddRawChanges(ctx, changes...)
res, err := tr.AddRawChanges(ctx, payload)
require.NoError(t, err)
require.Equal(t, expectedRes, res)
})
t.Run("AddRawChanges nothing", func(t *testing.T) {
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
payload := tree.RawChangesPayload{
NewHeads: nil,
RawChanges: changes,
}
expectedRes := tree.AddResult{
Added: changes,
Mode: tree.Nothing,
}
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)).
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(payload)).
Return(expectedRes, nil)
res, err := tr.AddRawChanges(ctx, changes...)
res, err := tr.AddRawChanges(ctx, payload)
require.NoError(t, err)
require.Equal(t, expectedRes, res)
})

View File

@ -8,37 +8,63 @@ import (
"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"
"go.uber.org/zap"
"sync"
)
type syncTreeHandler struct {
objTree tree.ObjectTree
syncClient SyncClient
objTree tree.ObjectTree
syncClient SyncClient
handlerLock sync.Mutex
queue ReceiveQueue
}
const maxQueueSize = 5
func newSyncTreeHandler(objTree tree.ObjectTree, syncClient SyncClient) synchandler.SyncHandler {
return &syncTreeHandler{
objTree: objTree,
syncClient: syncClient,
queue: newReceiveQueue(maxQueueSize),
}
}
func (s *syncTreeHandler) HandleMessage(ctx context.Context, senderId string, msg *spacesyncproto.ObjectSyncMessage) (err error) {
// TODO: when implementing sync status check msg heads before sending into queue
unmarshalled := &treechangeproto.TreeSyncMessage{}
err = proto.Unmarshal(msg.Payload, unmarshalled)
if err != nil {
return
}
content := unmarshalled.GetContent()
queueFull := s.queue.AddMessage(senderId, unmarshalled, msg.ReplyId)
if queueFull {
return
}
return s.handleMessage(ctx, senderId)
}
func (s *syncTreeHandler) handleMessage(ctx context.Context, senderId string) (err error) {
s.objTree.Lock()
defer s.objTree.Unlock()
msg, replyId, err := s.queue.GetMessage(senderId)
if err != nil {
return
}
defer s.queue.ClearQueue(senderId)
content := msg.GetContent()
switch {
case content.GetHeadUpdate() != nil:
return s.handleHeadUpdate(ctx, senderId, content.GetHeadUpdate(), msg.ReplyId)
return s.handleHeadUpdate(ctx, senderId, content.GetHeadUpdate(), replyId)
case content.GetFullSyncRequest() != nil:
return s.handleFullSyncRequest(ctx, senderId, content.GetFullSyncRequest(), msg.ReplyId)
return s.handleFullSyncRequest(ctx, senderId, content.GetFullSyncRequest(), replyId)
case content.GetFullSyncResponse() != nil:
return s.handleFullSyncResponse(ctx, senderId, content.GetFullSyncResponse())
}
return nil
return
}
func (s *syncTreeHandler) handleHeadUpdate(
@ -46,60 +72,66 @@ func (s *syncTreeHandler) handleHeadUpdate(
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()
log := log.With("senderId", senderId).
With("heads", objTree.Heads()).
With("treeId", objTree.ID())
log.Debug("received head update message")
// 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...)
defer func() {
if err != nil {
return err
log.With(zap.Error(err)).Debug("head update finished with error")
} else if fullRequest != nil {
log.Debug("sending full sync request")
} else {
if !isEmptyUpdate {
log.Debug("head update finished correctly")
}
}
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")
// 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
}
// we need to sync in any case
fullRequest, err = s.syncClient.CreateFullSyncRequest(objTree, update.Heads, update.SnapshotPath)
if err != nil {
return
}
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
if s.alreadyHasHeads(objTree, update.Heads) {
return
}
_, err = objTree.AddRawChanges(ctx, tree.RawChangesPayload{
NewHeads: update.Heads,
RawChanges: update.Changes,
})
if err != nil {
return
}
if s.alreadyHasHeads(objTree, update.Heads) {
return
}
fullRequest, err = s.syncClient.CreateFullSyncRequest(objTree, update.Heads, update.SnapshotPath)
if err != nil {
return
}
return s.syncClient.SendAsync(senderId, fullRequest, replyId)
}
func (s *syncTreeHandler) handleFullSyncRequest(
@ -107,40 +139,43 @@ func (s *syncTreeHandler) handleFullSyncRequest(
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
)
log := log.With("senderId", senderId).
With("heads", request.Heads).
With("treeId", s.objTree.ID()).
With("replyId", replyId)
log.Debug("received full sync request message")
defer func() {
if err != nil {
log.With(zap.Error(err)).Debug("full sync request finished with error")
s.syncClient.SendAsync(senderId, treechangeproto.WrapError(err, header), replyId)
return
} else if fullResponse != nil {
log.Debug("full sync response sent")
}
}()
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
}
if len(request.Changes) != 0 && !s.alreadyHasHeads(objTree, request.Heads) {
_, err = objTree.AddRawChanges(ctx, tree.RawChangesPayload{
NewHeads: request.Heads,
RawChanges: request.Changes,
})
if err != nil {
return
}
fullResponse, err = s.syncClient.CreateFullSyncResponse(objTree, request.Heads, request.SnapshotPath)
return err
}()
}
fullResponse, err = s.syncClient.CreateFullSyncResponse(objTree, request.Heads, request.SnapshotPath)
if err != nil {
return
}
return s.syncClient.SendAsync(senderId, fullResponse, replyId)
}
@ -148,34 +183,30 @@ func (s *syncTreeHandler) handleFullSyncResponse(
ctx context.Context,
senderId string,
response *treechangeproto.TreeFullSyncResponse) (err error) {
log.With("senderId", senderId).
var (
objTree = s.objTree
)
log := 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")
With("treeId", s.objTree.ID())
log.Debug("received full sync response message")
defer func() {
if err != nil {
log.With(zap.Error(err)).Debug("full sync response failed")
} else {
log.Debug("full sync response succeeded")
}
}()
if s.alreadyHasHeads(objTree, response.Heads) {
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")
_, err = objTree.AddRawChanges(ctx, tree.RawChangesPayload{
NewHeads: response.Heads,
RawChanges: response.Changes,
})
return
}

View File

@ -33,18 +33,46 @@ func (t *testObjTreeMock) Unlock() {
t.m.Unlock()
}
func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
type syncHandlerFixture struct {
ctrl *gomock.Controller
syncClientMock *mock_synctree.MockSyncClient
objectTreeMock *testObjTreeMock
receiveQueueMock *mock_synctree.MockReceiveQueue
ctx := context.Background()
syncHandler *syncTreeHandler
}
func newSyncHandlerFixture(t *testing.T) *syncHandlerFixture {
ctrl := gomock.NewController(t)
syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl))
receiveQueueMock := mock_synctree.NewMockReceiveQueue(ctrl)
syncHandler := newSyncTreeHandler(objectTreeMock, syncClientMock)
syncHandler := &syncTreeHandler{
objTree: objectTreeMock,
syncClient: syncClientMock,
queue: receiveQueueMock,
}
return &syncHandlerFixture{
ctrl: ctrl,
syncClientMock: syncClientMock,
objectTreeMock: objectTreeMock,
receiveQueueMock: receiveQueueMock,
syncHandler: syncHandler,
}
}
func (fx *syncHandlerFixture) stop() {
fx.ctrl.Finish()
}
func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
ctx := context.Background()
log = zap.NewNop().Sugar()
t.Run("head update non empty all heads added", func(t *testing.T) {
fx := newSyncHandlerFixture(t)
defer fx.stop()
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
@ -56,29 +84,29 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
treeMsg := treechangeproto.WrapHeadUpdate(headUpdate, chWithId)
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
objectTreeMock.EXPECT().
ID().AnyTimes().Return(treeId)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
objectTreeMock.EXPECT().
HasChanges(gomock.Eq([]string{"h1"})).
Return(false)
objectTreeMock.EXPECT().
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
Return(tree.AddResult{}, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2", "h1"})
objectTreeMock.EXPECT().
HasChanges(gomock.Eq([]string{"h1"})).
Return(true)
fx.receiveQueueMock.EXPECT().AddMessage(senderId, gomock.Eq(treeMsg), "").Return(false)
fx.receiveQueueMock.EXPECT().GetMessage(senderId).Return(treeMsg, "", nil)
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
fx.objectTreeMock.EXPECT().ID().AnyTimes().Return(treeId)
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h2"}).Times(2)
fx.objectTreeMock.EXPECT().HasChanges(gomock.Eq([]string{"h1"})).Return(false)
fx.objectTreeMock.EXPECT().
AddRawChanges(gomock.Any(), gomock.Eq(tree.RawChangesPayload{
NewHeads: []string{"h1"},
RawChanges: []*treechangeproto.RawTreeChangeWithId{chWithId},
})).
Return(tree.AddResult{}, nil)
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h2", "h1"})
fx.objectTreeMock.EXPECT().HasChanges(gomock.Eq([]string{"h1"})).Return(true)
fx.receiveQueueMock.EXPECT().ClearQueue(senderId)
err := fx.syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err)
})
t.Run("head update non empty heads not added", func(t *testing.T) {
fx := newSyncHandlerFixture(t)
defer fx.stop()
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
@ -90,38 +118,32 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
treeMsg := treechangeproto.WrapHeadUpdate(headUpdate, chWithId)
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
fullRequest := &treechangeproto.TreeSyncMessage{}
fx.receiveQueueMock.EXPECT().AddMessage(senderId, gomock.Eq(treeMsg), "").Return(false)
fx.receiveQueueMock.EXPECT().GetMessage(senderId).Return(treeMsg, "", nil)
objectTreeMock.EXPECT().
ID().AnyTimes().Return(treeId)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
objectTreeMock.EXPECT().
HasChanges(gomock.Eq([]string{"h1"})).
Return(false)
objectTreeMock.EXPECT().
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
fx.objectTreeMock.EXPECT().ID().AnyTimes().Return(treeId)
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h2"}).AnyTimes()
fx.objectTreeMock.EXPECT().HasChanges(gomock.Eq([]string{"h1"})).Return(false)
fx.objectTreeMock.EXPECT().
AddRawChanges(gomock.Any(), gomock.Eq(tree.RawChangesPayload{
NewHeads: []string{"h1"},
RawChanges: []*treechangeproto.RawTreeChangeWithId{chWithId},
})).
Return(tree.AddResult{}, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
objectTreeMock.EXPECT().
HasChanges(gomock.Eq([]string{"h1"})).
Return(false)
syncClientMock.EXPECT().
CreateFullSyncRequest(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
fx.objectTreeMock.EXPECT().HasChanges(gomock.Eq([]string{"h1"})).Return(false)
fx.syncClientMock.EXPECT().
CreateFullSyncRequest(gomock.Eq(fx.objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
Return(fullRequest, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
fx.syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Eq(fullRequest), gomock.Eq(""))
syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Eq(fullRequest), gomock.Eq(""))
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
fx.receiveQueueMock.EXPECT().ClearQueue(senderId)
err := fx.syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err)
})
t.Run("head update non empty equal heads", func(t *testing.T) {
fx := newSyncHandlerFixture(t)
defer fx.stop()
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
@ -132,18 +154,20 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
}
treeMsg := treechangeproto.WrapHeadUpdate(headUpdate, chWithId)
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
fx.receiveQueueMock.EXPECT().AddMessage(senderId, gomock.Eq(treeMsg), "").Return(false)
fx.receiveQueueMock.EXPECT().GetMessage(senderId).Return(treeMsg, "", nil)
objectTreeMock.EXPECT().
ID().AnyTimes().Return(treeId)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h1"})
fx.objectTreeMock.EXPECT().ID().AnyTimes().Return(treeId)
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h1"}).AnyTimes()
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
fx.receiveQueueMock.EXPECT().ClearQueue(senderId)
err := fx.syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err)
})
t.Run("head update empty", func(t *testing.T) {
fx := newSyncHandlerFixture(t)
defer fx.stop()
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
@ -155,26 +179,24 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
treeMsg := treechangeproto.WrapHeadUpdate(headUpdate, chWithId)
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
fullRequest := &treechangeproto.TreeSyncMessage{}
fx.receiveQueueMock.EXPECT().AddMessage(senderId, gomock.Eq(treeMsg), "").Return(false)
fx.receiveQueueMock.EXPECT().GetMessage(senderId).Return(treeMsg, "", nil)
objectTreeMock.EXPECT().
ID().AnyTimes().Return(treeId)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
syncClientMock.EXPECT().
CreateFullSyncRequest(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
fx.objectTreeMock.EXPECT().ID().AnyTimes().Return(treeId)
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h2"}).AnyTimes()
fx.syncClientMock.EXPECT().
CreateFullSyncRequest(gomock.Eq(fx.objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
Return(fullRequest, nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
fx.syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Eq(fullRequest), gomock.Eq(""))
syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Eq(fullRequest), gomock.Eq(""))
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
fx.receiveQueueMock.EXPECT().ClearQueue(senderId)
err := fx.syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err)
})
t.Run("head update empty equal heads", func(t *testing.T) {
fx := newSyncHandlerFixture(t)
defer fx.stop()
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
@ -185,29 +207,25 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
}
treeMsg := treechangeproto.WrapHeadUpdate(headUpdate, chWithId)
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
fx.receiveQueueMock.EXPECT().AddMessage(senderId, gomock.Eq(treeMsg), "").Return(false)
fx.receiveQueueMock.EXPECT().GetMessage(senderId).Return(treeMsg, "", nil)
objectTreeMock.EXPECT().
ID().AnyTimes().Return(treeId)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h1"})
fx.objectTreeMock.EXPECT().ID().AnyTimes().Return(treeId)
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h1"}).AnyTimes()
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
fx.receiveQueueMock.EXPECT().ClearQueue(senderId)
err := fx.syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err)
})
}
func TestSyncHandler_HandleFullSyncRequest(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.Background()
syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl))
syncHandler := newSyncTreeHandler(objectTreeMock, syncClientMock)
log = zap.NewNop().Sugar()
t.Run("full sync request with change", func(t *testing.T) {
fx := newSyncHandlerFixture(t)
defer fx.stop()
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
@ -219,27 +237,32 @@ func TestSyncHandler_HandleFullSyncRequest(t *testing.T) {
treeMsg := treechangeproto.WrapFullRequest(fullSyncRequest, chWithId)
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
fullResponse := &treechangeproto.TreeSyncMessage{}
objectTreeMock.EXPECT().
ID().AnyTimes().Return(treeId)
objectTreeMock.EXPECT().Header().Return(nil)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
objectTreeMock.EXPECT().
HasChanges(gomock.Eq([]string{"h1"})).
Return(false)
objectTreeMock.EXPECT().
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
fx.receiveQueueMock.EXPECT().AddMessage(senderId, gomock.Eq(treeMsg), "").Return(false)
fx.receiveQueueMock.EXPECT().GetMessage(senderId).Return(treeMsg, "", nil)
fx.objectTreeMock.EXPECT().ID().AnyTimes().Return(treeId)
fx.objectTreeMock.EXPECT().Header().Return(nil)
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h2"}).AnyTimes()
fx.objectTreeMock.EXPECT().HasChanges(gomock.Eq([]string{"h1"})).Return(false)
fx.objectTreeMock.EXPECT().
AddRawChanges(gomock.Any(), gomock.Eq(tree.RawChangesPayload{
NewHeads: []string{"h1"},
RawChanges: []*treechangeproto.RawTreeChangeWithId{chWithId},
})).
Return(tree.AddResult{}, nil)
syncClientMock.EXPECT().
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
fx.syncClientMock.EXPECT().
CreateFullSyncResponse(gomock.Eq(fx.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)
fx.syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Eq(fullResponse), gomock.Eq(""))
fx.receiveQueueMock.EXPECT().ClearQueue(senderId)
err := fx.syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err)
})
t.Run("full sync request with change same heads", func(t *testing.T) {
fx := newSyncHandlerFixture(t)
defer fx.stop()
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
@ -251,21 +274,28 @@ func TestSyncHandler_HandleFullSyncRequest(t *testing.T) {
treeMsg := treechangeproto.WrapFullRequest(fullSyncRequest, chWithId)
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
fullResponse := &treechangeproto.TreeSyncMessage{}
objectTreeMock.EXPECT().
fx.receiveQueueMock.EXPECT().AddMessage(senderId, gomock.Eq(treeMsg), "").Return(false)
fx.receiveQueueMock.EXPECT().GetMessage(senderId).Return(treeMsg, "", nil)
fx.objectTreeMock.EXPECT().
ID().AnyTimes().Return(treeId)
objectTreeMock.EXPECT().Header().Return(nil)
objectTreeMock.EXPECT().
fx.objectTreeMock.EXPECT().Header().Return(nil)
fx.objectTreeMock.EXPECT().
Heads().
Return([]string{"h1"})
syncClientMock.EXPECT().
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
Return([]string{"h1"}).AnyTimes()
fx.syncClientMock.EXPECT().
CreateFullSyncResponse(gomock.Eq(fx.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)
fx.syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Eq(fullResponse), gomock.Eq(""))
fx.receiveQueueMock.EXPECT().ClearQueue(senderId)
err := fx.syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err)
})
t.Run("full sync request without change but with reply id", func(t *testing.T) {
fx := newSyncHandlerFixture(t)
defer fx.stop()
treeId := "treeId"
senderId := "senderId"
replyId := "replyId"
@ -277,18 +307,25 @@ func TestSyncHandler_HandleFullSyncRequest(t *testing.T) {
treeMsg := treechangeproto.WrapFullRequest(fullSyncRequest, chWithId)
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, replyId)
fullResponse := &treechangeproto.TreeSyncMessage{}
objectTreeMock.EXPECT().
fx.receiveQueueMock.EXPECT().AddMessage(senderId, gomock.Eq(treeMsg), replyId).Return(false)
fx.receiveQueueMock.EXPECT().GetMessage(senderId).Return(treeMsg, replyId, nil)
fx.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"})).
fx.objectTreeMock.EXPECT().Header().Return(nil)
fx.syncClientMock.EXPECT().
CreateFullSyncResponse(gomock.Eq(fx.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)
fx.syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Eq(fullResponse), gomock.Eq(replyId))
fx.receiveQueueMock.EXPECT().ClearQueue(senderId)
err := fx.syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err)
})
t.Run("full sync request with add raw changes error", func(t *testing.T) {
fx := newSyncHandlerFixture(t)
defer fx.stop()
treeId := "treeId"
senderId := "senderId"
chWithId := &treechangeproto.RawTreeChangeWithId{}
@ -299,36 +336,39 @@ func TestSyncHandler_HandleFullSyncRequest(t *testing.T) {
}
treeMsg := treechangeproto.WrapFullRequest(fullSyncRequest, chWithId)
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, "")
objectTreeMock.EXPECT().
fx.receiveQueueMock.EXPECT().AddMessage(senderId, gomock.Eq(treeMsg), "").Return(false)
fx.receiveQueueMock.EXPECT().GetMessage(senderId).Return(treeMsg, "", nil)
fx.objectTreeMock.EXPECT().
ID().AnyTimes().Return(treeId)
objectTreeMock.EXPECT().Header().Return(nil)
objectTreeMock.EXPECT().
fx.objectTreeMock.EXPECT().Header().Return(nil)
fx.objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
objectTreeMock.EXPECT().
fx.objectTreeMock.EXPECT().
HasChanges(gomock.Eq([]string{"h1"})).
Return(false)
objectTreeMock.EXPECT().
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
fx.objectTreeMock.EXPECT().
AddRawChanges(gomock.Any(), gomock.Eq(tree.RawChangesPayload{
NewHeads: []string{"h1"},
RawChanges: []*treechangeproto.RawTreeChangeWithId{chWithId},
})).
Return(tree.AddResult{}, fmt.Errorf(""))
syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Any(), gomock.Eq(""))
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
fx.syncClientMock.EXPECT().SendAsync(gomock.Eq(senderId), gomock.Any(), gomock.Eq(""))
fx.receiveQueueMock.EXPECT().ClearQueue(senderId)
err := fx.syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.Error(t, err)
})
}
func TestSyncHandler_HandleFullSyncResponse(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.Background()
syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl))
syncHandler := newSyncTreeHandler(objectTreeMock, syncClientMock)
log = zap.NewNop().Sugar()
t.Run("full sync response with change", func(t *testing.T) {
fx := newSyncHandlerFixture(t)
defer fx.stop()
treeId := "treeId"
senderId := "senderId"
replyId := "replyId"
@ -340,22 +380,31 @@ func TestSyncHandler_HandleFullSyncResponse(t *testing.T) {
}
treeMsg := treechangeproto.WrapFullResponse(fullSyncResponse, chWithId)
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, replyId)
objectTreeMock.EXPECT().ID().AnyTimes().Return(treeId)
objectTreeMock.EXPECT().
fx.receiveQueueMock.EXPECT().AddMessage(senderId, gomock.Eq(treeMsg), replyId).Return(false)
fx.receiveQueueMock.EXPECT().GetMessage(senderId).Return(treeMsg, replyId, nil)
fx.objectTreeMock.EXPECT().ID().AnyTimes().Return(treeId)
fx.objectTreeMock.EXPECT().
Heads().
Return([]string{"h2"})
objectTreeMock.EXPECT().
Return([]string{"h2"}).AnyTimes()
fx.objectTreeMock.EXPECT().
HasChanges(gomock.Eq([]string{"h1"})).
Return(false)
objectTreeMock.EXPECT().
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
fx.objectTreeMock.EXPECT().
AddRawChanges(gomock.Any(), gomock.Eq(tree.RawChangesPayload{
NewHeads: []string{"h1"},
RawChanges: []*treechangeproto.RawTreeChangeWithId{chWithId},
})).
Return(tree.AddResult{}, nil)
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
fx.receiveQueueMock.EXPECT().ClearQueue(senderId)
err := fx.syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err)
})
t.Run("full sync response with same heads", func(t *testing.T) {
fx := newSyncHandlerFixture(t)
defer fx.stop()
treeId := "treeId"
senderId := "senderId"
replyId := "replyId"
@ -367,12 +416,16 @@ func TestSyncHandler_HandleFullSyncResponse(t *testing.T) {
}
treeMsg := treechangeproto.WrapFullResponse(fullSyncResponse, chWithId)
objectMsg, _ := marshallTreeMessage(treeMsg, treeId, replyId)
objectTreeMock.EXPECT().ID().AnyTimes().Return(treeId)
objectTreeMock.EXPECT().
Heads().
Return([]string{"h1"})
fx.receiveQueueMock.EXPECT().AddMessage(senderId, gomock.Eq(treeMsg), replyId).Return(false)
fx.receiveQueueMock.EXPECT().GetMessage(senderId).Return(treeMsg, replyId, nil)
err := syncHandler.HandleMessage(ctx, senderId, objectMsg)
fx.objectTreeMock.EXPECT().ID().AnyTimes().Return(treeId)
fx.objectTreeMock.EXPECT().
Heads().
Return([]string{"h1"}).AnyTimes()
fx.receiveQueueMock.EXPECT().ClearQueue(senderId)
err := fx.syncHandler.HandleMessage(ctx, senderId, objectMsg)
require.NoError(t, err)
})
}

View File

@ -32,6 +32,7 @@ type Config struct {
Storage Storage `yaml:"storage"`
Metric Metric `yaml:"metric"`
Log Log `yaml:"log"`
Stream Stream `yaml:"stream"`
}
func (c *Config) Init(a *app.App) (err error) {
@ -51,6 +52,10 @@ func (c Config) GetGRPCServer() GrpcServer {
return c.GrpcServer
}
func (c Config) GetStream() Stream {
return c.Stream
}
func (c Config) GetAccount() Account {
return c.Account
}

6
common/config/stream.go Normal file
View File

@ -0,0 +1,6 @@
package config
type Stream struct {
TimeoutMilliseconds int `yaml:"timeoutMilliseconds"`
MaxMsgSizeMb int `yaml:"maxMsgSizeMb"`
}

View File

@ -28,6 +28,7 @@ require (
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cheggaaa/mb/v3 v3.0.0-20221122160120-e9034545510c // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/fogleman/gg v1.3.0 // indirect
@ -55,7 +56,7 @@ require (
github.com/spaolacci/murmur3 v1.1.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/crypto v0.0.0-20220622213112-05595931fe9d // indirect
golang.org/x/image v0.0.0-20200119044424-58c23975cae1 // indirect
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
google.golang.org/protobuf v1.28.1 // indirect

View File

@ -56,6 +56,8 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cheggaaa/mb/v3 v3.0.0-20221122160120-e9034545510c h1:+bD75daSbsxyTzkKpNplC4xls+7/tGwty+zruzOnOmk=
github.com/cheggaaa/mb/v3 v3.0.0-20221122160120-e9034545510c/go.mod h1:zCt2QeYukhd/g0bIdNqF+b/kKz1hnLFNDkP49qN5kqI=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@ -313,6 +315,7 @@ golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=

View File

@ -8,12 +8,16 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/config"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/secure"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/timeoutconn"
"github.com/libp2p/go-libp2p/core/sec"
"go.uber.org/zap"
"net"
"storj.io/drpc"
"storj.io/drpc/drpcconn"
"storj.io/drpc/drpcmanager"
"storj.io/drpc/drpcwire"
"sync"
"time"
)
const CName = "common.net.dialer"
@ -34,6 +38,7 @@ type Dialer interface {
type dialer struct {
transport secure.Service
config *config.Config
peerAddrs map[string][]string
mu sync.RWMutex
@ -41,9 +46,9 @@ type dialer struct {
func (d *dialer) Init(a *app.App) (err error) {
d.transport = a.MustComponent(secure.CName).(secure.Service)
nodes := a.MustComponent(config.CName).(*config.Config).Nodes
d.config = a.MustComponent(config.CName).(*config.Config)
d.peerAddrs = map[string][]string{}
for _, n := range nodes {
for _, n := range d.config.Nodes {
d.peerAddrs[n.PeerId] = []string{n.Address}
}
return
@ -90,11 +95,15 @@ func (d *dialer) handshake(ctx context.Context, addr string) (conn drpc.Conn, sc
if err != nil {
return
}
sc, err = d.transport.TLSConn(ctx, tcpConn)
timeoutConn := timeoutconn.NewConn(tcpConn, time.Millisecond*time.Duration(d.config.Stream.TimeoutMilliseconds))
sc, err = d.transport.TLSConn(ctx, timeoutConn)
if err != nil {
return
}
log.Info("connected with remote host", zap.String("serverPeer", sc.RemotePeer().String()), zap.String("per", sc.LocalPeer().String()))
conn = drpcconn.New(sc)
conn = drpcconn.NewWithOptions(sc, drpcconn.Options{Manager: drpcmanager.Options{
Reader: drpcwire.ReaderOptions{MaximumBufferSize: d.config.Stream.MaxMsgSizeMb * (1 << 20)},
}})
return conn, sc, err
}

View File

@ -8,8 +8,10 @@ import (
"io"
"net"
"storj.io/drpc"
"storj.io/drpc/drpcmanager"
"storj.io/drpc/drpcmux"
"storj.io/drpc/drpcserver"
"storj.io/drpc/drpcwire"
"time"
)
@ -22,21 +24,31 @@ type BaseDrpcServer struct {
}
type DRPCHandlerWrapper func(handler drpc.Handler) drpc.Handler
type ListenerConverter func(listener net.Listener) secure.ContextListener
type ListenerConverter func(listener net.Listener, timeoutMillis int) secure.ContextListener
type Params struct {
BufferSizeMb int
ListenAddrs []string
Wrapper DRPCHandlerWrapper
Converter ListenerConverter
TimeoutMillis int
}
func NewBaseDrpcServer() *BaseDrpcServer {
return &BaseDrpcServer{Mux: drpcmux.New()}
}
func (s *BaseDrpcServer) Run(ctx context.Context, listenAddrs []string, wrapper DRPCHandlerWrapper, converter ListenerConverter) (err error) {
s.drpcServer = drpcserver.New(wrapper(s.Mux))
func (s *BaseDrpcServer) Run(ctx context.Context, params Params) (err error) {
s.drpcServer = drpcserver.NewWithOptions(params.Wrapper(s.Mux), drpcserver.Options{Manager: drpcmanager.Options{
Reader: drpcwire.ReaderOptions{MaximumBufferSize: params.BufferSizeMb * (1 << 20)},
}})
ctx, s.cancel = context.WithCancel(ctx)
for _, addr := range listenAddrs {
for _, addr := range params.ListenAddrs {
tcpList, err := net.Listen("tcp", addr)
if err != nil {
return err
}
tlsList := converter(tcpList)
tlsList := params.Converter(tcpList, params.TimeoutMillis)
go s.serve(ctx, tlsList)
}
return

View File

@ -26,17 +26,18 @@ type DRPCServer interface {
type configGetter interface {
GetGRPCServer() config.GrpcServer
GetStream() config.Stream
}
type drpcServer struct {
config config.GrpcServer
config configGetter
metric metric.Metric
transport secure.Service
*BaseDrpcServer
}
func (s *drpcServer) Init(a *app.App) (err error) {
s.config = a.MustComponent(config.CName).(configGetter).GetGRPCServer()
s.config = a.MustComponent(config.CName).(configGetter)
s.metric = a.MustComponent(metric.CName).(metric.Metric)
s.transport = a.MustComponent(secure.CName).(secure.Service)
return nil
@ -61,16 +62,19 @@ func (s *drpcServer) Run(ctx context.Context) (err error) {
if err = s.metric.Registry().Register(histVec); err != nil {
return
}
return s.BaseDrpcServer.Run(
ctx,
s.config.ListenAddrs,
func(handler drpc.Handler) drpc.Handler {
params := Params{
BufferSizeMb: s.config.GetStream().MaxMsgSizeMb,
TimeoutMillis: s.config.GetStream().TimeoutMilliseconds,
ListenAddrs: s.config.GetGRPCServer().ListenAddrs,
Wrapper: func(handler drpc.Handler) drpc.Handler {
return &metric.PrometheusDRPC{
Handler: handler,
SummaryVec: histVec,
}
},
s.transport.TLSListener)
Converter: s.transport.TLSListener,
}
return s.BaseDrpcServer.Run(ctx, params)
}
func (s *drpcServer) Close(ctx context.Context) (err error) {

View File

@ -2,18 +2,25 @@ package secure
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/timeoutconn"
"net"
"time"
)
type basicListener struct {
net.Listener
timeoutMillis int
}
func newBasicListener(listener net.Listener) ContextListener {
return &basicListener{listener}
func newBasicListener(listener net.Listener, timeoutMillis int) ContextListener {
return &basicListener{listener, timeoutMillis}
}
func (b *basicListener) Accept(ctx context.Context) (context.Context, net.Conn, error) {
conn, err := b.Listener.Accept()
return ctx, conn, err
if err != nil {
return nil, nil, err
}
timeoutConn := timeoutconn.NewConn(conn, time.Duration(b.timeoutMillis)*time.Millisecond)
return ctx, timeoutConn, err
}

View File

@ -25,8 +25,8 @@ func New() Service {
}
type Service interface {
TLSListener(lis net.Listener) ContextListener
BasicListener(lis net.Listener) ContextListener
TLSListener(lis net.Listener, timeoutMillis int) ContextListener
BasicListener(lis net.Listener, timeoutMillis int) ContextListener
TLSConn(ctx context.Context, conn net.Conn) (sec.SecureConn, error)
app.Component
}
@ -54,12 +54,12 @@ func (s *service) Name() (name string) {
return CName
}
func (s *service) TLSListener(lis net.Listener) ContextListener {
return newTLSListener(s.key, lis)
func (s *service) TLSListener(lis net.Listener, timeoutMillis int) ContextListener {
return newTLSListener(s.key, lis, timeoutMillis)
}
func (s *service) BasicListener(lis net.Listener) ContextListener {
return newBasicListener(lis)
func (s *service) BasicListener(lis net.Listener, timeoutMillis int) ContextListener {
return newBasicListener(lis, timeoutMillis)
}
func (s *service) TLSConn(ctx context.Context, conn net.Conn) (sec.SecureConn, error) {

View File

@ -3,9 +3,11 @@ package secure
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/timeoutconn"
"github.com/libp2p/go-libp2p/core/crypto"
libp2ptls "github.com/libp2p/go-libp2p/p2p/security/tls"
"net"
"time"
)
type ContextListener interface {
@ -20,17 +22,19 @@ type ContextListener interface {
Addr() net.Addr
}
func newTLSListener(key crypto.PrivKey, lis net.Listener) ContextListener {
func newTLSListener(key crypto.PrivKey, lis net.Listener, timeoutMillis int) ContextListener {
tr, _ := libp2ptls.New(key)
return &tlsListener{
tr: tr,
Listener: lis,
tr: tr,
Listener: lis,
timeoutMillis: timeoutMillis,
}
}
type tlsListener struct {
net.Listener
tr *libp2ptls.Transport
tr *libp2ptls.Transport
timeoutMillis int
}
func (p *tlsListener) Accept(ctx context.Context) (context.Context, net.Conn, error) {
@ -38,7 +42,8 @@ func (p *tlsListener) Accept(ctx context.Context) (context.Context, net.Conn, er
if err != nil {
return nil, nil, err
}
return p.upgradeConn(ctx, conn)
timeoutConn := timeoutconn.NewConn(conn, time.Duration(p.timeoutMillis)*time.Millisecond)
return p.upgradeConn(ctx, timeoutConn)
}
func (p *tlsListener) upgradeConn(ctx context.Context, conn net.Conn) (context.Context, net.Conn, error) {

View File

@ -0,0 +1,39 @@
package timeoutconn
import (
"errors"
"net"
"os"
"time"
)
type Conn struct {
net.Conn
timeout time.Duration
}
func NewConn(conn net.Conn, timeout time.Duration) *Conn {
return &Conn{conn, timeout}
}
func (c *Conn) Write(p []byte) (n int, err error) {
for {
if c.timeout != 0 {
c.Conn.SetWriteDeadline(time.Now().Add(c.timeout))
}
nn, err := c.Conn.Write(p[n:])
n += nn
if n < len(p) && nn > 0 && errors.Is(err, os.ErrDeadlineExceeded) {
// Keep extending the deadline so long as we're making progress.
continue
}
if c.timeout != 0 {
c.Conn.SetWriteDeadline(time.Time{})
}
if err != nil {
// if the connection is timed out and we should close it
c.Conn.Close()
}
return n, err
}
}

View File

@ -246,7 +246,7 @@ func (st *ACLState) applyChangeData(changeData *aclrecordproto.ACLData, hash uin
return
}
if !st.hasPermission(identity, aclrecordproto.ACLUserPermissions_Admin) {
if !st.HasPermission(identity, aclrecordproto.ACLUserPermissions_Admin) {
err = fmt.Errorf("user %s must have admin permissions", identity)
return
}
@ -413,7 +413,7 @@ func (st *ACLState) decryptReadKeyAndHash(msg []byte) (*symmetric.Key, uint64, e
return key, hasher.Sum64(), nil
}
func (st *ACLState) hasPermission(identity []byte, permission aclrecordproto.ACLUserPermissions) bool {
func (st *ACLState) HasPermission(identity []byte, permission aclrecordproto.ACLUserPermissions) bool {
state, exists := st.userStates[string(identity)]
if !exists {
return false

View File

@ -53,23 +53,18 @@ func (mr *MockObjectTreeMockRecorder) AddContent(arg0, arg1 interface{}) *gomock
}
// AddRawChanges mocks base method.
func (m *MockObjectTree) AddRawChanges(arg0 context.Context, arg1 ...*treechangeproto.RawTreeChangeWithId) (tree.AddResult, error) {
func (m *MockObjectTree) AddRawChanges(arg0 context.Context, arg1 tree.RawChangesPayload) (tree.AddResult, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0}
for _, a := range arg1 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "AddRawChanges", varargs...)
ret := m.ctrl.Call(m, "AddRawChanges", arg0, arg1)
ret0, _ := ret[0].(tree.AddResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AddRawChanges indicates an expected call of AddRawChanges.
func (mr *MockObjectTreeMockRecorder) AddRawChanges(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
func (mr *MockObjectTreeMockRecorder) AddRawChanges(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChanges", reflect.TypeOf((*MockObjectTree)(nil).AddRawChanges), varargs...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChanges", reflect.TypeOf((*MockObjectTree)(nil).AddRawChanges), arg0, arg1)
}
// ChangesAfterCommonSnapshot mocks base method.

View File

@ -4,6 +4,7 @@ package tree
import (
"context"
"errors"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/common"
list "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
@ -33,6 +34,11 @@ type AddResult struct {
Mode Mode
}
type RawChangesPayload struct {
NewHeads []string
RawChanges []*treechangeproto.RawTreeChangeWithId
}
type ChangeIterateFunc = func(change *Change) bool
type ChangeConvertFunc = func(decrypted []byte) (any, error)
@ -55,7 +61,7 @@ type ObjectTree interface {
Storage() storage.TreeStorage
AddContent(ctx context.Context, content SignableChangeContent) (AddResult, error)
AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (AddResult, error)
AddRawChanges(ctx context.Context, changes RawChangesPayload) (AddResult, error)
Delete() error
Close() error
@ -113,10 +119,10 @@ func defaultObjectTreeDeps(
}
}
func (ot *objectTree) rebuildFromStorage(newChanges []*Change) (err error) {
func (ot *objectTree) rebuildFromStorage(theirHeads []string, newChanges []*Change) (err error) {
ot.treeBuilder.Reset()
ot.tree, err = ot.treeBuilder.Build(newChanges)
ot.tree, err = ot.treeBuilder.Build(theirHeads, newChanges)
if err != nil {
return
}
@ -192,6 +198,13 @@ func (ot *objectTree) prepareBuilderContent(content SignableChangeContent) (cnt
readKey *symmetric.Key
readKeyHash uint64
)
canWrite := state.HasPermission(content.Identity, aclrecordproto.ACLUserPermissions_Writer) ||
state.HasPermission(content.Identity, aclrecordproto.ACLUserPermissions_Admin)
if !canWrite {
err = list.ErrInsufficientPermissions
return
}
if content.IsEncrypted {
readKeyHash = state.CurrentReadKeyHash()
readKey, err = state.CurrentReadKey()
@ -213,8 +226,8 @@ func (ot *objectTree) prepareBuilderContent(content SignableChangeContent) (cnt
return
}
func (ot *objectTree) AddRawChanges(ctx context.Context, rawChanges ...*treechangeproto.RawTreeChangeWithId) (addResult AddResult, err error) {
addResult, err = ot.addRawChanges(ctx, rawChanges...)
func (ot *objectTree) AddRawChanges(ctx context.Context, changesPayload RawChangesPayload) (addResult AddResult, err error) {
addResult, err = ot.addRawChanges(ctx, changesPayload)
if err != nil {
return
}
@ -235,7 +248,7 @@ func (ot *objectTree) AddRawChanges(ctx context.Context, rawChanges ...*treechan
return
}
func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechangeproto.RawTreeChangeWithId) (addResult AddResult, err error) {
func (ot *objectTree) addRawChanges(ctx context.Context, changesPayload RawChangesPayload) (addResult AddResult, err error) {
// resetting buffers
ot.newChangesBuf = ot.newChangesBuf[:0]
ot.notSeenIdxBuf = ot.notSeenIdxBuf[:0]
@ -252,7 +265,7 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechan
prevHeadsCopy := headsCopy()
// filtering changes, verifying and unmarshalling them
for idx, ch := range rawChanges {
for idx, ch := range changesPayload.RawChanges {
// not unmarshalling the changes if they were already added either as unattached or attached
if _, exists := ot.tree.attached[ch.Id]; exists {
continue
@ -331,17 +344,17 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechan
ot.newChangesBuf = discardFromSlice(ot.newChangesBuf, func(ch *Change) bool { return ch == nil })
if shouldRebuildFromStorage {
err = ot.rebuildFromStorage(ot.newChangesBuf)
err = ot.rebuildFromStorage(changesPayload.NewHeads, ot.newChangesBuf)
if err != nil {
// rebuilding without new changes
ot.rebuildFromStorage(nil)
ot.rebuildFromStorage(nil, nil)
return
}
addResult, err = ot.createAddResult(prevHeadsCopy, Rebuild, nil, rawChanges)
addResult, err = ot.createAddResult(prevHeadsCopy, Rebuild, nil, changesPayload.RawChanges)
if err != nil {
// that means that some unattached changes were somehow corrupted in memory
// this shouldn't happen but if that happens, then rebuilding from storage
ot.rebuildFromStorage(nil)
ot.rebuildFromStorage(nil, nil)
return
}
return
@ -366,11 +379,11 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechan
err = ErrHasInvalidChanges
return
}
addResult, err = ot.createAddResult(prevHeadsCopy, mode, treeChangesAdded, rawChanges)
addResult, err = ot.createAddResult(prevHeadsCopy, mode, treeChangesAdded, changesPayload.RawChanges)
if err != nil {
// that means that some unattached changes were somehow corrupted in memory
// this shouldn't happen but if that happens, then rebuilding from storage
ot.rebuildFromStorage(nil)
ot.rebuildFromStorage(nil, nil)
return
}
return

View File

@ -161,7 +161,11 @@ func TestObjectTree(t *testing.T) {
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"),
}
res, err := objTree.AddRawChanges(context.Background(), rawChanges...)
payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
RawChanges: rawChanges,
}
res, err := objTree.AddRawChanges(context.Background(), payload)
require.NoError(t, err, "adding changes should be without error")
// check result
@ -201,7 +205,11 @@ func TestObjectTree(t *testing.T) {
rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.createRaw("0", aclList.Head().Id, "", true, ""),
}
res, err := objTree.AddRawChanges(context.Background(), rawChanges...)
payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
RawChanges: rawChanges,
}
res, err := objTree.AddRawChanges(context.Background(), payload)
require.NoError(t, err, "adding changes should be without error")
// check result
@ -221,7 +229,11 @@ func TestObjectTree(t *testing.T) {
rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"),
}
res, err := objTree.AddRawChanges(context.Background(), rawChanges...)
payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
RawChanges: rawChanges,
}
res, err := objTree.AddRawChanges(context.Background(), payload)
require.NoError(t, err, "adding changes should be without error")
// check result
@ -246,7 +258,12 @@ func TestObjectTree(t *testing.T) {
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.createRaw("4", aclList.Head().Id, "3", false, "3"),
}
res, err := objTree.AddRawChanges(context.Background(), rawChanges...)
payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
RawChanges: rawChanges,
}
res, err := objTree.AddRawChanges(context.Background(), payload)
require.NoError(t, err, "adding changes should be without error")
// check result
@ -289,7 +306,12 @@ func TestObjectTree(t *testing.T) {
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"),
}
_, err := objTree.AddRawChanges(context.Background(), rawChanges...)
payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
RawChanges: rawChanges,
}
_, err := objTree.AddRawChanges(context.Background(), payload)
require.NoError(t, err, "adding changes should be without error")
snapshotPath := objTree.SnapshotPath()
@ -312,7 +334,12 @@ func TestObjectTree(t *testing.T) {
changeCreator.createRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"),
}
_, err := objTree.AddRawChanges(context.Background(), rawChanges...)
payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
RawChanges: rawChanges,
}
_, err := objTree.AddRawChanges(context.Background(), payload)
require.NoError(t, err, "adding changes should be without error")
require.Equal(t, "0", objTree.Root().Id)
@ -387,7 +414,12 @@ func TestObjectTree(t *testing.T) {
changeCreator.createRaw("6", aclList.Head().Id, "0", true, "3", "4", "5"),
}
_, err := objTree.AddRawChanges(context.Background(), rawChanges...)
payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
RawChanges: rawChanges,
}
_, err := objTree.AddRawChanges(context.Background(), payload)
require.NoError(t, err, "adding changes should be without error")
require.Equal(t, "6", objTree.Root().Id)
@ -458,7 +490,12 @@ func TestObjectTree(t *testing.T) {
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"),
}
res, err := objTree.AddRawChanges(context.Background(), rawChanges...)
payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
RawChanges: rawChanges,
}
res, err := objTree.AddRawChanges(context.Background(), payload)
require.NoError(t, err, "adding changes should be without error")
require.Equal(t, "3", objTree.Root().Id)
@ -467,7 +504,12 @@ func TestObjectTree(t *testing.T) {
changeCreator.createRaw("5", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"),
}
res, err = objTree.AddRawChanges(context.Background(), rawChanges...)
payload = RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
RawChanges: rawChanges,
}
res, err = objTree.AddRawChanges(context.Background(), payload)
require.NoError(t, err, "adding changes should be without error")
// check result

View File

@ -106,7 +106,7 @@ func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
newSnapshotsBuf: make([]*Change, 0, 10),
}
err := objTree.rebuildFromStorage(nil)
err := objTree.rebuildFromStorage(nil, nil)
if err != nil {
return nil, err
}

View File

@ -143,6 +143,7 @@ func (r *rawChangeLoader) LoadFromStorage(commonSnapshot string, heads, breakpoi
}
if !exists {
entry, err = r.loadEntry(id)
entry.position = -1
if err != nil {
continue
}
@ -204,7 +205,6 @@ func (r *rawChangeLoader) LoadFromStorage(commonSnapshot string, heads, breakpoi
if entry.position != -1 {
buffer[entry.position] = nil
}
entry.position = len(buffer) + 1
return entry
})

View File

@ -40,27 +40,49 @@ func (tb *treeBuilder) Reset() {
tb.tree = &Tree{}
}
func (tb *treeBuilder) Build(newChanges []*Change) (*Tree, error) {
var headsAndNewChanges []string
func (tb *treeBuilder) Build(theirHeads []string, newChanges []*Change) (*Tree, error) {
var proposedHeads []string
tb.cache = make(map[string]*Change)
heads, err := tb.treeStorage.Heads()
if err != nil {
return nil, err
}
headsAndNewChanges = append(headsAndNewChanges, heads...)
tb.cache = make(map[string]*Change)
for _, ch := range newChanges {
headsAndNewChanges = append(headsAndNewChanges, ch.Id)
tb.cache[ch.Id] = ch
}
log.With(zap.Strings("heads", heads)).Debug("building tree")
breakpoint, err := tb.findBreakpoint(headsAndNewChanges)
// TODO: we can actually get this from tree (though not sure, that there would always be
// an invariant where the tree has the closest common snapshot of heads)
// so if optimization is critical we can change this to inject from tree directly
// but then we have to be sure that invariant stays true
oldBreakpoint, err := tb.findBreakpoint(heads, true)
if err != nil {
// this should never error out, because otherwise we have broken data
return nil, fmt.Errorf("findBreakpoint error: %v", err)
}
if err = tb.buildTree(headsAndNewChanges, breakpoint); err != nil {
if len(theirHeads) > 0 {
proposedHeads = append(proposedHeads, theirHeads...)
}
for _, ch := range newChanges {
if len(theirHeads) == 0 {
// in this case we don't know what new heads are, so every change can be head
proposedHeads = append(proposedHeads, ch.Id)
}
tb.cache[ch.Id] = ch
}
// getting common snapshot for new heads
breakpoint, err := tb.findBreakpoint(proposedHeads, false)
if err != nil {
breakpoint = oldBreakpoint
} else {
breakpoint, err = tb.findCommonForTwoSnapshots(oldBreakpoint, breakpoint)
if err != nil {
breakpoint = oldBreakpoint
}
}
proposedHeads = append(proposedHeads, heads...)
log.With(zap.Strings("heads", proposedHeads)).Debug("building tree")
if err = tb.buildTree(proposedHeads, breakpoint); err != nil {
return nil, fmt.Errorf("buildTree error: %v", err)
}
@ -73,13 +95,12 @@ func (tb *treeBuilder) buildTree(heads []string, breakpoint string) (err error)
return
}
tb.tree.AddFast(ch)
changes, err := tb.dfs(heads, breakpoint)
changes := tb.dfs(heads, breakpoint)
tb.tree.AddFast(changes...)
return
}
func (tb *treeBuilder) dfs(heads []string, breakpoint string) (buf []*Change, err error) {
func (tb *treeBuilder) dfs(heads []string, breakpoint string) []*Change {
// initializing buffers
tb.idStack = tb.idStack[:0]
tb.loadBuffer = tb.loadBuffer[:0]
@ -113,7 +134,7 @@ func (tb *treeBuilder) dfs(heads []string, breakpoint string) (buf []*Change, er
tb.idStack = append(tb.idStack, prev)
}
}
return tb.loadBuffer, nil
return tb.loadBuffer
}
func (tb *treeBuilder) loadChange(id string) (ch *Change, err error) {
@ -138,18 +159,34 @@ func (tb *treeBuilder) loadChange(id string) (ch *Change, err error) {
return ch, nil
}
func (tb *treeBuilder) findBreakpoint(heads []string) (breakpoint string, err error) {
func (tb *treeBuilder) findBreakpoint(heads []string, noError bool) (breakpoint string, err error) {
var (
ch *Change
snapshotIds []string
)
for _, head := range heads {
if ch, err = tb.loadChange(head); err != nil {
return
if noError {
return
}
log.With(zap.String("head", head), zap.Error(err)).Debug("couldn't find head")
continue
}
shId := ch.SnapshotId
if ch.IsSnapshot {
shId = ch.Id
} else {
_, err = tb.loadChange(shId)
if err != nil {
if noError {
return
}
log.With(zap.String("snapshot id", shId), zap.Error(err)).Debug("couldn't find head's snapshot")
continue
}
}
if slice.FindPos(snapshotIds, shId) == -1 {
snapshotIds = append(snapshotIds, shId)
@ -165,6 +202,7 @@ func (tb *treeBuilder) findCommonSnapshot(snapshotIds []string) (snapshotId stri
return "", fmt.Errorf("snapshots not found")
}
// TODO: use divide and conquer to find the snapshot, then we will have only logN findCommonForTwoSnapshots calls
for len(snapshotIds) > 1 {
l := len(snapshotIds)
shId, e := tb.findCommonForTwoSnapshots(snapshotIds[l-2], snapshotIds[l-1])

View File

@ -14,7 +14,7 @@ type PeriodicSync interface {
type SyncerFunc func(ctx context.Context) error
func NewPeriodicSync(periodSeconds int, syncer SyncerFunc, l *zap.Logger) PeriodicSync {
func NewPeriodicSync(periodSeconds int, timeout time.Duration, syncer SyncerFunc, l *zap.Logger) PeriodicSync {
ctx, cancel := context.WithCancel(context.Background())
return &periodicSync{
syncer: syncer,
@ -23,6 +23,7 @@ func NewPeriodicSync(periodSeconds int, syncer SyncerFunc, l *zap.Logger) Period
syncCancel: cancel,
syncLoopDone: make(chan struct{}),
periodSeconds: periodSeconds,
timeout: timeout,
}
}
@ -33,6 +34,7 @@ type periodicSync struct {
syncCancel context.CancelFunc
syncLoopDone chan struct{}
periodSeconds int
timeout time.Duration
}
func (p *periodicSync) Run() {
@ -43,8 +45,12 @@ func (p *periodicSync) syncLoop(periodSeconds int) {
period := time.Duration(periodSeconds) * time.Second
defer close(p.syncLoopDone)
doSync := func() {
ctx, cancel := context.WithTimeout(p.syncCtx, time.Minute)
defer cancel()
ctx := p.syncCtx
if p.timeout != 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(p.syncCtx, p.timeout)
defer cancel()
}
if err := p.syncer(ctx); err != nil {
p.log.Warn("periodic sync error", zap.Error(err))
}

View File

@ -23,7 +23,7 @@ func TestPeriodicSync_Run(t *testing.T) {
times += 1
return nil
}
pSync := NewPeriodicSync(secs, diffSyncer, l)
pSync := NewPeriodicSync(secs, 0, diffSyncer, l)
pSync.Run()
pSync.Close()
@ -38,7 +38,7 @@ func TestPeriodicSync_Run(t *testing.T) {
times += 1
return nil
}
pSync := NewPeriodicSync(secs, diffSyncer, l)
pSync := NewPeriodicSync(secs, 0, diffSyncer, l)
pSync.Run()
time.Sleep(time.Second * time.Duration(secs))

View File

@ -27,6 +27,7 @@ type Config struct {
Mongo Mongo `yaml:"mongo"`
Metric config2.Metric `yaml:"metric"`
Log config2.Log `yaml:"log"`
Stream config2.Stream `yaml:"stream"`
}
func (c *Config) Init(a *app.App) (err error) {
@ -45,6 +46,10 @@ func (c Config) GetGRPCServer() config2.GrpcServer {
return c.GrpcServer
}
func (c Config) GetStream() config2.Stream {
return c.Stream
}
func (c Config) GetAccount() config2.Account {
return c.Account
}

View File

@ -5,30 +5,30 @@ grpcServer:
- 127.0.0.1:4630
tls: false
account:
peerId: 12D3KooWFgtCbkf47HhFyQW2cEdAkvaofpokCiaa24Phnz7hpepG
peerKey: 4nWcqWOZxv1iXWYuW35eJlF9nxownm38bZjQ27pmFgVXO26vobKLx70TnNTQzZQdoW/dZtxyE9PO37R74vfPQQ==
signingKey: ULbtmmyFjkJ6Z+54FI1OJWfu0QdIeoCckwcrBZDLGhw2o2cXTFH5KGxQuAruNTbREz9eAVGmhGoBZtKVi6/6ng==
encryptionKey: MIIEowIBAAKCAQEAuGAvw/JQuivjoFIhV9RGkoCjO60jNkQpVPWK52eUtEvKHT2EzufhCRwxhAreajoyzk0PsyJ75FWrrvYs2tkSVHFOSiBkZIsldn5gPg1cnvnJOZ9VKDFp8h85d/4cPQ5tX78043nYTgLje2EmbB83inIr4oiZgxDrtLkozJHleAyWuOLIvlWO1l4Uplf6+uooL/5+WeUCuSGUM0wgXfpn+I2IuRhVDVZiChfp51Q6D6brTdOzNcWq1dw6Vld67u8aCLF1EVZ+xM/rnLLBC7MFvIw44LqHvmvGs/lpE9nMNx5L2KfpbpHSBI0IH3FkLQe2Qz8OMZpIa+aga/DzrBpEdwIDAQABAoIBACudXU898AjKPxN6ujZ7maIoWfTQ9SZuI1TcrNomr4+i6hHWrqb/RUWRbMkuhQSd9czFf/RBMQuHlJBT3bJ7bRGaqAly9iyumdMY/A1RvdpBfm9qGIvkfIpxBngzHVz4H7lpkspI1XlGx6c1CRDEpa/TaDwzUhUmGIvszRDvZlfqQvjPjyYSV5Hdc4ywh5zjuSFlxOD/9gsPRE5v4M4FGrGv8cm859P1u95Wxxo3pWincpzjvWw2LpsUGctyU34MhErxh86vNhP9v+nR4VkdojVKkHQTYnPKUlaKj6F+IUSj8syxuTJb8bs0GBuvcXW9AKp/K0xq/GBC8Cu/XN7Ln7kCgYEAwZoqLnU9OuwkcN5AHYW7XsxmVCEnxOsncrUbIzEKPvy4wELdOCVVrX66zmIjb+1+mhaz+mGMGEpkVMBld3wdDfmGgo0CAPlF4efH1ppMzUm2aZ+HYQR8KMH1XOT9qjbGEnLeWcANQT0vZPpe77PQLNwLJ1zv6EtXMMrEH0s4ijUCgYEA88zCNsBtB07ayFr9r+RCfHx/X9wFkT59t2K+axIfZE02f62WWqJCZYMlZu9XAbYEQ94H43/NAL9wfA8dgnF7mKSL8stJKt0g2iPa3MluF4Gq5Y2XYEVf/EDEhP2jh8p1l+xs18rVzsQQ6b3CEU9ytmBJWvkWnwVXf+ZnsCFECXsCgYBM3YyJzXp1/nOpbFRAZGw0AytNk6xafpK29DjGDB5pS6V+kA2M0SXnMD2y2zv+oGh3fTQP4NLigga7r3eZrOlMNxm0k4+MG2wneQLarYB4sR9/aBsz5bf15qwoKbKc9gpGIN0u/RVGJai/irhOqzGn3eV/x2Jo9CC1+otLcW4NUQKBgQCOOHlnZTN1GuwICwSIkhiy9BF+AyUASLsfuquoXEcRxPUw4DugnZ0sCKhN9vsDlYHBcYmajhgyAnuE83BcgwT906eMOEhzh9G9T0NCnwLpFYxzIvkWgQHwbnv1tNyrv1CAEryf2cSGPNw87qSCYp1hhKPmPP6UP5J+mxMLrSw6dwKBgHHFweDS2tw4TNxJQjhfQOp5t9VQbQffFZAqpXGFTc4vf7XePlxIGoIpOg4ShHCKKHSy0PtsLe7QjLrdbMkyYh8oGqgNe5CYTzFFDeK6Im1DoiqNWT+YUWF/gzVRUSpo0QW+4J1hfChG2URp9KbnditXKsJ5Vh+QayHPoZwN7Kgl
peerId: 12D3KooWQajuCbCYJdh6fhfTQpwJpJ61mV1ZV4F4XuJnFHeVfeSF
peerKey: Gz1ARVeHzdusDtBL0DawuQKoKdKhL827WiCPekOndSnbYb65zdtgoxGP8Y+enTfKksPftODaiqzZr16Dfq+JvA==
signingKey: wKPnynjYCBVqDEiREnMRHz6id1NFNIfjV4XKmB27ave9BSyS8saW71BEb/0XT0IZDJep6oSKr9ua5kAxcr7tQA==
encryptionKey: MIIEpAIBAAKCAQEA1DJ/TtBpSEVZVfPWJdp7tPaGY9d+4zrD91LM/4N4DKKhhSFfcWlHgZeQiEtP6bKCdIp2nPMURiS8hd1JzYmNJNk/hUYlzCUJOZWyduVeaow9rlTT6I9a8BVUBQHtVD+PUu5pkfjLFgAojcSzg/mIPzJ0T76AlsFXBdXRfS2wnVKfF0/V+jHiLB1V2JBLjyuRf2V5HFglEmWfrCoG02Q9OENZJHy02NXGCs7FnZdYhHct9u00dXk6Xp0w+oBD74+h4gsyFAHnRodRnhC0WMSv2LIPIQUh7x5LfvKx85n6LMFk/aYgTNFKQfu15VTzjfbVbeAm8jsHgV/FifRvETHm6QIDAQABAoIBAF6RLqlaOkFqHpkutRZjm1QXtebTCAqOiv0zGocY+SxwYhlpuRZa+/ImMNR8891Ln9X+S0RBFJz6DEaASz7deVidtTBZBclIDCdsrn9MU1qaq3aA+XugP7/VUX91z2YHeYFVHRlfzmo8odYkfnhnga/gdXOAi+Ajw/umwdjOvvItKqzm4FHHrwmqKDGlMfPgVcbkE/1iDRSwGvuEPOtMuNrTGcPyz0w10BO5zfpxgxJ2Esgmg66VG+H/KPSoLCtStZilErC8gRx9AbbJGUJcLkjd3T6A02cS9IS/hyTEK7qjxNjVaW0DfCrjXfIFiVHeXTB1LSS2JR95kArG437WTw0CgYEA/JsW6qDjl1jF7tYr+E6PjnCk/dgm3nlsC8sTbZd5edPN3dp+D6qlwv4KYKDETpxohMMhOdSl5SYp4dirsnyPDF1BcGdrkq73aE6n4Tx7oQBMeuZLvK9hxWprJqRa9WP49CDiLOc/GLOe3N90s8ViSqU08/tqOtQLU4BmjHMCDzcCgYEA1wxpL7XUUeDa+bGXrtii3oXlZpyoUXft3JjhTazC1lQuwp5M5+0HA/BuTpl8b43+0gcgrUjqB7yeKWZ8Us0gE9ZMBPTGNNGjXjGOtOk1Lpm+PHrCxmADzfJ8V+rrQXvW2KcImJ0bZk87eNUKtDSsWy6+NIQ6W66GUFvv8iblit8CgYEAvBVKCedDrqQFtKC5Wog8MYXEA9IWlt33ygwp6ha39zLyfPa7mDSqebanyWzK3fFtjTSxH5sq7qTs2GF47kv6Qu2I1QXcPfqS8pJmQ7nCH43WZEfnKpW3icOEBuCnbUFD05pMbby86UqMxc6H2Xblicja1bNkVGsgB8t6D6duaB8CgYEAq337OA/x1KXTGoJ0avvZzkjK6uyNEgLozh2gtpfJ/K+/ZnZk8CNGj+6hmM6vvCpphsYmWeomr6rMGknfZQytwwQHNYCZu69eb5RnsH+1aIc0fPiM8TPKdOcmH9p4Z41BhR6XLVVEb29KBw8l7RWASWraRfkYrNpdxCG9FMfOD9MCgYBJ6Z7YNZsJq263s9oJ01npT2NlfXORd3KDHi/A6qC8Jx1dK3+Jew2VV53/PeXJKuPuePSV7nEOwA0wpg3+TuEsWHHOZVO4c+ZVJmonO0x0IzjMHzBB/8VZc+5n+yi/UOSupt/WRcoPOTjJ7tQdhc2m9C7YA248laYikbzkW5DHoA==
apiServer:
listenAddrs:
- 127.0.0.1:8090
tls: false
nodes:
- peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
- peerId: 12D3KooWHtnADt84naf6NeejZ1MxYGZPLk5SPEu2DL4ZV948uWPS
address: 127.0.0.1:4430
signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
- peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
signingKey: Fu/H792JFWVYQpOZeLBIr1Y5UuHdZzJxkGO7eakZDaZ3/vIDhjGgNab1+1NMdTJ0IUP6Tv3KQutcRwtX26/wmQ==
encryptionKey: MIIEowIBAAKCAQEAs+N32tT2Q4Nv9MlyH0B34TJZYLh1+Y/4hc0vupiS/Ct0Mt+Rh62KkPy6Hz2JRDd7ryYpz/Un+qAFQBhfugKy6a5R0U/OnaK8/WwJjstTPd59c7iGnCeW9mWumexT2wiQVbWcSdcAE5SPYmBkIPnwzgxZgtNzvEnbdUDWIOsR3ifDAt3iUqqlo+cZWIZaXiTjyrMlaWY/BR/SGrklYzxcUzNj+K6DdY4yFN5/5ywKIe81llooULTyM5U+fWEW5uri4ERgT/YcRAoii2UJ5kHzpIZmGKcrJ4kUdyFLE7VxYIQMHHXRkDlpTEYlAAJGl5frcHvFufTWIJaohBXAxg5tyQIDAQABAoIBAD3TI9I19x1lAwliYrKS+aCQKV+whftrm8KArrK21W2NkbYaWG4FGuaRtXYfNBoZ54xe1Wf/nenpLWTF+8B2RP9DRiNmBmDvGX0PsIk/IDDXUs5+0OTCRoQQll2Yd4mD+/c5H6nRFtmj6VOqRT+AJ17pp6nq+o/v4lj+G5ncsJtlAtq1xb20yHQYEl6sbK2UqYuiFtXpKMCK/8V3hDj+ROM8UMkxMj+qj9NFd2sCk4FEZ+S2QmHIjY55s4Rpe1RzZZZEYOuJ99Fism+HYXtf3JlFORaNIdhdWY1UkVAFuKY/ULoHOhf/RdJ8ZArak3CplpEdPTYC4IRBI1eZDDF2GgECgYEAw0jvV7E1kqfGD5Q1WTFsss4xHQntPtWRfyAI1viy16sqMX6wQ4ZixWXsOeMB1o5azqqjYo0BBiGw6ie1GKl0iZ09FxHmMDqFLf8a0JZXAlTvC/wEHgAXCzg7tpHRJD1B6gAiU6u6ALW14DtWe6tikFehrY0mwGb9koedQNgoGnkCgYEA69EcUTejGm5Hm6ANC5u5Vn1aaB4BrTJ36FGTaxjnSUPePBj0Eo2Bt+c25DiD3uGj2Jws5QrRhpu+NYhOTC+/P1/rm82w9Tpc8z/wA7nUk0gGEncgtJ8RFokom4B+Ui83JJiH0V7puZUhCc/TOmfa5N0SH5gM4q4rBoVDZtnTGdECgYEAlnssW9GlK6Z2++hEF7/7N+mldPACTkn6PRCtXyHzhjdSYyNxpgb3M49vsceY0gGOPfTFxBpNsLDjh/wjE6b4s1ZkDdPwIjfmCmSrABLpZ1WVgxGnBoshNrcVZIEGvTsrAKsryHfq88MSLIDtCo0tfXbZkkfTla2HNpOj/KTUelkCgYBl0pMRlp58qSWOUxuO6ZyrddD1qA89Q892ptKqqcQkZIOvG284G5XpXJLdFHIMaQ2gWD8iXvt9zf3hi4uTZgKEUNyhF73TBXJhLjhqw3DAb5b/niSnGQ/91ReNnXvt7Kk4ygvLIdp14ai0XeJtE672p2ZN8g+OSXoWhLBH1sJKIQKBgA7NH/Y4RbVHIMWY7jH/1d4ODZ4Hr1RK2Q99HJCAurfD5tjhpcMApoQQJKJDpv7J5Ipx6ynQJD7CFfx27+vqBEG4ffAUm66lKM5xrKcOevcyWemppurCLuza64GgWDP6jBRnHeqrUyZUqoI/I0FNwjxIJbu08NpRSt8khq59+iyF
- peerId: 12D3KooWG1r2SVzTMGDhkiw9McbZq98H9C1Ggzp7FSfWDGbVSCbZ
address: 127.0.0.1:4431
signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
- peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
signingKey: CZTN+NFi4g9MA4BKl3OiCKuzXh63ukIvYWo9D5t9qfZcFwIeOW8eP9W8mtnXaY3JAFyb6GliBW0uCaw4wjRcCA==
encryptionKey: MIIEpAIBAAKCAQEAo9Nuypzg9kZ+LP+8jQgSTaoRUu8VFdJdCOEjuroPQK+2NwBD/Z9BqKiN0Z+jmhkI9yA0/Fwdh21ibAKX3Je9uffAKOhXI2sxIAlccDORu1kGDnhcc7N3L644DK+uFZvKnMQWiCwmtTnNHkoCzWcIE44G56wMa2c4W7mrOuRWqG6a5Z9JUuLqafOIlf6Dw2fiVM6xXiTIMQ0OyXByxFNjsS5O/PYcwoIKMV8MY+gUnAmyPLE0bslvz/8W+3E7d/LDO4lhqW+N1kDmboe6sc7DBf5JD4DLnP2VWV8Ae/rfJvxwu9ZqVT8RdYKMsZqvs9sV+6jQC9UcX+K8Q4Wdo0eMHwIDAQABAoIBAACR57zEtvOkYyP878b91DJ4+P503nno9XHmdp1bsFnlQpkGYzYqq6vOik/EYmlS1PknH4gROfkSpFkD2UtnK73N4tlBlawF33HhFnU9eLBSKvc56/hrE2sTDBbfNZfVpurMs9ddb/UJcnE8iK32QczvnY6IxrJI9aU8DCB0UujbGDnya/HbFU9pLLxu2EUoHNxjSHG/jCx+AR7JRknRA65KPZG7mu5jeAaaklYTY/aLGlctgecDKfNKDsZo6rgAMUW6ZXI8ogNGqfKHUFazCVe0l1tp4hxvgmyjcw79iKvFr4mlpHtgjYTFCeoMJKvOXUImZUJL0vCA6WKvUdIfzAECgYEA0lCTXYwOHqOwYMb1qi8lIIApcI//B/Nzn++MDQ4ZO4SzVJTTv4rSdXAuoihsO6E7LYZK+wdVNjiCbeMukfTqEfaxWXIsIDaHSR3440NsYSwdBz04UhRgpxFE2FwPK7J5dQ57FBaCAgksnO3XjcByBMYgMWVbA+ezIWfVdN96YoECgYEAx2mm/W4ZGdDyJgDonzEGGxfaNqo6DIv+67fDwI6WyqOWFWJTBaVFkm1uPJfcXYuTI9YCNFRKuRU7dyqSPLErMVusC/8Iww8++kqmkc1m04tbkqh4KpREYuMw8/tTYSWDwgpY8ksM5YRpYRJLTuuC0cEmefGco1RsXG8bYYeZXp8CgYBq5fexYcG/gxXgauBtSx9E4L+vbhGD2hNYJKr768GZhf6crDTgs8/7TzT0yTUSLgZlQlAUPgrqz1hEQGfoWiMrVEeanjSdfvnOiUR7R0bsMT7j8hMRbTgfUuC6VDiFzmZ7wAuBD1uvazhY329jpoCNuqKcWNclKfzbqupNSFXtgQKBgQCTlR7Qm0YadChydeOzxX2GWa3XHT7fAFFHNPa8MQtqp40xAFb/a6TEzRZz49RkqyLXt9Bj2CqBNjSPakNWhay41+bJ7hMXAdaTOOJ0L/c1AwNf1C0zHg5KvWgCefPohvIvjqbrkx3VU50GCZsQqn5kLLYENAvAWX/lHRm/obKhcwKBgQC/iAOC8ZdZC5w4F0Mf7roZWa9P/42JWlCMzm/I/5mEIn4mYY6+1C5V+fXoET6845oAh+P8CkH4waJtqqN6BKQhj7SKqoCHgGBCQy+HrSCBtzk7NuXdpz6sk14zfcVpjR3y3l9TuXc4cVQMSLAqg8yUQf+qnEQTit4jyfikV/5XEw==
- peerId: 12D3KooWDXDcBYxtZ8KNRoJebNgNAv9nFbQatQMoWm1BLwmQh6u7
address: 127.0.0.1:4432
signingKey: /6+uYFwFf9nU6fvXQVtpHhjd8+v4dXc7esZzqkhjyfMJWlMiZOtQeb913FXofD5f20WksU0l6i22B09sFFYwDQ==
encryptionKey: MIIEogIBAAKCAQEAwCy84lzkxtzgn4ixGm0LSUTujOBpOh9m7XDoDPZnMTmExdOe9a5v/LXzdlCOCuBvK5u1T3ALBJMA3Zgvjv/jPRQUdiHprP3sbdfc6IgZPBFdLKFTc9yAA7GMbI4y7LhGMLGOMOqQXs+DOeImfmxEs3ykLXHKNas5ORnZPVnB6E9Qod8KH7UyMmBjQkOZYOOw10X4JZiU6xJp/E+VVWcmeXgNBbj5xOWMSzM+hhoA4wNOzBxACucaKDmqD6qugzebOqyUVSzFnEbquro+MYTWYdUDjZTXdvxgUUo80MGQ164gZhkFUKrmSpUvu3YErFySEGqAdFNwOZ6y/4X3s0BHvQIDAQABAoIBAAZiNhAK5+qXMbr67m8jSimv6YCyf6xXmLKwenTbxofDEl8D7ZbZqYyqeqDmgiFoXSkErhwqa6NGQtQZlxLX+zNvNFLMQ5fkg3MOpZ7vzm7JYN/3p+8EVxhIUJLWkmh8opBBhaioUg1kNUa59W9jp1CTBl0gF4h63JbB/g5kqeVOllUw7J1igAoaX36nOJGOwIynCWdizhDhgyjR4OcYfOLwcPDJueKTc5vM10g3LuMSK/sJmaD3TkJFPtDHw+RMW6wqyjsnkrg2D2oohXEyGWYYIXo2so4HCez0AB1I1JAxtVnRPvSIp7xLMm7+AkDoq12QYDHfxZtDTpfmvJg+Sn0CgYEAxCd+oribtdQW+JUctjsDbSQX5CeRISH5Ith3jveBx2jKIqQVnoVPz6URHOvnlIsqYYLANB8B3JHMWfR2UmkK11x0OcZecB06+oBoCZukvSXF+GqVHzLAQUxaoEBDCCPneskj5w+riMWBiiGDp32rUnkqv0nh7dnH+GfORcJ44L8CgYEA+s5s5EALj1jyU9w4+HVUyVsIrUitFnQg6qw/Td3Kj+8CXImKlS+rlmbQv0m1aOcvtFjQRIjjzZJAf/ausfAME+MayoNODgZsDk5RyDKuSWzMLvZLAa1LD52Uli5Pg8KtpzKVTn4xE1MbjsQcUNhFRAgrNEKNyuzXzdp4uXgGOoMCgYASXwiTQOsEepq0KXMI9jn57Nl3+uSyz7W/t7pq329+N6hG2ktUD3RMJE+X/9gup2IOw+owd377I4SaIDU8vq3PQc944cVShspRT9lunO8u7+y8uW7B/0TWWMpcG+irSIGTlGcSavtL0gOx5jWoaDK1hLemNss8NZtu/nnpOq+LjQKBgDisVozJMBOHPNLYS4NROAR77p0BdCNDwIBmxbM5r+EQWA9DAS6u4+4Lc5YV+MkonG37N6yU5iz4pFyGCHmqzX/c7JvgSc3/g4FED1TWpu1uiUD/ZHmPiAuSRxYchtk2L3k9g+GFwF8mg26iP+fAxv4VfnXDqDi3hhg9CtSWG4ozAoGAOWZXlFKqzGAfcucIe54FVQnweXG9sEuIPAvWvVRs4406ggNmL5eHccXpPHWTgetsr2TYMqPTDVMRmhBzSkyrYgk+b2tme79HPzTWs2Yg/pzjOfTgw7MBX/KlvOW5/J+dvrF3Gx8AHHZ9QQdYqi/MS1NKb2K3IbD0/m5gL5Pwi6A=
signingKey: c3D+0+BCl1xU35KBY+U3GPcU9aXdoLUiD4DJ2jF+IqI3CjGLhet3MBOkPXdIuPq/UpEqlp1k6FjNaU6DEU6Csg==
encryptionKey: MIIEpAIBAAKCAQEAuB7HsXuYmoif6/U4JnjC6L0QMu9qW1aPAxDrxWIedTzQhFZp3F3gYW/Zgdd2hvd0c2xyfhwf9C0X/UzfxWr54dDXzWNLN8BdVTik48cdYlgOmbgejiIjTaqSAlv4RtlqvooxCN0MwR2/RVAG/N5GqcAM7E4kJWPtvQYNl6wWCc92rKdutvmcj73wKzz9Hd/qdF612OVS3zRsjh3tJmYt55oovAUh1TAz/mSTTXjFHy35zLRBP+oQQsAOt2p0BOMSyOKZufGC8l3aZD//dp4/U/MaqCjeNuWxCfAZlSd+vt7T0aqDGdyRtrrGUcu4PCwXpOdbzw+uSZxnKawolYoEHwIDAQABAoIBAQCsxeVpvKtUx8QZrUCFiWiM8W0T/un0z+LfY696xzoBlZGtvVEVQtpdVJHsb31/5RFXhnphsI6jmPUb8llBbcMSjeETkItyw4ZRhBfmzl/aevsocEfr5EjwhpEAucDe6wJpzk95G8TuKrXjmtcTzpjMjbUSwbjVhVH/wIBcxVTg2j6z4AOADDRI5UsvZ0NV//If+nNzMjcuIji95PNk7lAuwsqkX3FycxvqXKUMGxRE2bgGMxaBRAP0kqL2vdxyS1M7wp/x04ZAtSnPXHe4qqmDOt69ec3XqbmZHOsZHzkCFePKcPB472/G0bPJeiq/idevEqS89RwvbphDtq3KGrRBAoGBAOrHqlPh36WZBOi6SueUmcrg579KDMUekgeea5payiySbRWztCL2yCYbSgFqSbyCLRppyXK51xvo8iUejR231or6u/nd7T0CON0Nf/8Qtbb13vtTGpIBiWYGqeDrWucUUlyS+K3sDfNk1AJqjUdaIMVu4yTpgzEvrdYCcT312RBPAoGBAMjC83/0EKnsbypFprxKS3Fbg963HhyKjfffQ2w4yncM6kxXF3ehVjg1LInok/6/dmy2LxkAf3r0YYZrGJWmG4Sv4UqHn6JxAjQgarPbdmGhJ8VIUMvMbZRsX3i8Z8D2o8k1M1kr6MYsQ53iX6q/Cp3gnucMeJPk6Xs9Q4TO7YsxAoGAWrXEOF6X01p4zBZWJH2Eoh8dSwooPuzdzPXHaz7SyD/Wx8DDw5KHqDl48W0Iij3dgUwIGjx1QQJStEbGjQnfaZkQkazOIXk/USELKBhjrQn4GjB0np7bYEEI1673UzrFy6C5VjFS/owhYcGbTksjSETcnAFgv9tFFd+hsyfOsv8CgYALk4o875LiaXrDgj6qDtKo17ET75Ux6h9jkqEtpVyvXrRH8KGuyUPSe+Z0kU+vWdT3Uc4HcArpyRuyh4xkXK6riQTBqm5fDIsm/FOKyXXbDVLgwlm+Vqxe6Zzbtml5K/+nw4SReMG0Y6sGeJ4xl1CCaAhhpEtzo7h+3bp99vylkQKBgQDDdR6N4wb3DHTzrW0EFb8XhXZN7CIE3EWhToNDsCkguUB7lwqD4p2c4yLscS0YAqxk7I3NW0nDaUV/340RrVtPJDqB4NZJ+MvhfvV3TW2FkZmru/iW+DMUsfZGAOPdQz9jLGAzUXrXFw/qGBtLIUL6UWqWLOrBO9QHb21nnB1Ssg==
space:
gcTTL: 60
syncPeriod: 11
syncPeriod: 20
storage:
path: db
metric:
@ -37,3 +37,6 @@ log:
production: false
defaultLevel: ""
namedLevels: {}
stream:
timeoutMilliseconds: 1000
maxMsgSizeMb: 256

View File

@ -5,30 +5,30 @@ grpcServer:
- 127.0.0.1:4430
tls: false
account:
peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
peerKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
peerId: 12D3KooWHtnADt84naf6NeejZ1MxYGZPLk5SPEu2DL4ZV948uWPS
peerKey: Fu/H792JFWVYQpOZeLBIr1Y5UuHdZzJxkGO7eakZDaZ3/vIDhjGgNab1+1NMdTJ0IUP6Tv3KQutcRwtX26/wmQ==
signingKey: Fu/H792JFWVYQpOZeLBIr1Y5UuHdZzJxkGO7eakZDaZ3/vIDhjGgNab1+1NMdTJ0IUP6Tv3KQutcRwtX26/wmQ==
encryptionKey: MIIEowIBAAKCAQEAs+N32tT2Q4Nv9MlyH0B34TJZYLh1+Y/4hc0vupiS/Ct0Mt+Rh62KkPy6Hz2JRDd7ryYpz/Un+qAFQBhfugKy6a5R0U/OnaK8/WwJjstTPd59c7iGnCeW9mWumexT2wiQVbWcSdcAE5SPYmBkIPnwzgxZgtNzvEnbdUDWIOsR3ifDAt3iUqqlo+cZWIZaXiTjyrMlaWY/BR/SGrklYzxcUzNj+K6DdY4yFN5/5ywKIe81llooULTyM5U+fWEW5uri4ERgT/YcRAoii2UJ5kHzpIZmGKcrJ4kUdyFLE7VxYIQMHHXRkDlpTEYlAAJGl5frcHvFufTWIJaohBXAxg5tyQIDAQABAoIBAD3TI9I19x1lAwliYrKS+aCQKV+whftrm8KArrK21W2NkbYaWG4FGuaRtXYfNBoZ54xe1Wf/nenpLWTF+8B2RP9DRiNmBmDvGX0PsIk/IDDXUs5+0OTCRoQQll2Yd4mD+/c5H6nRFtmj6VOqRT+AJ17pp6nq+o/v4lj+G5ncsJtlAtq1xb20yHQYEl6sbK2UqYuiFtXpKMCK/8V3hDj+ROM8UMkxMj+qj9NFd2sCk4FEZ+S2QmHIjY55s4Rpe1RzZZZEYOuJ99Fism+HYXtf3JlFORaNIdhdWY1UkVAFuKY/ULoHOhf/RdJ8ZArak3CplpEdPTYC4IRBI1eZDDF2GgECgYEAw0jvV7E1kqfGD5Q1WTFsss4xHQntPtWRfyAI1viy16sqMX6wQ4ZixWXsOeMB1o5azqqjYo0BBiGw6ie1GKl0iZ09FxHmMDqFLf8a0JZXAlTvC/wEHgAXCzg7tpHRJD1B6gAiU6u6ALW14DtWe6tikFehrY0mwGb9koedQNgoGnkCgYEA69EcUTejGm5Hm6ANC5u5Vn1aaB4BrTJ36FGTaxjnSUPePBj0Eo2Bt+c25DiD3uGj2Jws5QrRhpu+NYhOTC+/P1/rm82w9Tpc8z/wA7nUk0gGEncgtJ8RFokom4B+Ui83JJiH0V7puZUhCc/TOmfa5N0SH5gM4q4rBoVDZtnTGdECgYEAlnssW9GlK6Z2++hEF7/7N+mldPACTkn6PRCtXyHzhjdSYyNxpgb3M49vsceY0gGOPfTFxBpNsLDjh/wjE6b4s1ZkDdPwIjfmCmSrABLpZ1WVgxGnBoshNrcVZIEGvTsrAKsryHfq88MSLIDtCo0tfXbZkkfTla2HNpOj/KTUelkCgYBl0pMRlp58qSWOUxuO6ZyrddD1qA89Q892ptKqqcQkZIOvG284G5XpXJLdFHIMaQ2gWD8iXvt9zf3hi4uTZgKEUNyhF73TBXJhLjhqw3DAb5b/niSnGQ/91ReNnXvt7Kk4ygvLIdp14ai0XeJtE672p2ZN8g+OSXoWhLBH1sJKIQKBgA7NH/Y4RbVHIMWY7jH/1d4ODZ4Hr1RK2Q99HJCAurfD5tjhpcMApoQQJKJDpv7J5Ipx6ynQJD7CFfx27+vqBEG4ffAUm66lKM5xrKcOevcyWemppurCLuza64GgWDP6jBRnHeqrUyZUqoI/I0FNwjxIJbu08NpRSt8khq59+iyF
apiServer:
listenAddrs:
- 127.0.0.1:8080
tls: false
nodes:
- peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
- peerId: 12D3KooWHtnADt84naf6NeejZ1MxYGZPLk5SPEu2DL4ZV948uWPS
address: 127.0.0.1:4430
signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
- peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
signingKey: Fu/H792JFWVYQpOZeLBIr1Y5UuHdZzJxkGO7eakZDaZ3/vIDhjGgNab1+1NMdTJ0IUP6Tv3KQutcRwtX26/wmQ==
encryptionKey: MIIEowIBAAKCAQEAs+N32tT2Q4Nv9MlyH0B34TJZYLh1+Y/4hc0vupiS/Ct0Mt+Rh62KkPy6Hz2JRDd7ryYpz/Un+qAFQBhfugKy6a5R0U/OnaK8/WwJjstTPd59c7iGnCeW9mWumexT2wiQVbWcSdcAE5SPYmBkIPnwzgxZgtNzvEnbdUDWIOsR3ifDAt3iUqqlo+cZWIZaXiTjyrMlaWY/BR/SGrklYzxcUzNj+K6DdY4yFN5/5ywKIe81llooULTyM5U+fWEW5uri4ERgT/YcRAoii2UJ5kHzpIZmGKcrJ4kUdyFLE7VxYIQMHHXRkDlpTEYlAAJGl5frcHvFufTWIJaohBXAxg5tyQIDAQABAoIBAD3TI9I19x1lAwliYrKS+aCQKV+whftrm8KArrK21W2NkbYaWG4FGuaRtXYfNBoZ54xe1Wf/nenpLWTF+8B2RP9DRiNmBmDvGX0PsIk/IDDXUs5+0OTCRoQQll2Yd4mD+/c5H6nRFtmj6VOqRT+AJ17pp6nq+o/v4lj+G5ncsJtlAtq1xb20yHQYEl6sbK2UqYuiFtXpKMCK/8V3hDj+ROM8UMkxMj+qj9NFd2sCk4FEZ+S2QmHIjY55s4Rpe1RzZZZEYOuJ99Fism+HYXtf3JlFORaNIdhdWY1UkVAFuKY/ULoHOhf/RdJ8ZArak3CplpEdPTYC4IRBI1eZDDF2GgECgYEAw0jvV7E1kqfGD5Q1WTFsss4xHQntPtWRfyAI1viy16sqMX6wQ4ZixWXsOeMB1o5azqqjYo0BBiGw6ie1GKl0iZ09FxHmMDqFLf8a0JZXAlTvC/wEHgAXCzg7tpHRJD1B6gAiU6u6ALW14DtWe6tikFehrY0mwGb9koedQNgoGnkCgYEA69EcUTejGm5Hm6ANC5u5Vn1aaB4BrTJ36FGTaxjnSUPePBj0Eo2Bt+c25DiD3uGj2Jws5QrRhpu+NYhOTC+/P1/rm82w9Tpc8z/wA7nUk0gGEncgtJ8RFokom4B+Ui83JJiH0V7puZUhCc/TOmfa5N0SH5gM4q4rBoVDZtnTGdECgYEAlnssW9GlK6Z2++hEF7/7N+mldPACTkn6PRCtXyHzhjdSYyNxpgb3M49vsceY0gGOPfTFxBpNsLDjh/wjE6b4s1ZkDdPwIjfmCmSrABLpZ1WVgxGnBoshNrcVZIEGvTsrAKsryHfq88MSLIDtCo0tfXbZkkfTla2HNpOj/KTUelkCgYBl0pMRlp58qSWOUxuO6ZyrddD1qA89Q892ptKqqcQkZIOvG284G5XpXJLdFHIMaQ2gWD8iXvt9zf3hi4uTZgKEUNyhF73TBXJhLjhqw3DAb5b/niSnGQ/91ReNnXvt7Kk4ygvLIdp14ai0XeJtE672p2ZN8g+OSXoWhLBH1sJKIQKBgA7NH/Y4RbVHIMWY7jH/1d4ODZ4Hr1RK2Q99HJCAurfD5tjhpcMApoQQJKJDpv7J5Ipx6ynQJD7CFfx27+vqBEG4ffAUm66lKM5xrKcOevcyWemppurCLuza64GgWDP6jBRnHeqrUyZUqoI/I0FNwjxIJbu08NpRSt8khq59+iyF
- peerId: 12D3KooWG1r2SVzTMGDhkiw9McbZq98H9C1Ggzp7FSfWDGbVSCbZ
address: 127.0.0.1:4431
signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
- peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
signingKey: CZTN+NFi4g9MA4BKl3OiCKuzXh63ukIvYWo9D5t9qfZcFwIeOW8eP9W8mtnXaY3JAFyb6GliBW0uCaw4wjRcCA==
encryptionKey: MIIEpAIBAAKCAQEAo9Nuypzg9kZ+LP+8jQgSTaoRUu8VFdJdCOEjuroPQK+2NwBD/Z9BqKiN0Z+jmhkI9yA0/Fwdh21ibAKX3Je9uffAKOhXI2sxIAlccDORu1kGDnhcc7N3L644DK+uFZvKnMQWiCwmtTnNHkoCzWcIE44G56wMa2c4W7mrOuRWqG6a5Z9JUuLqafOIlf6Dw2fiVM6xXiTIMQ0OyXByxFNjsS5O/PYcwoIKMV8MY+gUnAmyPLE0bslvz/8W+3E7d/LDO4lhqW+N1kDmboe6sc7DBf5JD4DLnP2VWV8Ae/rfJvxwu9ZqVT8RdYKMsZqvs9sV+6jQC9UcX+K8Q4Wdo0eMHwIDAQABAoIBAACR57zEtvOkYyP878b91DJ4+P503nno9XHmdp1bsFnlQpkGYzYqq6vOik/EYmlS1PknH4gROfkSpFkD2UtnK73N4tlBlawF33HhFnU9eLBSKvc56/hrE2sTDBbfNZfVpurMs9ddb/UJcnE8iK32QczvnY6IxrJI9aU8DCB0UujbGDnya/HbFU9pLLxu2EUoHNxjSHG/jCx+AR7JRknRA65KPZG7mu5jeAaaklYTY/aLGlctgecDKfNKDsZo6rgAMUW6ZXI8ogNGqfKHUFazCVe0l1tp4hxvgmyjcw79iKvFr4mlpHtgjYTFCeoMJKvOXUImZUJL0vCA6WKvUdIfzAECgYEA0lCTXYwOHqOwYMb1qi8lIIApcI//B/Nzn++MDQ4ZO4SzVJTTv4rSdXAuoihsO6E7LYZK+wdVNjiCbeMukfTqEfaxWXIsIDaHSR3440NsYSwdBz04UhRgpxFE2FwPK7J5dQ57FBaCAgksnO3XjcByBMYgMWVbA+ezIWfVdN96YoECgYEAx2mm/W4ZGdDyJgDonzEGGxfaNqo6DIv+67fDwI6WyqOWFWJTBaVFkm1uPJfcXYuTI9YCNFRKuRU7dyqSPLErMVusC/8Iww8++kqmkc1m04tbkqh4KpREYuMw8/tTYSWDwgpY8ksM5YRpYRJLTuuC0cEmefGco1RsXG8bYYeZXp8CgYBq5fexYcG/gxXgauBtSx9E4L+vbhGD2hNYJKr768GZhf6crDTgs8/7TzT0yTUSLgZlQlAUPgrqz1hEQGfoWiMrVEeanjSdfvnOiUR7R0bsMT7j8hMRbTgfUuC6VDiFzmZ7wAuBD1uvazhY329jpoCNuqKcWNclKfzbqupNSFXtgQKBgQCTlR7Qm0YadChydeOzxX2GWa3XHT7fAFFHNPa8MQtqp40xAFb/a6TEzRZz49RkqyLXt9Bj2CqBNjSPakNWhay41+bJ7hMXAdaTOOJ0L/c1AwNf1C0zHg5KvWgCefPohvIvjqbrkx3VU50GCZsQqn5kLLYENAvAWX/lHRm/obKhcwKBgQC/iAOC8ZdZC5w4F0Mf7roZWa9P/42JWlCMzm/I/5mEIn4mYY6+1C5V+fXoET6845oAh+P8CkH4waJtqqN6BKQhj7SKqoCHgGBCQy+HrSCBtzk7NuXdpz6sk14zfcVpjR3y3l9TuXc4cVQMSLAqg8yUQf+qnEQTit4jyfikV/5XEw==
- peerId: 12D3KooWDXDcBYxtZ8KNRoJebNgNAv9nFbQatQMoWm1BLwmQh6u7
address: 127.0.0.1:4432
signingKey: /6+uYFwFf9nU6fvXQVtpHhjd8+v4dXc7esZzqkhjyfMJWlMiZOtQeb913FXofD5f20WksU0l6i22B09sFFYwDQ==
encryptionKey: MIIEogIBAAKCAQEAwCy84lzkxtzgn4ixGm0LSUTujOBpOh9m7XDoDPZnMTmExdOe9a5v/LXzdlCOCuBvK5u1T3ALBJMA3Zgvjv/jPRQUdiHprP3sbdfc6IgZPBFdLKFTc9yAA7GMbI4y7LhGMLGOMOqQXs+DOeImfmxEs3ykLXHKNas5ORnZPVnB6E9Qod8KH7UyMmBjQkOZYOOw10X4JZiU6xJp/E+VVWcmeXgNBbj5xOWMSzM+hhoA4wNOzBxACucaKDmqD6qugzebOqyUVSzFnEbquro+MYTWYdUDjZTXdvxgUUo80MGQ164gZhkFUKrmSpUvu3YErFySEGqAdFNwOZ6y/4X3s0BHvQIDAQABAoIBAAZiNhAK5+qXMbr67m8jSimv6YCyf6xXmLKwenTbxofDEl8D7ZbZqYyqeqDmgiFoXSkErhwqa6NGQtQZlxLX+zNvNFLMQ5fkg3MOpZ7vzm7JYN/3p+8EVxhIUJLWkmh8opBBhaioUg1kNUa59W9jp1CTBl0gF4h63JbB/g5kqeVOllUw7J1igAoaX36nOJGOwIynCWdizhDhgyjR4OcYfOLwcPDJueKTc5vM10g3LuMSK/sJmaD3TkJFPtDHw+RMW6wqyjsnkrg2D2oohXEyGWYYIXo2so4HCez0AB1I1JAxtVnRPvSIp7xLMm7+AkDoq12QYDHfxZtDTpfmvJg+Sn0CgYEAxCd+oribtdQW+JUctjsDbSQX5CeRISH5Ith3jveBx2jKIqQVnoVPz6URHOvnlIsqYYLANB8B3JHMWfR2UmkK11x0OcZecB06+oBoCZukvSXF+GqVHzLAQUxaoEBDCCPneskj5w+riMWBiiGDp32rUnkqv0nh7dnH+GfORcJ44L8CgYEA+s5s5EALj1jyU9w4+HVUyVsIrUitFnQg6qw/Td3Kj+8CXImKlS+rlmbQv0m1aOcvtFjQRIjjzZJAf/ausfAME+MayoNODgZsDk5RyDKuSWzMLvZLAa1LD52Uli5Pg8KtpzKVTn4xE1MbjsQcUNhFRAgrNEKNyuzXzdp4uXgGOoMCgYASXwiTQOsEepq0KXMI9jn57Nl3+uSyz7W/t7pq329+N6hG2ktUD3RMJE+X/9gup2IOw+owd377I4SaIDU8vq3PQc944cVShspRT9lunO8u7+y8uW7B/0TWWMpcG+irSIGTlGcSavtL0gOx5jWoaDK1hLemNss8NZtu/nnpOq+LjQKBgDisVozJMBOHPNLYS4NROAR77p0BdCNDwIBmxbM5r+EQWA9DAS6u4+4Lc5YV+MkonG37N6yU5iz4pFyGCHmqzX/c7JvgSc3/g4FED1TWpu1uiUD/ZHmPiAuSRxYchtk2L3k9g+GFwF8mg26iP+fAxv4VfnXDqDi3hhg9CtSWG4ozAoGAOWZXlFKqzGAfcucIe54FVQnweXG9sEuIPAvWvVRs4406ggNmL5eHccXpPHWTgetsr2TYMqPTDVMRmhBzSkyrYgk+b2tme79HPzTWs2Yg/pzjOfTgw7MBX/KlvOW5/J+dvrF3Gx8AHHZ9QQdYqi/MS1NKb2K3IbD0/m5gL5Pwi6A=
signingKey: c3D+0+BCl1xU35KBY+U3GPcU9aXdoLUiD4DJ2jF+IqI3CjGLhet3MBOkPXdIuPq/UpEqlp1k6FjNaU6DEU6Csg==
encryptionKey: MIIEpAIBAAKCAQEAuB7HsXuYmoif6/U4JnjC6L0QMu9qW1aPAxDrxWIedTzQhFZp3F3gYW/Zgdd2hvd0c2xyfhwf9C0X/UzfxWr54dDXzWNLN8BdVTik48cdYlgOmbgejiIjTaqSAlv4RtlqvooxCN0MwR2/RVAG/N5GqcAM7E4kJWPtvQYNl6wWCc92rKdutvmcj73wKzz9Hd/qdF612OVS3zRsjh3tJmYt55oovAUh1TAz/mSTTXjFHy35zLRBP+oQQsAOt2p0BOMSyOKZufGC8l3aZD//dp4/U/MaqCjeNuWxCfAZlSd+vt7T0aqDGdyRtrrGUcu4PCwXpOdbzw+uSZxnKawolYoEHwIDAQABAoIBAQCsxeVpvKtUx8QZrUCFiWiM8W0T/un0z+LfY696xzoBlZGtvVEVQtpdVJHsb31/5RFXhnphsI6jmPUb8llBbcMSjeETkItyw4ZRhBfmzl/aevsocEfr5EjwhpEAucDe6wJpzk95G8TuKrXjmtcTzpjMjbUSwbjVhVH/wIBcxVTg2j6z4AOADDRI5UsvZ0NV//If+nNzMjcuIji95PNk7lAuwsqkX3FycxvqXKUMGxRE2bgGMxaBRAP0kqL2vdxyS1M7wp/x04ZAtSnPXHe4qqmDOt69ec3XqbmZHOsZHzkCFePKcPB472/G0bPJeiq/idevEqS89RwvbphDtq3KGrRBAoGBAOrHqlPh36WZBOi6SueUmcrg579KDMUekgeea5payiySbRWztCL2yCYbSgFqSbyCLRppyXK51xvo8iUejR231or6u/nd7T0CON0Nf/8Qtbb13vtTGpIBiWYGqeDrWucUUlyS+K3sDfNk1AJqjUdaIMVu4yTpgzEvrdYCcT312RBPAoGBAMjC83/0EKnsbypFprxKS3Fbg963HhyKjfffQ2w4yncM6kxXF3ehVjg1LInok/6/dmy2LxkAf3r0YYZrGJWmG4Sv4UqHn6JxAjQgarPbdmGhJ8VIUMvMbZRsX3i8Z8D2o8k1M1kr6MYsQ53iX6q/Cp3gnucMeJPk6Xs9Q4TO7YsxAoGAWrXEOF6X01p4zBZWJH2Eoh8dSwooPuzdzPXHaz7SyD/Wx8DDw5KHqDl48W0Iij3dgUwIGjx1QQJStEbGjQnfaZkQkazOIXk/USELKBhjrQn4GjB0np7bYEEI1673UzrFy6C5VjFS/owhYcGbTksjSETcnAFgv9tFFd+hsyfOsv8CgYALk4o875LiaXrDgj6qDtKo17ET75Ux6h9jkqEtpVyvXrRH8KGuyUPSe+Z0kU+vWdT3Uc4HcArpyRuyh4xkXK6riQTBqm5fDIsm/FOKyXXbDVLgwlm+Vqxe6Zzbtml5K/+nw4SReMG0Y6sGeJ4xl1CCaAhhpEtzo7h+3bp99vylkQKBgQDDdR6N4wb3DHTzrW0EFb8XhXZN7CIE3EWhToNDsCkguUB7lwqD4p2c4yLscS0YAqxk7I3NW0nDaUV/340RrVtPJDqB4NZJ+MvhfvV3TW2FkZmru/iW+DMUsfZGAOPdQz9jLGAzUXrXFw/qGBtLIUL6UWqWLOrBO9QHb21nnB1Ssg==
space:
gcTTL: 60
syncPeriod: 11
syncPeriod: 600
storage:
path: db
metric:
@ -37,3 +37,6 @@ log:
production: false
defaultLevel: ""
namedLevels: {}
stream:
timeoutMilliseconds: 1000
maxMsgSizeMb: 256

View File

@ -5,30 +5,30 @@ grpcServer:
- 127.0.0.1:4630
tls: false
account:
peerId: 12D3KooWFgtCbkf47HhFyQW2cEdAkvaofpokCiaa24Phnz7hpepG
peerKey: 4nWcqWOZxv1iXWYuW35eJlF9nxownm38bZjQ27pmFgVXO26vobKLx70TnNTQzZQdoW/dZtxyE9PO37R74vfPQQ==
signingKey: ULbtmmyFjkJ6Z+54FI1OJWfu0QdIeoCckwcrBZDLGhw2o2cXTFH5KGxQuAruNTbREz9eAVGmhGoBZtKVi6/6ng==
encryptionKey: MIIEowIBAAKCAQEAuGAvw/JQuivjoFIhV9RGkoCjO60jNkQpVPWK52eUtEvKHT2EzufhCRwxhAreajoyzk0PsyJ75FWrrvYs2tkSVHFOSiBkZIsldn5gPg1cnvnJOZ9VKDFp8h85d/4cPQ5tX78043nYTgLje2EmbB83inIr4oiZgxDrtLkozJHleAyWuOLIvlWO1l4Uplf6+uooL/5+WeUCuSGUM0wgXfpn+I2IuRhVDVZiChfp51Q6D6brTdOzNcWq1dw6Vld67u8aCLF1EVZ+xM/rnLLBC7MFvIw44LqHvmvGs/lpE9nMNx5L2KfpbpHSBI0IH3FkLQe2Qz8OMZpIa+aga/DzrBpEdwIDAQABAoIBACudXU898AjKPxN6ujZ7maIoWfTQ9SZuI1TcrNomr4+i6hHWrqb/RUWRbMkuhQSd9czFf/RBMQuHlJBT3bJ7bRGaqAly9iyumdMY/A1RvdpBfm9qGIvkfIpxBngzHVz4H7lpkspI1XlGx6c1CRDEpa/TaDwzUhUmGIvszRDvZlfqQvjPjyYSV5Hdc4ywh5zjuSFlxOD/9gsPRE5v4M4FGrGv8cm859P1u95Wxxo3pWincpzjvWw2LpsUGctyU34MhErxh86vNhP9v+nR4VkdojVKkHQTYnPKUlaKj6F+IUSj8syxuTJb8bs0GBuvcXW9AKp/K0xq/GBC8Cu/XN7Ln7kCgYEAwZoqLnU9OuwkcN5AHYW7XsxmVCEnxOsncrUbIzEKPvy4wELdOCVVrX66zmIjb+1+mhaz+mGMGEpkVMBld3wdDfmGgo0CAPlF4efH1ppMzUm2aZ+HYQR8KMH1XOT9qjbGEnLeWcANQT0vZPpe77PQLNwLJ1zv6EtXMMrEH0s4ijUCgYEA88zCNsBtB07ayFr9r+RCfHx/X9wFkT59t2K+axIfZE02f62WWqJCZYMlZu9XAbYEQ94H43/NAL9wfA8dgnF7mKSL8stJKt0g2iPa3MluF4Gq5Y2XYEVf/EDEhP2jh8p1l+xs18rVzsQQ6b3CEU9ytmBJWvkWnwVXf+ZnsCFECXsCgYBM3YyJzXp1/nOpbFRAZGw0AytNk6xafpK29DjGDB5pS6V+kA2M0SXnMD2y2zv+oGh3fTQP4NLigga7r3eZrOlMNxm0k4+MG2wneQLarYB4sR9/aBsz5bf15qwoKbKc9gpGIN0u/RVGJai/irhOqzGn3eV/x2Jo9CC1+otLcW4NUQKBgQCOOHlnZTN1GuwICwSIkhiy9BF+AyUASLsfuquoXEcRxPUw4DugnZ0sCKhN9vsDlYHBcYmajhgyAnuE83BcgwT906eMOEhzh9G9T0NCnwLpFYxzIvkWgQHwbnv1tNyrv1CAEryf2cSGPNw87qSCYp1hhKPmPP6UP5J+mxMLrSw6dwKBgHHFweDS2tw4TNxJQjhfQOp5t9VQbQffFZAqpXGFTc4vf7XePlxIGoIpOg4ShHCKKHSy0PtsLe7QjLrdbMkyYh8oGqgNe5CYTzFFDeK6Im1DoiqNWT+YUWF/gzVRUSpo0QW+4J1hfChG2URp9KbnditXKsJ5Vh+QayHPoZwN7Kgl
peerId: 12D3KooWQajuCbCYJdh6fhfTQpwJpJ61mV1ZV4F4XuJnFHeVfeSF
peerKey: Gz1ARVeHzdusDtBL0DawuQKoKdKhL827WiCPekOndSnbYb65zdtgoxGP8Y+enTfKksPftODaiqzZr16Dfq+JvA==
signingKey: wKPnynjYCBVqDEiREnMRHz6id1NFNIfjV4XKmB27ave9BSyS8saW71BEb/0XT0IZDJep6oSKr9ua5kAxcr7tQA==
encryptionKey: MIIEpAIBAAKCAQEA1DJ/TtBpSEVZVfPWJdp7tPaGY9d+4zrD91LM/4N4DKKhhSFfcWlHgZeQiEtP6bKCdIp2nPMURiS8hd1JzYmNJNk/hUYlzCUJOZWyduVeaow9rlTT6I9a8BVUBQHtVD+PUu5pkfjLFgAojcSzg/mIPzJ0T76AlsFXBdXRfS2wnVKfF0/V+jHiLB1V2JBLjyuRf2V5HFglEmWfrCoG02Q9OENZJHy02NXGCs7FnZdYhHct9u00dXk6Xp0w+oBD74+h4gsyFAHnRodRnhC0WMSv2LIPIQUh7x5LfvKx85n6LMFk/aYgTNFKQfu15VTzjfbVbeAm8jsHgV/FifRvETHm6QIDAQABAoIBAF6RLqlaOkFqHpkutRZjm1QXtebTCAqOiv0zGocY+SxwYhlpuRZa+/ImMNR8891Ln9X+S0RBFJz6DEaASz7deVidtTBZBclIDCdsrn9MU1qaq3aA+XugP7/VUX91z2YHeYFVHRlfzmo8odYkfnhnga/gdXOAi+Ajw/umwdjOvvItKqzm4FHHrwmqKDGlMfPgVcbkE/1iDRSwGvuEPOtMuNrTGcPyz0w10BO5zfpxgxJ2Esgmg66VG+H/KPSoLCtStZilErC8gRx9AbbJGUJcLkjd3T6A02cS9IS/hyTEK7qjxNjVaW0DfCrjXfIFiVHeXTB1LSS2JR95kArG437WTw0CgYEA/JsW6qDjl1jF7tYr+E6PjnCk/dgm3nlsC8sTbZd5edPN3dp+D6qlwv4KYKDETpxohMMhOdSl5SYp4dirsnyPDF1BcGdrkq73aE6n4Tx7oQBMeuZLvK9hxWprJqRa9WP49CDiLOc/GLOe3N90s8ViSqU08/tqOtQLU4BmjHMCDzcCgYEA1wxpL7XUUeDa+bGXrtii3oXlZpyoUXft3JjhTazC1lQuwp5M5+0HA/BuTpl8b43+0gcgrUjqB7yeKWZ8Us0gE9ZMBPTGNNGjXjGOtOk1Lpm+PHrCxmADzfJ8V+rrQXvW2KcImJ0bZk87eNUKtDSsWy6+NIQ6W66GUFvv8iblit8CgYEAvBVKCedDrqQFtKC5Wog8MYXEA9IWlt33ygwp6ha39zLyfPa7mDSqebanyWzK3fFtjTSxH5sq7qTs2GF47kv6Qu2I1QXcPfqS8pJmQ7nCH43WZEfnKpW3icOEBuCnbUFD05pMbby86UqMxc6H2Xblicja1bNkVGsgB8t6D6duaB8CgYEAq337OA/x1KXTGoJ0avvZzkjK6uyNEgLozh2gtpfJ/K+/ZnZk8CNGj+6hmM6vvCpphsYmWeomr6rMGknfZQytwwQHNYCZu69eb5RnsH+1aIc0fPiM8TPKdOcmH9p4Z41BhR6XLVVEb29KBw8l7RWASWraRfkYrNpdxCG9FMfOD9MCgYBJ6Z7YNZsJq263s9oJ01npT2NlfXORd3KDHi/A6qC8Jx1dK3+Jew2VV53/PeXJKuPuePSV7nEOwA0wpg3+TuEsWHHOZVO4c+ZVJmonO0x0IzjMHzBB/8VZc+5n+yi/UOSupt/WRcoPOTjJ7tQdhc2m9C7YA248laYikbzkW5DHoA==
apiServer:
listenAddrs:
- 127.0.0.1:8090
tls: false
nodes:
- peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
- peerId: 12D3KooWHtnADt84naf6NeejZ1MxYGZPLk5SPEu2DL4ZV948uWPS
address: 127.0.0.1:4430
signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
- peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
signingKey: Fu/H792JFWVYQpOZeLBIr1Y5UuHdZzJxkGO7eakZDaZ3/vIDhjGgNab1+1NMdTJ0IUP6Tv3KQutcRwtX26/wmQ==
encryptionKey: MIIEowIBAAKCAQEAs+N32tT2Q4Nv9MlyH0B34TJZYLh1+Y/4hc0vupiS/Ct0Mt+Rh62KkPy6Hz2JRDd7ryYpz/Un+qAFQBhfugKy6a5R0U/OnaK8/WwJjstTPd59c7iGnCeW9mWumexT2wiQVbWcSdcAE5SPYmBkIPnwzgxZgtNzvEnbdUDWIOsR3ifDAt3iUqqlo+cZWIZaXiTjyrMlaWY/BR/SGrklYzxcUzNj+K6DdY4yFN5/5ywKIe81llooULTyM5U+fWEW5uri4ERgT/YcRAoii2UJ5kHzpIZmGKcrJ4kUdyFLE7VxYIQMHHXRkDlpTEYlAAJGl5frcHvFufTWIJaohBXAxg5tyQIDAQABAoIBAD3TI9I19x1lAwliYrKS+aCQKV+whftrm8KArrK21W2NkbYaWG4FGuaRtXYfNBoZ54xe1Wf/nenpLWTF+8B2RP9DRiNmBmDvGX0PsIk/IDDXUs5+0OTCRoQQll2Yd4mD+/c5H6nRFtmj6VOqRT+AJ17pp6nq+o/v4lj+G5ncsJtlAtq1xb20yHQYEl6sbK2UqYuiFtXpKMCK/8V3hDj+ROM8UMkxMj+qj9NFd2sCk4FEZ+S2QmHIjY55s4Rpe1RzZZZEYOuJ99Fism+HYXtf3JlFORaNIdhdWY1UkVAFuKY/ULoHOhf/RdJ8ZArak3CplpEdPTYC4IRBI1eZDDF2GgECgYEAw0jvV7E1kqfGD5Q1WTFsss4xHQntPtWRfyAI1viy16sqMX6wQ4ZixWXsOeMB1o5azqqjYo0BBiGw6ie1GKl0iZ09FxHmMDqFLf8a0JZXAlTvC/wEHgAXCzg7tpHRJD1B6gAiU6u6ALW14DtWe6tikFehrY0mwGb9koedQNgoGnkCgYEA69EcUTejGm5Hm6ANC5u5Vn1aaB4BrTJ36FGTaxjnSUPePBj0Eo2Bt+c25DiD3uGj2Jws5QrRhpu+NYhOTC+/P1/rm82w9Tpc8z/wA7nUk0gGEncgtJ8RFokom4B+Ui83JJiH0V7puZUhCc/TOmfa5N0SH5gM4q4rBoVDZtnTGdECgYEAlnssW9GlK6Z2++hEF7/7N+mldPACTkn6PRCtXyHzhjdSYyNxpgb3M49vsceY0gGOPfTFxBpNsLDjh/wjE6b4s1ZkDdPwIjfmCmSrABLpZ1WVgxGnBoshNrcVZIEGvTsrAKsryHfq88MSLIDtCo0tfXbZkkfTla2HNpOj/KTUelkCgYBl0pMRlp58qSWOUxuO6ZyrddD1qA89Q892ptKqqcQkZIOvG284G5XpXJLdFHIMaQ2gWD8iXvt9zf3hi4uTZgKEUNyhF73TBXJhLjhqw3DAb5b/niSnGQ/91ReNnXvt7Kk4ygvLIdp14ai0XeJtE672p2ZN8g+OSXoWhLBH1sJKIQKBgA7NH/Y4RbVHIMWY7jH/1d4ODZ4Hr1RK2Q99HJCAurfD5tjhpcMApoQQJKJDpv7J5Ipx6ynQJD7CFfx27+vqBEG4ffAUm66lKM5xrKcOevcyWemppurCLuza64GgWDP6jBRnHeqrUyZUqoI/I0FNwjxIJbu08NpRSt8khq59+iyF
- peerId: 12D3KooWG1r2SVzTMGDhkiw9McbZq98H9C1Ggzp7FSfWDGbVSCbZ
address: 127.0.0.1:4431
signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
- peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
signingKey: CZTN+NFi4g9MA4BKl3OiCKuzXh63ukIvYWo9D5t9qfZcFwIeOW8eP9W8mtnXaY3JAFyb6GliBW0uCaw4wjRcCA==
encryptionKey: MIIEpAIBAAKCAQEAo9Nuypzg9kZ+LP+8jQgSTaoRUu8VFdJdCOEjuroPQK+2NwBD/Z9BqKiN0Z+jmhkI9yA0/Fwdh21ibAKX3Je9uffAKOhXI2sxIAlccDORu1kGDnhcc7N3L644DK+uFZvKnMQWiCwmtTnNHkoCzWcIE44G56wMa2c4W7mrOuRWqG6a5Z9JUuLqafOIlf6Dw2fiVM6xXiTIMQ0OyXByxFNjsS5O/PYcwoIKMV8MY+gUnAmyPLE0bslvz/8W+3E7d/LDO4lhqW+N1kDmboe6sc7DBf5JD4DLnP2VWV8Ae/rfJvxwu9ZqVT8RdYKMsZqvs9sV+6jQC9UcX+K8Q4Wdo0eMHwIDAQABAoIBAACR57zEtvOkYyP878b91DJ4+P503nno9XHmdp1bsFnlQpkGYzYqq6vOik/EYmlS1PknH4gROfkSpFkD2UtnK73N4tlBlawF33HhFnU9eLBSKvc56/hrE2sTDBbfNZfVpurMs9ddb/UJcnE8iK32QczvnY6IxrJI9aU8DCB0UujbGDnya/HbFU9pLLxu2EUoHNxjSHG/jCx+AR7JRknRA65KPZG7mu5jeAaaklYTY/aLGlctgecDKfNKDsZo6rgAMUW6ZXI8ogNGqfKHUFazCVe0l1tp4hxvgmyjcw79iKvFr4mlpHtgjYTFCeoMJKvOXUImZUJL0vCA6WKvUdIfzAECgYEA0lCTXYwOHqOwYMb1qi8lIIApcI//B/Nzn++MDQ4ZO4SzVJTTv4rSdXAuoihsO6E7LYZK+wdVNjiCbeMukfTqEfaxWXIsIDaHSR3440NsYSwdBz04UhRgpxFE2FwPK7J5dQ57FBaCAgksnO3XjcByBMYgMWVbA+ezIWfVdN96YoECgYEAx2mm/W4ZGdDyJgDonzEGGxfaNqo6DIv+67fDwI6WyqOWFWJTBaVFkm1uPJfcXYuTI9YCNFRKuRU7dyqSPLErMVusC/8Iww8++kqmkc1m04tbkqh4KpREYuMw8/tTYSWDwgpY8ksM5YRpYRJLTuuC0cEmefGco1RsXG8bYYeZXp8CgYBq5fexYcG/gxXgauBtSx9E4L+vbhGD2hNYJKr768GZhf6crDTgs8/7TzT0yTUSLgZlQlAUPgrqz1hEQGfoWiMrVEeanjSdfvnOiUR7R0bsMT7j8hMRbTgfUuC6VDiFzmZ7wAuBD1uvazhY329jpoCNuqKcWNclKfzbqupNSFXtgQKBgQCTlR7Qm0YadChydeOzxX2GWa3XHT7fAFFHNPa8MQtqp40xAFb/a6TEzRZz49RkqyLXt9Bj2CqBNjSPakNWhay41+bJ7hMXAdaTOOJ0L/c1AwNf1C0zHg5KvWgCefPohvIvjqbrkx3VU50GCZsQqn5kLLYENAvAWX/lHRm/obKhcwKBgQC/iAOC8ZdZC5w4F0Mf7roZWa9P/42JWlCMzm/I/5mEIn4mYY6+1C5V+fXoET6845oAh+P8CkH4waJtqqN6BKQhj7SKqoCHgGBCQy+HrSCBtzk7NuXdpz6sk14zfcVpjR3y3l9TuXc4cVQMSLAqg8yUQf+qnEQTit4jyfikV/5XEw==
- peerId: 12D3KooWDXDcBYxtZ8KNRoJebNgNAv9nFbQatQMoWm1BLwmQh6u7
address: 127.0.0.1:4432
signingKey: /6+uYFwFf9nU6fvXQVtpHhjd8+v4dXc7esZzqkhjyfMJWlMiZOtQeb913FXofD5f20WksU0l6i22B09sFFYwDQ==
encryptionKey: MIIEogIBAAKCAQEAwCy84lzkxtzgn4ixGm0LSUTujOBpOh9m7XDoDPZnMTmExdOe9a5v/LXzdlCOCuBvK5u1T3ALBJMA3Zgvjv/jPRQUdiHprP3sbdfc6IgZPBFdLKFTc9yAA7GMbI4y7LhGMLGOMOqQXs+DOeImfmxEs3ykLXHKNas5ORnZPVnB6E9Qod8KH7UyMmBjQkOZYOOw10X4JZiU6xJp/E+VVWcmeXgNBbj5xOWMSzM+hhoA4wNOzBxACucaKDmqD6qugzebOqyUVSzFnEbquro+MYTWYdUDjZTXdvxgUUo80MGQ164gZhkFUKrmSpUvu3YErFySEGqAdFNwOZ6y/4X3s0BHvQIDAQABAoIBAAZiNhAK5+qXMbr67m8jSimv6YCyf6xXmLKwenTbxofDEl8D7ZbZqYyqeqDmgiFoXSkErhwqa6NGQtQZlxLX+zNvNFLMQ5fkg3MOpZ7vzm7JYN/3p+8EVxhIUJLWkmh8opBBhaioUg1kNUa59W9jp1CTBl0gF4h63JbB/g5kqeVOllUw7J1igAoaX36nOJGOwIynCWdizhDhgyjR4OcYfOLwcPDJueKTc5vM10g3LuMSK/sJmaD3TkJFPtDHw+RMW6wqyjsnkrg2D2oohXEyGWYYIXo2so4HCez0AB1I1JAxtVnRPvSIp7xLMm7+AkDoq12QYDHfxZtDTpfmvJg+Sn0CgYEAxCd+oribtdQW+JUctjsDbSQX5CeRISH5Ith3jveBx2jKIqQVnoVPz6URHOvnlIsqYYLANB8B3JHMWfR2UmkK11x0OcZecB06+oBoCZukvSXF+GqVHzLAQUxaoEBDCCPneskj5w+riMWBiiGDp32rUnkqv0nh7dnH+GfORcJ44L8CgYEA+s5s5EALj1jyU9w4+HVUyVsIrUitFnQg6qw/Td3Kj+8CXImKlS+rlmbQv0m1aOcvtFjQRIjjzZJAf/ausfAME+MayoNODgZsDk5RyDKuSWzMLvZLAa1LD52Uli5Pg8KtpzKVTn4xE1MbjsQcUNhFRAgrNEKNyuzXzdp4uXgGOoMCgYASXwiTQOsEepq0KXMI9jn57Nl3+uSyz7W/t7pq329+N6hG2ktUD3RMJE+X/9gup2IOw+owd377I4SaIDU8vq3PQc944cVShspRT9lunO8u7+y8uW7B/0TWWMpcG+irSIGTlGcSavtL0gOx5jWoaDK1hLemNss8NZtu/nnpOq+LjQKBgDisVozJMBOHPNLYS4NROAR77p0BdCNDwIBmxbM5r+EQWA9DAS6u4+4Lc5YV+MkonG37N6yU5iz4pFyGCHmqzX/c7JvgSc3/g4FED1TWpu1uiUD/ZHmPiAuSRxYchtk2L3k9g+GFwF8mg26iP+fAxv4VfnXDqDi3hhg9CtSWG4ozAoGAOWZXlFKqzGAfcucIe54FVQnweXG9sEuIPAvWvVRs4406ggNmL5eHccXpPHWTgetsr2TYMqPTDVMRmhBzSkyrYgk+b2tme79HPzTWs2Yg/pzjOfTgw7MBX/KlvOW5/J+dvrF3Gx8AHHZ9QQdYqi/MS1NKb2K3IbD0/m5gL5Pwi6A=
signingKey: c3D+0+BCl1xU35KBY+U3GPcU9aXdoLUiD4DJ2jF+IqI3CjGLhet3MBOkPXdIuPq/UpEqlp1k6FjNaU6DEU6Csg==
encryptionKey: MIIEpAIBAAKCAQEAuB7HsXuYmoif6/U4JnjC6L0QMu9qW1aPAxDrxWIedTzQhFZp3F3gYW/Zgdd2hvd0c2xyfhwf9C0X/UzfxWr54dDXzWNLN8BdVTik48cdYlgOmbgejiIjTaqSAlv4RtlqvooxCN0MwR2/RVAG/N5GqcAM7E4kJWPtvQYNl6wWCc92rKdutvmcj73wKzz9Hd/qdF612OVS3zRsjh3tJmYt55oovAUh1TAz/mSTTXjFHy35zLRBP+oQQsAOt2p0BOMSyOKZufGC8l3aZD//dp4/U/MaqCjeNuWxCfAZlSd+vt7T0aqDGdyRtrrGUcu4PCwXpOdbzw+uSZxnKawolYoEHwIDAQABAoIBAQCsxeVpvKtUx8QZrUCFiWiM8W0T/un0z+LfY696xzoBlZGtvVEVQtpdVJHsb31/5RFXhnphsI6jmPUb8llBbcMSjeETkItyw4ZRhBfmzl/aevsocEfr5EjwhpEAucDe6wJpzk95G8TuKrXjmtcTzpjMjbUSwbjVhVH/wIBcxVTg2j6z4AOADDRI5UsvZ0NV//If+nNzMjcuIji95PNk7lAuwsqkX3FycxvqXKUMGxRE2bgGMxaBRAP0kqL2vdxyS1M7wp/x04ZAtSnPXHe4qqmDOt69ec3XqbmZHOsZHzkCFePKcPB472/G0bPJeiq/idevEqS89RwvbphDtq3KGrRBAoGBAOrHqlPh36WZBOi6SueUmcrg579KDMUekgeea5payiySbRWztCL2yCYbSgFqSbyCLRppyXK51xvo8iUejR231or6u/nd7T0CON0Nf/8Qtbb13vtTGpIBiWYGqeDrWucUUlyS+K3sDfNk1AJqjUdaIMVu4yTpgzEvrdYCcT312RBPAoGBAMjC83/0EKnsbypFprxKS3Fbg963HhyKjfffQ2w4yncM6kxXF3ehVjg1LInok/6/dmy2LxkAf3r0YYZrGJWmG4Sv4UqHn6JxAjQgarPbdmGhJ8VIUMvMbZRsX3i8Z8D2o8k1M1kr6MYsQ53iX6q/Cp3gnucMeJPk6Xs9Q4TO7YsxAoGAWrXEOF6X01p4zBZWJH2Eoh8dSwooPuzdzPXHaz7SyD/Wx8DDw5KHqDl48W0Iij3dgUwIGjx1QQJStEbGjQnfaZkQkazOIXk/USELKBhjrQn4GjB0np7bYEEI1673UzrFy6C5VjFS/owhYcGbTksjSETcnAFgv9tFFd+hsyfOsv8CgYALk4o875LiaXrDgj6qDtKo17ET75Ux6h9jkqEtpVyvXrRH8KGuyUPSe+Z0kU+vWdT3Uc4HcArpyRuyh4xkXK6riQTBqm5fDIsm/FOKyXXbDVLgwlm+Vqxe6Zzbtml5K/+nw4SReMG0Y6sGeJ4xl1CCaAhhpEtzo7h+3bp99vylkQKBgQDDdR6N4wb3DHTzrW0EFb8XhXZN7CIE3EWhToNDsCkguUB7lwqD4p2c4yLscS0YAqxk7I3NW0nDaUV/340RrVtPJDqB4NZJ+MvhfvV3TW2FkZmru/iW+DMUsfZGAOPdQz9jLGAzUXrXFw/qGBtLIUL6UWqWLOrBO9QHb21nnB1Ssg==
space:
gcTTL: 60
syncPeriod: 11
syncPeriod: 20
storage:
path: db
metric:
@ -37,3 +37,6 @@ log:
production: false
defaultLevel: ""
namedLevels: {}
stream:
timeoutMilliseconds: 1000
maxMsgSizeMb: 256

View File

@ -5,30 +5,30 @@ grpcServer:
- 127.0.0.1:4631
tls: false
account:
peerId: 12D3KooWQuD9ShSHt4nb7bXefg8ndpDXCDzwrm9pjHsnDY2khbRi
peerKey: fp/Q18I7TNM4kgKXbbOBQJbJonlrQqAlZwTF6Rx/sKXgHQGZ1dBcS45oXGbTb15Bi2r7sOX+d6HJaaQE29MisQ==
signingKey: ULbtmmyFjkJ6Z+54FI1OJWfu0QdIeoCckwcrBZDLGhw2o2cXTFH5KGxQuAruNTbREz9eAVGmhGoBZtKVi6/6ng==
encryptionKey: MIIEowIBAAKCAQEAuGAvw/JQuivjoFIhV9RGkoCjO60jNkQpVPWK52eUtEvKHT2EzufhCRwxhAreajoyzk0PsyJ75FWrrvYs2tkSVHFOSiBkZIsldn5gPg1cnvnJOZ9VKDFp8h85d/4cPQ5tX78043nYTgLje2EmbB83inIr4oiZgxDrtLkozJHleAyWuOLIvlWO1l4Uplf6+uooL/5+WeUCuSGUM0wgXfpn+I2IuRhVDVZiChfp51Q6D6brTdOzNcWq1dw6Vld67u8aCLF1EVZ+xM/rnLLBC7MFvIw44LqHvmvGs/lpE9nMNx5L2KfpbpHSBI0IH3FkLQe2Qz8OMZpIa+aga/DzrBpEdwIDAQABAoIBACudXU898AjKPxN6ujZ7maIoWfTQ9SZuI1TcrNomr4+i6hHWrqb/RUWRbMkuhQSd9czFf/RBMQuHlJBT3bJ7bRGaqAly9iyumdMY/A1RvdpBfm9qGIvkfIpxBngzHVz4H7lpkspI1XlGx6c1CRDEpa/TaDwzUhUmGIvszRDvZlfqQvjPjyYSV5Hdc4ywh5zjuSFlxOD/9gsPRE5v4M4FGrGv8cm859P1u95Wxxo3pWincpzjvWw2LpsUGctyU34MhErxh86vNhP9v+nR4VkdojVKkHQTYnPKUlaKj6F+IUSj8syxuTJb8bs0GBuvcXW9AKp/K0xq/GBC8Cu/XN7Ln7kCgYEAwZoqLnU9OuwkcN5AHYW7XsxmVCEnxOsncrUbIzEKPvy4wELdOCVVrX66zmIjb+1+mhaz+mGMGEpkVMBld3wdDfmGgo0CAPlF4efH1ppMzUm2aZ+HYQR8KMH1XOT9qjbGEnLeWcANQT0vZPpe77PQLNwLJ1zv6EtXMMrEH0s4ijUCgYEA88zCNsBtB07ayFr9r+RCfHx/X9wFkT59t2K+axIfZE02f62WWqJCZYMlZu9XAbYEQ94H43/NAL9wfA8dgnF7mKSL8stJKt0g2iPa3MluF4Gq5Y2XYEVf/EDEhP2jh8p1l+xs18rVzsQQ6b3CEU9ytmBJWvkWnwVXf+ZnsCFECXsCgYBM3YyJzXp1/nOpbFRAZGw0AytNk6xafpK29DjGDB5pS6V+kA2M0SXnMD2y2zv+oGh3fTQP4NLigga7r3eZrOlMNxm0k4+MG2wneQLarYB4sR9/aBsz5bf15qwoKbKc9gpGIN0u/RVGJai/irhOqzGn3eV/x2Jo9CC1+otLcW4NUQKBgQCOOHlnZTN1GuwICwSIkhiy9BF+AyUASLsfuquoXEcRxPUw4DugnZ0sCKhN9vsDlYHBcYmajhgyAnuE83BcgwT906eMOEhzh9G9T0NCnwLpFYxzIvkWgQHwbnv1tNyrv1CAEryf2cSGPNw87qSCYp1hhKPmPP6UP5J+mxMLrSw6dwKBgHHFweDS2tw4TNxJQjhfQOp5t9VQbQffFZAqpXGFTc4vf7XePlxIGoIpOg4ShHCKKHSy0PtsLe7QjLrdbMkyYh8oGqgNe5CYTzFFDeK6Im1DoiqNWT+YUWF/gzVRUSpo0QW+4J1hfChG2URp9KbnditXKsJ5Vh+QayHPoZwN7Kgl
peerId: 12D3KooWNRjRHDUytVA8gsaUBMfSArFgRSipdfka85KQ7FqL3FK8
peerKey: 7FV/hHBDlj8uzDm4TBcfE2vmXVJSfvQryruCwcaQKta7W5l+eXQEsfxW46N1PJ+g4MCMIba8lQxQXsWGKXTQEw==
signingKey: wKPnynjYCBVqDEiREnMRHz6id1NFNIfjV4XKmB27ave9BSyS8saW71BEb/0XT0IZDJep6oSKr9ua5kAxcr7tQA==
encryptionKey: MIIEpAIBAAKCAQEA1DJ/TtBpSEVZVfPWJdp7tPaGY9d+4zrD91LM/4N4DKKhhSFfcWlHgZeQiEtP6bKCdIp2nPMURiS8hd1JzYmNJNk/hUYlzCUJOZWyduVeaow9rlTT6I9a8BVUBQHtVD+PUu5pkfjLFgAojcSzg/mIPzJ0T76AlsFXBdXRfS2wnVKfF0/V+jHiLB1V2JBLjyuRf2V5HFglEmWfrCoG02Q9OENZJHy02NXGCs7FnZdYhHct9u00dXk6Xp0w+oBD74+h4gsyFAHnRodRnhC0WMSv2LIPIQUh7x5LfvKx85n6LMFk/aYgTNFKQfu15VTzjfbVbeAm8jsHgV/FifRvETHm6QIDAQABAoIBAF6RLqlaOkFqHpkutRZjm1QXtebTCAqOiv0zGocY+SxwYhlpuRZa+/ImMNR8891Ln9X+S0RBFJz6DEaASz7deVidtTBZBclIDCdsrn9MU1qaq3aA+XugP7/VUX91z2YHeYFVHRlfzmo8odYkfnhnga/gdXOAi+Ajw/umwdjOvvItKqzm4FHHrwmqKDGlMfPgVcbkE/1iDRSwGvuEPOtMuNrTGcPyz0w10BO5zfpxgxJ2Esgmg66VG+H/KPSoLCtStZilErC8gRx9AbbJGUJcLkjd3T6A02cS9IS/hyTEK7qjxNjVaW0DfCrjXfIFiVHeXTB1LSS2JR95kArG437WTw0CgYEA/JsW6qDjl1jF7tYr+E6PjnCk/dgm3nlsC8sTbZd5edPN3dp+D6qlwv4KYKDETpxohMMhOdSl5SYp4dirsnyPDF1BcGdrkq73aE6n4Tx7oQBMeuZLvK9hxWprJqRa9WP49CDiLOc/GLOe3N90s8ViSqU08/tqOtQLU4BmjHMCDzcCgYEA1wxpL7XUUeDa+bGXrtii3oXlZpyoUXft3JjhTazC1lQuwp5M5+0HA/BuTpl8b43+0gcgrUjqB7yeKWZ8Us0gE9ZMBPTGNNGjXjGOtOk1Lpm+PHrCxmADzfJ8V+rrQXvW2KcImJ0bZk87eNUKtDSsWy6+NIQ6W66GUFvv8iblit8CgYEAvBVKCedDrqQFtKC5Wog8MYXEA9IWlt33ygwp6ha39zLyfPa7mDSqebanyWzK3fFtjTSxH5sq7qTs2GF47kv6Qu2I1QXcPfqS8pJmQ7nCH43WZEfnKpW3icOEBuCnbUFD05pMbby86UqMxc6H2Xblicja1bNkVGsgB8t6D6duaB8CgYEAq337OA/x1KXTGoJ0avvZzkjK6uyNEgLozh2gtpfJ/K+/ZnZk8CNGj+6hmM6vvCpphsYmWeomr6rMGknfZQytwwQHNYCZu69eb5RnsH+1aIc0fPiM8TPKdOcmH9p4Z41BhR6XLVVEb29KBw8l7RWASWraRfkYrNpdxCG9FMfOD9MCgYBJ6Z7YNZsJq263s9oJ01npT2NlfXORd3KDHi/A6qC8Jx1dK3+Jew2VV53/PeXJKuPuePSV7nEOwA0wpg3+TuEsWHHOZVO4c+ZVJmonO0x0IzjMHzBB/8VZc+5n+yi/UOSupt/WRcoPOTjJ7tQdhc2m9C7YA248laYikbzkW5DHoA==
apiServer:
listenAddrs:
- 127.0.0.1:8091
tls: false
nodes:
- peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
- peerId: 12D3KooWHtnADt84naf6NeejZ1MxYGZPLk5SPEu2DL4ZV948uWPS
address: 127.0.0.1:4430
signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
- peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
signingKey: Fu/H792JFWVYQpOZeLBIr1Y5UuHdZzJxkGO7eakZDaZ3/vIDhjGgNab1+1NMdTJ0IUP6Tv3KQutcRwtX26/wmQ==
encryptionKey: MIIEowIBAAKCAQEAs+N32tT2Q4Nv9MlyH0B34TJZYLh1+Y/4hc0vupiS/Ct0Mt+Rh62KkPy6Hz2JRDd7ryYpz/Un+qAFQBhfugKy6a5R0U/OnaK8/WwJjstTPd59c7iGnCeW9mWumexT2wiQVbWcSdcAE5SPYmBkIPnwzgxZgtNzvEnbdUDWIOsR3ifDAt3iUqqlo+cZWIZaXiTjyrMlaWY/BR/SGrklYzxcUzNj+K6DdY4yFN5/5ywKIe81llooULTyM5U+fWEW5uri4ERgT/YcRAoii2UJ5kHzpIZmGKcrJ4kUdyFLE7VxYIQMHHXRkDlpTEYlAAJGl5frcHvFufTWIJaohBXAxg5tyQIDAQABAoIBAD3TI9I19x1lAwliYrKS+aCQKV+whftrm8KArrK21W2NkbYaWG4FGuaRtXYfNBoZ54xe1Wf/nenpLWTF+8B2RP9DRiNmBmDvGX0PsIk/IDDXUs5+0OTCRoQQll2Yd4mD+/c5H6nRFtmj6VOqRT+AJ17pp6nq+o/v4lj+G5ncsJtlAtq1xb20yHQYEl6sbK2UqYuiFtXpKMCK/8V3hDj+ROM8UMkxMj+qj9NFd2sCk4FEZ+S2QmHIjY55s4Rpe1RzZZZEYOuJ99Fism+HYXtf3JlFORaNIdhdWY1UkVAFuKY/ULoHOhf/RdJ8ZArak3CplpEdPTYC4IRBI1eZDDF2GgECgYEAw0jvV7E1kqfGD5Q1WTFsss4xHQntPtWRfyAI1viy16sqMX6wQ4ZixWXsOeMB1o5azqqjYo0BBiGw6ie1GKl0iZ09FxHmMDqFLf8a0JZXAlTvC/wEHgAXCzg7tpHRJD1B6gAiU6u6ALW14DtWe6tikFehrY0mwGb9koedQNgoGnkCgYEA69EcUTejGm5Hm6ANC5u5Vn1aaB4BrTJ36FGTaxjnSUPePBj0Eo2Bt+c25DiD3uGj2Jws5QrRhpu+NYhOTC+/P1/rm82w9Tpc8z/wA7nUk0gGEncgtJ8RFokom4B+Ui83JJiH0V7puZUhCc/TOmfa5N0SH5gM4q4rBoVDZtnTGdECgYEAlnssW9GlK6Z2++hEF7/7N+mldPACTkn6PRCtXyHzhjdSYyNxpgb3M49vsceY0gGOPfTFxBpNsLDjh/wjE6b4s1ZkDdPwIjfmCmSrABLpZ1WVgxGnBoshNrcVZIEGvTsrAKsryHfq88MSLIDtCo0tfXbZkkfTla2HNpOj/KTUelkCgYBl0pMRlp58qSWOUxuO6ZyrddD1qA89Q892ptKqqcQkZIOvG284G5XpXJLdFHIMaQ2gWD8iXvt9zf3hi4uTZgKEUNyhF73TBXJhLjhqw3DAb5b/niSnGQ/91ReNnXvt7Kk4ygvLIdp14ai0XeJtE672p2ZN8g+OSXoWhLBH1sJKIQKBgA7NH/Y4RbVHIMWY7jH/1d4ODZ4Hr1RK2Q99HJCAurfD5tjhpcMApoQQJKJDpv7J5Ipx6ynQJD7CFfx27+vqBEG4ffAUm66lKM5xrKcOevcyWemppurCLuza64GgWDP6jBRnHeqrUyZUqoI/I0FNwjxIJbu08NpRSt8khq59+iyF
- peerId: 12D3KooWG1r2SVzTMGDhkiw9McbZq98H9C1Ggzp7FSfWDGbVSCbZ
address: 127.0.0.1:4431
signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
- peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
signingKey: CZTN+NFi4g9MA4BKl3OiCKuzXh63ukIvYWo9D5t9qfZcFwIeOW8eP9W8mtnXaY3JAFyb6GliBW0uCaw4wjRcCA==
encryptionKey: MIIEpAIBAAKCAQEAo9Nuypzg9kZ+LP+8jQgSTaoRUu8VFdJdCOEjuroPQK+2NwBD/Z9BqKiN0Z+jmhkI9yA0/Fwdh21ibAKX3Je9uffAKOhXI2sxIAlccDORu1kGDnhcc7N3L644DK+uFZvKnMQWiCwmtTnNHkoCzWcIE44G56wMa2c4W7mrOuRWqG6a5Z9JUuLqafOIlf6Dw2fiVM6xXiTIMQ0OyXByxFNjsS5O/PYcwoIKMV8MY+gUnAmyPLE0bslvz/8W+3E7d/LDO4lhqW+N1kDmboe6sc7DBf5JD4DLnP2VWV8Ae/rfJvxwu9ZqVT8RdYKMsZqvs9sV+6jQC9UcX+K8Q4Wdo0eMHwIDAQABAoIBAACR57zEtvOkYyP878b91DJ4+P503nno9XHmdp1bsFnlQpkGYzYqq6vOik/EYmlS1PknH4gROfkSpFkD2UtnK73N4tlBlawF33HhFnU9eLBSKvc56/hrE2sTDBbfNZfVpurMs9ddb/UJcnE8iK32QczvnY6IxrJI9aU8DCB0UujbGDnya/HbFU9pLLxu2EUoHNxjSHG/jCx+AR7JRknRA65KPZG7mu5jeAaaklYTY/aLGlctgecDKfNKDsZo6rgAMUW6ZXI8ogNGqfKHUFazCVe0l1tp4hxvgmyjcw79iKvFr4mlpHtgjYTFCeoMJKvOXUImZUJL0vCA6WKvUdIfzAECgYEA0lCTXYwOHqOwYMb1qi8lIIApcI//B/Nzn++MDQ4ZO4SzVJTTv4rSdXAuoihsO6E7LYZK+wdVNjiCbeMukfTqEfaxWXIsIDaHSR3440NsYSwdBz04UhRgpxFE2FwPK7J5dQ57FBaCAgksnO3XjcByBMYgMWVbA+ezIWfVdN96YoECgYEAx2mm/W4ZGdDyJgDonzEGGxfaNqo6DIv+67fDwI6WyqOWFWJTBaVFkm1uPJfcXYuTI9YCNFRKuRU7dyqSPLErMVusC/8Iww8++kqmkc1m04tbkqh4KpREYuMw8/tTYSWDwgpY8ksM5YRpYRJLTuuC0cEmefGco1RsXG8bYYeZXp8CgYBq5fexYcG/gxXgauBtSx9E4L+vbhGD2hNYJKr768GZhf6crDTgs8/7TzT0yTUSLgZlQlAUPgrqz1hEQGfoWiMrVEeanjSdfvnOiUR7R0bsMT7j8hMRbTgfUuC6VDiFzmZ7wAuBD1uvazhY329jpoCNuqKcWNclKfzbqupNSFXtgQKBgQCTlR7Qm0YadChydeOzxX2GWa3XHT7fAFFHNPa8MQtqp40xAFb/a6TEzRZz49RkqyLXt9Bj2CqBNjSPakNWhay41+bJ7hMXAdaTOOJ0L/c1AwNf1C0zHg5KvWgCefPohvIvjqbrkx3VU50GCZsQqn5kLLYENAvAWX/lHRm/obKhcwKBgQC/iAOC8ZdZC5w4F0Mf7roZWa9P/42JWlCMzm/I/5mEIn4mYY6+1C5V+fXoET6845oAh+P8CkH4waJtqqN6BKQhj7SKqoCHgGBCQy+HrSCBtzk7NuXdpz6sk14zfcVpjR3y3l9TuXc4cVQMSLAqg8yUQf+qnEQTit4jyfikV/5XEw==
- peerId: 12D3KooWDXDcBYxtZ8KNRoJebNgNAv9nFbQatQMoWm1BLwmQh6u7
address: 127.0.0.1:4432
signingKey: /6+uYFwFf9nU6fvXQVtpHhjd8+v4dXc7esZzqkhjyfMJWlMiZOtQeb913FXofD5f20WksU0l6i22B09sFFYwDQ==
encryptionKey: MIIEogIBAAKCAQEAwCy84lzkxtzgn4ixGm0LSUTujOBpOh9m7XDoDPZnMTmExdOe9a5v/LXzdlCOCuBvK5u1T3ALBJMA3Zgvjv/jPRQUdiHprP3sbdfc6IgZPBFdLKFTc9yAA7GMbI4y7LhGMLGOMOqQXs+DOeImfmxEs3ykLXHKNas5ORnZPVnB6E9Qod8KH7UyMmBjQkOZYOOw10X4JZiU6xJp/E+VVWcmeXgNBbj5xOWMSzM+hhoA4wNOzBxACucaKDmqD6qugzebOqyUVSzFnEbquro+MYTWYdUDjZTXdvxgUUo80MGQ164gZhkFUKrmSpUvu3YErFySEGqAdFNwOZ6y/4X3s0BHvQIDAQABAoIBAAZiNhAK5+qXMbr67m8jSimv6YCyf6xXmLKwenTbxofDEl8D7ZbZqYyqeqDmgiFoXSkErhwqa6NGQtQZlxLX+zNvNFLMQ5fkg3MOpZ7vzm7JYN/3p+8EVxhIUJLWkmh8opBBhaioUg1kNUa59W9jp1CTBl0gF4h63JbB/g5kqeVOllUw7J1igAoaX36nOJGOwIynCWdizhDhgyjR4OcYfOLwcPDJueKTc5vM10g3LuMSK/sJmaD3TkJFPtDHw+RMW6wqyjsnkrg2D2oohXEyGWYYIXo2so4HCez0AB1I1JAxtVnRPvSIp7xLMm7+AkDoq12QYDHfxZtDTpfmvJg+Sn0CgYEAxCd+oribtdQW+JUctjsDbSQX5CeRISH5Ith3jveBx2jKIqQVnoVPz6URHOvnlIsqYYLANB8B3JHMWfR2UmkK11x0OcZecB06+oBoCZukvSXF+GqVHzLAQUxaoEBDCCPneskj5w+riMWBiiGDp32rUnkqv0nh7dnH+GfORcJ44L8CgYEA+s5s5EALj1jyU9w4+HVUyVsIrUitFnQg6qw/Td3Kj+8CXImKlS+rlmbQv0m1aOcvtFjQRIjjzZJAf/ausfAME+MayoNODgZsDk5RyDKuSWzMLvZLAa1LD52Uli5Pg8KtpzKVTn4xE1MbjsQcUNhFRAgrNEKNyuzXzdp4uXgGOoMCgYASXwiTQOsEepq0KXMI9jn57Nl3+uSyz7W/t7pq329+N6hG2ktUD3RMJE+X/9gup2IOw+owd377I4SaIDU8vq3PQc944cVShspRT9lunO8u7+y8uW7B/0TWWMpcG+irSIGTlGcSavtL0gOx5jWoaDK1hLemNss8NZtu/nnpOq+LjQKBgDisVozJMBOHPNLYS4NROAR77p0BdCNDwIBmxbM5r+EQWA9DAS6u4+4Lc5YV+MkonG37N6yU5iz4pFyGCHmqzX/c7JvgSc3/g4FED1TWpu1uiUD/ZHmPiAuSRxYchtk2L3k9g+GFwF8mg26iP+fAxv4VfnXDqDi3hhg9CtSWG4ozAoGAOWZXlFKqzGAfcucIe54FVQnweXG9sEuIPAvWvVRs4406ggNmL5eHccXpPHWTgetsr2TYMqPTDVMRmhBzSkyrYgk+b2tme79HPzTWs2Yg/pzjOfTgw7MBX/KlvOW5/J+dvrF3Gx8AHHZ9QQdYqi/MS1NKb2K3IbD0/m5gL5Pwi6A=
signingKey: c3D+0+BCl1xU35KBY+U3GPcU9aXdoLUiD4DJ2jF+IqI3CjGLhet3MBOkPXdIuPq/UpEqlp1k6FjNaU6DEU6Csg==
encryptionKey: MIIEpAIBAAKCAQEAuB7HsXuYmoif6/U4JnjC6L0QMu9qW1aPAxDrxWIedTzQhFZp3F3gYW/Zgdd2hvd0c2xyfhwf9C0X/UzfxWr54dDXzWNLN8BdVTik48cdYlgOmbgejiIjTaqSAlv4RtlqvooxCN0MwR2/RVAG/N5GqcAM7E4kJWPtvQYNl6wWCc92rKdutvmcj73wKzz9Hd/qdF612OVS3zRsjh3tJmYt55oovAUh1TAz/mSTTXjFHy35zLRBP+oQQsAOt2p0BOMSyOKZufGC8l3aZD//dp4/U/MaqCjeNuWxCfAZlSd+vt7T0aqDGdyRtrrGUcu4PCwXpOdbzw+uSZxnKawolYoEHwIDAQABAoIBAQCsxeVpvKtUx8QZrUCFiWiM8W0T/un0z+LfY696xzoBlZGtvVEVQtpdVJHsb31/5RFXhnphsI6jmPUb8llBbcMSjeETkItyw4ZRhBfmzl/aevsocEfr5EjwhpEAucDe6wJpzk95G8TuKrXjmtcTzpjMjbUSwbjVhVH/wIBcxVTg2j6z4AOADDRI5UsvZ0NV//If+nNzMjcuIji95PNk7lAuwsqkX3FycxvqXKUMGxRE2bgGMxaBRAP0kqL2vdxyS1M7wp/x04ZAtSnPXHe4qqmDOt69ec3XqbmZHOsZHzkCFePKcPB472/G0bPJeiq/idevEqS89RwvbphDtq3KGrRBAoGBAOrHqlPh36WZBOi6SueUmcrg579KDMUekgeea5payiySbRWztCL2yCYbSgFqSbyCLRppyXK51xvo8iUejR231or6u/nd7T0CON0Nf/8Qtbb13vtTGpIBiWYGqeDrWucUUlyS+K3sDfNk1AJqjUdaIMVu4yTpgzEvrdYCcT312RBPAoGBAMjC83/0EKnsbypFprxKS3Fbg963HhyKjfffQ2w4yncM6kxXF3ehVjg1LInok/6/dmy2LxkAf3r0YYZrGJWmG4Sv4UqHn6JxAjQgarPbdmGhJ8VIUMvMbZRsX3i8Z8D2o8k1M1kr6MYsQ53iX6q/Cp3gnucMeJPk6Xs9Q4TO7YsxAoGAWrXEOF6X01p4zBZWJH2Eoh8dSwooPuzdzPXHaz7SyD/Wx8DDw5KHqDl48W0Iij3dgUwIGjx1QQJStEbGjQnfaZkQkazOIXk/USELKBhjrQn4GjB0np7bYEEI1673UzrFy6C5VjFS/owhYcGbTksjSETcnAFgv9tFFd+hsyfOsv8CgYALk4o875LiaXrDgj6qDtKo17ET75Ux6h9jkqEtpVyvXrRH8KGuyUPSe+Z0kU+vWdT3Uc4HcArpyRuyh4xkXK6riQTBqm5fDIsm/FOKyXXbDVLgwlm+Vqxe6Zzbtml5K/+nw4SReMG0Y6sGeJ4xl1CCaAhhpEtzo7h+3bp99vylkQKBgQDDdR6N4wb3DHTzrW0EFb8XhXZN7CIE3EWhToNDsCkguUB7lwqD4p2c4yLscS0YAqxk7I3NW0nDaUV/340RrVtPJDqB4NZJ+MvhfvV3TW2FkZmru/iW+DMUsfZGAOPdQz9jLGAzUXrXFw/qGBtLIUL6UWqWLOrBO9QHb21nnB1Ssg==
space:
gcTTL: 60
syncPeriod: 11
syncPeriod: 20
storage:
path: db
metric:
@ -37,3 +37,6 @@ log:
production: false
defaultLevel: ""
namedLevels: {}
stream:
timeoutMilliseconds: 1000
maxMsgSizeMb: 256

View File

@ -3,10 +3,10 @@ grpcServer:
- 127.0.0.1:4530
tls: false
account:
peerId: 12D3KooWPHN8pCMgVaNfjzuXhHjsacrryW7DCyicurH3uKHXCyE5
peerKey: yHyVKOM1zEIbaHgwIAcBD/s9TmYQj6dU3dSzs5OHyBTIEpMC+jaTKKmS/5QCzgLzJFBnvayFtXwR/dH9G49M7g==
signingKey: yHyVKOM1zEIbaHgwIAcBD/s9TmYQj6dU3dSzs5OHyBTIEpMC+jaTKKmS/5QCzgLzJFBnvayFtXwR/dH9G49M7g==
encryptionKey: MIIEowIBAAKCAQEAu7C6g3bFuQb113lDuKJKa2zzeZNQxdjEQTcC5NVZkt5Qbz1cV4o1Rav0+nrMYT0mRFz6HPElUM7D1o+e/FIxrCsVnoCm4hinORhpilrR/DBXpnSTMmRyBIocaBK0T8shY4zNMYztQ0eiwkGZnxJSqi3Jk+oa7B871YIVDxzgD3AkOkTcRnFR+5SE+B+2G9qzhvRVj+LvjdEbkgnqMImZOPGsa9sSCfDrC928aSAokick4u8JqCfDnl9lYLlBYaVxGipiMayIg8TgXvUhiNWKrCoNyONHDtAKsmrTDj9DWEWtdX/h01uHrWBGq1/AVUpJ1w/5zHUYKF7kopTEskTYwQIDAQABAoIBAHhmiW817OahwWkFQF0btrOtA48U4nbYdCUFnhSfjEN724tQiIEbhsr34UIhLiSeroKiRkv0oaRxzw0/upRQQc8ZIFg6XVOizvsAXwvC8PtfI4sDMz3bU4z37/sPLJ4XR4bt1t+XcMh9FrqYjGyPu3mxv6LkRXr9Gkv/k3TLaCxd/88AlxLNquCYw5HKzZIN7XxzvYRHgn6YULSE48BewpqPPhSS5APItFyFoE9esafSBAcr54LSlwJ4X0Vee3QCxy1WZl17PzUE3M+lGvQ/gdsm+WrY5zUP0MTz4z95urknrPIP8WDXrfK+SzEXwrBvP1XVk1Sl/KKBJaAf+NMS7cECgYEAw/LEz+TuazDlsSAe1/fx9UNHQOAy5hrNIHd37uWaBUC3DszZEDqenJ6WZhtJD4DHfXwqtvXuj9Ju76YfGInFxxucg8AS4cD4+J+KfZ3p2JmYz9d+f/wPXtvG01HubV/KAPVdpDrN9QF/U+YC3W3QAw30V40X1nzgoZWMcPwjITkCgYEA9TYTh9U1oV23meaXUE8ux2ubufxy+Y/J4x57Zp77ttEU8xRTCKHAPdgm5PbMwhXTsUJEoFrH06iTkbwy9yIjJom4sl00E+p9//fEdCg8sEvpSJms6TwB6CkPsWgkwqNJDYwU5XLXd8EP16WZ83vyewZvCz5ssn7UXq0nKEtk28kCgYEAwHogSfafHDwT5EGhCpRL4JgNzfRtCwsYo+O2s7xl5vMC3k7qib6LP12obvQueEQPsXvemYpKpIwY3N9ZfEkZNdQxklmCMq/T4KUW7P3JTzLRoJgVcrKuhodsbvf0NQv66aYcLc51sU2fPVKbTdcolVeHxNibqd1Q6mh0ZCfIekECgYAsRxl7u5o1izCuD59fFw1BYUL7cIRqX/Z6lnR98VNOja6UviTIODz4beGIErCik0JojajKs9nFdHlBJZSmX3mtacz6GC5hMkSSRfEpcGKVCwAS5fz9GKLXgyKcTEvnAYkdcyAK1pPlwezUacjE2KrOYDkI9Lq3+ILsnaOmeQa7UQKBgGvHLrUvRsi04mB+TVQYwrlwRA0NNsxQTMek1UvFlpx/KN8oaDn7Aylao9zxutXP1jBH3kYmhn56/9lJpluDWJAKtBVXl9a4dh/ppC3WTAloU3+4u0aC0Mk49Hg9730S5LVozqH+q8VWiFh3qbxkrlE/4yocWvm18X5C6+kejKOh
peerId: 12D3KooWCVWC68UrG4yvhuMK3Jz29a5yXGNaMMtVpgabPzRE53Mk
peerKey: +cn5htkdQ4CzBA2z3uW3Cn7HiFVmPqDQL+w+fvDJ5NgnvhjlhFBJH2dm5XKcUZ3RSvb4NT1L9KebJm2Bz1kTqw==
signingKey: +cn5htkdQ4CzBA2z3uW3Cn7HiFVmPqDQL+w+fvDJ5NgnvhjlhFBJH2dm5XKcUZ3RSvb4NT1L9KebJm2Bz1kTqw==
encryptionKey: MIIEowIBAAKCAQEAuowvr/WyEhl7jXKo7flCjH5a21Uyd1V3GUY2M8EaZgl581jGM/FqGGQAyGDc/Go8ml5eTFPqagCkj37crLkQg4tlE3H0JK/Yqw4liBFU0uzXKBsHBtVgyjCgCgtPjzx3VvrfshDDm5YHqfqPsOiqfcbUvgbL24o1KY8SGzAVcTzZSSTr818UZaf5lNLRcQ6/v5dyaHWl+Dt9g2VNNuKAgr/BtvFRErQrOb8UWCGZlUgr8pkOB8E4hWLqqYPd8C50X+J7U5pClNeEodDEl5Y12w+xKLhLXyXuVAYXjmuvo0QhlaimhMh5cR0PJXonoh0JLCtbbFl9I9xqkqV/GFz+OwIDAQABAoIBAGXMKB26UsEDvON0RXEPS1yFeykjddWfAs38/YkCgFhcJXtA32/q9n123OJ70TvA8W8/ve+i/1F3JlXT4bIzjyppf++7iIIYn4DAyIRXCNXNPp/5F72H5TiQjlTM1U6RrYH+huGRulyF44rDW3QrkxXt0Zwc81PLOLWECFpjw9+1aAWW+oXsS9QHU7/Fk39LOMPu7JgMyjEjJ8zmoe5elnMaZNixldeoY97V4YRKJT7mM8DRv7nRmWsZiG+/J2ZF0+8dZhyfumOMXwWUbqkJKiW3YKknPdWIaXX5PnySP608AvZpt/COqqJjUVCFm2RXgf/kj/XJ0RJxpGwB7bprRXkCgYEA8niW97T/UekLeTXGM0TZbW+Tiqd3DiJWWnK+zXmJ2OqcYY93EVRMJNgeGoiiv0Vw/IfEb+tQy4cx5mph10NEM3N1Q2pQoDvAmHG+uuXc1B00nEuGjymWJktWa5GMnAGqchaEEyxE2JNiIfGBZ6pqqqRYNEISD9QaT+8PfLO/KBcCgYEAxPTL8Y9dF2q6nE8mBUCRfZU+qdmCOzkIvhOEiqCWhHbA18SIhp2giuZxyxoQtlsRkf5D38p/GwiFal8ExPIKXwKQjpcXO6HrTatCrSYycp8g/kh9Yi6EJGMA+MaHKE7U9iNkEQywloAodsrpKsEm1qZqQ7AuvT7nEfVlGy30zX0CgYAG38hX6Xe7mMHMg+vElFUdtyYVrj2/1tVf5xTlumZgEfaxBWI4yY0HFmF0Gx+SEKPtZOP60E8QFhsiDy4K7ktGsiVG7gKvKEKDj+X6Yn3qPZG6RKHh+SnamBQxJIU5/woYBe9ko8Kn6TXFBJXInJo9kD837A+bB0ZfscVcobPvrQKBgHF5EB8GF/4r0YPI3gDcqHYQDGBTHoL8YxsPp6cuyklbGdO2OWpFWn9sMVdwlvxZD5BrS7OduQlcKXGVeOv2/x6qHZrpVctXiHfhGbMkdKAxKhMWtJZicmN8Xsz1pF0Gvg9paHeiNgMfpzB5y0iEq9mzWznQQb1qhjqEhVHZclcJAoGBAJPUMuwLsWAkVPg0Nu/uNYnkoves5GQcosbsKs91pMhFpsfr1X7oQLQ4ahRzWd2mWIEOF9moHJn4T5a0ZxPadbLXxjIqTkVKBcuV+WpIH0RvnXxd16LZJc8rCz0up1zvOzz+b1pcsu/6/ehFCJ+AQyqlutPuBNNLPygRVRZLNDvi
mongo:
connect: mongodb://localhost:27017/?w=majority
database: consensus
@ -17,3 +17,6 @@ log:
production: false
defaultLevel: ""
namedLevels: {}
stream:
timeoutMilliseconds: 1000
maxMsgSizeMb: 256

View File

@ -3,10 +3,10 @@ grpcServer:
- 127.0.0.1:4531
tls: false
account:
peerId: 12D3KooWA5veToUAwEVVXV6PoR4dFH91HQZA339NZzqeT3C6mMS7
peerKey: gGwpn8J8b1WXK3Lhaq3NnQMix+qQsHNRxAH/DUalvM0D/G9dc/GRiAu+NDtGKRc9z2YAw6HKJ5GJAfzWTMDREA==
signingKey: gGwpn8J8b1WXK3Lhaq3NnQMix+qQsHNRxAH/DUalvM0D/G9dc/GRiAu+NDtGKRc9z2YAw6HKJ5GJAfzWTMDREA==
encryptionKey: MIIEowIBAAKCAQEAw4BsTVcK6Rnt3kYtvMZ7HU3EmD6uQzjn0bqoCsFKFNOMh0x+GE4aDox6j8rEzbeNWFwkn7RI6kPuByuSxe5RPG9QP3mxoIgWc737IKx6X0K9vBc8rLTgbr/OCctQs5zfsvEYZa4sKG+mfXPh5oxNsLfAO87OiPsTEPXLYTrEGZ4GZ71HLO7EBsI8N4JvNWZVQq3bbv+S7kiXtXpI1kdfE1Nu5XZIVw3dSEWoP3X9Tp9zavLM/obwoN8IXFGqAbEKOZE9zZkqvwIVymFxqEn7bcqtkfhbvvyTpg/VSeRAQhJkhmx92QDgz8mt7d2ADan3hgqFO68qHK+VlH7D0eaMOQIDAQABAoIBAQCOG42d8kV2B2kGhxC8BbJ8LIlY+UcGihjINNvtZW8KEHQ37PxDgpIiPS7h0syXlHLj5aahiBTwZIxjHeNEiOT3/xnf6f+Z5xIa89/VckpJcGQmkuWBzMDPABEuwWFaDg/1LJdFYgOrKO1mh5OPWDEo4YiUcNFkdMz5KRG7DVJ6I0NNm2x4sRJf8KVfLiOBDX9CKEUpmXZCciUlA3PnXAiJwpYxHoTSktqMrVj7YWgUuaYB0ZQdaXTG5jPZAL7zdVP3Ub1h5Oc9i56UgP0qAo6uXhQR+Xr7wKptnQk9g27zddx7ofa8NtnDpgzMOfXvJjWsMBB8ego0rQjydUihsvLhAoGBAMree7cd/NgqXgDc8V2zusb1gZ0Ao1uvCcYmp/w7v/tUF/UOuvjYuFkHosvHEOjy3gHNrnFYcj1US3K8OFIRkp7b8TKkEL/ho01SVI9PMfczEws5K6ufBZQ+33hJ7+drOlirRQxW8lIZspL3im/CLxm9K2zSfj/oMreO0ZY5jM4dAoGBAPaz/DJOLSKzeu9LBzFjfDMhYN5N3dLHIG0dPIDYDJYyquXYIARZrOD5wWh3WahX1YyCC5bBgugRi3SG0/IaKZQg2+/X70RdLXNK5sZHxR2ZildGFFaA9ERLYy9Gq75hAGTA0dt4CA4iM90jy0Prwoya32SF+zywoMcGV3LLX0vNAoGAPQya2k5R6pNFWqkikXomuPzklmS8xDh2joTPhJ5Odcmms/5M0doWD+S2XvB27EM5//zvg/iD2GTnl42AvWHAZ8H0YbLxv2ydggVGoSHJ/YQHNRdtRuZB/Yy2HzLQ2Slxk4Fm9AGuRnqpPIT1yg/7sJk22ja1+3Fa4dY+yCBleRkCgYAU9L8Eiu18mCBmOUpYIKpJMZmn6JdiMzYG7sfX7gJLs+wecBhwJinwRmbud8zu5t8l+1n+qVt0WSEuedGBLEXB5nSoUABsHzogJAmsaCZPWF6PAU3y9ytIrdq0Bl3KYzUEWfi5mt2cTb14GHVIxLsW9ITrZhIsWpidr2U4RBxJNQKBgFl5qZd8wFwm1kv8j1BtiGMN3e9cIJlfuIm97SOuaEFSwo/QWnhLQ5QBNwIijXDx+Rx3jPPedMO/fYd8IjFdG1x+1g4XVlnCV8PMCsGFwsu3/Q4Av9q2uflsZlAc+6vdjB9uEr4jhiKd+j7f5SWpPHKCUWyeem47WSjyq3dsM7HG
peerId: 12D3KooWB79zLr5KqDCe3uHkEEZ4EchbdRNMMeZFrcVXeRzpBa8d
peerKey: abZsspXm7Y0Ndl+oADxJskTS76KVvHQ5hBwZI0vOyAkTKMoaL+SMOISDiyPEFDoBQO9xwSXwTF2ES7dultLT/g==
signingKey: abZsspXm7Y0Ndl+oADxJskTS76KVvHQ5hBwZI0vOyAkTKMoaL+SMOISDiyPEFDoBQO9xwSXwTF2ES7dultLT/g==
encryptionKey: MIIEpAIBAAKCAQEA4we17FV9hPMq6jayCoLnWQri1tvZiCtroC5aRnzmosjxM3dBp7rjskQBSC8U89WWTRlQOMDxcCiq7meFiIoLO7nKL6YVw3w5w3hmc1s+/KIXkzMq25VC9OwrUBLR1rL7CR9slwYEYCizl+jS80q+unDqFeKPr9fqY8V6WSOrRRWqQtGLL/6Wq5KrgNc9rKwcIpvtb0w+UHewreVx2UBiasN/seydT0JEihIO0yyPxHtQ9ZtT/QV6IvRG4VE1UmxDAIIPc2gOJN9poiUCDlPDkogU2ZZ6XPUZ/nJwvp1Yh3hS5HjEb/5EiGSGgIQ1+tiKKREE/ZYtj8x8iJI+pnTT8QIDAQABAoIBADccdxAQzLCKav+CGYQttMVLvDcWFV9V0wGGXwm/ZilcCBlLONfjqURr97ezHi32yk6a93tfcvycEqpe3O6BPCradfdNJPlYXZlSz+Pu4YJoQrrL7/pv6FoWPolomCG7Pu8+/phGsKc7GiWlMhg3K8eMg3aekezIyDBCDuo2m2vgWkBzXrFm3s01doDlSkwMwvEx9UQpnekzUEC8qxjyfe9c5mEiN894/qsiiwCXIDwg0av/tu9Xrnz3LyejDoroSUnAKkSNJZJKXdUqxOGHlZSHqibS1H6WNouoQMdIyToQGYThBRBHpU7WynOXQF2jtaX4UUgAxMdUxEPCkmOjm/UCgYEA46Lc2CD/uI4hWT92PKHrZ54Js/V+YbLX7KziYPKQIkuvWIJjK4J6MaU+B7xc/3Thf3FWWv1+gTh3+9Li7swWNb8QEQhG6thz/AJgOSpeq3tvexIohjDhATsTAcnl/LEJ4jN93AJ+pOtqj+bCTFvBKn+w5dMlqaowD1T1G918Rf8CgYEA/1GECle4Xg6y1aMKq4KV2oK45q7X+28Vc6Rf1hfCFO8g7xLy4IfZPb5Ve1UEv76hqICYJpnBKXhB0I3z4Wf9g1nI0shnwve3AhNsw2oe+oMdUhVcbM249+Ppv8ZlUOG470BhCq6Hbzv5owPepxnR80IZw/xu3H7HBv7y6tj3Rg8CgYEA2ESK/OudCIJAPMKGWuSa+j6ziT3bbIa1ji5ShTjupyaw2K5H+bZk0XXkkQTsdeddte6/1IKyBaLYm2+oGqfbEgUMBqKOfeBXkT3QnX8bomALcim2Rod5vemaDUD8OC8a7MVu9e+I0ra27zCVuGYUB4R5VGBej+sY7fgRRwAOaZECgYAoRVI/U2C4LTdV7RaEwN8kDRRfBlr4xKesitO28B5jsOgP7XwzoBnK3FedUWajW80hx8633+6QvPAclhdOiVl6O1IqtQNwxCOwhyHTnMxwFPgt90KRws0XBHLdFczrOf8ydYQY7DheeiZA6R5YWwE7jkSEHi/aRYDdAJ+OHVS7TwKBgQCE6pWmO0g7PD2d4r9NPC6x6rp7KL6NjfYqia1VZJn2yJWikyMDQg0hNj1gTlC4dDpX6RhpFvNThHUPlnl2FHwpRkBe6/+Jv0sMdpB9Bj9nSKNrqOvWrfcIOqjU3D+W5nVM0/YWJAzb4xlC3h5IodEigOJaN+r9Eg8te34nb6lJsw==
mongo:
connect: mongodb://localhost:27017/?w=majority
database: consensus
@ -17,3 +17,6 @@ log:
production: false
defaultLevel: ""
namedLevels: {}
stream:
timeoutMilliseconds: 1000
maxMsgSizeMb: 256

View File

@ -3,10 +3,10 @@ grpcServer:
- 127.0.0.1:4532
tls: false
account:
peerId: 12D3KooWS9fMHSbogWfa2o2NLm2Y7o3SGXojn5anj5zPz1TeZDz7
peerKey: UYx7nyuYqq2+j/t8kTZczAoXCNflp1FNW60tNUfkEtzyrHQg/MAHjYwYGhYxzQ00xsntqLsuA0FAuyR+YtVrsA==
signingKey: UYx7nyuYqq2+j/t8kTZczAoXCNflp1FNW60tNUfkEtzyrHQg/MAHjYwYGhYxzQ00xsntqLsuA0FAuyR+YtVrsA==
encryptionKey: MIIEpQIBAAKCAQEAvbd32m4jCtCVSPthnycxPmbKNnnLUn8tHNQZr5Sl2cH1MBaRBEo1DBhI9UXIqd0iprFCvTJjo6s6vWVdLAXgkGpKbuWvh1wdVuMOsq5kQ34m+XEWKXVpSkpNboUh8LdBTrk7NqvpMy9vC2aUt6bKY2zPDnRFQKFeRobfapwntWLoIhmAtBJJRbZuvc8OsFHUQRjcN4ZXLBziRcMqG0IBFPstpiXJNp4f7oB/bWGKg9yKM4vkgaIXEq5RXSvtPD+Zx1ovt4YF0vStWxxM9rEIAAK49HlCJ/aQ7+YYpFGjzjMQMVjLlH+8pcP0ZO75/DgJa1YZDiZ6ICPJ7YADTURKQwIDAQABAoIBAQCdAKRzZAoj/RJOX5sedvTNy4s1If4du5m97dmD8OSAHX+n2EUS48aax845DRNPX+45PSEaKgVDgYUPED/XGtYJLa2DsRleT+EH8shLHv9iy5e9ftT0YnJMRMln2U2JRF8Lo0dZq1NGRM8FBFO22JVNStLgB2D4Z5L5ksx6Edjaxh5wIWxs3ETihzNSZFWvh1bVXdUzC0VfxO6VuiiTN7IMAeL7DiM0/QVc8vk4BKG00XtV9KvtnGqnynpHYvWZ4xRU4GYYwDwLZFWDssLgU+3SNJCeucGrrckC1/73B5gjJ3Lq39dbr2maEdKvo6KdE8kOLQyZxTMHWdAVH6MKGmPhAoGBAOZGlR5V6P/cI8d594VHz8txEp72IsK3Y73acbdqkV4kmvQUq36oj3ObO6ZNhaH3/j+M9xw12eizh2KV512aDmywEHGXbs2FY9Flck6fMRAamOrEkGHUUDdACDyyCRtO3EQMMNndy00dPY/Q+nrwHKLfwYcfDcrJXsBVS6Zy+hFdAoGBANLo+sMU4grnp/XurIIB+3Zahzfoeo4xMiLNRDOy0nuwG23mgozZKaRnsiyxrtBQ3un3cjQS3+mggsa+N95mF6h+aNzM98ySqqByw7v7N8c7LQjon/BxonBXLi/bETLS5+cdRRXHD6QbvREtFVtD9oRZJAeLvS++BdtS1s8vOfAfAoGBANh7JHbnVusqXmyKKfsfXqcoPtQ4GsepNlhmQx+mTNEPYqjxwaOJ/Yo2NmaKXIW/KUM/V5QqwBf2puE0gdTKHqNpBZx0O5N0wjk5wLNPDwXPq1CRyBZgTaUTSmsdCFim04YZW9eFnjl5ssVANipbDuDDsCFCPWoV00DHLx5k2th1AoGBAJmwA+rb8MuZex8OyM4Du8XGufnXglbTKoGJqkUx7YcMETDIZCFWra2Lkp5W69gI1icPlTy09E0+FY3VVsjNBDhXxPoAsiF0TrmUZ2U37rFTQcHYIZQIeiH6pUFiFOpAHZSgE5OG9rLTM7asb3+Nyrkua77D6Rw9D+9+MeHPvBxpAoGAPD6fta40UAA/SB8lLmviQ4odWlbbN4AiUO/oIey6PswU2ZJllHEOY67snzhfafdT8y8pHCQQGDnPELfdB/2b/4x7Pi4+xQ6LepxMkIgBnW4zrbsokbvuZ64anCAvK8cfqqvcD4OFEdh/GlTQHGSzlQ/RGbOAuQ7GTAYlsQmb+So=
peerId: 12D3KooWHKcJRGnk5wHYo9Tgy5Dg48pX3D64mQU6yjkWcmzK1R7P
peerKey: VhENG7mg6uNVoor852BDJD68zZpY/2ROX27m6qSf585vf6GkpR/lCL77GSN70ifDEgstGF1f4c3AoVMNYDqOEg==
signingKey: VhENG7mg6uNVoor852BDJD68zZpY/2ROX27m6qSf585vf6GkpR/lCL77GSN70ifDEgstGF1f4c3AoVMNYDqOEg==
encryptionKey: MIIEowIBAAKCAQEAmHu87SqfW1dypmaBGqbwSraRI3DPV3cGObbbf953+AEtbTszx2c6tVJNX+3lpC1D9mZm9iY8MRZjoeUFdOjx0bzE7CIDKgtWixE4tJoEqzpr8UeYKsUYtJeWpANSJGeUUoeBcY1aQKkxJqGTXLxU3faOfxfUyKwlJ1If28pkSeaEPxWtdcgEx7ddKCic0Z7FkjVmqqpoSaSMf7rKByPJL3zHb21FohNQKAyVLoMno7IK6p8oW1TifOcS2f+Bt8nAxt27XJKbCwOoXazsJbm5HXjMNxg4l3riR8BhA38rTvhfb4gblIcF79Lx8W8wvjtoBcBrAcG+HWRc+wXCgim6PwIDAQABAoIBAByx5HrJM5Xv3e58ib0nPz8AHk4KE6rFBlHkHGhyyCbOqerNYlAbGAw5QcBUt4tuzURYPvYBegBO008LFzzJ/X/Xw0Mgn3HREmc3RXGPLmO+qcONEpCx6JVLlZil21Zoe5wQTga9cAeND2fSrjWcZ2gh1u0J4gwlgRRmOwKUkszpHwbjmgs2KwvrCFF145ol7N6z+xnXRKwykXqe5Z1pCfOyy+qY39JWT4DsepjAOpw+g3Z8JXgSp6tauGgcJbGh+lgFtr0g/f1WQw7VxZO+hdCPY1njaxp9i98uz3DJlUddKdoXQBOzr+gVB3wC7I7woNL6ELS36wwmX/wa7lk4TPkCgYEAyeNKiMIu053ON+EKq3deDuNV1p2ER13sfU+bvUPEq0bQCsLQFz6OAR0qOHabvTmYdnvJipE2/xP1/GXX5lbO2mvEgg7adDDWwhOjaT3voeQyj1ezP3r5nvfH6dC04RGegJflLHAzOfcfrjNASbCvJHlQEtOJeJbLhBedp/sIxysCgYEAwVqDqBQYQ1MXc0YIhRo0nJlPPbtGQBFeJTUjAnYOx0tG+MzQHGiVMQB25AfSwTDj4v/aaYnuu6jTHn2GiMOa2zA7xNu5ygTI8eP6GdI4ch5JH/kDhIT2iMWhMFytj3y2xpeuWOFzwBpkBa18YLbh2ebsGy3lP0bCcSy+dyTUTz0CgYAh7DMl75r2q9luwj2Mui3vynst6KHFbB7En4/HqY9uSCPE6x8UCMrLnR7vBd79WKQppHsk8WmQSsZWdrZkWcnAIcOPJvfF9j7ftXULxgBx72ofc9kGnZ87+t54hz0dZFyBtwQnB2NUJhYIq0vuFeYX9tphj3HV9WCU/XLcOu4qqQKBgEeDIbSVkg+8eKzi1x3bfl/49+zeCfKCOe7LA2LSpU6ikeJNZh9LsvpHsLFQD2vymCaJ+I8WO9zeaQ8a4BpPNkQhR8ncdo+4S1Xjusm4DbZvax5PLDTkNIaLib1oWaz7NGKpEQvAft4rJJlQ+/KNUWUVWngG9oX7tsjDAsLwNTIFAoGBAKBhYmGsNn/E6PQGW/I9u1QrAwtB+HyYG4i6aazyonlIfKRaBd4RMTN4twhSilTIZb/1DOyq/yWfANsci03gaH3sv14E4kb0hFyTlDmu+XYJGSh4AKZLVU2fLbZIkSDrWogL8+VZaQy8tdwQAJ3yUpHw5+Aqxv/HE1tinyI+FSqk
mongo:
connect: mongodb://localhost:27017/?w=majority
database: consensus
@ -17,3 +17,6 @@ log:
production: false
defaultLevel: ""
namedLevels: {}
stream:
timeoutMilliseconds: 1000
maxMsgSizeMb: 256

View File

@ -5,30 +5,30 @@ grpcServer:
- 127.0.0.1:4430
tls: false
account:
peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
peerKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
peerId: 12D3KooWHtnADt84naf6NeejZ1MxYGZPLk5SPEu2DL4ZV948uWPS
peerKey: Fu/H792JFWVYQpOZeLBIr1Y5UuHdZzJxkGO7eakZDaZ3/vIDhjGgNab1+1NMdTJ0IUP6Tv3KQutcRwtX26/wmQ==
signingKey: Fu/H792JFWVYQpOZeLBIr1Y5UuHdZzJxkGO7eakZDaZ3/vIDhjGgNab1+1NMdTJ0IUP6Tv3KQutcRwtX26/wmQ==
encryptionKey: MIIEowIBAAKCAQEAs+N32tT2Q4Nv9MlyH0B34TJZYLh1+Y/4hc0vupiS/Ct0Mt+Rh62KkPy6Hz2JRDd7ryYpz/Un+qAFQBhfugKy6a5R0U/OnaK8/WwJjstTPd59c7iGnCeW9mWumexT2wiQVbWcSdcAE5SPYmBkIPnwzgxZgtNzvEnbdUDWIOsR3ifDAt3iUqqlo+cZWIZaXiTjyrMlaWY/BR/SGrklYzxcUzNj+K6DdY4yFN5/5ywKIe81llooULTyM5U+fWEW5uri4ERgT/YcRAoii2UJ5kHzpIZmGKcrJ4kUdyFLE7VxYIQMHHXRkDlpTEYlAAJGl5frcHvFufTWIJaohBXAxg5tyQIDAQABAoIBAD3TI9I19x1lAwliYrKS+aCQKV+whftrm8KArrK21W2NkbYaWG4FGuaRtXYfNBoZ54xe1Wf/nenpLWTF+8B2RP9DRiNmBmDvGX0PsIk/IDDXUs5+0OTCRoQQll2Yd4mD+/c5H6nRFtmj6VOqRT+AJ17pp6nq+o/v4lj+G5ncsJtlAtq1xb20yHQYEl6sbK2UqYuiFtXpKMCK/8V3hDj+ROM8UMkxMj+qj9NFd2sCk4FEZ+S2QmHIjY55s4Rpe1RzZZZEYOuJ99Fism+HYXtf3JlFORaNIdhdWY1UkVAFuKY/ULoHOhf/RdJ8ZArak3CplpEdPTYC4IRBI1eZDDF2GgECgYEAw0jvV7E1kqfGD5Q1WTFsss4xHQntPtWRfyAI1viy16sqMX6wQ4ZixWXsOeMB1o5azqqjYo0BBiGw6ie1GKl0iZ09FxHmMDqFLf8a0JZXAlTvC/wEHgAXCzg7tpHRJD1B6gAiU6u6ALW14DtWe6tikFehrY0mwGb9koedQNgoGnkCgYEA69EcUTejGm5Hm6ANC5u5Vn1aaB4BrTJ36FGTaxjnSUPePBj0Eo2Bt+c25DiD3uGj2Jws5QrRhpu+NYhOTC+/P1/rm82w9Tpc8z/wA7nUk0gGEncgtJ8RFokom4B+Ui83JJiH0V7puZUhCc/TOmfa5N0SH5gM4q4rBoVDZtnTGdECgYEAlnssW9GlK6Z2++hEF7/7N+mldPACTkn6PRCtXyHzhjdSYyNxpgb3M49vsceY0gGOPfTFxBpNsLDjh/wjE6b4s1ZkDdPwIjfmCmSrABLpZ1WVgxGnBoshNrcVZIEGvTsrAKsryHfq88MSLIDtCo0tfXbZkkfTla2HNpOj/KTUelkCgYBl0pMRlp58qSWOUxuO6ZyrddD1qA89Q892ptKqqcQkZIOvG284G5XpXJLdFHIMaQ2gWD8iXvt9zf3hi4uTZgKEUNyhF73TBXJhLjhqw3DAb5b/niSnGQ/91ReNnXvt7Kk4ygvLIdp14ai0XeJtE672p2ZN8g+OSXoWhLBH1sJKIQKBgA7NH/Y4RbVHIMWY7jH/1d4ODZ4Hr1RK2Q99HJCAurfD5tjhpcMApoQQJKJDpv7J5Ipx6ynQJD7CFfx27+vqBEG4ffAUm66lKM5xrKcOevcyWemppurCLuza64GgWDP6jBRnHeqrUyZUqoI/I0FNwjxIJbu08NpRSt8khq59+iyF
apiServer:
listenAddrs:
- 127.0.0.1:8080
tls: false
nodes:
- peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
- peerId: 12D3KooWHtnADt84naf6NeejZ1MxYGZPLk5SPEu2DL4ZV948uWPS
address: 127.0.0.1:4430
signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
- peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
signingKey: Fu/H792JFWVYQpOZeLBIr1Y5UuHdZzJxkGO7eakZDaZ3/vIDhjGgNab1+1NMdTJ0IUP6Tv3KQutcRwtX26/wmQ==
encryptionKey: MIIEowIBAAKCAQEAs+N32tT2Q4Nv9MlyH0B34TJZYLh1+Y/4hc0vupiS/Ct0Mt+Rh62KkPy6Hz2JRDd7ryYpz/Un+qAFQBhfugKy6a5R0U/OnaK8/WwJjstTPd59c7iGnCeW9mWumexT2wiQVbWcSdcAE5SPYmBkIPnwzgxZgtNzvEnbdUDWIOsR3ifDAt3iUqqlo+cZWIZaXiTjyrMlaWY/BR/SGrklYzxcUzNj+K6DdY4yFN5/5ywKIe81llooULTyM5U+fWEW5uri4ERgT/YcRAoii2UJ5kHzpIZmGKcrJ4kUdyFLE7VxYIQMHHXRkDlpTEYlAAJGl5frcHvFufTWIJaohBXAxg5tyQIDAQABAoIBAD3TI9I19x1lAwliYrKS+aCQKV+whftrm8KArrK21W2NkbYaWG4FGuaRtXYfNBoZ54xe1Wf/nenpLWTF+8B2RP9DRiNmBmDvGX0PsIk/IDDXUs5+0OTCRoQQll2Yd4mD+/c5H6nRFtmj6VOqRT+AJ17pp6nq+o/v4lj+G5ncsJtlAtq1xb20yHQYEl6sbK2UqYuiFtXpKMCK/8V3hDj+ROM8UMkxMj+qj9NFd2sCk4FEZ+S2QmHIjY55s4Rpe1RzZZZEYOuJ99Fism+HYXtf3JlFORaNIdhdWY1UkVAFuKY/ULoHOhf/RdJ8ZArak3CplpEdPTYC4IRBI1eZDDF2GgECgYEAw0jvV7E1kqfGD5Q1WTFsss4xHQntPtWRfyAI1viy16sqMX6wQ4ZixWXsOeMB1o5azqqjYo0BBiGw6ie1GKl0iZ09FxHmMDqFLf8a0JZXAlTvC/wEHgAXCzg7tpHRJD1B6gAiU6u6ALW14DtWe6tikFehrY0mwGb9koedQNgoGnkCgYEA69EcUTejGm5Hm6ANC5u5Vn1aaB4BrTJ36FGTaxjnSUPePBj0Eo2Bt+c25DiD3uGj2Jws5QrRhpu+NYhOTC+/P1/rm82w9Tpc8z/wA7nUk0gGEncgtJ8RFokom4B+Ui83JJiH0V7puZUhCc/TOmfa5N0SH5gM4q4rBoVDZtnTGdECgYEAlnssW9GlK6Z2++hEF7/7N+mldPACTkn6PRCtXyHzhjdSYyNxpgb3M49vsceY0gGOPfTFxBpNsLDjh/wjE6b4s1ZkDdPwIjfmCmSrABLpZ1WVgxGnBoshNrcVZIEGvTsrAKsryHfq88MSLIDtCo0tfXbZkkfTla2HNpOj/KTUelkCgYBl0pMRlp58qSWOUxuO6ZyrddD1qA89Q892ptKqqcQkZIOvG284G5XpXJLdFHIMaQ2gWD8iXvt9zf3hi4uTZgKEUNyhF73TBXJhLjhqw3DAb5b/niSnGQ/91ReNnXvt7Kk4ygvLIdp14ai0XeJtE672p2ZN8g+OSXoWhLBH1sJKIQKBgA7NH/Y4RbVHIMWY7jH/1d4ODZ4Hr1RK2Q99HJCAurfD5tjhpcMApoQQJKJDpv7J5Ipx6ynQJD7CFfx27+vqBEG4ffAUm66lKM5xrKcOevcyWemppurCLuza64GgWDP6jBRnHeqrUyZUqoI/I0FNwjxIJbu08NpRSt8khq59+iyF
- peerId: 12D3KooWG1r2SVzTMGDhkiw9McbZq98H9C1Ggzp7FSfWDGbVSCbZ
address: 127.0.0.1:4431
signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
- peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
signingKey: CZTN+NFi4g9MA4BKl3OiCKuzXh63ukIvYWo9D5t9qfZcFwIeOW8eP9W8mtnXaY3JAFyb6GliBW0uCaw4wjRcCA==
encryptionKey: MIIEpAIBAAKCAQEAo9Nuypzg9kZ+LP+8jQgSTaoRUu8VFdJdCOEjuroPQK+2NwBD/Z9BqKiN0Z+jmhkI9yA0/Fwdh21ibAKX3Je9uffAKOhXI2sxIAlccDORu1kGDnhcc7N3L644DK+uFZvKnMQWiCwmtTnNHkoCzWcIE44G56wMa2c4W7mrOuRWqG6a5Z9JUuLqafOIlf6Dw2fiVM6xXiTIMQ0OyXByxFNjsS5O/PYcwoIKMV8MY+gUnAmyPLE0bslvz/8W+3E7d/LDO4lhqW+N1kDmboe6sc7DBf5JD4DLnP2VWV8Ae/rfJvxwu9ZqVT8RdYKMsZqvs9sV+6jQC9UcX+K8Q4Wdo0eMHwIDAQABAoIBAACR57zEtvOkYyP878b91DJ4+P503nno9XHmdp1bsFnlQpkGYzYqq6vOik/EYmlS1PknH4gROfkSpFkD2UtnK73N4tlBlawF33HhFnU9eLBSKvc56/hrE2sTDBbfNZfVpurMs9ddb/UJcnE8iK32QczvnY6IxrJI9aU8DCB0UujbGDnya/HbFU9pLLxu2EUoHNxjSHG/jCx+AR7JRknRA65KPZG7mu5jeAaaklYTY/aLGlctgecDKfNKDsZo6rgAMUW6ZXI8ogNGqfKHUFazCVe0l1tp4hxvgmyjcw79iKvFr4mlpHtgjYTFCeoMJKvOXUImZUJL0vCA6WKvUdIfzAECgYEA0lCTXYwOHqOwYMb1qi8lIIApcI//B/Nzn++MDQ4ZO4SzVJTTv4rSdXAuoihsO6E7LYZK+wdVNjiCbeMukfTqEfaxWXIsIDaHSR3440NsYSwdBz04UhRgpxFE2FwPK7J5dQ57FBaCAgksnO3XjcByBMYgMWVbA+ezIWfVdN96YoECgYEAx2mm/W4ZGdDyJgDonzEGGxfaNqo6DIv+67fDwI6WyqOWFWJTBaVFkm1uPJfcXYuTI9YCNFRKuRU7dyqSPLErMVusC/8Iww8++kqmkc1m04tbkqh4KpREYuMw8/tTYSWDwgpY8ksM5YRpYRJLTuuC0cEmefGco1RsXG8bYYeZXp8CgYBq5fexYcG/gxXgauBtSx9E4L+vbhGD2hNYJKr768GZhf6crDTgs8/7TzT0yTUSLgZlQlAUPgrqz1hEQGfoWiMrVEeanjSdfvnOiUR7R0bsMT7j8hMRbTgfUuC6VDiFzmZ7wAuBD1uvazhY329jpoCNuqKcWNclKfzbqupNSFXtgQKBgQCTlR7Qm0YadChydeOzxX2GWa3XHT7fAFFHNPa8MQtqp40xAFb/a6TEzRZz49RkqyLXt9Bj2CqBNjSPakNWhay41+bJ7hMXAdaTOOJ0L/c1AwNf1C0zHg5KvWgCefPohvIvjqbrkx3VU50GCZsQqn5kLLYENAvAWX/lHRm/obKhcwKBgQC/iAOC8ZdZC5w4F0Mf7roZWa9P/42JWlCMzm/I/5mEIn4mYY6+1C5V+fXoET6845oAh+P8CkH4waJtqqN6BKQhj7SKqoCHgGBCQy+HrSCBtzk7NuXdpz6sk14zfcVpjR3y3l9TuXc4cVQMSLAqg8yUQf+qnEQTit4jyfikV/5XEw==
- peerId: 12D3KooWDXDcBYxtZ8KNRoJebNgNAv9nFbQatQMoWm1BLwmQh6u7
address: 127.0.0.1:4432
signingKey: /6+uYFwFf9nU6fvXQVtpHhjd8+v4dXc7esZzqkhjyfMJWlMiZOtQeb913FXofD5f20WksU0l6i22B09sFFYwDQ==
encryptionKey: MIIEogIBAAKCAQEAwCy84lzkxtzgn4ixGm0LSUTujOBpOh9m7XDoDPZnMTmExdOe9a5v/LXzdlCOCuBvK5u1T3ALBJMA3Zgvjv/jPRQUdiHprP3sbdfc6IgZPBFdLKFTc9yAA7GMbI4y7LhGMLGOMOqQXs+DOeImfmxEs3ykLXHKNas5ORnZPVnB6E9Qod8KH7UyMmBjQkOZYOOw10X4JZiU6xJp/E+VVWcmeXgNBbj5xOWMSzM+hhoA4wNOzBxACucaKDmqD6qugzebOqyUVSzFnEbquro+MYTWYdUDjZTXdvxgUUo80MGQ164gZhkFUKrmSpUvu3YErFySEGqAdFNwOZ6y/4X3s0BHvQIDAQABAoIBAAZiNhAK5+qXMbr67m8jSimv6YCyf6xXmLKwenTbxofDEl8D7ZbZqYyqeqDmgiFoXSkErhwqa6NGQtQZlxLX+zNvNFLMQ5fkg3MOpZ7vzm7JYN/3p+8EVxhIUJLWkmh8opBBhaioUg1kNUa59W9jp1CTBl0gF4h63JbB/g5kqeVOllUw7J1igAoaX36nOJGOwIynCWdizhDhgyjR4OcYfOLwcPDJueKTc5vM10g3LuMSK/sJmaD3TkJFPtDHw+RMW6wqyjsnkrg2D2oohXEyGWYYIXo2so4HCez0AB1I1JAxtVnRPvSIp7xLMm7+AkDoq12QYDHfxZtDTpfmvJg+Sn0CgYEAxCd+oribtdQW+JUctjsDbSQX5CeRISH5Ith3jveBx2jKIqQVnoVPz6URHOvnlIsqYYLANB8B3JHMWfR2UmkK11x0OcZecB06+oBoCZukvSXF+GqVHzLAQUxaoEBDCCPneskj5w+riMWBiiGDp32rUnkqv0nh7dnH+GfORcJ44L8CgYEA+s5s5EALj1jyU9w4+HVUyVsIrUitFnQg6qw/Td3Kj+8CXImKlS+rlmbQv0m1aOcvtFjQRIjjzZJAf/ausfAME+MayoNODgZsDk5RyDKuSWzMLvZLAa1LD52Uli5Pg8KtpzKVTn4xE1MbjsQcUNhFRAgrNEKNyuzXzdp4uXgGOoMCgYASXwiTQOsEepq0KXMI9jn57Nl3+uSyz7W/t7pq329+N6hG2ktUD3RMJE+X/9gup2IOw+owd377I4SaIDU8vq3PQc944cVShspRT9lunO8u7+y8uW7B/0TWWMpcG+irSIGTlGcSavtL0gOx5jWoaDK1hLemNss8NZtu/nnpOq+LjQKBgDisVozJMBOHPNLYS4NROAR77p0BdCNDwIBmxbM5r+EQWA9DAS6u4+4Lc5YV+MkonG37N6yU5iz4pFyGCHmqzX/c7JvgSc3/g4FED1TWpu1uiUD/ZHmPiAuSRxYchtk2L3k9g+GFwF8mg26iP+fAxv4VfnXDqDi3hhg9CtSWG4ozAoGAOWZXlFKqzGAfcucIe54FVQnweXG9sEuIPAvWvVRs4406ggNmL5eHccXpPHWTgetsr2TYMqPTDVMRmhBzSkyrYgk+b2tme79HPzTWs2Yg/pzjOfTgw7MBX/KlvOW5/J+dvrF3Gx8AHHZ9QQdYqi/MS1NKb2K3IbD0/m5gL5Pwi6A=
signingKey: c3D+0+BCl1xU35KBY+U3GPcU9aXdoLUiD4DJ2jF+IqI3CjGLhet3MBOkPXdIuPq/UpEqlp1k6FjNaU6DEU6Csg==
encryptionKey: MIIEpAIBAAKCAQEAuB7HsXuYmoif6/U4JnjC6L0QMu9qW1aPAxDrxWIedTzQhFZp3F3gYW/Zgdd2hvd0c2xyfhwf9C0X/UzfxWr54dDXzWNLN8BdVTik48cdYlgOmbgejiIjTaqSAlv4RtlqvooxCN0MwR2/RVAG/N5GqcAM7E4kJWPtvQYNl6wWCc92rKdutvmcj73wKzz9Hd/qdF612OVS3zRsjh3tJmYt55oovAUh1TAz/mSTTXjFHy35zLRBP+oQQsAOt2p0BOMSyOKZufGC8l3aZD//dp4/U/MaqCjeNuWxCfAZlSd+vt7T0aqDGdyRtrrGUcu4PCwXpOdbzw+uSZxnKawolYoEHwIDAQABAoIBAQCsxeVpvKtUx8QZrUCFiWiM8W0T/un0z+LfY696xzoBlZGtvVEVQtpdVJHsb31/5RFXhnphsI6jmPUb8llBbcMSjeETkItyw4ZRhBfmzl/aevsocEfr5EjwhpEAucDe6wJpzk95G8TuKrXjmtcTzpjMjbUSwbjVhVH/wIBcxVTg2j6z4AOADDRI5UsvZ0NV//If+nNzMjcuIji95PNk7lAuwsqkX3FycxvqXKUMGxRE2bgGMxaBRAP0kqL2vdxyS1M7wp/x04ZAtSnPXHe4qqmDOt69ec3XqbmZHOsZHzkCFePKcPB472/G0bPJeiq/idevEqS89RwvbphDtq3KGrRBAoGBAOrHqlPh36WZBOi6SueUmcrg579KDMUekgeea5payiySbRWztCL2yCYbSgFqSbyCLRppyXK51xvo8iUejR231or6u/nd7T0CON0Nf/8Qtbb13vtTGpIBiWYGqeDrWucUUlyS+K3sDfNk1AJqjUdaIMVu4yTpgzEvrdYCcT312RBPAoGBAMjC83/0EKnsbypFprxKS3Fbg963HhyKjfffQ2w4yncM6kxXF3ehVjg1LInok/6/dmy2LxkAf3r0YYZrGJWmG4Sv4UqHn6JxAjQgarPbdmGhJ8VIUMvMbZRsX3i8Z8D2o8k1M1kr6MYsQ53iX6q/Cp3gnucMeJPk6Xs9Q4TO7YsxAoGAWrXEOF6X01p4zBZWJH2Eoh8dSwooPuzdzPXHaz7SyD/Wx8DDw5KHqDl48W0Iij3dgUwIGjx1QQJStEbGjQnfaZkQkazOIXk/USELKBhjrQn4GjB0np7bYEEI1673UzrFy6C5VjFS/owhYcGbTksjSETcnAFgv9tFFd+hsyfOsv8CgYALk4o875LiaXrDgj6qDtKo17ET75Ux6h9jkqEtpVyvXrRH8KGuyUPSe+Z0kU+vWdT3Uc4HcArpyRuyh4xkXK6riQTBqm5fDIsm/FOKyXXbDVLgwlm+Vqxe6Zzbtml5K/+nw4SReMG0Y6sGeJ4xl1CCaAhhpEtzo7h+3bp99vylkQKBgQDDdR6N4wb3DHTzrW0EFb8XhXZN7CIE3EWhToNDsCkguUB7lwqD4p2c4yLscS0YAqxk7I3NW0nDaUV/340RrVtPJDqB4NZJ+MvhfvV3TW2FkZmru/iW+DMUsfZGAOPdQz9jLGAzUXrXFw/qGBtLIUL6UWqWLOrBO9QHb21nnB1Ssg==
space:
gcTTL: 60
syncPeriod: 11
syncPeriod: 600
storage:
path: db
metric:
@ -37,3 +37,6 @@ log:
production: false
defaultLevel: ""
namedLevels: {}
stream:
timeoutMilliseconds: 1000
maxMsgSizeMb: 256

View File

@ -5,30 +5,30 @@ grpcServer:
- 127.0.0.1:4431
tls: false
account:
peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
peerKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
peerId: 12D3KooWG1r2SVzTMGDhkiw9McbZq98H9C1Ggzp7FSfWDGbVSCbZ
peerKey: CZTN+NFi4g9MA4BKl3OiCKuzXh63ukIvYWo9D5t9qfZcFwIeOW8eP9W8mtnXaY3JAFyb6GliBW0uCaw4wjRcCA==
signingKey: CZTN+NFi4g9MA4BKl3OiCKuzXh63ukIvYWo9D5t9qfZcFwIeOW8eP9W8mtnXaY3JAFyb6GliBW0uCaw4wjRcCA==
encryptionKey: MIIEpAIBAAKCAQEAo9Nuypzg9kZ+LP+8jQgSTaoRUu8VFdJdCOEjuroPQK+2NwBD/Z9BqKiN0Z+jmhkI9yA0/Fwdh21ibAKX3Je9uffAKOhXI2sxIAlccDORu1kGDnhcc7N3L644DK+uFZvKnMQWiCwmtTnNHkoCzWcIE44G56wMa2c4W7mrOuRWqG6a5Z9JUuLqafOIlf6Dw2fiVM6xXiTIMQ0OyXByxFNjsS5O/PYcwoIKMV8MY+gUnAmyPLE0bslvz/8W+3E7d/LDO4lhqW+N1kDmboe6sc7DBf5JD4DLnP2VWV8Ae/rfJvxwu9ZqVT8RdYKMsZqvs9sV+6jQC9UcX+K8Q4Wdo0eMHwIDAQABAoIBAACR57zEtvOkYyP878b91DJ4+P503nno9XHmdp1bsFnlQpkGYzYqq6vOik/EYmlS1PknH4gROfkSpFkD2UtnK73N4tlBlawF33HhFnU9eLBSKvc56/hrE2sTDBbfNZfVpurMs9ddb/UJcnE8iK32QczvnY6IxrJI9aU8DCB0UujbGDnya/HbFU9pLLxu2EUoHNxjSHG/jCx+AR7JRknRA65KPZG7mu5jeAaaklYTY/aLGlctgecDKfNKDsZo6rgAMUW6ZXI8ogNGqfKHUFazCVe0l1tp4hxvgmyjcw79iKvFr4mlpHtgjYTFCeoMJKvOXUImZUJL0vCA6WKvUdIfzAECgYEA0lCTXYwOHqOwYMb1qi8lIIApcI//B/Nzn++MDQ4ZO4SzVJTTv4rSdXAuoihsO6E7LYZK+wdVNjiCbeMukfTqEfaxWXIsIDaHSR3440NsYSwdBz04UhRgpxFE2FwPK7J5dQ57FBaCAgksnO3XjcByBMYgMWVbA+ezIWfVdN96YoECgYEAx2mm/W4ZGdDyJgDonzEGGxfaNqo6DIv+67fDwI6WyqOWFWJTBaVFkm1uPJfcXYuTI9YCNFRKuRU7dyqSPLErMVusC/8Iww8++kqmkc1m04tbkqh4KpREYuMw8/tTYSWDwgpY8ksM5YRpYRJLTuuC0cEmefGco1RsXG8bYYeZXp8CgYBq5fexYcG/gxXgauBtSx9E4L+vbhGD2hNYJKr768GZhf6crDTgs8/7TzT0yTUSLgZlQlAUPgrqz1hEQGfoWiMrVEeanjSdfvnOiUR7R0bsMT7j8hMRbTgfUuC6VDiFzmZ7wAuBD1uvazhY329jpoCNuqKcWNclKfzbqupNSFXtgQKBgQCTlR7Qm0YadChydeOzxX2GWa3XHT7fAFFHNPa8MQtqp40xAFb/a6TEzRZz49RkqyLXt9Bj2CqBNjSPakNWhay41+bJ7hMXAdaTOOJ0L/c1AwNf1C0zHg5KvWgCefPohvIvjqbrkx3VU50GCZsQqn5kLLYENAvAWX/lHRm/obKhcwKBgQC/iAOC8ZdZC5w4F0Mf7roZWa9P/42JWlCMzm/I/5mEIn4mYY6+1C5V+fXoET6845oAh+P8CkH4waJtqqN6BKQhj7SKqoCHgGBCQy+HrSCBtzk7NuXdpz6sk14zfcVpjR3y3l9TuXc4cVQMSLAqg8yUQf+qnEQTit4jyfikV/5XEw==
apiServer:
listenAddrs:
- 127.0.0.1:8081
tls: false
nodes:
- peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
- peerId: 12D3KooWHtnADt84naf6NeejZ1MxYGZPLk5SPEu2DL4ZV948uWPS
address: 127.0.0.1:4430
signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
- peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
signingKey: Fu/H792JFWVYQpOZeLBIr1Y5UuHdZzJxkGO7eakZDaZ3/vIDhjGgNab1+1NMdTJ0IUP6Tv3KQutcRwtX26/wmQ==
encryptionKey: MIIEowIBAAKCAQEAs+N32tT2Q4Nv9MlyH0B34TJZYLh1+Y/4hc0vupiS/Ct0Mt+Rh62KkPy6Hz2JRDd7ryYpz/Un+qAFQBhfugKy6a5R0U/OnaK8/WwJjstTPd59c7iGnCeW9mWumexT2wiQVbWcSdcAE5SPYmBkIPnwzgxZgtNzvEnbdUDWIOsR3ifDAt3iUqqlo+cZWIZaXiTjyrMlaWY/BR/SGrklYzxcUzNj+K6DdY4yFN5/5ywKIe81llooULTyM5U+fWEW5uri4ERgT/YcRAoii2UJ5kHzpIZmGKcrJ4kUdyFLE7VxYIQMHHXRkDlpTEYlAAJGl5frcHvFufTWIJaohBXAxg5tyQIDAQABAoIBAD3TI9I19x1lAwliYrKS+aCQKV+whftrm8KArrK21W2NkbYaWG4FGuaRtXYfNBoZ54xe1Wf/nenpLWTF+8B2RP9DRiNmBmDvGX0PsIk/IDDXUs5+0OTCRoQQll2Yd4mD+/c5H6nRFtmj6VOqRT+AJ17pp6nq+o/v4lj+G5ncsJtlAtq1xb20yHQYEl6sbK2UqYuiFtXpKMCK/8V3hDj+ROM8UMkxMj+qj9NFd2sCk4FEZ+S2QmHIjY55s4Rpe1RzZZZEYOuJ99Fism+HYXtf3JlFORaNIdhdWY1UkVAFuKY/ULoHOhf/RdJ8ZArak3CplpEdPTYC4IRBI1eZDDF2GgECgYEAw0jvV7E1kqfGD5Q1WTFsss4xHQntPtWRfyAI1viy16sqMX6wQ4ZixWXsOeMB1o5azqqjYo0BBiGw6ie1GKl0iZ09FxHmMDqFLf8a0JZXAlTvC/wEHgAXCzg7tpHRJD1B6gAiU6u6ALW14DtWe6tikFehrY0mwGb9koedQNgoGnkCgYEA69EcUTejGm5Hm6ANC5u5Vn1aaB4BrTJ36FGTaxjnSUPePBj0Eo2Bt+c25DiD3uGj2Jws5QrRhpu+NYhOTC+/P1/rm82w9Tpc8z/wA7nUk0gGEncgtJ8RFokom4B+Ui83JJiH0V7puZUhCc/TOmfa5N0SH5gM4q4rBoVDZtnTGdECgYEAlnssW9GlK6Z2++hEF7/7N+mldPACTkn6PRCtXyHzhjdSYyNxpgb3M49vsceY0gGOPfTFxBpNsLDjh/wjE6b4s1ZkDdPwIjfmCmSrABLpZ1WVgxGnBoshNrcVZIEGvTsrAKsryHfq88MSLIDtCo0tfXbZkkfTla2HNpOj/KTUelkCgYBl0pMRlp58qSWOUxuO6ZyrddD1qA89Q892ptKqqcQkZIOvG284G5XpXJLdFHIMaQ2gWD8iXvt9zf3hi4uTZgKEUNyhF73TBXJhLjhqw3DAb5b/niSnGQ/91ReNnXvt7Kk4ygvLIdp14ai0XeJtE672p2ZN8g+OSXoWhLBH1sJKIQKBgA7NH/Y4RbVHIMWY7jH/1d4ODZ4Hr1RK2Q99HJCAurfD5tjhpcMApoQQJKJDpv7J5Ipx6ynQJD7CFfx27+vqBEG4ffAUm66lKM5xrKcOevcyWemppurCLuza64GgWDP6jBRnHeqrUyZUqoI/I0FNwjxIJbu08NpRSt8khq59+iyF
- peerId: 12D3KooWG1r2SVzTMGDhkiw9McbZq98H9C1Ggzp7FSfWDGbVSCbZ
address: 127.0.0.1:4431
signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
- peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
signingKey: CZTN+NFi4g9MA4BKl3OiCKuzXh63ukIvYWo9D5t9qfZcFwIeOW8eP9W8mtnXaY3JAFyb6GliBW0uCaw4wjRcCA==
encryptionKey: MIIEpAIBAAKCAQEAo9Nuypzg9kZ+LP+8jQgSTaoRUu8VFdJdCOEjuroPQK+2NwBD/Z9BqKiN0Z+jmhkI9yA0/Fwdh21ibAKX3Je9uffAKOhXI2sxIAlccDORu1kGDnhcc7N3L644DK+uFZvKnMQWiCwmtTnNHkoCzWcIE44G56wMa2c4W7mrOuRWqG6a5Z9JUuLqafOIlf6Dw2fiVM6xXiTIMQ0OyXByxFNjsS5O/PYcwoIKMV8MY+gUnAmyPLE0bslvz/8W+3E7d/LDO4lhqW+N1kDmboe6sc7DBf5JD4DLnP2VWV8Ae/rfJvxwu9ZqVT8RdYKMsZqvs9sV+6jQC9UcX+K8Q4Wdo0eMHwIDAQABAoIBAACR57zEtvOkYyP878b91DJ4+P503nno9XHmdp1bsFnlQpkGYzYqq6vOik/EYmlS1PknH4gROfkSpFkD2UtnK73N4tlBlawF33HhFnU9eLBSKvc56/hrE2sTDBbfNZfVpurMs9ddb/UJcnE8iK32QczvnY6IxrJI9aU8DCB0UujbGDnya/HbFU9pLLxu2EUoHNxjSHG/jCx+AR7JRknRA65KPZG7mu5jeAaaklYTY/aLGlctgecDKfNKDsZo6rgAMUW6ZXI8ogNGqfKHUFazCVe0l1tp4hxvgmyjcw79iKvFr4mlpHtgjYTFCeoMJKvOXUImZUJL0vCA6WKvUdIfzAECgYEA0lCTXYwOHqOwYMb1qi8lIIApcI//B/Nzn++MDQ4ZO4SzVJTTv4rSdXAuoihsO6E7LYZK+wdVNjiCbeMukfTqEfaxWXIsIDaHSR3440NsYSwdBz04UhRgpxFE2FwPK7J5dQ57FBaCAgksnO3XjcByBMYgMWVbA+ezIWfVdN96YoECgYEAx2mm/W4ZGdDyJgDonzEGGxfaNqo6DIv+67fDwI6WyqOWFWJTBaVFkm1uPJfcXYuTI9YCNFRKuRU7dyqSPLErMVusC/8Iww8++kqmkc1m04tbkqh4KpREYuMw8/tTYSWDwgpY8ksM5YRpYRJLTuuC0cEmefGco1RsXG8bYYeZXp8CgYBq5fexYcG/gxXgauBtSx9E4L+vbhGD2hNYJKr768GZhf6crDTgs8/7TzT0yTUSLgZlQlAUPgrqz1hEQGfoWiMrVEeanjSdfvnOiUR7R0bsMT7j8hMRbTgfUuC6VDiFzmZ7wAuBD1uvazhY329jpoCNuqKcWNclKfzbqupNSFXtgQKBgQCTlR7Qm0YadChydeOzxX2GWa3XHT7fAFFHNPa8MQtqp40xAFb/a6TEzRZz49RkqyLXt9Bj2CqBNjSPakNWhay41+bJ7hMXAdaTOOJ0L/c1AwNf1C0zHg5KvWgCefPohvIvjqbrkx3VU50GCZsQqn5kLLYENAvAWX/lHRm/obKhcwKBgQC/iAOC8ZdZC5w4F0Mf7roZWa9P/42JWlCMzm/I/5mEIn4mYY6+1C5V+fXoET6845oAh+P8CkH4waJtqqN6BKQhj7SKqoCHgGBCQy+HrSCBtzk7NuXdpz6sk14zfcVpjR3y3l9TuXc4cVQMSLAqg8yUQf+qnEQTit4jyfikV/5XEw==
- peerId: 12D3KooWDXDcBYxtZ8KNRoJebNgNAv9nFbQatQMoWm1BLwmQh6u7
address: 127.0.0.1:4432
signingKey: /6+uYFwFf9nU6fvXQVtpHhjd8+v4dXc7esZzqkhjyfMJWlMiZOtQeb913FXofD5f20WksU0l6i22B09sFFYwDQ==
encryptionKey: MIIEogIBAAKCAQEAwCy84lzkxtzgn4ixGm0LSUTujOBpOh9m7XDoDPZnMTmExdOe9a5v/LXzdlCOCuBvK5u1T3ALBJMA3Zgvjv/jPRQUdiHprP3sbdfc6IgZPBFdLKFTc9yAA7GMbI4y7LhGMLGOMOqQXs+DOeImfmxEs3ykLXHKNas5ORnZPVnB6E9Qod8KH7UyMmBjQkOZYOOw10X4JZiU6xJp/E+VVWcmeXgNBbj5xOWMSzM+hhoA4wNOzBxACucaKDmqD6qugzebOqyUVSzFnEbquro+MYTWYdUDjZTXdvxgUUo80MGQ164gZhkFUKrmSpUvu3YErFySEGqAdFNwOZ6y/4X3s0BHvQIDAQABAoIBAAZiNhAK5+qXMbr67m8jSimv6YCyf6xXmLKwenTbxofDEl8D7ZbZqYyqeqDmgiFoXSkErhwqa6NGQtQZlxLX+zNvNFLMQ5fkg3MOpZ7vzm7JYN/3p+8EVxhIUJLWkmh8opBBhaioUg1kNUa59W9jp1CTBl0gF4h63JbB/g5kqeVOllUw7J1igAoaX36nOJGOwIynCWdizhDhgyjR4OcYfOLwcPDJueKTc5vM10g3LuMSK/sJmaD3TkJFPtDHw+RMW6wqyjsnkrg2D2oohXEyGWYYIXo2so4HCez0AB1I1JAxtVnRPvSIp7xLMm7+AkDoq12QYDHfxZtDTpfmvJg+Sn0CgYEAxCd+oribtdQW+JUctjsDbSQX5CeRISH5Ith3jveBx2jKIqQVnoVPz6URHOvnlIsqYYLANB8B3JHMWfR2UmkK11x0OcZecB06+oBoCZukvSXF+GqVHzLAQUxaoEBDCCPneskj5w+riMWBiiGDp32rUnkqv0nh7dnH+GfORcJ44L8CgYEA+s5s5EALj1jyU9w4+HVUyVsIrUitFnQg6qw/Td3Kj+8CXImKlS+rlmbQv0m1aOcvtFjQRIjjzZJAf/ausfAME+MayoNODgZsDk5RyDKuSWzMLvZLAa1LD52Uli5Pg8KtpzKVTn4xE1MbjsQcUNhFRAgrNEKNyuzXzdp4uXgGOoMCgYASXwiTQOsEepq0KXMI9jn57Nl3+uSyz7W/t7pq329+N6hG2ktUD3RMJE+X/9gup2IOw+owd377I4SaIDU8vq3PQc944cVShspRT9lunO8u7+y8uW7B/0TWWMpcG+irSIGTlGcSavtL0gOx5jWoaDK1hLemNss8NZtu/nnpOq+LjQKBgDisVozJMBOHPNLYS4NROAR77p0BdCNDwIBmxbM5r+EQWA9DAS6u4+4Lc5YV+MkonG37N6yU5iz4pFyGCHmqzX/c7JvgSc3/g4FED1TWpu1uiUD/ZHmPiAuSRxYchtk2L3k9g+GFwF8mg26iP+fAxv4VfnXDqDi3hhg9CtSWG4ozAoGAOWZXlFKqzGAfcucIe54FVQnweXG9sEuIPAvWvVRs4406ggNmL5eHccXpPHWTgetsr2TYMqPTDVMRmhBzSkyrYgk+b2tme79HPzTWs2Yg/pzjOfTgw7MBX/KlvOW5/J+dvrF3Gx8AHHZ9QQdYqi/MS1NKb2K3IbD0/m5gL5Pwi6A=
signingKey: c3D+0+BCl1xU35KBY+U3GPcU9aXdoLUiD4DJ2jF+IqI3CjGLhet3MBOkPXdIuPq/UpEqlp1k6FjNaU6DEU6Csg==
encryptionKey: MIIEpAIBAAKCAQEAuB7HsXuYmoif6/U4JnjC6L0QMu9qW1aPAxDrxWIedTzQhFZp3F3gYW/Zgdd2hvd0c2xyfhwf9C0X/UzfxWr54dDXzWNLN8BdVTik48cdYlgOmbgejiIjTaqSAlv4RtlqvooxCN0MwR2/RVAG/N5GqcAM7E4kJWPtvQYNl6wWCc92rKdutvmcj73wKzz9Hd/qdF612OVS3zRsjh3tJmYt55oovAUh1TAz/mSTTXjFHy35zLRBP+oQQsAOt2p0BOMSyOKZufGC8l3aZD//dp4/U/MaqCjeNuWxCfAZlSd+vt7T0aqDGdyRtrrGUcu4PCwXpOdbzw+uSZxnKawolYoEHwIDAQABAoIBAQCsxeVpvKtUx8QZrUCFiWiM8W0T/un0z+LfY696xzoBlZGtvVEVQtpdVJHsb31/5RFXhnphsI6jmPUb8llBbcMSjeETkItyw4ZRhBfmzl/aevsocEfr5EjwhpEAucDe6wJpzk95G8TuKrXjmtcTzpjMjbUSwbjVhVH/wIBcxVTg2j6z4AOADDRI5UsvZ0NV//If+nNzMjcuIji95PNk7lAuwsqkX3FycxvqXKUMGxRE2bgGMxaBRAP0kqL2vdxyS1M7wp/x04ZAtSnPXHe4qqmDOt69ec3XqbmZHOsZHzkCFePKcPB472/G0bPJeiq/idevEqS89RwvbphDtq3KGrRBAoGBAOrHqlPh36WZBOi6SueUmcrg579KDMUekgeea5payiySbRWztCL2yCYbSgFqSbyCLRppyXK51xvo8iUejR231or6u/nd7T0CON0Nf/8Qtbb13vtTGpIBiWYGqeDrWucUUlyS+K3sDfNk1AJqjUdaIMVu4yTpgzEvrdYCcT312RBPAoGBAMjC83/0EKnsbypFprxKS3Fbg963HhyKjfffQ2w4yncM6kxXF3ehVjg1LInok/6/dmy2LxkAf3r0YYZrGJWmG4Sv4UqHn6JxAjQgarPbdmGhJ8VIUMvMbZRsX3i8Z8D2o8k1M1kr6MYsQ53iX6q/Cp3gnucMeJPk6Xs9Q4TO7YsxAoGAWrXEOF6X01p4zBZWJH2Eoh8dSwooPuzdzPXHaz7SyD/Wx8DDw5KHqDl48W0Iij3dgUwIGjx1QQJStEbGjQnfaZkQkazOIXk/USELKBhjrQn4GjB0np7bYEEI1673UzrFy6C5VjFS/owhYcGbTksjSETcnAFgv9tFFd+hsyfOsv8CgYALk4o875LiaXrDgj6qDtKo17ET75Ux6h9jkqEtpVyvXrRH8KGuyUPSe+Z0kU+vWdT3Uc4HcArpyRuyh4xkXK6riQTBqm5fDIsm/FOKyXXbDVLgwlm+Vqxe6Zzbtml5K/+nw4SReMG0Y6sGeJ4xl1CCaAhhpEtzo7h+3bp99vylkQKBgQDDdR6N4wb3DHTzrW0EFb8XhXZN7CIE3EWhToNDsCkguUB7lwqD4p2c4yLscS0YAqxk7I3NW0nDaUV/340RrVtPJDqB4NZJ+MvhfvV3TW2FkZmru/iW+DMUsfZGAOPdQz9jLGAzUXrXFw/qGBtLIUL6UWqWLOrBO9QHb21nnB1Ssg==
space:
gcTTL: 60
syncPeriod: 11
syncPeriod: 600
storage:
path: db
metric:
@ -37,3 +37,6 @@ log:
production: false
defaultLevel: ""
namedLevels: {}
stream:
timeoutMilliseconds: 1000
maxMsgSizeMb: 256

View File

@ -5,30 +5,30 @@ grpcServer:
- 127.0.0.1:4432
tls: false
account:
peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
peerKey: /6+uYFwFf9nU6fvXQVtpHhjd8+v4dXc7esZzqkhjyfMJWlMiZOtQeb913FXofD5f20WksU0l6i22B09sFFYwDQ==
signingKey: /6+uYFwFf9nU6fvXQVtpHhjd8+v4dXc7esZzqkhjyfMJWlMiZOtQeb913FXofD5f20WksU0l6i22B09sFFYwDQ==
encryptionKey: MIIEogIBAAKCAQEAwCy84lzkxtzgn4ixGm0LSUTujOBpOh9m7XDoDPZnMTmExdOe9a5v/LXzdlCOCuBvK5u1T3ALBJMA3Zgvjv/jPRQUdiHprP3sbdfc6IgZPBFdLKFTc9yAA7GMbI4y7LhGMLGOMOqQXs+DOeImfmxEs3ykLXHKNas5ORnZPVnB6E9Qod8KH7UyMmBjQkOZYOOw10X4JZiU6xJp/E+VVWcmeXgNBbj5xOWMSzM+hhoA4wNOzBxACucaKDmqD6qugzebOqyUVSzFnEbquro+MYTWYdUDjZTXdvxgUUo80MGQ164gZhkFUKrmSpUvu3YErFySEGqAdFNwOZ6y/4X3s0BHvQIDAQABAoIBAAZiNhAK5+qXMbr67m8jSimv6YCyf6xXmLKwenTbxofDEl8D7ZbZqYyqeqDmgiFoXSkErhwqa6NGQtQZlxLX+zNvNFLMQ5fkg3MOpZ7vzm7JYN/3p+8EVxhIUJLWkmh8opBBhaioUg1kNUa59W9jp1CTBl0gF4h63JbB/g5kqeVOllUw7J1igAoaX36nOJGOwIynCWdizhDhgyjR4OcYfOLwcPDJueKTc5vM10g3LuMSK/sJmaD3TkJFPtDHw+RMW6wqyjsnkrg2D2oohXEyGWYYIXo2so4HCez0AB1I1JAxtVnRPvSIp7xLMm7+AkDoq12QYDHfxZtDTpfmvJg+Sn0CgYEAxCd+oribtdQW+JUctjsDbSQX5CeRISH5Ith3jveBx2jKIqQVnoVPz6URHOvnlIsqYYLANB8B3JHMWfR2UmkK11x0OcZecB06+oBoCZukvSXF+GqVHzLAQUxaoEBDCCPneskj5w+riMWBiiGDp32rUnkqv0nh7dnH+GfORcJ44L8CgYEA+s5s5EALj1jyU9w4+HVUyVsIrUitFnQg6qw/Td3Kj+8CXImKlS+rlmbQv0m1aOcvtFjQRIjjzZJAf/ausfAME+MayoNODgZsDk5RyDKuSWzMLvZLAa1LD52Uli5Pg8KtpzKVTn4xE1MbjsQcUNhFRAgrNEKNyuzXzdp4uXgGOoMCgYASXwiTQOsEepq0KXMI9jn57Nl3+uSyz7W/t7pq329+N6hG2ktUD3RMJE+X/9gup2IOw+owd377I4SaIDU8vq3PQc944cVShspRT9lunO8u7+y8uW7B/0TWWMpcG+irSIGTlGcSavtL0gOx5jWoaDK1hLemNss8NZtu/nnpOq+LjQKBgDisVozJMBOHPNLYS4NROAR77p0BdCNDwIBmxbM5r+EQWA9DAS6u4+4Lc5YV+MkonG37N6yU5iz4pFyGCHmqzX/c7JvgSc3/g4FED1TWpu1uiUD/ZHmPiAuSRxYchtk2L3k9g+GFwF8mg26iP+fAxv4VfnXDqDi3hhg9CtSWG4ozAoGAOWZXlFKqzGAfcucIe54FVQnweXG9sEuIPAvWvVRs4406ggNmL5eHccXpPHWTgetsr2TYMqPTDVMRmhBzSkyrYgk+b2tme79HPzTWs2Yg/pzjOfTgw7MBX/KlvOW5/J+dvrF3Gx8AHHZ9QQdYqi/MS1NKb2K3IbD0/m5gL5Pwi6A=
peerId: 12D3KooWDXDcBYxtZ8KNRoJebNgNAv9nFbQatQMoWm1BLwmQh6u7
peerKey: c3D+0+BCl1xU35KBY+U3GPcU9aXdoLUiD4DJ2jF+IqI3CjGLhet3MBOkPXdIuPq/UpEqlp1k6FjNaU6DEU6Csg==
signingKey: c3D+0+BCl1xU35KBY+U3GPcU9aXdoLUiD4DJ2jF+IqI3CjGLhet3MBOkPXdIuPq/UpEqlp1k6FjNaU6DEU6Csg==
encryptionKey: MIIEpAIBAAKCAQEAuB7HsXuYmoif6/U4JnjC6L0QMu9qW1aPAxDrxWIedTzQhFZp3F3gYW/Zgdd2hvd0c2xyfhwf9C0X/UzfxWr54dDXzWNLN8BdVTik48cdYlgOmbgejiIjTaqSAlv4RtlqvooxCN0MwR2/RVAG/N5GqcAM7E4kJWPtvQYNl6wWCc92rKdutvmcj73wKzz9Hd/qdF612OVS3zRsjh3tJmYt55oovAUh1TAz/mSTTXjFHy35zLRBP+oQQsAOt2p0BOMSyOKZufGC8l3aZD//dp4/U/MaqCjeNuWxCfAZlSd+vt7T0aqDGdyRtrrGUcu4PCwXpOdbzw+uSZxnKawolYoEHwIDAQABAoIBAQCsxeVpvKtUx8QZrUCFiWiM8W0T/un0z+LfY696xzoBlZGtvVEVQtpdVJHsb31/5RFXhnphsI6jmPUb8llBbcMSjeETkItyw4ZRhBfmzl/aevsocEfr5EjwhpEAucDe6wJpzk95G8TuKrXjmtcTzpjMjbUSwbjVhVH/wIBcxVTg2j6z4AOADDRI5UsvZ0NV//If+nNzMjcuIji95PNk7lAuwsqkX3FycxvqXKUMGxRE2bgGMxaBRAP0kqL2vdxyS1M7wp/x04ZAtSnPXHe4qqmDOt69ec3XqbmZHOsZHzkCFePKcPB472/G0bPJeiq/idevEqS89RwvbphDtq3KGrRBAoGBAOrHqlPh36WZBOi6SueUmcrg579KDMUekgeea5payiySbRWztCL2yCYbSgFqSbyCLRppyXK51xvo8iUejR231or6u/nd7T0CON0Nf/8Qtbb13vtTGpIBiWYGqeDrWucUUlyS+K3sDfNk1AJqjUdaIMVu4yTpgzEvrdYCcT312RBPAoGBAMjC83/0EKnsbypFprxKS3Fbg963HhyKjfffQ2w4yncM6kxXF3ehVjg1LInok/6/dmy2LxkAf3r0YYZrGJWmG4Sv4UqHn6JxAjQgarPbdmGhJ8VIUMvMbZRsX3i8Z8D2o8k1M1kr6MYsQ53iX6q/Cp3gnucMeJPk6Xs9Q4TO7YsxAoGAWrXEOF6X01p4zBZWJH2Eoh8dSwooPuzdzPXHaz7SyD/Wx8DDw5KHqDl48W0Iij3dgUwIGjx1QQJStEbGjQnfaZkQkazOIXk/USELKBhjrQn4GjB0np7bYEEI1673UzrFy6C5VjFS/owhYcGbTksjSETcnAFgv9tFFd+hsyfOsv8CgYALk4o875LiaXrDgj6qDtKo17ET75Ux6h9jkqEtpVyvXrRH8KGuyUPSe+Z0kU+vWdT3Uc4HcArpyRuyh4xkXK6riQTBqm5fDIsm/FOKyXXbDVLgwlm+Vqxe6Zzbtml5K/+nw4SReMG0Y6sGeJ4xl1CCaAhhpEtzo7h+3bp99vylkQKBgQDDdR6N4wb3DHTzrW0EFb8XhXZN7CIE3EWhToNDsCkguUB7lwqD4p2c4yLscS0YAqxk7I3NW0nDaUV/340RrVtPJDqB4NZJ+MvhfvV3TW2FkZmru/iW+DMUsfZGAOPdQz9jLGAzUXrXFw/qGBtLIUL6UWqWLOrBO9QHb21nnB1Ssg==
apiServer:
listenAddrs:
- 127.0.0.1:8082
tls: false
nodes:
- peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
- peerId: 12D3KooWHtnADt84naf6NeejZ1MxYGZPLk5SPEu2DL4ZV948uWPS
address: 127.0.0.1:4430
signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
- peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
signingKey: Fu/H792JFWVYQpOZeLBIr1Y5UuHdZzJxkGO7eakZDaZ3/vIDhjGgNab1+1NMdTJ0IUP6Tv3KQutcRwtX26/wmQ==
encryptionKey: MIIEowIBAAKCAQEAs+N32tT2Q4Nv9MlyH0B34TJZYLh1+Y/4hc0vupiS/Ct0Mt+Rh62KkPy6Hz2JRDd7ryYpz/Un+qAFQBhfugKy6a5R0U/OnaK8/WwJjstTPd59c7iGnCeW9mWumexT2wiQVbWcSdcAE5SPYmBkIPnwzgxZgtNzvEnbdUDWIOsR3ifDAt3iUqqlo+cZWIZaXiTjyrMlaWY/BR/SGrklYzxcUzNj+K6DdY4yFN5/5ywKIe81llooULTyM5U+fWEW5uri4ERgT/YcRAoii2UJ5kHzpIZmGKcrJ4kUdyFLE7VxYIQMHHXRkDlpTEYlAAJGl5frcHvFufTWIJaohBXAxg5tyQIDAQABAoIBAD3TI9I19x1lAwliYrKS+aCQKV+whftrm8KArrK21W2NkbYaWG4FGuaRtXYfNBoZ54xe1Wf/nenpLWTF+8B2RP9DRiNmBmDvGX0PsIk/IDDXUs5+0OTCRoQQll2Yd4mD+/c5H6nRFtmj6VOqRT+AJ17pp6nq+o/v4lj+G5ncsJtlAtq1xb20yHQYEl6sbK2UqYuiFtXpKMCK/8V3hDj+ROM8UMkxMj+qj9NFd2sCk4FEZ+S2QmHIjY55s4Rpe1RzZZZEYOuJ99Fism+HYXtf3JlFORaNIdhdWY1UkVAFuKY/ULoHOhf/RdJ8ZArak3CplpEdPTYC4IRBI1eZDDF2GgECgYEAw0jvV7E1kqfGD5Q1WTFsss4xHQntPtWRfyAI1viy16sqMX6wQ4ZixWXsOeMB1o5azqqjYo0BBiGw6ie1GKl0iZ09FxHmMDqFLf8a0JZXAlTvC/wEHgAXCzg7tpHRJD1B6gAiU6u6ALW14DtWe6tikFehrY0mwGb9koedQNgoGnkCgYEA69EcUTejGm5Hm6ANC5u5Vn1aaB4BrTJ36FGTaxjnSUPePBj0Eo2Bt+c25DiD3uGj2Jws5QrRhpu+NYhOTC+/P1/rm82w9Tpc8z/wA7nUk0gGEncgtJ8RFokom4B+Ui83JJiH0V7puZUhCc/TOmfa5N0SH5gM4q4rBoVDZtnTGdECgYEAlnssW9GlK6Z2++hEF7/7N+mldPACTkn6PRCtXyHzhjdSYyNxpgb3M49vsceY0gGOPfTFxBpNsLDjh/wjE6b4s1ZkDdPwIjfmCmSrABLpZ1WVgxGnBoshNrcVZIEGvTsrAKsryHfq88MSLIDtCo0tfXbZkkfTla2HNpOj/KTUelkCgYBl0pMRlp58qSWOUxuO6ZyrddD1qA89Q892ptKqqcQkZIOvG284G5XpXJLdFHIMaQ2gWD8iXvt9zf3hi4uTZgKEUNyhF73TBXJhLjhqw3DAb5b/niSnGQ/91ReNnXvt7Kk4ygvLIdp14ai0XeJtE672p2ZN8g+OSXoWhLBH1sJKIQKBgA7NH/Y4RbVHIMWY7jH/1d4ODZ4Hr1RK2Q99HJCAurfD5tjhpcMApoQQJKJDpv7J5Ipx6ynQJD7CFfx27+vqBEG4ffAUm66lKM5xrKcOevcyWemppurCLuza64GgWDP6jBRnHeqrUyZUqoI/I0FNwjxIJbu08NpRSt8khq59+iyF
- peerId: 12D3KooWG1r2SVzTMGDhkiw9McbZq98H9C1Ggzp7FSfWDGbVSCbZ
address: 127.0.0.1:4431
signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
- peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
signingKey: CZTN+NFi4g9MA4BKl3OiCKuzXh63ukIvYWo9D5t9qfZcFwIeOW8eP9W8mtnXaY3JAFyb6GliBW0uCaw4wjRcCA==
encryptionKey: MIIEpAIBAAKCAQEAo9Nuypzg9kZ+LP+8jQgSTaoRUu8VFdJdCOEjuroPQK+2NwBD/Z9BqKiN0Z+jmhkI9yA0/Fwdh21ibAKX3Je9uffAKOhXI2sxIAlccDORu1kGDnhcc7N3L644DK+uFZvKnMQWiCwmtTnNHkoCzWcIE44G56wMa2c4W7mrOuRWqG6a5Z9JUuLqafOIlf6Dw2fiVM6xXiTIMQ0OyXByxFNjsS5O/PYcwoIKMV8MY+gUnAmyPLE0bslvz/8W+3E7d/LDO4lhqW+N1kDmboe6sc7DBf5JD4DLnP2VWV8Ae/rfJvxwu9ZqVT8RdYKMsZqvs9sV+6jQC9UcX+K8Q4Wdo0eMHwIDAQABAoIBAACR57zEtvOkYyP878b91DJ4+P503nno9XHmdp1bsFnlQpkGYzYqq6vOik/EYmlS1PknH4gROfkSpFkD2UtnK73N4tlBlawF33HhFnU9eLBSKvc56/hrE2sTDBbfNZfVpurMs9ddb/UJcnE8iK32QczvnY6IxrJI9aU8DCB0UujbGDnya/HbFU9pLLxu2EUoHNxjSHG/jCx+AR7JRknRA65KPZG7mu5jeAaaklYTY/aLGlctgecDKfNKDsZo6rgAMUW6ZXI8ogNGqfKHUFazCVe0l1tp4hxvgmyjcw79iKvFr4mlpHtgjYTFCeoMJKvOXUImZUJL0vCA6WKvUdIfzAECgYEA0lCTXYwOHqOwYMb1qi8lIIApcI//B/Nzn++MDQ4ZO4SzVJTTv4rSdXAuoihsO6E7LYZK+wdVNjiCbeMukfTqEfaxWXIsIDaHSR3440NsYSwdBz04UhRgpxFE2FwPK7J5dQ57FBaCAgksnO3XjcByBMYgMWVbA+ezIWfVdN96YoECgYEAx2mm/W4ZGdDyJgDonzEGGxfaNqo6DIv+67fDwI6WyqOWFWJTBaVFkm1uPJfcXYuTI9YCNFRKuRU7dyqSPLErMVusC/8Iww8++kqmkc1m04tbkqh4KpREYuMw8/tTYSWDwgpY8ksM5YRpYRJLTuuC0cEmefGco1RsXG8bYYeZXp8CgYBq5fexYcG/gxXgauBtSx9E4L+vbhGD2hNYJKr768GZhf6crDTgs8/7TzT0yTUSLgZlQlAUPgrqz1hEQGfoWiMrVEeanjSdfvnOiUR7R0bsMT7j8hMRbTgfUuC6VDiFzmZ7wAuBD1uvazhY329jpoCNuqKcWNclKfzbqupNSFXtgQKBgQCTlR7Qm0YadChydeOzxX2GWa3XHT7fAFFHNPa8MQtqp40xAFb/a6TEzRZz49RkqyLXt9Bj2CqBNjSPakNWhay41+bJ7hMXAdaTOOJ0L/c1AwNf1C0zHg5KvWgCefPohvIvjqbrkx3VU50GCZsQqn5kLLYENAvAWX/lHRm/obKhcwKBgQC/iAOC8ZdZC5w4F0Mf7roZWa9P/42JWlCMzm/I/5mEIn4mYY6+1C5V+fXoET6845oAh+P8CkH4waJtqqN6BKQhj7SKqoCHgGBCQy+HrSCBtzk7NuXdpz6sk14zfcVpjR3y3l9TuXc4cVQMSLAqg8yUQf+qnEQTit4jyfikV/5XEw==
- peerId: 12D3KooWDXDcBYxtZ8KNRoJebNgNAv9nFbQatQMoWm1BLwmQh6u7
address: 127.0.0.1:4432
signingKey: /6+uYFwFf9nU6fvXQVtpHhjd8+v4dXc7esZzqkhjyfMJWlMiZOtQeb913FXofD5f20WksU0l6i22B09sFFYwDQ==
encryptionKey: MIIEogIBAAKCAQEAwCy84lzkxtzgn4ixGm0LSUTujOBpOh9m7XDoDPZnMTmExdOe9a5v/LXzdlCOCuBvK5u1T3ALBJMA3Zgvjv/jPRQUdiHprP3sbdfc6IgZPBFdLKFTc9yAA7GMbI4y7LhGMLGOMOqQXs+DOeImfmxEs3ykLXHKNas5ORnZPVnB6E9Qod8KH7UyMmBjQkOZYOOw10X4JZiU6xJp/E+VVWcmeXgNBbj5xOWMSzM+hhoA4wNOzBxACucaKDmqD6qugzebOqyUVSzFnEbquro+MYTWYdUDjZTXdvxgUUo80MGQ164gZhkFUKrmSpUvu3YErFySEGqAdFNwOZ6y/4X3s0BHvQIDAQABAoIBAAZiNhAK5+qXMbr67m8jSimv6YCyf6xXmLKwenTbxofDEl8D7ZbZqYyqeqDmgiFoXSkErhwqa6NGQtQZlxLX+zNvNFLMQ5fkg3MOpZ7vzm7JYN/3p+8EVxhIUJLWkmh8opBBhaioUg1kNUa59W9jp1CTBl0gF4h63JbB/g5kqeVOllUw7J1igAoaX36nOJGOwIynCWdizhDhgyjR4OcYfOLwcPDJueKTc5vM10g3LuMSK/sJmaD3TkJFPtDHw+RMW6wqyjsnkrg2D2oohXEyGWYYIXo2so4HCez0AB1I1JAxtVnRPvSIp7xLMm7+AkDoq12QYDHfxZtDTpfmvJg+Sn0CgYEAxCd+oribtdQW+JUctjsDbSQX5CeRISH5Ith3jveBx2jKIqQVnoVPz6URHOvnlIsqYYLANB8B3JHMWfR2UmkK11x0OcZecB06+oBoCZukvSXF+GqVHzLAQUxaoEBDCCPneskj5w+riMWBiiGDp32rUnkqv0nh7dnH+GfORcJ44L8CgYEA+s5s5EALj1jyU9w4+HVUyVsIrUitFnQg6qw/Td3Kj+8CXImKlS+rlmbQv0m1aOcvtFjQRIjjzZJAf/ausfAME+MayoNODgZsDk5RyDKuSWzMLvZLAa1LD52Uli5Pg8KtpzKVTn4xE1MbjsQcUNhFRAgrNEKNyuzXzdp4uXgGOoMCgYASXwiTQOsEepq0KXMI9jn57Nl3+uSyz7W/t7pq329+N6hG2ktUD3RMJE+X/9gup2IOw+owd377I4SaIDU8vq3PQc944cVShspRT9lunO8u7+y8uW7B/0TWWMpcG+irSIGTlGcSavtL0gOx5jWoaDK1hLemNss8NZtu/nnpOq+LjQKBgDisVozJMBOHPNLYS4NROAR77p0BdCNDwIBmxbM5r+EQWA9DAS6u4+4Lc5YV+MkonG37N6yU5iz4pFyGCHmqzX/c7JvgSc3/g4FED1TWpu1uiUD/ZHmPiAuSRxYchtk2L3k9g+GFwF8mg26iP+fAxv4VfnXDqDi3hhg9CtSWG4ozAoGAOWZXlFKqzGAfcucIe54FVQnweXG9sEuIPAvWvVRs4406ggNmL5eHccXpPHWTgetsr2TYMqPTDVMRmhBzSkyrYgk+b2tme79HPzTWs2Yg/pzjOfTgw7MBX/KlvOW5/J+dvrF3Gx8AHHZ9QQdYqi/MS1NKb2K3IbD0/m5gL5Pwi6A=
signingKey: c3D+0+BCl1xU35KBY+U3GPcU9aXdoLUiD4DJ2jF+IqI3CjGLhet3MBOkPXdIuPq/UpEqlp1k6FjNaU6DEU6Csg==
encryptionKey: MIIEpAIBAAKCAQEAuB7HsXuYmoif6/U4JnjC6L0QMu9qW1aPAxDrxWIedTzQhFZp3F3gYW/Zgdd2hvd0c2xyfhwf9C0X/UzfxWr54dDXzWNLN8BdVTik48cdYlgOmbgejiIjTaqSAlv4RtlqvooxCN0MwR2/RVAG/N5GqcAM7E4kJWPtvQYNl6wWCc92rKdutvmcj73wKzz9Hd/qdF612OVS3zRsjh3tJmYt55oovAUh1TAz/mSTTXjFHy35zLRBP+oQQsAOt2p0BOMSyOKZufGC8l3aZD//dp4/U/MaqCjeNuWxCfAZlSd+vt7T0aqDGdyRtrrGUcu4PCwXpOdbzw+uSZxnKawolYoEHwIDAQABAoIBAQCsxeVpvKtUx8QZrUCFiWiM8W0T/un0z+LfY696xzoBlZGtvVEVQtpdVJHsb31/5RFXhnphsI6jmPUb8llBbcMSjeETkItyw4ZRhBfmzl/aevsocEfr5EjwhpEAucDe6wJpzk95G8TuKrXjmtcTzpjMjbUSwbjVhVH/wIBcxVTg2j6z4AOADDRI5UsvZ0NV//If+nNzMjcuIji95PNk7lAuwsqkX3FycxvqXKUMGxRE2bgGMxaBRAP0kqL2vdxyS1M7wp/x04ZAtSnPXHe4qqmDOt69ec3XqbmZHOsZHzkCFePKcPB472/G0bPJeiq/idevEqS89RwvbphDtq3KGrRBAoGBAOrHqlPh36WZBOi6SueUmcrg579KDMUekgeea5payiySbRWztCL2yCYbSgFqSbyCLRppyXK51xvo8iUejR231or6u/nd7T0CON0Nf/8Qtbb13vtTGpIBiWYGqeDrWucUUlyS+K3sDfNk1AJqjUdaIMVu4yTpgzEvrdYCcT312RBPAoGBAMjC83/0EKnsbypFprxKS3Fbg963HhyKjfffQ2w4yncM6kxXF3ehVjg1LInok/6/dmy2LxkAf3r0YYZrGJWmG4Sv4UqHn6JxAjQgarPbdmGhJ8VIUMvMbZRsX3i8Z8D2o8k1M1kr6MYsQ53iX6q/Cp3gnucMeJPk6Xs9Q4TO7YsxAoGAWrXEOF6X01p4zBZWJH2Eoh8dSwooPuzdzPXHaz7SyD/Wx8DDw5KHqDl48W0Iij3dgUwIGjx1QQJStEbGjQnfaZkQkazOIXk/USELKBhjrQn4GjB0np7bYEEI1673UzrFy6C5VjFS/owhYcGbTksjSETcnAFgv9tFFd+hsyfOsv8CgYALk4o875LiaXrDgj6qDtKo17ET75Ux6h9jkqEtpVyvXrRH8KGuyUPSe+Z0kU+vWdT3Uc4HcArpyRuyh4xkXK6riQTBqm5fDIsm/FOKyXXbDVLgwlm+Vqxe6Zzbtml5K/+nw4SReMG0Y6sGeJ4xl1CCaAhhpEtzo7h+3bp99vylkQKBgQDDdR6N4wb3DHTzrW0EFb8XhXZN7CIE3EWhToNDsCkguUB7lwqD4p2c4yLscS0YAqxk7I3NW0nDaUV/340RrVtPJDqB4NZJ+MvhfvV3TW2FkZmru/iW+DMUsfZGAOPdQz9jLGAzUXrXFw/qGBtLIUL6UWqWLOrBO9QHb21nnB1Ssg==
space:
gcTTL: 60
syncPeriod: 11
syncPeriod: 600
storage:
path: db
metric:
@ -37,3 +37,6 @@ log:
production: false
defaultLevel: ""
namedLevels: {}
stream:
timeoutMilliseconds: 1000
maxMsgSizeMb: 256

View File

@ -51,13 +51,16 @@ func (s *service) Name() (name string) {
}
func (s *service) Run(ctx context.Context) (err error) {
err = s.BaseDrpcServer.Run(
ctx,
s.cfg.APIServer.ListenAddrs,
func(handler drpc.Handler) drpc.Handler {
params := server.Params{
BufferSizeMb: s.cfg.Stream.MaxMsgSizeMb,
TimeoutMillis: s.cfg.Stream.TimeoutMilliseconds,
ListenAddrs: s.cfg.APIServer.ListenAddrs,
Wrapper: func(handler drpc.Handler) drpc.Handler {
return handler
},
s.transport.BasicListener)
Converter: s.transport.BasicListener,
}
err = s.BaseDrpcServer.Run(ctx, params)
if err != nil {
return
}

View File

@ -37,3 +37,8 @@ log-client-2:
debug:
@(echo "To run debug api please run './init.sh debug [params]' with respective args to debug client")
run-all: nodes-start clients-start
sleep 3000000
run-clean: clean-all run-all

View File

@ -21,6 +21,7 @@ do_usage() {
do_nodes_start() {
for NUMBER in {1..3}; do
install -d tmp/node$NUMBER/ tmp/log/
export ANYPROF="127.0.0.1:607$NUMBER"
(cd tmp/node$NUMBER && go run $NODE_GO -c $CONFIGS_DIR/node$NUMBER.yml &>../log/node$NUMBER.log) &
NODE_PID=$!
echo $NODE_PID >tmp/node$NUMBER.pid
@ -54,6 +55,7 @@ do_config_gen() {
do_clients_start() {
for NUMBER in {1..2}; do
export ANYPROF="127.0.0.1:606$NUMBER"
install -d tmp/client$NUMBER/ tmp/log/
(cd tmp/client$NUMBER && go run $CLIENT_GO -c $CONFIGS_DIR/client$NUMBER.yml &>../log/client$NUMBER.log) &
CLIENT_PID=$!

View File

@ -58,7 +58,7 @@ func (s *service) registerScripts() {
}
for _, p := range addresses {
wg.Add(1)
createMany(p)
go createMany(p)
}
wg.Wait()
if mError.Err() != nil {

View File

@ -198,7 +198,11 @@ func genNodeConfig(addresses []string, apiAddresses []string) (config.Config, er
},
Space: config.Space{
GCTTL: 60,
SyncPeriod: 11,
SyncPeriod: 600,
},
Stream: config.Stream{
TimeoutMilliseconds: 1000,
MaxMsgSizeMb: 256,
},
}, nil
}
@ -248,7 +252,11 @@ func genClientConfig(addresses []string, apiAddresses []string, encKey encryptio
},
Space: config.Space{
GCTTL: 60,
SyncPeriod: 11,
SyncPeriod: 20,
},
Stream: config.Stream{
TimeoutMilliseconds: 1000,
MaxMsgSizeMb: 256,
},
}, nil
}
@ -295,5 +303,9 @@ func genConsensusConfig(addresses []string) (cconfig.Config, error) {
Database: "consensus",
LogCollection: "log",
},
Stream: config.Stream{
TimeoutMilliseconds: 1000,
MaxMsgSizeMb: 256,
},
}, nil
}