From 46e88bfc9578d0870da56b53eec05cfe66856da6 Mon Sep 17 00:00:00 2001 From: petricadaipegsp <155911522+petricadaipegsp@users.noreply.github.com> Date: Thu, 28 Nov 2024 12:04:18 +0100 Subject: [PATCH 01/14] Deprecate zero timestamp transactions (#391) --- node/consensus/data/message_validators.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/node/consensus/data/message_validators.go b/node/consensus/data/message_validators.go index 582bdb1..993eede 100644 --- a/node/consensus/data/message_validators.go +++ b/node/consensus/data/message_validators.go @@ -94,11 +94,6 @@ func (e *DataClockConsensusEngine) validateTxMessage(peerID peer.ID, message *pb return p2p.ValidationResultIgnore } } - if tx.Timestamp == 0 { - // NOTE: The timestamp was added in later versions of the protocol, - // and as such it is possible to receive requests without it. - return p2p.ValidationResultAccept - } if ts := time.UnixMilli(tx.Timestamp); time.Since(ts) > 10*time.Minute { return p2p.ValidationResultIgnore } From dd030560bc8c074185ba73870be637079aeea20b Mon Sep 17 00:00:00 2001 From: petricadaipegsp <155911522+petricadaipegsp@users.noreply.github.com> Date: Thu, 28 Nov 2024 13:21:04 +0100 Subject: [PATCH 02/14] Do not clone full tries (#392) --- node/consensus/data/consensus_frames.go | 5 ++- node/consensus/data/main_data_loop.go | 33 ++++++++++++++----- node/consensus/data/message_handler.go | 4 +-- node/consensus/data/peer_messaging.go | 6 ++-- .../token/application/token_application.go | 6 ++++ .../token/application/token_handle_mint.go | 7 ++++ 6 files changed, 47 insertions(+), 14 deletions(-) diff --git a/node/consensus/data/consensus_frames.go b/node/consensus/data/consensus_frames.go index 9743cd2..85453de 100644 --- a/node/consensus/data/consensus_frames.go +++ b/node/consensus/data/consensus_frames.go @@ -116,6 +116,9 @@ func (e *DataClockConsensusEngine) prove( "applied transitions", zap.Int("successful", len(validTransactions.Requests)), zap.Int("failed", len(invalidTransactions.Requests)), + zap.Uint64("mint_out_of_order", app.MintOutOfOrder), + zap.Uint64("mint_too_old", app.MintTooOld), + zap.Uint64("mint_tree_verification_failed", app.MintTreeVerificationFailure), ) outputState, err := app.MaterializeStateFromApplication() @@ -219,7 +222,7 @@ func (e *DataClockConsensusEngine) prove( } func (e *DataClockConsensusEngine) GetAheadPeers(frameNumber uint64) []internal.PeerCandidate { - if e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { + if e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) { return nil } diff --git a/node/consensus/data/main_data_loop.go b/node/consensus/data/main_data_loop.go index 2fb64a1..b30b3b5 100644 --- a/node/consensus/data/main_data_loop.go +++ b/node/consensus/data/main_data_loop.go @@ -42,10 +42,27 @@ func ( return frameProverTries } +func (e *DataClockConsensusEngine) GetFrameProverTrie(i int) *tries.RollingFrecencyCritbitTrie { + e.frameProverTriesMx.RLock() + defer e.frameProverTriesMx.RUnlock() + newTrie := &tries.RollingFrecencyCritbitTrie{} + if i < 0 || i >= len(e.frameProverTries) { + return newTrie + } + b, err := e.frameProverTries[i].Serialize() + if err != nil { + panic(err) + } + if err := newTrie.Deserialize(b); err != nil { + panic(err) + } + return newTrie +} + func (e *DataClockConsensusEngine) runFramePruning() { defer e.wg.Done() // A full prover should _never_ do this - if e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) || + if e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) || e.config.Engine.MaxFrames == -1 || e.config.Engine.FullProver { e.logger.Info("frame pruning not enabled") return @@ -88,7 +105,7 @@ func (e *DataClockConsensusEngine) runFramePruning() { func (e *DataClockConsensusEngine) runSync() { defer e.wg.Done() // small optimization, beacon should never collect for now: - if e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { + if e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) { return } @@ -130,7 +147,7 @@ func (e *DataClockConsensusEngine) runLoop() { } if runOnce { - if e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { + if e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) { dataFrame, err := e.dataTimeReel.Head() if err != nil { panic(err) @@ -148,7 +165,7 @@ func (e *DataClockConsensusEngine) runLoop() { e.validationFilterMx.Lock() e.validationFilter = make(map[string]struct{}, len(e.validationFilter)) e.validationFilterMx.Unlock() - if e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { + if e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) { if err = e.publishProof(dataFrame); err != nil { e.logger.Error("could not publish", zap.Error(err)) e.stateMx.Lock() @@ -174,7 +191,7 @@ func (e *DataClockConsensusEngine) processFrame( zap.Duration("frame_age", frametime.Since(dataFrame)), ) var err error - if !e.GetFrameProverTries()[0].Contains(e.provingKeyBytes) { + if !e.GetFrameProverTrie(0).Contains(e.provingKeyBytes) { select { case e.requestSyncCh <- struct{}{}: default: @@ -190,7 +207,7 @@ func (e *DataClockConsensusEngine) processFrame( e.frameProverTries = e.dataTimeReel.GetFrameProverTries() e.frameProverTriesMx.Unlock() - trie := e.GetFrameProverTries()[0] + trie := e.GetFrameProverTrie(0) selBI, _ := dataFrame.GetSelector() sel := make([]byte, 32) sel = selBI.FillBytes(sel) @@ -234,8 +251,8 @@ func (e *DataClockConsensusEngine) processFrame( peerProvingKeyAddress := h.FillBytes(make([]byte, 32)) ring := -1 - if len(e.GetFrameProverTries()) > 1 { - for i, tries := range e.GetFrameProverTries()[1:] { + if tries := e.GetFrameProverTries(); len(tries) > 1 { + for i, tries := range tries[1:] { i := i if tries.Contains(peerProvingKeyAddress) { ring = i diff --git a/node/consensus/data/message_handler.go b/node/consensus/data/message_handler.go index 7123fc9..fe24470 100644 --- a/node/consensus/data/message_handler.go +++ b/node/consensus/data/message_handler.go @@ -182,7 +182,7 @@ func (e *DataClockConsensusEngine) handleClockFrame( return errors.Wrap(err, "handle clock frame data") } - trie := e.GetFrameProverTries()[0] + trie := e.GetFrameProverTrie(0) if !trie.Contains(addr.FillBytes(make([]byte, 32))) { e.logger.Debug( "prover not in trie at frame, address may be in fork", @@ -369,7 +369,7 @@ func TokenRequestIdentifiers(transition *protobufs.TokenRequest) []string { func (e *DataClockConsensusEngine) handleTokenRequest( transition *protobufs.TokenRequest, ) error { - if e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { + if e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) { identifiers := TokenRequestIdentifiers(transition) e.stagedTransactionsMx.Lock() diff --git a/node/consensus/data/peer_messaging.go b/node/consensus/data/peer_messaging.go index ccfe157..89c9478 100644 --- a/node/consensus/data/peer_messaging.go +++ b/node/consensus/data/peer_messaging.go @@ -128,7 +128,7 @@ func (e *DataClockConsensusEngine) GetPreMidnightMintStatus( ctx context.Context, t *protobufs.PreMidnightMintStatusRequest, ) (*protobufs.PreMidnightMintResponse, error) { - if !e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { + if !e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) { return nil, errors.Wrap( errors.New("wrong destination"), "get pre midnight mint status", @@ -182,7 +182,7 @@ func (e *DataClockConsensusEngine) GetPreMidnightMintStatus( func (e *DataClockConsensusEngine) handleMint( t *protobufs.MintCoinRequest, ) ([]byte, error) { - if !e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { + if !e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) { return nil, errors.Wrap(errors.New("wrong destination"), "handle mint") } @@ -243,7 +243,7 @@ func (e *DataClockConsensusEngine) handleMint( t.Proofs[0], []byte("pre-dusk"), ) && (!bytes.Equal(t.Proofs[1], make([]byte, 32)) || - time.Now().Unix() < 1730523600) && e.GetFrameProverTries()[0].Contains( + time.Now().Unix() < 1730523600) && e.GetFrameProverTrie(0).Contains( e.provingKeyAddress, ) { prevInput := []byte{} diff --git a/node/execution/intrinsics/token/application/token_application.go b/node/execution/intrinsics/token/application/token_application.go index d7c57ca..a493113 100644 --- a/node/execution/intrinsics/token/application/token_application.go +++ b/node/execution/intrinsics/token/application/token_application.go @@ -5,6 +5,7 @@ import ( "crypto" "encoding/binary" "sync" + "sync/atomic" "github.com/iden3/go-iden3-crypto/poseidon" "github.com/pkg/errors" @@ -29,6 +30,10 @@ var TOKEN_ADDRESS = []byte{ } type TokenApplication struct { + MintTreeVerificationFailure uint64 + MintOutOfOrder uint64 + MintTooOld uint64 + Beacon []byte TokenOutputs *protobufs.TokenOutputs Tries []*tries.RollingFrecencyCritbitTrie @@ -188,6 +193,7 @@ func (a *TokenApplication) ApplyTransitions( } else if len(t.Mint.Proofs) >= 3 && currentFrameNumber > PROOF_FRAME_CUTOFF { frameNumber := binary.BigEndian.Uint64(t.Mint.Proofs[2]) if frameNumber < currentFrameNumber-2 { + atomic.AddUint64(&a.MintTooOld, 1) fails[i] = transition continue } diff --git a/node/execution/intrinsics/token/application/token_handle_mint.go b/node/execution/intrinsics/token/application/token_handle_mint.go index 870396b..ebae60e 100644 --- a/node/execution/intrinsics/token/application/token_handle_mint.go +++ b/node/execution/intrinsics/token/application/token_handle_mint.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/binary" "math/big" + "sync/atomic" "github.com/iden3/go-iden3-crypto/poseidon" pcrypto "github.com/libp2p/go-libp2p/core/crypto" @@ -205,6 +206,7 @@ func (a *TokenApplication) handleMint( } if !verified { + atomic.AddUint64(&a.MintTreeVerificationFailure, 1) a.Logger.Debug( "tree verification failed", zap.String("peer_id", base58.Encode([]byte(peerId))), @@ -222,6 +224,11 @@ func (a *TokenApplication) handleMint( if previousFrame != nil { previousFrameNumber = previousFrame.FrameNumber } + if newFrameNumber < currentFrameNumber-2 { + atomic.AddUint64(&a.MintTooOld, 1) + } else { + atomic.AddUint64(&a.MintOutOfOrder, 1) + } a.Logger.Debug( "received out of order proofs, ignoring", zap.Error(err), From 4be18884968261a5d06a895fc019041a2ab08054 Mon Sep 17 00:00:00 2001 From: petricadaipegsp <155911522+petricadaipegsp@users.noreply.github.com> Date: Sun, 1 Dec 2024 22:02:07 +0100 Subject: [PATCH 03/14] Separate dialing from retrieval (#398) --- client/cmd/all.go | 5 ++-- node/consensus/data/consensus_frames.go | 23 +++++++++++-------- node/consensus/data/peer_messaging.go | 2 +- .../data/pre_midnight_proof_worker.go | 4 ++-- node/consensus/data/token_handle_mint_test.go | 2 +- node/p2p/blossomsub.go | 5 ++-- node/p2p/pubsub.go | 2 +- 7 files changed, 24 insertions(+), 19 deletions(-) diff --git a/client/cmd/all.go b/client/cmd/all.go index ba9bff4..4f623c8 100644 --- a/client/cmd/all.go +++ b/client/cmd/all.go @@ -89,8 +89,9 @@ var allCmd = &cobra.Command{ panic(errors.Wrap(err, "error getting peer id")) } + ctx := context.Background() resume := make([]byte, 32) - cc, err := pubSub.GetDirectChannel([]byte(bpeerId), "worker") + cc, err := pubSub.GetDirectChannel(ctx, []byte(bpeerId), "worker") if err != nil { logger.Info( "could not establish direct channel, waiting...", @@ -100,7 +101,7 @@ var allCmd = &cobra.Command{ } for { if cc == nil { - cc, err = pubSub.GetDirectChannel([]byte(bpeerId), "worker") + cc, err = pubSub.GetDirectChannel(ctx, []byte(bpeerId), "worker") if err != nil { logger.Info( "could not establish direct channel, waiting...", diff --git a/node/consensus/data/consensus_frames.go b/node/consensus/data/consensus_frames.go index 85453de..e9c9f27 100644 --- a/node/consensus/data/consensus_frames.go +++ b/node/consensus/data/consensus_frames.go @@ -291,6 +291,7 @@ func (e *DataClockConsensusEngine) syncWithPeer( zap.Uint64("current_frame", latest.FrameNumber), zap.Uint64("max_frame", maxFrame), ) + var cooperative bool = true defer func() { if cooperative { @@ -304,7 +305,15 @@ func (e *DataClockConsensusEngine) syncWithPeer( delete(e.peerMap, string(peerId)) } }() - cc, err := e.pubSub.GetDirectChannel(peerId, "sync") + + syncTimeout := e.config.Engine.SyncTimeout + if syncTimeout == 0 { + syncTimeout = defaultSyncTimeout + } + + dialCtx, cancelDial := context.WithTimeout(e.ctx, syncTimeout) + defer cancelDial() + cc, err := e.pubSub.GetDirectChannel(dialCtx, peerId, "sync") if err != nil { e.logger.Debug( "could not establish direct channel", @@ -320,22 +329,16 @@ func (e *DataClockConsensusEngine) syncWithPeer( }() client := protobufs.NewDataServiceClient(cc) - - syncTimeout := e.config.Engine.SyncTimeout - if syncTimeout == 0 { - syncTimeout = defaultSyncTimeout - } - for { - ctx, cancel := context.WithTimeout(e.ctx, syncTimeout) + getCtx, cancelGet := context.WithTimeout(e.ctx, syncTimeout) response, err := client.GetDataFrame( - ctx, + getCtx, &protobufs.GetDataFrameRequest{ FrameNumber: latest.FrameNumber + 1, }, grpc.MaxCallRecvMsgSize(600*1024*1024), ) - cancel() + cancelGet() if err != nil { e.logger.Debug( "could not get frame", diff --git a/node/consensus/data/peer_messaging.go b/node/consensus/data/peer_messaging.go index 89c9478..d51deec 100644 --- a/node/consensus/data/peer_messaging.go +++ b/node/consensus/data/peer_messaging.go @@ -636,7 +636,7 @@ func (e *DataClockConsensusEngine) GetPublicChannelForProvingKey( ) } } else { - cc, err := e.pubSub.GetDirectChannel(peerID, base58.Encode(provingKey)) + cc, err := e.pubSub.GetDirectChannel(e.ctx, peerID, base58.Encode(provingKey)) if err != nil { e.logger.Error( "could not get public channel for proving key", diff --git a/node/consensus/data/pre_midnight_proof_worker.go b/node/consensus/data/pre_midnight_proof_worker.go index 24ef1fb..5eab95e 100644 --- a/node/consensus/data/pre_midnight_proof_worker.go +++ b/node/consensus/data/pre_midnight_proof_worker.go @@ -85,7 +85,7 @@ func (e *DataClockConsensusEngine) runPreMidnightProofWorker() { } resume := make([]byte, 32) - cc, err := e.pubSub.GetDirectChannel([]byte(peerId), "worker") + cc, err := e.pubSub.GetDirectChannel(e.ctx, []byte(peerId), "worker") if err != nil { e.logger.Info( "could not establish direct channel, waiting...", @@ -110,7 +110,7 @@ func (e *DataClockConsensusEngine) runPreMidnightProofWorker() { } if cc == nil { - cc, err = e.pubSub.GetDirectChannel([]byte(peerId), "worker") + cc, err = e.pubSub.GetDirectChannel(e.ctx, []byte(peerId), "worker") if err != nil { e.logger.Info( "could not establish direct channel, waiting...", diff --git a/node/consensus/data/token_handle_mint_test.go b/node/consensus/data/token_handle_mint_test.go index caa3e27..d01e2d9 100644 --- a/node/consensus/data/token_handle_mint_test.go +++ b/node/consensus/data/token_handle_mint_test.go @@ -64,7 +64,7 @@ func (pubsub) StartDirectChannelListener( ) error { return nil } -func (pubsub) GetDirectChannel(peerId []byte, purpose string) (*grpc.ClientConn, error) { +func (pubsub) GetDirectChannel(ctx context.Context, peerId []byte, purpose string) (*grpc.ClientConn, error) { return nil, nil } func (pubsub) GetNetworkInfo() *protobufs.NetworkInfoResponse { diff --git a/node/p2p/blossomsub.go b/node/p2p/blossomsub.go index b49c245..81622ad 100644 --- a/node/p2p/blossomsub.go +++ b/node/p2p/blossomsub.go @@ -937,7 +937,7 @@ func (c *extraCloseConn) Close() error { return err } -func (b *BlossomSub) GetDirectChannel(peerID []byte, purpose string) ( +func (b *BlossomSub) GetDirectChannel(ctx context.Context, peerID []byte, purpose string) ( cc *grpc.ClientConn, err error, ) { // Kind of a weird hack, but gostream can induce panics if the peer drops at @@ -954,7 +954,7 @@ func (b *BlossomSub) GetDirectChannel(peerID []byte, purpose string) ( // Open question: should we prefix this so a node can run both in mainnet and // testnet? Feels like a bad idea and would be preferable to discourage. cc, err = qgrpc.DialContext( - b.ctx, + ctx, "passthrough:///", grpc.WithContextDialer( func(ctx context.Context, _ string) (net.Conn, error) { @@ -991,6 +991,7 @@ func (b *BlossomSub) GetDirectChannel(peerID []byte, purpose string) ( }, ), grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithBlock(), ) if err != nil { return nil, errors.Wrap(err, "dial context") diff --git a/node/p2p/pubsub.go b/node/p2p/pubsub.go index d02acc4..3b7227a 100644 --- a/node/p2p/pubsub.go +++ b/node/p2p/pubsub.go @@ -44,7 +44,7 @@ type PubSub interface { purpose string, server *grpc.Server, ) error - GetDirectChannel(peerId []byte, purpose string) (*grpc.ClientConn, error) + GetDirectChannel(ctx context.Context, peerId []byte, purpose string) (*grpc.ClientConn, error) GetNetworkInfo() *protobufs.NetworkInfoResponse SignMessage(msg []byte) ([]byte, error) GetPublicKey() []byte From 1e441e280dc0b788702647ac80255cabbbc07e4f Mon Sep 17 00:00:00 2001 From: petricadaipegsp <155911522+petricadaipegsp@users.noreply.github.com> Date: Sun, 1 Dec 2024 22:04:01 +0100 Subject: [PATCH 04/14] Memory management adjustments (#397) * Do not vendor go-buffer-pool * Do not change GOGC * Use local buffer --- client/go.mod | 2 - client/go.sum | 2 + go-buffer-pool/.github/workflows/go-check.yml | 18 - go-buffer-pool/.github/workflows/go-test.yml | 20 - .../.github/workflows/release-check.yml | 19 - go-buffer-pool/.github/workflows/releaser.yml | 17 - go-buffer-pool/.github/workflows/stale.yml | 13 - go-buffer-pool/.github/workflows/tagpush.yml | 18 - go-buffer-pool/LICENSE | 21 - go-buffer-pool/LICENSE-BSD | 29 -- go-buffer-pool/README.md | 56 --- go-buffer-pool/buffer.go | 302 ------------- go-buffer-pool/buffer_test.go | 400 ------------------ go-buffer-pool/codecov.yml | 3 - go-buffer-pool/go.mod | 3 - go-buffer-pool/pool.go | 103 ----- go-buffer-pool/pool_test.go | 185 -------- go-buffer-pool/version.json | 3 - go-buffer-pool/writer.go | 119 ------ go-buffer-pool/writer_test.go | 91 ---- go-libp2p-blossomsub/comm.go | 30 +- go-libp2p-blossomsub/go.mod | 2 - go-libp2p-blossomsub/go.sum | 2 + go-libp2p-kad-dht/go.mod | 2 - go-libp2p-kad-dht/go.sum | 4 + go-libp2p/go.mod | 2 - go-libp2p/go.sum | 2 + node/go.mod | 2 - node/go.sum | 2 + node/main.go | 4 - 30 files changed, 40 insertions(+), 1436 deletions(-) delete mode 100644 go-buffer-pool/.github/workflows/go-check.yml delete mode 100644 go-buffer-pool/.github/workflows/go-test.yml delete mode 100644 go-buffer-pool/.github/workflows/release-check.yml delete mode 100644 go-buffer-pool/.github/workflows/releaser.yml delete mode 100644 go-buffer-pool/.github/workflows/stale.yml delete mode 100644 go-buffer-pool/.github/workflows/tagpush.yml delete mode 100644 go-buffer-pool/LICENSE delete mode 100644 go-buffer-pool/LICENSE-BSD delete mode 100644 go-buffer-pool/README.md delete mode 100644 go-buffer-pool/buffer.go delete mode 100644 go-buffer-pool/buffer_test.go delete mode 100644 go-buffer-pool/codecov.yml delete mode 100644 go-buffer-pool/go.mod delete mode 100644 go-buffer-pool/pool.go delete mode 100644 go-buffer-pool/pool_test.go delete mode 100644 go-buffer-pool/version.json delete mode 100644 go-buffer-pool/writer.go delete mode 100644 go-buffer-pool/writer_test.go diff --git a/client/go.mod b/client/go.mod index 98ebc72..cf7c94e 100644 --- a/client/go.mod +++ b/client/go.mod @@ -14,8 +14,6 @@ replace github.com/multiformats/go-multiaddr => ../go-multiaddr replace github.com/multiformats/go-multiaddr-dns => ../go-multiaddr-dns -replace github.com/libp2p/go-buffer-pool => ../go-buffer-pool - replace github.com/libp2p/go-libp2p => ../go-libp2p replace github.com/libp2p/go-libp2p-kad-dht => ../go-libp2p-kad-dht diff --git a/client/go.sum b/client/go.sum index 830b59c..23e5817 100644 --- a/client/go.sum +++ b/client/go.sum @@ -263,6 +263,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= diff --git a/go-buffer-pool/.github/workflows/go-check.yml b/go-buffer-pool/.github/workflows/go-check.yml deleted file mode 100644 index 26f63bc..0000000 --- a/go-buffer-pool/.github/workflows/go-check.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Go Checks - -on: - pull_request: - push: - branches: ["master"] - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }} - cancel-in-progress: true - -jobs: - go-check: - uses: ipdxco/unified-github-workflows/.github/workflows/go-check.yml@v1.0 diff --git a/go-buffer-pool/.github/workflows/go-test.yml b/go-buffer-pool/.github/workflows/go-test.yml deleted file mode 100644 index 778de6e..0000000 --- a/go-buffer-pool/.github/workflows/go-test.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Go Test - -on: - pull_request: - push: - branches: ["master"] - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }} - cancel-in-progress: true - -jobs: - go-test: - uses: ipdxco/unified-github-workflows/.github/workflows/go-test.yml@v1.0 - secrets: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/go-buffer-pool/.github/workflows/release-check.yml b/go-buffer-pool/.github/workflows/release-check.yml deleted file mode 100644 index 0b5ff60..0000000 --- a/go-buffer-pool/.github/workflows/release-check.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Release Checker - -on: - pull_request_target: - paths: [ 'version.json' ] - types: [ opened, synchronize, reopened, labeled, unlabeled ] - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - release-check: - uses: ipdxco/unified-github-workflows/.github/workflows/release-check.yml@v1.0 diff --git a/go-buffer-pool/.github/workflows/releaser.yml b/go-buffer-pool/.github/workflows/releaser.yml deleted file mode 100644 index 2ebdbed..0000000 --- a/go-buffer-pool/.github/workflows/releaser.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Releaser - -on: - push: - paths: [ 'version.json' ] - workflow_dispatch: - -permissions: - contents: write - -concurrency: - group: ${{ github.workflow }}-${{ github.sha }} - cancel-in-progress: true - -jobs: - releaser: - uses: ipdxco/unified-github-workflows/.github/workflows/releaser.yml@v1.0 diff --git a/go-buffer-pool/.github/workflows/stale.yml b/go-buffer-pool/.github/workflows/stale.yml deleted file mode 100644 index 16d65d7..0000000 --- a/go-buffer-pool/.github/workflows/stale.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Close and mark stale issue - -on: - schedule: - - cron: '0 0 * * *' - -permissions: - issues: write - pull-requests: write - -jobs: - stale: - uses: pl-strflt/.github/.github/workflows/reusable-stale-issue.yml@v0.3 diff --git a/go-buffer-pool/.github/workflows/tagpush.yml b/go-buffer-pool/.github/workflows/tagpush.yml deleted file mode 100644 index 5ef3fb9..0000000 --- a/go-buffer-pool/.github/workflows/tagpush.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Tag Push Checker - -on: - push: - tags: - - v* - -permissions: - contents: read - issues: write - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - releaser: - uses: ipdxco/unified-github-workflows/.github/workflows/tagpush.yml@v1.0 diff --git a/go-buffer-pool/LICENSE b/go-buffer-pool/LICENSE deleted file mode 100644 index c7386b3..0000000 --- a/go-buffer-pool/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Juan Batiz-Benet - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/go-buffer-pool/LICENSE-BSD b/go-buffer-pool/LICENSE-BSD deleted file mode 100644 index 97ece78..0000000 --- a/go-buffer-pool/LICENSE-BSD +++ /dev/null @@ -1,29 +0,0 @@ -### Applies to buffer.go and buffer_test.go ### - -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/go-buffer-pool/README.md b/go-buffer-pool/README.md deleted file mode 100644 index fe1244e..0000000 --- a/go-buffer-pool/README.md +++ /dev/null @@ -1,56 +0,0 @@ -go-buffer-pool -================== - -[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](https://protocol.ai) -[![](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](https://libp2p.io/) -[![](https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23libp2p) -[![codecov](https://codecov.io/gh/libp2p/go-buffer-pool/branch/master/graph/badge.svg)](https://codecov.io/gh/libp2p/go-buffer-pool) -[![Travis CI](https://travis-ci.org/libp2p/go-buffer-pool.svg?branch=master)](https://travis-ci.org/libp2p/go-buffer-pool) -[![Discourse posts](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg)](https://discuss.libp2p.io) - -> A variable size buffer pool for go. - -## Table of Contents - -- [About](#about) - - [Advantages over GC](#advantages-over-gc) - - [Disadvantages over GC:](#disadvantages-over-gc) -- [Contribute](#contribute) -- [License](#license) - -## About - -This library provides: - -1. `BufferPool`: A pool for re-using byte slices of varied sizes. This pool will always return a slice with at least the size requested and a capacity up to the next power of two. Each size class is pooled independently which makes the `BufferPool` more space efficient than a plain `sync.Pool` when used in situations where data size may vary over an arbitrary range. -2. `Buffer`: a buffer compatible with `bytes.Buffer` but backed by a `BufferPool`. Unlike `bytes.Buffer`, `Buffer` will automatically "shrink" on read, using the buffer pool to avoid causing too much work for the allocator. This is primarily useful for long lived buffers that usually sit empty. - -### Advantages over GC - -* Reduces Memory Usage: - * We don't have to wait for a GC to run before we can reuse memory. This is essential if you're repeatedly allocating large short-lived buffers. - -* Reduces CPU usage: - * It takes some load off of the GC (due to buffer reuse). - * We don't have to zero buffers (fewer wasteful memory writes). - -### Disadvantages over GC: - -* Can leak memory contents. Unlike the go GC, we *don't* zero memory. -* All buffers have a capacity of a power of 2. This is fine if you either expect these buffers to be temporary or you need buffers of this size. -* Requires that buffers be explicitly put back into the pool. This can lead to race conditions and memory corruption if the buffer is released while it's still in use. - -## Contribute - -PRs are welcome! - -Small note: If editing the Readme, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. - -## License - -MIT © Protocol Labs -BSD © The Go Authors - ---- - -The last gx published version of this module was: 0.1.3: QmQDvJoB6aJWN3sjr3xsgXqKCXf4jU5zdMXpDMsBkYVNqa diff --git a/go-buffer-pool/buffer.go b/go-buffer-pool/buffer.go deleted file mode 100644 index 04ae7c9..0000000 --- a/go-buffer-pool/buffer.go +++ /dev/null @@ -1,302 +0,0 @@ -// This is a derivitive work of Go's bytes.Buffer implementation. -// -// Originally copyright 2009 The Go Authors. All rights reserved. -// -// Modifications copyright 2018 Steven Allen. All rights reserved. -// -// Use of this source code is governed by both a BSD-style and an MIT-style -// license that can be found in the LICENSE_BSD and LICENSE files. - -package pool - -import ( - "io" -) - -// Buffer is a buffer like bytes.Buffer that: -// -// 1. Uses a buffer pool. -// 2. Frees memory on read. -// -// If you only have a few buffers and read/write at a steady rate, *don't* use -// this package, it'll be slower. -// -// However: -// -// 1. If you frequently create/destroy buffers, this implementation will be -// significantly nicer to the allocator. -// 2. If you have many buffers with bursty traffic, this implementation will use -// significantly less memory. -type Buffer struct { - // Pool is the buffer pool to use. If nil, this Buffer will use the - // global buffer pool. - Pool *BufferPool - - buf []byte - rOff int - - // Preallocated slice for samll reads/writes. - // This is *really* important for performance and only costs 8 words. - bootstrap [64]byte -} - -// NewBuffer constructs a new buffer initialized to `buf`. -// Unlike `bytes.Buffer`, we *copy* the buffer but don't reuse it (to ensure -// that we *only* use buffers from the pool). -func NewBuffer(buf []byte) *Buffer { - b := new(Buffer) - if len(buf) > 0 { - b.buf = b.getBuf(len(buf)) - copy(b.buf, buf) - } - return b -} - -// NewBufferString is identical to NewBuffer *except* that it allows one to -// initialize the buffer from a string (without having to allocate an -// intermediate bytes slice). -func NewBufferString(buf string) *Buffer { - b := new(Buffer) - if len(buf) > 0 { - b.buf = b.getBuf(len(buf)) - copy(b.buf, buf) - } - return b -} - -func (b *Buffer) grow(n int) int { - wOff := len(b.buf) - bCap := cap(b.buf) - - if bCap >= wOff+n { - b.buf = b.buf[:wOff+n] - return wOff - } - - bSize := b.Len() - - minCap := 2*bSize + n - - // Slide if cap >= minCap. - // Reallocate otherwise. - if bCap >= minCap { - copy(b.buf, b.buf[b.rOff:]) - } else { - // Needs new buffer. - newBuf := b.getBuf(minCap) - copy(newBuf, b.buf[b.rOff:]) - b.returnBuf() - b.buf = newBuf - } - - b.rOff = 0 - b.buf = b.buf[:bSize+n] - return bSize -} - -func (b *Buffer) getPool() *BufferPool { - if b.Pool == nil { - return GlobalPool - } - return b.Pool -} - -func (b *Buffer) returnBuf() { - if cap(b.buf) > len(b.bootstrap) { - b.getPool().Put(b.buf) - } - b.buf = nil -} - -func (b *Buffer) getBuf(n int) []byte { - if n <= len(b.bootstrap) { - return b.bootstrap[:n] - } - return b.getPool().Get(n) -} - -// Len returns the number of bytes that can be read from this buffer. -func (b *Buffer) Len() int { - return len(b.buf) - b.rOff -} - -// Cap returns the current capacity of the buffer. -// -// Note: Buffer *may* re-allocate when writing (or growing by) `n` bytes even if -// `Cap() < Len() + n` to avoid excessive copying. -func (b *Buffer) Cap() int { - return cap(b.buf) -} - -// Bytes returns the slice of bytes currently buffered in the Buffer. -// -// The buffer returned by Bytes is valid until the next call grow, truncate, -// read, or write. Really, just don't touch the Buffer until you're done with -// the return value of this function. -func (b *Buffer) Bytes() []byte { - return b.buf[b.rOff:] -} - -// String returns the string representation of the buffer. -// -// It returns `` the buffer is a nil pointer. -func (b *Buffer) String() string { - if b == nil { - return "" - } - return string(b.buf[b.rOff:]) -} - -// WriteString writes a string to the buffer. -// -// This function is identical to Write except that it allows one to write a -// string directly without allocating an intermediate byte slice. -func (b *Buffer) WriteString(buf string) (int, error) { - wOff := b.grow(len(buf)) - return copy(b.buf[wOff:], buf), nil -} - -// Truncate truncates the Buffer. -// -// Panics if `n > b.Len()`. -// -// This function may free memory by shrinking the internal buffer. -func (b *Buffer) Truncate(n int) { - if n < 0 || n > b.Len() { - panic("truncation out of range") - } - b.buf = b.buf[:b.rOff+n] - b.shrink() -} - -// Reset is equivalent to Truncate(0). -func (b *Buffer) Reset() { - b.returnBuf() - b.rOff = 0 -} - -// ReadByte reads a single byte from the Buffer. -func (b *Buffer) ReadByte() (byte, error) { - if b.rOff >= len(b.buf) { - return 0, io.EOF - } - c := b.buf[b.rOff] - b.rOff++ - return c, nil -} - -// WriteByte writes a single byte to the Buffer. -func (b *Buffer) WriteByte(c byte) error { - wOff := b.grow(1) - b.buf[wOff] = c - return nil -} - -// Grow grows the internal buffer such that `n` bytes can be written without -// reallocating. -func (b *Buffer) Grow(n int) { - wOff := b.grow(n) - b.buf = b.buf[:wOff] -} - -// Next is an alternative to `Read` that returns a byte slice instead of taking -// one. -// -// The returned byte slice is valid until the next read, write, grow, or -// truncate. -func (b *Buffer) Next(n int) []byte { - m := b.Len() - if m < n { - n = m - } - data := b.buf[b.rOff : b.rOff+n] - b.rOff += n - return data -} - -// Write writes the byte slice to the buffer. -func (b *Buffer) Write(buf []byte) (int, error) { - wOff := b.grow(len(buf)) - return copy(b.buf[wOff:], buf), nil -} - -// WriteTo copies from the buffer into the given writer until the buffer is -// empty. -func (b *Buffer) WriteTo(w io.Writer) (int64, error) { - if b.rOff < len(b.buf) { - n, err := w.Write(b.buf[b.rOff:]) - b.rOff += n - if b.rOff > len(b.buf) { - panic("invalid write count") - } - b.shrink() - return int64(n), err - } - return 0, nil -} - -// MinRead is the minimum slice size passed to a Read call by -// Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond -// what is required to hold the contents of r, ReadFrom will not grow the -// underlying buffer. -const MinRead = 512 - -// ReadFrom reads from the given reader into the buffer. -func (b *Buffer) ReadFrom(r io.Reader) (int64, error) { - n := int64(0) - for { - wOff := b.grow(MinRead) - // Use *entire* buffer. - b.buf = b.buf[:cap(b.buf)] - - read, err := r.Read(b.buf[wOff:]) - b.buf = b.buf[:wOff+read] - n += int64(read) - switch err { - case nil: - case io.EOF: - err = nil - fallthrough - default: - b.shrink() - return n, err - } - } -} - -// Read reads at most `len(buf)` bytes from the internal buffer into the given -// buffer. -func (b *Buffer) Read(buf []byte) (int, error) { - if len(buf) == 0 { - return 0, nil - } - if b.rOff >= len(b.buf) { - return 0, io.EOF - } - n := copy(buf, b.buf[b.rOff:]) - b.rOff += n - b.shrink() - return n, nil -} - -func (b *Buffer) shrink() { - c := b.Cap() - // Either nil or bootstrap. - if c <= len(b.bootstrap) { - return - } - - l := b.Len() - if l == 0 { - // Shortcut if empty. - b.returnBuf() - b.rOff = 0 - } else if l*8 < c { - // Only shrink when capacity > 8x length. Avoids shrinking too aggressively. - newBuf := b.getBuf(l) - copy(newBuf, b.buf[b.rOff:]) - b.returnBuf() - b.rOff = 0 - b.buf = newBuf[:l] - } -} diff --git a/go-buffer-pool/buffer_test.go b/go-buffer-pool/buffer_test.go deleted file mode 100644 index 196ee3b..0000000 --- a/go-buffer-pool/buffer_test.go +++ /dev/null @@ -1,400 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Modified by stebalien, 2018 - -package pool - -import ( - "bytes" - "math/rand" - "runtime" - "testing" -) - -const N = 10000 // make this bigger for a larger (and slower) test -var data string // test data for write tests -var testBytes []byte // test data; same as data but as a slice. - -func init() { - testBytes = make([]byte, N) - for i := 0; i < N; i++ { - testBytes[i] = 'a' + byte(i%26) - } - data = string(testBytes) -} - -// Verify that contents of buf match the string s. -func check(t *testing.T, testname string, buf *Buffer, s string) { - bytes := buf.Bytes() - str := buf.String() - if buf.Len() != len(bytes) { - t.Errorf("%s: buf.Len() == %d, len(buf.Bytes()) == %d", testname, buf.Len(), len(bytes)) - } - - if buf.Len() != len(str) { - t.Errorf("%s: buf.Len() == %d, len(buf.String()) == %d", testname, buf.Len(), len(str)) - } - - if buf.Len() != len(s) { - t.Errorf("%s: buf.Len() == %d, len(s) == %d", testname, buf.Len(), len(s)) - } - - if string(bytes) != s { - t.Errorf("%s: string(buf.Bytes()) == %q, s == %q", testname, string(bytes), s) - } -} - -// Fill buf through n writes of string fus. -// The initial contents of buf corresponds to the string s; -// the result is the final contents of buf returned as a string. -func fillString(t *testing.T, testname string, buf *Buffer, s string, n int, fus string) string { - check(t, testname+" (fill 1)", buf, s) - for ; n > 0; n-- { - m, err := buf.WriteString(fus) - if m != len(fus) { - t.Errorf(testname+" (fill 2): m == %d, expected %d", m, len(fus)) - } - if err != nil { - t.Errorf(testname+" (fill 3): err should always be nil, found err == %s", err) - } - s += fus - check(t, testname+" (fill 4)", buf, s) - } - return s -} - -// Fill buf through n writes of byte slice fub. -// The initial contents of buf corresponds to the string s; -// the result is the final contents of buf returned as a string. -func fillBytes(t *testing.T, testname string, buf *Buffer, s string, n int, fub []byte) string { - check(t, testname+" (fill 1)", buf, s) - for ; n > 0; n-- { - m, err := buf.Write(fub) - if m != len(fub) { - t.Errorf(testname+" (fill 2): m == %d, expected %d", m, len(fub)) - } - if err != nil { - t.Errorf(testname+" (fill 3): err should always be nil, found err == %s", err) - } - s += string(fub) - check(t, testname+" (fill 4)", buf, s) - } - return s -} - -func TestNewBuffer(t *testing.T) { - buf := NewBuffer(testBytes) - check(t, "NewBuffer", buf, data) -} - -func TestNewBufferString(t *testing.T) { - buf := NewBufferString(data) - check(t, "NewBufferString", buf, data) -} - -// Empty buf through repeated reads into fub. -// The initial contents of buf corresponds to the string s. -func empty(t *testing.T, testname string, buf *Buffer, s string, fub []byte) { - check(t, testname+" (empty 1)", buf, s) - - for { - n, err := buf.Read(fub) - if n == 0 { - break - } - if err != nil { - t.Errorf(testname+" (empty 2): err should always be nil, found err == %s", err) - } - s = s[n:] - check(t, testname+" (empty 3)", buf, s) - } - - check(t, testname+" (empty 4)", buf, "") -} - -func TestBasicOperations(t *testing.T) { - var buf Buffer - - for i := 0; i < 5; i++ { - check(t, "TestBasicOperations (1)", &buf, "") - - buf.Reset() - check(t, "TestBasicOperations (2)", &buf, "") - - buf.Truncate(0) - check(t, "TestBasicOperations (3)", &buf, "") - - n, err := buf.Write([]byte(data[0:1])) - if n != 1 { - t.Errorf("wrote 1 byte, but n == %d", n) - } - if err != nil { - t.Errorf("err should always be nil, but err == %s", err) - } - check(t, "TestBasicOperations (4)", &buf, "a") - - buf.WriteByte(data[1]) - check(t, "TestBasicOperations (5)", &buf, "ab") - - n, err = buf.Write([]byte(data[2:26])) - if err != nil { - t.Fatal(err) - } - if n != 24 { - t.Errorf("wrote 25 bytes, but n == %d", n) - } - check(t, "TestBasicOperations (6)", &buf, string(data[0:26])) - - buf.Truncate(26) - check(t, "TestBasicOperations (7)", &buf, string(data[0:26])) - - buf.Truncate(20) - check(t, "TestBasicOperations (8)", &buf, string(data[0:20])) - - empty(t, "TestBasicOperations (9)", &buf, string(data[0:20]), make([]byte, 5)) - empty(t, "TestBasicOperations (10)", &buf, "", make([]byte, 100)) - - buf.WriteByte(data[1]) - c, err := buf.ReadByte() - if err != nil { - t.Error("ReadByte unexpected eof") - } - if c != data[1] { - t.Errorf("ReadByte wrong value c=%v", c) - } - if _, err = buf.ReadByte(); err == nil { - t.Error("ReadByte unexpected not eof") - } - } -} - -func TestLargeStringWrites(t *testing.T) { - var buf Buffer - limit := 30 - if testing.Short() { - limit = 9 - } - for i := 3; i < limit; i += 3 { - s := fillString(t, "TestLargeWrites (1)", &buf, "", 5, data) - empty(t, "TestLargeStringWrites (2)", &buf, s, make([]byte, len(data)/i)) - } - check(t, "TestLargeStringWrites (3)", &buf, "") -} - -func TestLargeByteWrites(t *testing.T) { - var buf Buffer - limit := 30 - if testing.Short() { - limit = 9 - } - for i := 3; i < limit; i += 3 { - s := fillBytes(t, "TestLargeWrites (1)", &buf, "", 5, testBytes) - empty(t, "TestLargeByteWrites (2)", &buf, s, make([]byte, len(data)/i)) - } - check(t, "TestLargeByteWrites (3)", &buf, "") -} - -func TestLargeStringReads(t *testing.T) { - var buf Buffer - for i := 3; i < 30; i += 3 { - s := fillString(t, "TestLargeReads (1)", &buf, "", 5, data[0:len(data)/i]) - empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(data))) - } - check(t, "TestLargeStringReads (3)", &buf, "") -} - -func TestLargeByteReads(t *testing.T) { - var buf Buffer - for i := 3; i < 30; i += 3 { - s := fillBytes(t, "TestLargeReads (1)", &buf, "", 5, testBytes[0:len(testBytes)/i]) - empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(data))) - } - check(t, "TestLargeByteReads (3)", &buf, "") -} - -func TestMixedReadsAndWrites(t *testing.T) { - var buf Buffer - s := "" - for i := 0; i < 50; i++ { - wlen := rand.Intn(len(data)) - if i%2 == 0 { - s = fillString(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, data[0:wlen]) - } else { - s = fillBytes(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, testBytes[0:wlen]) - } - - rlen := rand.Intn(len(data)) - fub := make([]byte, rlen) - n, _ := buf.Read(fub) - s = s[n:] - } - empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len())) -} - -func TestNil(t *testing.T) { - var b *Buffer - if b.String() != "" { - t.Errorf("expected ; got %q", b.String()) - } -} - -func TestReadFrom(t *testing.T) { - var buf Buffer - for i := 3; i < 30; i += 3 { - s := fillBytes(t, "TestReadFrom (1)", &buf, "", 5, testBytes[0:len(testBytes)/i]) - var b Buffer - b.ReadFrom(&buf) - empty(t, "TestReadFrom (2)", &b, s, make([]byte, len(data))) - } -} - -func TestWriteTo(t *testing.T) { - var buf Buffer - for i := 3; i < 30; i += 3 { - s := fillBytes(t, "TestWriteTo (1)", &buf, "", 5, testBytes[0:len(testBytes)/i]) - var b Buffer - buf.WriteTo(&b) - empty(t, "TestWriteTo (2)", &b, s, make([]byte, len(data))) - } -} - -func TestNext(t *testing.T) { - b := []byte{0, 1, 2, 3, 4} - tmp := make([]byte, 5) - for i := 0; i <= 5; i++ { - for j := i; j <= 5; j++ { - for k := 0; k <= 6; k++ { - // 0 <= i <= j <= 5; 0 <= k <= 6 - // Check that if we start with a buffer - // of length j at offset i and ask for - // Next(k), we get the right bytes. - buf := NewBuffer(b[0:j]) - n, _ := buf.Read(tmp[0:i]) - if n != i { - t.Fatalf("Read %d returned %d", i, n) - } - bb := buf.Next(k) - want := k - if want > j-i { - want = j - i - } - if len(bb) != want { - t.Fatalf("in %d,%d: len(Next(%d)) == %d", i, j, k, len(bb)) - } - for l, v := range bb { - if v != byte(l+i) { - t.Fatalf("in %d,%d: Next(%d)[%d] = %d, want %d", i, j, k, l, v, l+i) - } - } - } - } - } -} - -func TestGrow(t *testing.T) { - x := []byte{'x'} - y := []byte{'y'} - tmp := make([]byte, 72) - for _, startLen := range []int{0, 100, 1000, 10000, 100000} { - xBytes := bytes.Repeat(x, startLen) - for _, growLen := range []int{0, 100, 1000, 10000, 100000} { - buf := NewBuffer(xBytes) - // If we read, this affects buf.off, which is good to test. - readBytes, _ := buf.Read(tmp) - buf.Grow(growLen) - yBytes := bytes.Repeat(y, growLen) - // Check no allocation occurs in write, as long as we're single-threaded. - var m1, m2 runtime.MemStats - runtime.ReadMemStats(&m1) - buf.Write(yBytes) - runtime.ReadMemStats(&m2) - if runtime.GOMAXPROCS(-1) == 1 && m1.Mallocs != m2.Mallocs { - t.Errorf("allocation occurred during write") - } - // Check that buffer has correct data. - if !bytes.Equal(buf.Bytes()[0:startLen-readBytes], xBytes[readBytes:]) { - t.Errorf("bad initial data at %d %d", startLen, growLen) - } - if !bytes.Equal(buf.Bytes()[startLen-readBytes:startLen-readBytes+growLen], yBytes) { - t.Errorf("bad written data at %d %d", startLen, growLen) - } - } - } -} - -// Was a bug: used to give EOF reading empty slice at EOF. -func TestReadEmptyAtEOF(t *testing.T) { - b := new(Buffer) - slice := make([]byte, 0) - n, err := b.Read(slice) - if err != nil { - t.Errorf("read error: %v", err) - } - if n != 0 { - t.Errorf("wrong count; got %d want 0", n) - } -} - -// Tests that we occasionally compact. Issue 5154. -func TestBufferGrowth(t *testing.T) { - var b Buffer - buf := make([]byte, 1024) - b.Write(buf[0:1]) - var cap0 int - for i := 0; i < 5<<10; i++ { - b.Write(buf) - b.Read(buf) - if i == 0 { - cap0 = b.Cap() - } - } - cap1 := b.Cap() - // (*Buffer).grow allows for 2x capacity slop before sliding, - // so set our error threshold at 3x. - if cap1 > cap0*3 { - t.Errorf("buffer cap = %d; too big (grew from %d)", cap1, cap0) - } -} - -func BenchmarkWriteByte(b *testing.B) { - const n = 4 << 10 - b.SetBytes(n) - buf := NewBuffer(make([]byte, n)) - for i := 0; i < b.N; i++ { - buf.Reset() - for i := 0; i < n; i++ { - buf.WriteByte('x') - } - } -} - -// From Issue 5154. -func BenchmarkBufferNotEmptyWriteRead(b *testing.B) { - buf := make([]byte, 1024) - for i := 0; i < b.N; i++ { - var b Buffer - b.Write(buf[0:1]) - for i := 0; i < 5<<10; i++ { - b.Write(buf) - b.Read(buf) - } - } -} - -// Check that we don't compact too often. From Issue 5154. -func BenchmarkBufferFullSmallReads(b *testing.B) { - buf := make([]byte, 1024) - for i := 0; i < b.N; i++ { - var b Buffer - b.Write(buf) - for b.Len()+20 < b.Cap() { - b.Write(buf[:10]) - } - for i := 0; i < 5<<10; i++ { - b.Read(buf[:1]) - b.Write(buf[:1]) - } - } -} diff --git a/go-buffer-pool/codecov.yml b/go-buffer-pool/codecov.yml deleted file mode 100644 index 5f88a9e..0000000 --- a/go-buffer-pool/codecov.yml +++ /dev/null @@ -1,3 +0,0 @@ -coverage: - range: "50...100" -comment: off diff --git a/go-buffer-pool/go.mod b/go-buffer-pool/go.mod deleted file mode 100644 index ec99f0a..0000000 --- a/go-buffer-pool/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/libp2p/go-buffer-pool - -go 1.22 diff --git a/go-buffer-pool/pool.go b/go-buffer-pool/pool.go deleted file mode 100644 index aec3b0c..0000000 --- a/go-buffer-pool/pool.go +++ /dev/null @@ -1,103 +0,0 @@ -// Package pool provides a sync.Pool equivalent that buckets incoming -// requests to one of 32 sub-pools, one for each power of 2, 0-32. -// -// import (pool "github.com/libp2p/go-buffer-pool") -// var p pool.BufferPool -// -// small := make([]byte, 1024) -// large := make([]byte, 4194304) -// p.Put(small) -// p.Put(large) -// -// small2 := p.Get(1024) -// large2 := p.Get(4194304) -// fmt.Println("small2 len:", len(small2)) -// fmt.Println("large2 len:", len(large2)) -// -// // Output: -// // small2 len: 1024 -// // large2 len: 4194304 -package pool - -import ( - "math" - "math/bits" - "sync" -) - -// GlobalPool is a static Pool for reusing byteslices of various sizes. -var GlobalPool = new(BufferPool) - -// MaxLength is the maximum length of an element that can be added to the Pool. -const MaxLength = math.MaxInt32 - -// BufferPool is a pool to handle cases of reusing elements of varying sizes. It -// maintains 32 internal pools, for each power of 2 in 0-32. -// -// You should generally just call the package level Get and Put methods or use -// the GlobalPool BufferPool instead of constructing your own. -// -// You MUST NOT copy Pool after using. -type BufferPool struct { - pools [32]sync.Pool // a list of singlePools -} - -// Get retrieves a buffer of the appropriate length from the buffer pool or -// allocates a new one. Get may choose to ignore the pool and treat it as empty. -// Callers should not assume any relation between values passed to Put and the -// values returned by Get. -// -// If no suitable buffer exists in the pool, Get creates one. -func (p *BufferPool) Get(length int) []byte { - if length == 0 { - return nil - } - // Calling this function with a negative length is invalid. - // make will panic if length is negative, so we don't have to. - if length > MaxLength || length < 0 { - return make([]byte, length) - } - idx := nextLogBase2(uint32(length)) - if ptr := p.pools[idx].Get(); ptr != nil { - buf := ptr.([]byte) - buf = buf[:uint32(length)] - return buf - } - return make([]byte, 1< MaxLength { - return // drop it - } - idx := prevLogBase2(uint32(capacity)) - // nolint: staticcheck - p.pools[idx].Put(buf) -} - -// Get retrieves a buffer of the appropriate length from the global buffer pool -// (or allocates a new one). -func Get(length int) []byte { - return GlobalPool.Get(length) -} - -// Put returns a buffer to the global buffer pool. -func Put(slice []byte) { - GlobalPool.Put(slice) -} - -// Log of base two, round up (for v > 0). -func nextLogBase2(v uint32) uint32 { - return uint32(bits.Len32(v - 1)) -} - -// Log of base two, round down (for v > 0) -func prevLogBase2(num uint32) uint32 { - next := nextLogBase2(num) - if num == (1 << uint32(next)) { - return next - } - return next - 1 -} diff --git a/go-buffer-pool/pool_test.go b/go-buffer-pool/pool_test.go deleted file mode 100644 index cf17c0e..0000000 --- a/go-buffer-pool/pool_test.go +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Pool is no-op under race detector, so all these tests do not work. -//go:build !race - -package pool - -import ( - "bytes" - "fmt" - "math/rand" - "runtime" - "runtime/debug" - "testing" -) - -func TestRange(t *testing.T) { - min := nextLogBase2(1) - max := nextLogBase2(uint32(MaxLength)) - if int(max) != len(GlobalPool.pools)-1 { - t.Errorf("expected %d pools, found %d", max, len(GlobalPool.pools)) - } - if min != 0 { - t.Errorf("unused min pool") - } -} - -func TestPool(t *testing.T) { - // disable GC so we can control when it happens. - defer debug.SetGCPercent(debug.SetGCPercent(-1)) - var p BufferPool - - a := make([]byte, 21) - a[0] = 1 - b := make([]byte, 2050) - b[0] = 2 - p.Put(a) - p.Put(b) - if g := p.Get(16); &g[0] != &a[0] { - t.Fatalf("got [%d,...]; want [1,...]", g[0]) - } - if g := p.Get(2048); &g[0] != &b[0] { - t.Fatalf("got [%d,...]; want [2,...]", g[0]) - } - if g := p.Get(16); cap(g) != 16 || !bytes.Equal(g[:16], make([]byte, 16)) { - t.Fatalf("got existing slice; want new slice") - } - if g := p.Get(2048); cap(g) != 2048 || !bytes.Equal(g[:2048], make([]byte, 2048)) { - t.Fatalf("got existing slice; want new slice") - } - if g := p.Get(1); cap(g) != 1 || !bytes.Equal(g[:1], make([]byte, 1)) { - t.Fatalf("got existing slice; want new slice") - } - d := make([]byte, 1023) - d[0] = 3 - p.Put(d) - if g := p.Get(1024); cap(g) != 1024 || !bytes.Equal(g, make([]byte, 1024)) { - t.Fatalf("got existing slice; want new slice") - } - if g := p.Get(512); cap(g) != 1023 || g[0] != 3 { - t.Fatalf("got [%d,...]; want [3,...]", g[0]) - } - p.Put(a) - - debug.SetGCPercent(100) // to allow following GC to actually run - runtime.GC() - // For some reason, you need to run GC twice on go 1.16 if you want it to reliably work. - runtime.GC() - if g := p.Get(10); &g[0] == &a[0] { - t.Fatalf("got a; want new slice after GC") - } -} - -func TestPoolStressByteSlicePool(t *testing.T) { - var p BufferPool - - const P = 10 - chs := 10 - maxSize := 1 << 16 - N := int(1e4) - if testing.Short() { - N /= 100 - } - done := make(chan bool) - errs := make(chan error) - for i := 0; i < P; i++ { - go func() { - ch := make(chan []byte, chs+1) - - for i := 0; i < chs; i++ { - j := rand.Int() % maxSize - ch <- p.Get(j) - } - - for j := 0; j < N; j++ { - r := 0 - for i := 0; i < chs; i++ { - v := <-ch - p.Put(v) - r = rand.Int() % maxSize - v = p.Get(r) - if len(v) < r { - errs <- fmt.Errorf("expect len(v) >= %d, got %d", j, len(v)) - } - ch <- v - } - - if r%1000 == 0 { - runtime.GC() - } - } - done <- true - }() - } - - for i := 0; i < P; { - select { - case <-done: - i++ - case err := <-errs: - t.Error(err) - } - } -} - -func BenchmarkPool(b *testing.B) { - var p BufferPool - b.RunParallel(func(pb *testing.PB) { - i := 7 - for pb.Next() { - if i > 1<<20 { - i = 7 - } else { - i = i << 1 - } - b := p.Get(i) - b[0] = byte(i) - p.Put(b) - } - }) -} - -func BenchmarkAlloc(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - i := 7 - for pb.Next() { - if i > 1<<20 { - i = 7 - } else { - i = i << 1 - } - b := make([]byte, i) - b[1] = byte(i) - } - }) -} - -func BenchmarkPoolOverlflow(b *testing.B) { - var p BufferPool - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - bufs := make([][]byte, 2100) - for pow := uint32(0); pow < 21; pow++ { - for i := 0; i < 100; i++ { - bufs = append(bufs, p.Get(1<= WriterBufferSize { - return w.W.Write(b) - } - w.bufw = bufioWriterPool.Get().(*bufio.Writer) - w.bufw.Reset(w.W) - } - return w.bufw.Write(b) -} - -// Size returns the size of the underlying buffer. -func (w *Writer) Size() int { - return WriterBufferSize -} - -// Available returns the amount buffer space available. -func (w *Writer) Available() int { - if w.bufw != nil { - return w.bufw.Available() - } - return WriterBufferSize -} - -// Buffered returns the amount of data buffered. -func (w *Writer) Buffered() int { - if w.bufw != nil { - return w.bufw.Buffered() - } - return 0 -} - -// WriteByte writes a single byte. -func (w *Writer) WriteByte(b byte) error { - w.ensureBuffer() - return w.bufw.WriteByte(b) -} - -// WriteRune writes a single rune, returning the number of bytes written. -func (w *Writer) WriteRune(r rune) (int, error) { - w.ensureBuffer() - return w.bufw.WriteRune(r) -} - -// WriteString writes a string, returning the number of bytes written. -func (w *Writer) WriteString(s string) (int, error) { - w.ensureBuffer() - return w.bufw.WriteString(s) -} - -// Flush flushes the write buffer, if any, and returns it to the pool. -func (w *Writer) Flush() error { - if w.bufw == nil { - return nil - } - if err := w.bufw.Flush(); err != nil { - return err - } - w.bufw.Reset(nil) - bufioWriterPool.Put(w.bufw) - w.bufw = nil - return nil -} - -// Close flushes the underlying writer and closes it if it implements the -// io.Closer interface. -// -// Note: Close() closes the writer even if Flush() fails to avoid leaking system -// resources. If you want to make sure Flush() succeeds, call it first. -func (w *Writer) Close() error { - var ( - ferr, cerr error - ) - ferr = w.Flush() - - // always close even if flush fails. - if closer, ok := w.W.(io.Closer); ok { - cerr = closer.Close() - } - - if ferr != nil { - return ferr - } - return cerr -} diff --git a/go-buffer-pool/writer_test.go b/go-buffer-pool/writer_test.go deleted file mode 100644 index ae57520..0000000 --- a/go-buffer-pool/writer_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package pool - -import ( - "bytes" - "testing" -) - -func checkSize(t *testing.T, w *Writer) { - if w.Size()-w.Buffered() != w.Available() { - t.Fatalf("size (%d), buffered (%d), available (%d) mismatch", w.Size(), w.Buffered(), w.Available()) - } -} - -func TestWriter(t *testing.T) { - var b bytes.Buffer - w := Writer{W: &b} - n, err := w.Write([]byte("foobar")) - checkSize(t, &w) - - if err != nil || n != 6 { - t.Fatalf("write failed: %d, %s", n, err) - } - if b.Len() != 0 { - t.Fatal("expected the buffer to be empty") - } - if w.Buffered() != 6 { - t.Fatalf("expected 6 bytes to be buffered, got %d", w.Buffered()) - } - checkSize(t, &w) - if err := w.Flush(); err != nil { - t.Fatal(err) - } - checkSize(t, &w) - if err := w.Flush(); err != nil { - t.Fatal(err) - } - checkSize(t, &w) - if b.String() != "foobar" { - t.Fatal("expected to have written foobar") - } - b.Reset() - - buf := make([]byte, WriterBufferSize) - n, err = w.Write(buf) - if n != WriterBufferSize || err != nil { - t.Fatalf("write failed: %d, %s", n, err) - } - checkSize(t, &w) - if b.Len() != WriterBufferSize { - t.Fatal("large write should have gone through directly") - } - if err := w.Flush(); err != nil { - t.Fatal(err) - } - checkSize(t, &w) - - b.Reset() - if err := w.WriteByte(1); err != nil { - t.Fatal(err) - } - if w.Buffered() != 1 { - t.Fatalf("expected 1 byte to be buffered, got %d", w.Buffered()) - } - if n, err := w.WriteRune('1'); err != nil || n != 1 { - t.Fatal(err) - } - if w.Buffered() != 2 { - t.Fatalf("expected 2 bytes to be buffered, got %d", w.Buffered()) - } - checkSize(t, &w) - if n, err := w.WriteString("foobar"); err != nil || n != 6 { - t.Fatal(err) - } - if w.Buffered() != 8 { - t.Fatalf("expected 8 bytes to be buffered, got %d", w.Buffered()) - } - checkSize(t, &w) - if b.Len() != 0 { - t.Fatal("write should have been buffered") - } - n, err = w.Write(buf) - if n != WriterBufferSize || err != nil { - t.Fatalf("write failed: %d, %s", n, err) - } - if b.Len() != WriterBufferSize || b.Bytes()[0] != 1 || b.String()[1:8] != "1foobar" { - t.Fatalf("failed to flush properly: len:%d, prefix:%#v", b.Len(), b.Bytes()[:10]) - } - if err := w.Close(); err != nil { - t.Fatal(err) - } -} diff --git a/go-libp2p-blossomsub/comm.go b/go-libp2p-blossomsub/comm.go index 61e5b37..e70cd7d 100644 --- a/go-libp2p-blossomsub/comm.go +++ b/go-libp2p-blossomsub/comm.go @@ -169,10 +169,11 @@ func (p *PubSub) handlePeerDead(s network.Stream) { } func (p *PubSub) handleSendingMessages(ctx context.Context, s network.Stream, q *rpcQueue) { + getBuffer, returnLastBuffer := makeBufferSource() + defer returnLastBuffer() writeRPC := func(rpc *RPC) error { size := uint64(rpc.Size()) - buf := pool.Get(varint.UvarintSize(size) + int(size)) - defer pool.Put(buf) + buf := getBuffer(varint.UvarintSize(size) + int(size)) n := binary.PutUvarint(buf, size) _, err := rpc.MarshalTo(buf[n:]) if err != nil { @@ -234,3 +235,28 @@ func copyRPC(rpc *RPC) *RPC { res.RPC = (proto.Clone(rpc.RPC)).(*pb.RPC) return res } + +// makeBufferSource returns a function that can be used to allocate buffers of +// a given size, and a function that can be used to return the last buffer +// allocated. +// The returned function will attempt to reuse the last buffer allocated if +// the requested size is less than or equal to the capacity of the last buffer. +// If the requested size is greater than the capacity of the last buffer, the +// last buffer is returned to the pool and a new buffer is allocated. +// If the requested size is less than or equal to half the capacity of the last +// buffer, the last buffer is returned to the pool and a new buffer is allocated. +func makeBufferSource() (func(int) []byte, func()) { + b := pool.Get(0) + mk := func(n int) []byte { + if c := cap(b); c/2 < n && n <= c { + return b[:n] + } + pool.Put(b) + b = pool.Get(n) + return b + } + rt := func() { + pool.Put(b) + } + return mk, rt +} diff --git a/go-libp2p-blossomsub/go.mod b/go-libp2p-blossomsub/go.mod index b598c2d..f078c58 100644 --- a/go-libp2p-blossomsub/go.mod +++ b/go-libp2p-blossomsub/go.mod @@ -8,8 +8,6 @@ replace github.com/multiformats/go-multiaddr => ../go-multiaddr replace github.com/multiformats/go-multiaddr-dns => ../go-multiaddr-dns -replace github.com/libp2p/go-buffer-pool => ../go-buffer-pool - replace github.com/libp2p/go-libp2p => ../go-libp2p replace github.com/libp2p/go-libp2p-gostream => ../go-libp2p-gostream diff --git a/go-libp2p-blossomsub/go.sum b/go-libp2p-blossomsub/go.sum index 1a1f7a3..0c010da 100644 --- a/go-libp2p-blossomsub/go.sum +++ b/go-libp2p-blossomsub/go.sum @@ -140,6 +140,8 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= diff --git a/go-libp2p-kad-dht/go.mod b/go-libp2p-kad-dht/go.mod index feb885c..fa44936 100644 --- a/go-libp2p-kad-dht/go.mod +++ b/go-libp2p-kad-dht/go.mod @@ -10,8 +10,6 @@ replace github.com/multiformats/go-multiaddr => ../go-multiaddr replace github.com/multiformats/go-multiaddr-dns => ../go-multiaddr-dns -replace github.com/libp2p/go-buffer-pool => ../go-buffer-pool - replace github.com/libp2p/go-libp2p => ../go-libp2p require ( diff --git a/go-libp2p-kad-dht/go.sum b/go-libp2p-kad-dht/go.sum index 6e33381..1a20f93 100644 --- a/go-libp2p-kad-dht/go.sum +++ b/go-libp2p-kad-dht/go.sum @@ -246,6 +246,10 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= diff --git a/go-libp2p/go.mod b/go-libp2p/go.mod index 8bc90ea..d3735ed 100644 --- a/go-libp2p/go.mod +++ b/go-libp2p/go.mod @@ -6,8 +6,6 @@ toolchain go1.22.5 retract v0.26.1 // Tag was applied incorrectly due to a bug in the release workflow. -replace github.com/libp2p/go-buffer-pool => ../go-buffer-pool - replace github.com/multiformats/go-multiaddr => ../go-multiaddr replace github.com/multiformats/go-multiaddr-dns => ../go-multiaddr-dns diff --git a/go-libp2p/go.sum b/go-libp2p/go.sum index fa8e975..2bf30e0 100644 --- a/go-libp2p/go.sum +++ b/go-libp2p/go.sum @@ -186,6 +186,8 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= diff --git a/node/go.mod b/node/go.mod index 8d971b8..9da7c47 100644 --- a/node/go.mod +++ b/node/go.mod @@ -15,8 +15,6 @@ replace github.com/multiformats/go-multiaddr => ../go-multiaddr replace github.com/multiformats/go-multiaddr-dns => ../go-multiaddr-dns -replace github.com/libp2p/go-buffer-pool => ../go-buffer-pool - replace github.com/libp2p/go-libp2p => ../go-libp2p replace github.com/libp2p/go-libp2p-kad-dht => ../go-libp2p-kad-dht diff --git a/node/go.sum b/node/go.sum index cfeaced..888035b 100644 --- a/node/go.sum +++ b/node/go.sum @@ -275,6 +275,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= diff --git a/node/main.go b/node/main.go index c03fde0..a94e2a5 100644 --- a/node/main.go +++ b/node/main.go @@ -406,7 +406,6 @@ func main() { } if *core != 0 { - rdebug.SetGCPercent(9999) rdebug.SetMemoryLimit(nodeConfig.Engine.DataWorkerMemoryLimit) if *parentProcess == 0 && len(nodeConfig.Engine.DataWorkerMultiaddrs) == 0 { @@ -458,9 +457,6 @@ func main() { fmt.Println("The memory available to the node, unallocated to the data workers, is less than 8GiB.") fmt.Println("You are at risk of running out of memory during runtime.") default: - if _, explicitGOGC := os.LookupEnv("GOGC"); !explicitGOGC { - rdebug.SetGCPercent(9999) - } if _, explicitGOMEMLIMIT := os.LookupEnv("GOMEMLIMIT"); !explicitGOMEMLIMIT { rdebug.SetMemoryLimit(availableOverhead * 8 / 10) } From 1b78d758f5557c0d692888baf5acd8a065026108 Mon Sep 17 00:00:00 2001 From: petricadaipegsp <155911522+petricadaipegsp@users.noreply.github.com> Date: Sun, 1 Dec 2024 22:07:08 +0100 Subject: [PATCH 05/14] Prefer connected peers for sync (#395) * Add externally reachable data peer flag * Announce node reachability * Go through candidates based on reachability --- node/consensus/data/broadcast_messaging.go | 3 + node/consensus/data/consensus_frames.go | 59 ++- .../data/data_clock_consensus_engine.go | 6 + node/consensus/data/message_handler.go | 1 + node/consensus/data/token_handle_mint_test.go | 3 + node/p2p/blossomsub.go | 52 +- node/p2p/pubsub.go | 3 + node/protobufs/data.pb.go | 496 +++++++++--------- node/protobufs/data.proto | 3 + 9 files changed, 363 insertions(+), 263 deletions(-) diff --git a/node/consensus/data/broadcast_messaging.go b/node/consensus/data/broadcast_messaging.go index 46ae6bd..6d0ed2a 100644 --- a/node/consensus/data/broadcast_messaging.go +++ b/node/consensus/data/broadcast_messaging.go @@ -62,6 +62,7 @@ func (e *DataClockConsensusEngine) publishProof( ) timestamp := time.Now().UnixMilli() + reachability := e.pubSub.Reachability() e.peerMapMx.Lock() e.peerMap[string(e.pubSub.GetPeerID())] = &peerInfo{ @@ -74,6 +75,7 @@ func (e *DataClockConsensusEngine) publishProof( totalDistance: e.dataTimeReel.GetTotalDistance().FillBytes( make([]byte, 256), ), + reachability: reachability, } list := &protobufs.DataPeerListAnnounce{ Peer: &protobufs.DataPeer{ @@ -86,6 +88,7 @@ func (e *DataClockConsensusEngine) publishProof( TotalDistance: e.dataTimeReel.GetTotalDistance().FillBytes( make([]byte, 256), ), + ExternallyReachable: reachability, }, } e.peerMapMx.Unlock() diff --git a/node/consensus/data/consensus_frames.go b/node/consensus/data/consensus_frames.go index e9c9f27..2568427 100644 --- a/node/consensus/data/consensus_frames.go +++ b/node/consensus/data/consensus_frames.go @@ -3,6 +3,7 @@ package data import ( "bytes" "context" + "slices" "time" "golang.org/x/crypto/sha3" @@ -226,15 +227,21 @@ func (e *DataClockConsensusEngine) GetAheadPeers(frameNumber uint64) []internal. return nil } + e.peerMapMx.RLock() + peerMapLen, uncooperativePeerMapLen := len(e.peerMap), len(e.uncooperativePeersMap) + e.peerMapMx.RUnlock() + e.logger.Debug( "checking peer list", - zap.Int("peers", len(e.peerMap)), - zap.Int("uncooperative_peers", len(e.uncooperativePeersMap)), + zap.Int("peers", peerMapLen), + zap.Int("uncooperative_peers", uncooperativePeerMapLen), zap.Uint64("current_head_frame", frameNumber), ) - candidates := make([]internal.WeightedPeerCandidate, 0, len(e.peerMap)) - maxDiff := uint64(0) + nearCandidates, nearMaxDiff := make([]internal.WeightedPeerCandidate, 0, peerMapLen), uint64(0) + reachableCandidates, reachableMaxDiff := make([]internal.WeightedPeerCandidate, 0, peerMapLen), uint64(0) + unreachableCandidates, unreachableMaxDiff := make([]internal.WeightedPeerCandidate, 0, peerMapLen), uint64(0) + unknownCandidates, unknownMaxDiff := make([]internal.WeightedPeerCandidate, 0, peerMapLen), uint64(0) e.peerMapMx.RLock() for _, v := range e.peerMap { @@ -257,24 +264,54 @@ func (e *DataClockConsensusEngine) GetAheadPeers(frameNumber uint64) []internal. if bytes.Compare(v.version, config.GetMinimumVersion()) < 0 { continue } - maxDiff = max(maxDiff, v.maxFrame-frameNumber) - candidates = append(candidates, internal.WeightedPeerCandidate{ + candidate, diff := internal.WeightedPeerCandidate{ PeerCandidate: internal.PeerCandidate{ PeerID: v.peerId, MaxFrame: v.maxFrame, }, - }) + }, v.maxFrame-frameNumber + switch { + case e.pubSub.IsPeerConnected(v.peerId): + nearMaxDiff = max(nearMaxDiff, diff) + nearCandidates = append(nearCandidates, candidate) + case v.reachability == nil: + unknownMaxDiff = max(unknownMaxDiff, diff) + unknownCandidates = append(unknownCandidates, candidate) + case v.reachability.Value: + reachableMaxDiff = max(reachableMaxDiff, diff) + reachableCandidates = append(reachableCandidates, candidate) + default: + unreachableMaxDiff = max(unreachableMaxDiff, diff) + unreachableCandidates = append(unreachableCandidates, candidate) + } } e.peerMapMx.RUnlock() - if len(candidates) == 0 { + if len(nearCandidates)+len(reachableCandidates)+len(unreachableCandidates)+len(unknownCandidates) == 0 { return nil } - for i := range candidates { - candidates[i].Weight = float64(candidates[i].MaxFrame-frameNumber) / float64(maxDiff) + for _, pair := range []struct { + maxDiff uint64 + candidates []internal.WeightedPeerCandidate + }{ + {nearMaxDiff, nearCandidates}, + {reachableMaxDiff, reachableCandidates}, + {unknownMaxDiff, unknownCandidates}, + {unreachableMaxDiff, unreachableCandidates}, + } { + maxDiff, candidates := pair.maxDiff, pair.candidates + for i := range candidates { + candidates[i].Weight = float64(candidates[i].MaxFrame-frameNumber) / float64(maxDiff) + } } - return internal.WeightedSampleWithoutReplacement(candidates, len(candidates)) + + return slices.Concat( + internal.WeightedSampleWithoutReplacement(nearCandidates, len(nearCandidates)), + internal.WeightedSampleWithoutReplacement(reachableCandidates, len(reachableCandidates)), + internal.WeightedSampleWithoutReplacement(unknownCandidates, len(unknownCandidates)), + internal.WeightedSampleWithoutReplacement(unreachableCandidates, len(unreachableCandidates)), + ) } func (e *DataClockConsensusEngine) syncWithPeer( diff --git a/node/consensus/data/data_clock_consensus_engine.go b/node/consensus/data/data_clock_consensus_engine.go index e6bf3ad..327c0f9 100644 --- a/node/consensus/data/data_clock_consensus_engine.go +++ b/node/consensus/data/data_clock_consensus_engine.go @@ -21,6 +21,7 @@ import ( "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/anypb" + "google.golang.org/protobuf/types/known/wrapperspb" "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb" "source.quilibrium.com/quilibrium/monorepo/node/config" "source.quilibrium.com/quilibrium/monorepo/node/consensus" @@ -58,6 +59,7 @@ type peerInfo struct { version []byte patchVersion byte totalDistance []byte + reachability *wrapperspb.BoolValue } type ChannelServer = protobufs.DataService_GetPublicChannelServer @@ -431,6 +433,8 @@ func (e *DataClockConsensusEngine) Start() <-chan error { frame = nextFrame timestamp := time.Now().UnixMilli() + reachability := e.pubSub.Reachability() + list := &protobufs.DataPeerListAnnounce{ Peer: &protobufs.DataPeer{ PeerId: nil, @@ -442,6 +446,7 @@ func (e *DataClockConsensusEngine) Start() <-chan error { TotalDistance: e.dataTimeReel.GetTotalDistance().FillBytes( make([]byte, 256), ), + ExternallyReachable: reachability, }, } @@ -463,6 +468,7 @@ func (e *DataClockConsensusEngine) Start() <-chan error { totalDistance: e.dataTimeReel.GetTotalDistance().FillBytes( make([]byte, 256), ), + reachability: reachability, } deletes := []*peerInfo{} for _, v := range e.peerMap { diff --git a/node/consensus/data/message_handler.go b/node/consensus/data/message_handler.go index fe24470..6a8ad83 100644 --- a/node/consensus/data/message_handler.go +++ b/node/consensus/data/message_handler.go @@ -314,6 +314,7 @@ func (e *DataClockConsensusEngine) handleDataPeerListAnnounce( version: p.Version, patchVersion: patchVersion, totalDistance: p.TotalDistance, + reachability: p.ExternallyReachable, } e.peerMapMx.Unlock() diff --git a/node/consensus/data/token_handle_mint_test.go b/node/consensus/data/token_handle_mint_test.go index d01e2d9..4bc9a90 100644 --- a/node/consensus/data/token_handle_mint_test.go +++ b/node/consensus/data/token_handle_mint_test.go @@ -21,6 +21,7 @@ import ( "google.golang.org/grpc" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" + "google.golang.org/protobuf/types/known/wrapperspb" "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb" "source.quilibrium.com/quilibrium/monorepo/node/consensus" qtime "source.quilibrium.com/quilibrium/monorepo/node/consensus/time" @@ -80,6 +81,8 @@ func (pubsub) AddPeerScore(peerId []byte, scoreDelta int64) {} func (pubsub) Reconnect(peerId []byte) error { return nil } func (pubsub) Bootstrap(context.Context) error { return nil } func (pubsub) DiscoverPeers(context.Context) error { return nil } +func (pubsub) IsPeerConnected(peerId []byte) bool { return false } +func (pubsub) Reachability() *wrapperspb.BoolValue { return nil } type outputs struct { difficulty uint32 diff --git a/node/p2p/blossomsub.go b/node/p2p/blossomsub.go index 81622ad..a5ba56d 100644 --- a/node/p2p/blossomsub.go +++ b/node/p2p/blossomsub.go @@ -11,6 +11,7 @@ import ( "math/bits" "net" "sync" + "sync/atomic" "time" "github.com/libp2p/go-libp2p" @@ -38,6 +39,7 @@ import ( "go.uber.org/zap" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" + "google.golang.org/protobuf/types/known/wrapperspb" blossomsub "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub" "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb" "source.quilibrium.com/quilibrium/monorepo/node/config" @@ -71,18 +73,19 @@ type appScore struct { } type BlossomSub struct { - ps *blossomsub.PubSub - ctx context.Context - logger *zap.Logger - peerID peer.ID - bitmaskMap map[string]*blossomsub.Bitmask - h host.Host - signKey crypto.PrivKey - peerScore map[string]*appScore - peerScoreMx sync.Mutex - network uint8 - bootstrap internal.PeerConnector - discovery internal.PeerConnector + ps *blossomsub.PubSub + ctx context.Context + logger *zap.Logger + peerID peer.ID + bitmaskMap map[string]*blossomsub.Bitmask + h host.Host + signKey crypto.PrivKey + peerScore map[string]*appScore + peerScoreMx sync.Mutex + network uint8 + bootstrap internal.PeerConnector + discovery internal.PeerConnector + reachability atomic.Pointer[network.Reachability] } var _ PubSub = (*BlossomSub)(nil) @@ -337,7 +340,9 @@ func NewBlossomSub( if !ok { return } - switch state := evt.(event.EvtLocalReachabilityChanged).Reachability; state { + state := evt.(event.EvtLocalReachabilityChanged).Reachability + bs.reachability.Store(&state) + switch state { case network.ReachabilityPublic: logger.Info("node is externally reachable") case network.ReachabilityPrivate: @@ -752,6 +757,27 @@ func (b *BlossomSub) GetRandomPeer(bitmask []byte) ([]byte, error) { return []byte(peers[sel.Int64()]), nil } +func (b *BlossomSub) IsPeerConnected(peerId []byte) bool { + peerID := peer.ID(peerId) + connectedness := b.h.Network().Connectedness(peerID) + return connectedness == network.Connected || connectedness == network.Limited +} + +func (b *BlossomSub) Reachability() *wrapperspb.BoolValue { + reachability := b.reachability.Load() + if reachability == nil { + return nil + } + switch *reachability { + case network.ReachabilityPublic: + return wrapperspb.Bool(true) + case network.ReachabilityPrivate: + return wrapperspb.Bool(false) + default: + return nil + } +} + func initDHT( ctx context.Context, logger *zap.Logger, diff --git a/node/p2p/pubsub.go b/node/p2p/pubsub.go index 3b7227a..cb2c761 100644 --- a/node/p2p/pubsub.go +++ b/node/p2p/pubsub.go @@ -6,6 +6,7 @@ import ( "github.com/libp2p/go-libp2p/core/peer" "github.com/multiformats/go-multiaddr" "google.golang.org/grpc" + "google.golang.org/protobuf/types/known/wrapperspb" "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb" "source.quilibrium.com/quilibrium/monorepo/node/protobufs" ) @@ -55,4 +56,6 @@ type PubSub interface { Bootstrap(ctx context.Context) error DiscoverPeers(ctx context.Context) error GetNetwork() uint + IsPeerConnected(peerId []byte) bool + Reachability() *wrapperspb.BoolValue } diff --git a/node/protobufs/data.pb.go b/node/protobufs/data.pb.go index 099acd5..e232f97 100644 --- a/node/protobufs/data.pb.go +++ b/node/protobufs/data.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 -// protoc v3.21.12 +// protoc-gen-go v1.34.1 +// protoc v5.27.0 // source: data.proto package protobufs @@ -9,6 +9,7 @@ package protobufs import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" reflect "reflect" sync "sync" ) @@ -72,13 +73,14 @@ type DataPeer struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - PeerId []byte `protobuf:"bytes,1,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` - Multiaddr string `protobuf:"bytes,2,opt,name=multiaddr,proto3" json:"multiaddr,omitempty"` - MaxFrame uint64 `protobuf:"varint,3,opt,name=max_frame,json=maxFrame,proto3" json:"max_frame,omitempty"` - Timestamp int64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - Version []byte `protobuf:"bytes,5,opt,name=version,proto3" json:"version,omitempty"` - TotalDistance []byte `protobuf:"bytes,8,opt,name=total_distance,json=totalDistance,proto3" json:"total_distance,omitempty"` - PatchVersion []byte `protobuf:"bytes,9,opt,name=patch_version,json=patchVersion,proto3" json:"patch_version,omitempty"` + PeerId []byte `protobuf:"bytes,1,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` + Multiaddr string `protobuf:"bytes,2,opt,name=multiaddr,proto3" json:"multiaddr,omitempty"` + MaxFrame uint64 `protobuf:"varint,3,opt,name=max_frame,json=maxFrame,proto3" json:"max_frame,omitempty"` + Timestamp int64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Version []byte `protobuf:"bytes,5,opt,name=version,proto3" json:"version,omitempty"` + TotalDistance []byte `protobuf:"bytes,8,opt,name=total_distance,json=totalDistance,proto3" json:"total_distance,omitempty"` + PatchVersion []byte `protobuf:"bytes,9,opt,name=patch_version,json=patchVersion,proto3" json:"patch_version,omitempty"` + ExternallyReachable *wrapperspb.BoolValue `protobuf:"bytes,10,opt,name=externally_reachable,json=externallyReachable,proto3" json:"externally_reachable,omitempty"` } func (x *DataPeer) Reset() { @@ -162,6 +164,13 @@ func (x *DataPeer) GetPatchVersion() []byte { return nil } +func (x *DataPeer) GetExternallyReachable() *wrapperspb.BoolValue { + if x != nil { + return x.ExternallyReachable + } + return nil +} + type DataCompressedSync struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1086,7 +1095,9 @@ var File_data_proto protoreflect.FileDescriptor var file_data_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x17, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, - 0x74, 0x61, 0x2e, 0x70, 0x62, 0x1a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, + 0x74, 0x61, 0x2e, 0x70, 0x62, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0b, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0a, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0a, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5e, 0x0a, 0x14, 0x44, 0x61, 0x74, @@ -1095,7 +1106,7 @@ var file_data_proto_rawDesc = []byte{ 0x21, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x50, 0x65, 0x65, 0x72, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x52, 0x09, - 0x70, 0x65, 0x65, 0x72, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x85, 0x02, 0x0a, 0x08, 0x44, 0x61, + 0x70, 0x65, 0x65, 0x72, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x22, 0xd4, 0x02, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x50, 0x65, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, @@ -1109,204 +1120,209 @@ var file_data_proto_rawDesc = []byte{ 0x61, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0c, 0x70, 0x61, 0x74, 0x63, 0x68, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4a, 0x04, - 0x08, 0x06, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, - 0x79, 0x22, 0xd4, 0x02, 0x0a, 0x12, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x2a, 0x0a, 0x11, 0x66, 0x72, 0x6f, 0x6d, - 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0f, 0x66, 0x72, 0x6f, 0x6d, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x6f, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, - 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x74, - 0x6f, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x5a, 0x0a, 0x16, - 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, - 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x71, - 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, - 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, - 0x6d, 0x65, 0x52, 0x14, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x6f, - 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x43, 0x0a, 0x06, 0x70, 0x72, 0x6f, 0x6f, - 0x66, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, - 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, - 0x66, 0x73, 0x4d, 0x61, 0x70, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x12, 0x49, 0x0a, - 0x08, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x2d, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, - 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x52, 0x08, - 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x97, 0x01, 0x0a, 0x19, 0x53, 0x79, 0x6e, - 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, - 0x1c, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x12, 0x43, 0x0a, - 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x53, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0xaa, 0x02, 0x0a, 0x20, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x70, 0x72, 0x65, 0x66, 0x6c, - 0x69, 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x71, 0x75, 0x69, - 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, - 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, - 0x73, 0x50, 0x72, 0x65, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x48, 0x00, 0x52, 0x09, 0x70, 0x72, - 0x65, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x12, 0x48, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, - 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x5c, 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x71, 0x75, 0x69, 0x6c, - 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, - 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, - 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, - 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, - 0x0e, 0x0a, 0x0c, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, - 0xce, 0x01, 0x0a, 0x21, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x70, 0x72, 0x65, 0x66, 0x6c, 0x69, 0x67, - 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, - 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, - 0x72, 0x65, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x48, 0x00, 0x52, 0x09, 0x70, 0x72, 0x65, 0x66, - 0x6c, 0x69, 0x67, 0x68, 0x74, 0x12, 0x49, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x52, 0x0c, 0x70, 0x61, 0x74, 0x63, 0x68, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4d, + 0x0a, 0x14, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x72, 0x65, 0x61, + 0x63, 0x68, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, + 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x6c, 0x79, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x6c, 0x65, 0x4a, 0x04, 0x08, + 0x06, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x52, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, + 0x22, 0xd4, 0x02, 0x0a, 0x12, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x2a, 0x0a, 0x11, 0x66, 0x72, 0x6f, 0x6d, 0x5f, + 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0f, 0x66, 0x72, 0x6f, 0x6d, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x6f, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x74, 0x6f, + 0x46, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x5a, 0x0a, 0x16, 0x74, + 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x66, + 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, + 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, + 0x65, 0x52, 0x14, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x6f, 0x63, + 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x43, 0x0a, 0x06, 0x70, 0x72, 0x6f, 0x6f, 0x66, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, - 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, - 0x53, 0x79, 0x6e, 0x63, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x42, 0x0e, 0x0a, 0x0c, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x22, 0xa1, 0x01, 0x0a, 0x12, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, - 0x6f, 0x6f, 0x66, 0x73, 0x4d, 0x61, 0x70, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, - 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x66, - 0x72, 0x61, 0x6d, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, - 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, - 0x12, 0x52, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, - 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, - 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, - 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, - 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3e, 0x0a, 0x14, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, - 0x6e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x12, 0x12, 0x0a, 0x04, - 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, - 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, - 0x64, 0x61, 0x74, 0x61, 0x22, 0x7b, 0x0a, 0x17, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, - 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x12, - 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, - 0x19, 0x0a, 0x08, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x74, 0x79, 0x70, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, - 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x0c, 0x52, 0x0d, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, - 0x73, 0x22, 0x51, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x46, 0x72, 0x61, 0x6d, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, - 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, - 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x70, - 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x65, - 0x65, 0x72, 0x49, 0x64, 0x22, 0x70, 0x0a, 0x11, 0x44, 0x61, 0x74, 0x61, 0x46, 0x72, 0x61, 0x6d, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0b, 0x63, 0x6c, 0x6f, - 0x63, 0x6b, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, + 0x62, 0x2e, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, + 0x73, 0x4d, 0x61, 0x70, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x12, 0x49, 0x0a, 0x08, + 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, + 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, + 0x6f, 0x6e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x52, 0x08, 0x73, + 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x97, 0x01, 0x0a, 0x19, 0x53, 0x79, 0x6e, 0x63, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, + 0x0a, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x12, 0x43, 0x0a, 0x08, + 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, + 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0xaa, 0x02, 0x0a, 0x20, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x70, 0x72, 0x65, 0x66, 0x6c, 0x69, + 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, + 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, + 0x50, 0x72, 0x65, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x48, 0x00, 0x52, 0x09, 0x70, 0x72, 0x65, + 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x12, 0x48, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, + 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x5c, 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, + 0x70, 0x62, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0e, + 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0e, + 0x0a, 0x0c, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xce, + 0x01, 0x0a, 0x21, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x70, 0x72, 0x65, 0x66, 0x6c, 0x69, 0x67, 0x68, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, + 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x72, + 0x65, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x48, 0x00, 0x52, 0x09, 0x70, 0x72, 0x65, 0x66, 0x6c, + 0x69, 0x67, 0x68, 0x74, 0x12, 0x49, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, + 0x2e, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, + 0x79, 0x6e, 0x63, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, + 0x0e, 0x0a, 0x0c, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0xa1, 0x01, 0x0a, 0x12, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, + 0x6f, 0x66, 0x73, 0x4d, 0x61, 0x70, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, + 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x66, 0x72, + 0x61, 0x6d, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, + 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x12, + 0x52, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x49, + 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x22, 0x3e, 0x0a, 0x14, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, + 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x68, + 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, + 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, + 0x61, 0x74, 0x61, 0x22, 0x7b, 0x0a, 0x17, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, + 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x12, 0x1e, + 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x19, + 0x0a, 0x08, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x74, 0x79, 0x70, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x67, + 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0c, 0x52, 0x0d, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, + 0x22, 0x51, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x46, 0x72, 0x61, 0x6d, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, + 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, + 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x65, 0x65, + 0x72, 0x49, 0x64, 0x22, 0x70, 0x0a, 0x11, 0x44, 0x61, 0x74, 0x61, 0x46, 0x72, 0x61, 0x6d, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0b, 0x63, 0x6c, 0x6f, 0x63, + 0x6b, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, + 0x61, 0x6d, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, + 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x51, 0x0a, 0x17, 0x50, 0x72, 0x65, 0x4d, 0x69, 0x64, 0x6e, + 0x69, 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, + 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x69, + 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x34, 0x0a, 0x1c, 0x50, 0x72, 0x65, 0x4d, + 0x69, 0x64, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x22, 0x97, + 0x01, 0x0a, 0x10, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, + 0x61, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x47, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, + 0x61, 0x6d, 0x65, 0x52, 0x0b, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, + 0x12, 0x16, 0x0a, 0x06, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x06, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x22, 0xe6, 0x01, 0x0a, 0x15, 0x43, 0x68, 0x61, + 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x63, + 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x63, 0x6f, 0x72, 0x65, 0x12, + 0x45, 0x0a, 0x0b, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, + 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x6f, 0x63, + 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x21, + 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, + 0x79, 0x22, 0x30, 0x0a, 0x16, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x32, 0xff, 0x05, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x76, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, - 0x72, 0x61, 0x6d, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, - 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x51, 0x0a, 0x17, 0x50, 0x72, 0x65, 0x4d, 0x69, 0x64, - 0x6e, 0x69, 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x69, - 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, - 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x34, 0x0a, 0x1c, 0x50, 0x72, 0x65, - 0x4d, 0x69, 0x64, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, - 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x22, - 0x97, 0x01, 0x0a, 0x10, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x62, 0x72, 0x6f, 0x61, 0x64, - 0x63, 0x61, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x47, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, 0x63, - 0x6b, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, - 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, - 0x72, 0x61, 0x6d, 0x65, 0x52, 0x0b, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, - 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x06, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x22, 0xe6, 0x01, 0x0a, 0x15, 0x43, 0x68, - 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, - 0x63, 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x63, 0x6f, 0x72, 0x65, - 0x12, 0x45, 0x0a, 0x0b, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, - 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, - 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x6f, - 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, - 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, - 0x74, 0x79, 0x22, 0x30, 0x0a, 0x16, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x50, - 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x32, 0xff, 0x05, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x76, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, - 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, - 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, + 0x72, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, + 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x30, 0x01, 0x12, 0x9a, 0x01, 0x0a, 0x1d, + 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x39, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x30, 0x01, 0x12, 0x9a, 0x01, 0x0a, - 0x1d, 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x39, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, + 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x76, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x2e, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x32, 0x50, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x1a, 0x2e, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x32, 0x50, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x28, 0x01, 0x30, 0x01, + 0x12, 0x68, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x46, 0x72, 0x61, 0x6d, 0x65, + 0x12, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x61, + 0x74, 0x61, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, - 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3a, 0x2e, 0x71, 0x75, 0x69, 0x6c, - 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, - 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x76, 0x0a, 0x10, 0x47, 0x65, 0x74, - 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x2e, 0x2e, - 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x32, 0x50, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x1a, 0x2e, 0x2e, - 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x32, 0x50, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x28, 0x01, 0x30, - 0x01, 0x12, 0x68, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x46, 0x72, 0x61, 0x6d, - 0x65, 0x12, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x44, - 0x61, 0x74, 0x61, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x46, 0x72, - 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x73, 0x0a, 0x15, 0x48, - 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x50, 0x72, 0x65, 0x4d, 0x69, 0x64, 0x6e, 0x69, 0x67, 0x68, 0x74, - 0x4d, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4d, - 0x69, 0x6e, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, - 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x65, 0x4d, 0x69, 0x64, 0x6e, - 0x69, 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x83, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x50, 0x72, 0x65, 0x4d, 0x69, 0x64, 0x6e, 0x69, - 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x35, 0x2e, + 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x46, 0x72, 0x61, + 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x73, 0x0a, 0x15, 0x48, 0x61, + 0x6e, 0x64, 0x6c, 0x65, 0x50, 0x72, 0x65, 0x4d, 0x69, 0x64, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x4d, + 0x69, 0x6e, 0x74, 0x12, 0x28, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x69, + 0x6e, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x65, 0x4d, 0x69, 0x64, 0x6e, 0x69, - 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x50, - 0x72, 0x65, 0x4d, 0x69, 0x64, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x8c, 0x01, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x49, - 0x50, 0x43, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7a, 0x0a, 0x17, 0x43, 0x61, 0x6c, - 0x63, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x50, - 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x43, - 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x43, - 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3a, 0x5a, 0x38, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x71, - 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x6d, 0x6f, 0x6e, 0x6f, 0x72, 0x65, - 0x70, 0x6f, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x83, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x50, 0x72, 0x65, 0x4d, 0x69, 0x64, 0x6e, 0x69, 0x67, + 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x35, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, + 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x65, 0x4d, 0x69, 0x64, 0x6e, 0x69, 0x67, + 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, + 0x65, 0x4d, 0x69, 0x64, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x8c, 0x01, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x49, 0x50, + 0x43, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7a, 0x0a, 0x17, 0x43, 0x61, 0x6c, 0x63, + 0x75, 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x12, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x68, + 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x68, + 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3a, 0x5a, 0x38, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x6d, 0x6f, 0x6e, 0x6f, 0x72, 0x65, 0x70, + 0x6f, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x73, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1339,47 +1355,49 @@ var file_data_proto_goTypes = []interface{}{ (*FrameRebroadcast)(nil), // 13: quilibrium.node.data.pb.FrameRebroadcast (*ChallengeProofRequest)(nil), // 14: quilibrium.node.data.pb.ChallengeProofRequest (*ChallengeProofResponse)(nil), // 15: quilibrium.node.data.pb.ChallengeProofResponse - (*ClockFrame)(nil), // 16: quilibrium.node.clock.pb.ClockFrame - (*Ed448Signature)(nil), // 17: quilibrium.node.keys.pb.Ed448Signature - (*ClockFramesPreflight)(nil), // 18: quilibrium.node.clock.pb.ClockFramesPreflight - (*ClockFramesRequest)(nil), // 19: quilibrium.node.clock.pb.ClockFramesRequest - (*P2PChannelEnvelope)(nil), // 20: quilibrium.node.channel.pb.P2PChannelEnvelope - (*MintCoinRequest)(nil), // 21: quilibrium.node.node.pb.MintCoinRequest + (*wrapperspb.BoolValue)(nil), // 16: google.protobuf.BoolValue + (*ClockFrame)(nil), // 17: quilibrium.node.clock.pb.ClockFrame + (*Ed448Signature)(nil), // 18: quilibrium.node.keys.pb.Ed448Signature + (*ClockFramesPreflight)(nil), // 19: quilibrium.node.clock.pb.ClockFramesPreflight + (*ClockFramesRequest)(nil), // 20: quilibrium.node.clock.pb.ClockFramesRequest + (*P2PChannelEnvelope)(nil), // 21: quilibrium.node.channel.pb.P2PChannelEnvelope + (*MintCoinRequest)(nil), // 22: quilibrium.node.node.pb.MintCoinRequest } var file_data_proto_depIdxs = []int32{ 1, // 0: quilibrium.node.data.pb.DataPeerListAnnounce.peer:type_name -> quilibrium.node.data.pb.DataPeer - 16, // 1: quilibrium.node.data.pb.DataCompressedSync.truncated_clock_frames:type_name -> quilibrium.node.clock.pb.ClockFrame - 6, // 2: quilibrium.node.data.pb.DataCompressedSync.proofs:type_name -> quilibrium.node.data.pb.InclusionProofsMap - 7, // 3: quilibrium.node.data.pb.DataCompressedSync.segments:type_name -> quilibrium.node.data.pb.InclusionSegmentsMap - 17, // 4: quilibrium.node.data.pb.SyncRequestAuthentication.response:type_name -> quilibrium.node.keys.pb.Ed448Signature - 18, // 5: quilibrium.node.data.pb.DataCompressedSyncRequestMessage.preflight:type_name -> quilibrium.node.clock.pb.ClockFramesPreflight - 19, // 6: quilibrium.node.data.pb.DataCompressedSyncRequestMessage.request:type_name -> quilibrium.node.clock.pb.ClockFramesRequest - 3, // 7: quilibrium.node.data.pb.DataCompressedSyncRequestMessage.authentication:type_name -> quilibrium.node.data.pb.SyncRequestAuthentication - 18, // 8: quilibrium.node.data.pb.DataCompressedSyncResponseMessage.preflight:type_name -> quilibrium.node.clock.pb.ClockFramesPreflight - 2, // 9: quilibrium.node.data.pb.DataCompressedSyncResponseMessage.response:type_name -> quilibrium.node.data.pb.DataCompressedSync - 8, // 10: quilibrium.node.data.pb.InclusionProofsMap.commitments:type_name -> quilibrium.node.data.pb.InclusionCommitmentsMap - 16, // 11: quilibrium.node.data.pb.DataFrameResponse.clock_frame:type_name -> quilibrium.node.clock.pb.ClockFrame - 16, // 12: quilibrium.node.data.pb.FrameRebroadcast.clock_frames:type_name -> quilibrium.node.clock.pb.ClockFrame - 16, // 13: quilibrium.node.data.pb.ChallengeProofRequest.clock_frame:type_name -> quilibrium.node.clock.pb.ClockFrame - 19, // 14: quilibrium.node.data.pb.DataService.GetCompressedSyncFrames:input_type -> quilibrium.node.clock.pb.ClockFramesRequest - 4, // 15: quilibrium.node.data.pb.DataService.NegotiateCompressedSyncFrames:input_type -> quilibrium.node.data.pb.DataCompressedSyncRequestMessage - 20, // 16: quilibrium.node.data.pb.DataService.GetPublicChannel:input_type -> quilibrium.node.channel.pb.P2PChannelEnvelope - 9, // 17: quilibrium.node.data.pb.DataService.GetDataFrame:input_type -> quilibrium.node.data.pb.GetDataFrameRequest - 21, // 18: quilibrium.node.data.pb.DataService.HandlePreMidnightMint:input_type -> quilibrium.node.node.pb.MintCoinRequest - 12, // 19: quilibrium.node.data.pb.DataService.GetPreMidnightMintStatus:input_type -> quilibrium.node.data.pb.PreMidnightMintStatusRequest - 14, // 20: quilibrium.node.data.pb.DataIPCService.CalculateChallengeProof:input_type -> quilibrium.node.data.pb.ChallengeProofRequest - 2, // 21: quilibrium.node.data.pb.DataService.GetCompressedSyncFrames:output_type -> quilibrium.node.data.pb.DataCompressedSync - 5, // 22: quilibrium.node.data.pb.DataService.NegotiateCompressedSyncFrames:output_type -> quilibrium.node.data.pb.DataCompressedSyncResponseMessage - 20, // 23: quilibrium.node.data.pb.DataService.GetPublicChannel:output_type -> quilibrium.node.channel.pb.P2PChannelEnvelope - 10, // 24: quilibrium.node.data.pb.DataService.GetDataFrame:output_type -> quilibrium.node.data.pb.DataFrameResponse - 11, // 25: quilibrium.node.data.pb.DataService.HandlePreMidnightMint:output_type -> quilibrium.node.data.pb.PreMidnightMintResponse - 11, // 26: quilibrium.node.data.pb.DataService.GetPreMidnightMintStatus:output_type -> quilibrium.node.data.pb.PreMidnightMintResponse - 15, // 27: quilibrium.node.data.pb.DataIPCService.CalculateChallengeProof:output_type -> quilibrium.node.data.pb.ChallengeProofResponse - 21, // [21:28] is the sub-list for method output_type - 14, // [14:21] is the sub-list for method input_type - 14, // [14:14] is the sub-list for extension type_name - 14, // [14:14] is the sub-list for extension extendee - 0, // [0:14] is the sub-list for field type_name + 16, // 1: quilibrium.node.data.pb.DataPeer.externally_reachable:type_name -> google.protobuf.BoolValue + 17, // 2: quilibrium.node.data.pb.DataCompressedSync.truncated_clock_frames:type_name -> quilibrium.node.clock.pb.ClockFrame + 6, // 3: quilibrium.node.data.pb.DataCompressedSync.proofs:type_name -> quilibrium.node.data.pb.InclusionProofsMap + 7, // 4: quilibrium.node.data.pb.DataCompressedSync.segments:type_name -> quilibrium.node.data.pb.InclusionSegmentsMap + 18, // 5: quilibrium.node.data.pb.SyncRequestAuthentication.response:type_name -> quilibrium.node.keys.pb.Ed448Signature + 19, // 6: quilibrium.node.data.pb.DataCompressedSyncRequestMessage.preflight:type_name -> quilibrium.node.clock.pb.ClockFramesPreflight + 20, // 7: quilibrium.node.data.pb.DataCompressedSyncRequestMessage.request:type_name -> quilibrium.node.clock.pb.ClockFramesRequest + 3, // 8: quilibrium.node.data.pb.DataCompressedSyncRequestMessage.authentication:type_name -> quilibrium.node.data.pb.SyncRequestAuthentication + 19, // 9: quilibrium.node.data.pb.DataCompressedSyncResponseMessage.preflight:type_name -> quilibrium.node.clock.pb.ClockFramesPreflight + 2, // 10: quilibrium.node.data.pb.DataCompressedSyncResponseMessage.response:type_name -> quilibrium.node.data.pb.DataCompressedSync + 8, // 11: quilibrium.node.data.pb.InclusionProofsMap.commitments:type_name -> quilibrium.node.data.pb.InclusionCommitmentsMap + 17, // 12: quilibrium.node.data.pb.DataFrameResponse.clock_frame:type_name -> quilibrium.node.clock.pb.ClockFrame + 17, // 13: quilibrium.node.data.pb.FrameRebroadcast.clock_frames:type_name -> quilibrium.node.clock.pb.ClockFrame + 17, // 14: quilibrium.node.data.pb.ChallengeProofRequest.clock_frame:type_name -> quilibrium.node.clock.pb.ClockFrame + 20, // 15: quilibrium.node.data.pb.DataService.GetCompressedSyncFrames:input_type -> quilibrium.node.clock.pb.ClockFramesRequest + 4, // 16: quilibrium.node.data.pb.DataService.NegotiateCompressedSyncFrames:input_type -> quilibrium.node.data.pb.DataCompressedSyncRequestMessage + 21, // 17: quilibrium.node.data.pb.DataService.GetPublicChannel:input_type -> quilibrium.node.channel.pb.P2PChannelEnvelope + 9, // 18: quilibrium.node.data.pb.DataService.GetDataFrame:input_type -> quilibrium.node.data.pb.GetDataFrameRequest + 22, // 19: quilibrium.node.data.pb.DataService.HandlePreMidnightMint:input_type -> quilibrium.node.node.pb.MintCoinRequest + 12, // 20: quilibrium.node.data.pb.DataService.GetPreMidnightMintStatus:input_type -> quilibrium.node.data.pb.PreMidnightMintStatusRequest + 14, // 21: quilibrium.node.data.pb.DataIPCService.CalculateChallengeProof:input_type -> quilibrium.node.data.pb.ChallengeProofRequest + 2, // 22: quilibrium.node.data.pb.DataService.GetCompressedSyncFrames:output_type -> quilibrium.node.data.pb.DataCompressedSync + 5, // 23: quilibrium.node.data.pb.DataService.NegotiateCompressedSyncFrames:output_type -> quilibrium.node.data.pb.DataCompressedSyncResponseMessage + 21, // 24: quilibrium.node.data.pb.DataService.GetPublicChannel:output_type -> quilibrium.node.channel.pb.P2PChannelEnvelope + 10, // 25: quilibrium.node.data.pb.DataService.GetDataFrame:output_type -> quilibrium.node.data.pb.DataFrameResponse + 11, // 26: quilibrium.node.data.pb.DataService.HandlePreMidnightMint:output_type -> quilibrium.node.data.pb.PreMidnightMintResponse + 11, // 27: quilibrium.node.data.pb.DataService.GetPreMidnightMintStatus:output_type -> quilibrium.node.data.pb.PreMidnightMintResponse + 15, // 28: quilibrium.node.data.pb.DataIPCService.CalculateChallengeProof:output_type -> quilibrium.node.data.pb.ChallengeProofResponse + 22, // [22:29] is the sub-list for method output_type + 15, // [15:22] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name } func init() { file_data_proto_init() } diff --git a/node/protobufs/data.proto b/node/protobufs/data.proto index d162742..34ee4ce 100644 --- a/node/protobufs/data.proto +++ b/node/protobufs/data.proto @@ -4,6 +4,8 @@ package quilibrium.node.data.pb; option go_package = "source.quilibrium.com/quilibrium/monorepo/node/protobufs"; +import "google/protobuf/wrappers.proto"; + import "channel.proto"; import "clock.proto"; import "keys.proto"; @@ -27,6 +29,7 @@ message DataPeer { reserved "public_key"; bytes total_distance = 8; bytes patch_version = 9; + google.protobuf.BoolValue externally_reachable = 10; } message DataCompressedSync { From e0993a94ead62af8e05c7979498a3a00d95212dc Mon Sep 17 00:00:00 2001 From: petricadaipegsp <155911522+petricadaipegsp@users.noreply.github.com> Date: Sun, 1 Dec 2024 22:24:38 +0100 Subject: [PATCH 06/14] Avoid further copies of the tries (#393) * Revert logging change * Avoid further copies of tries * Avoid sync on beacon * Avoid recreating the address for each transaction --- node/consensus/data/consensus_frames.go | 5 +-- node/consensus/data/main_data_loop.go | 35 ++++++++++++++++--- node/consensus/data/message_handler.go | 5 ++- node/consensus/data/peer_messaging.go | 6 ++-- node/consensus/data/prover_lookup.go | 9 +---- .../token/application/token_application.go | 6 ---- .../token/application/token_handle_mint.go | 7 ---- .../token/token_execution_engine.go | 2 +- 8 files changed, 38 insertions(+), 37 deletions(-) diff --git a/node/consensus/data/consensus_frames.go b/node/consensus/data/consensus_frames.go index 2568427..3561a77 100644 --- a/node/consensus/data/consensus_frames.go +++ b/node/consensus/data/consensus_frames.go @@ -117,9 +117,6 @@ func (e *DataClockConsensusEngine) prove( "applied transitions", zap.Int("successful", len(validTransactions.Requests)), zap.Int("failed", len(invalidTransactions.Requests)), - zap.Uint64("mint_out_of_order", app.MintOutOfOrder), - zap.Uint64("mint_too_old", app.MintTooOld), - zap.Uint64("mint_tree_verification_failed", app.MintTreeVerificationFailure), ) outputState, err := app.MaterializeStateFromApplication() @@ -223,7 +220,7 @@ func (e *DataClockConsensusEngine) prove( } func (e *DataClockConsensusEngine) GetAheadPeers(frameNumber uint64) []internal.PeerCandidate { - if e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) { + if e.FrameProverTrieContains(0, e.provingKeyAddress) { return nil } diff --git a/node/consensus/data/main_data_loop.go b/node/consensus/data/main_data_loop.go index b30b3b5..0dd9cbf 100644 --- a/node/consensus/data/main_data_loop.go +++ b/node/consensus/data/main_data_loop.go @@ -59,10 +59,35 @@ func (e *DataClockConsensusEngine) GetFrameProverTrie(i int) *tries.RollingFrece return newTrie } +func (e *DataClockConsensusEngine) FrameProverTriesContains( + key []byte, +) bool { + e.frameProverTriesMx.RLock() + defer e.frameProverTriesMx.RUnlock() + for _, trie := range e.frameProverTries { + if trie.Contains(key) { + return true + } + } + return false +} + +func (e *DataClockConsensusEngine) FrameProverTrieContains( + i int, + key []byte, +) bool { + e.frameProverTriesMx.RLock() + defer e.frameProverTriesMx.RUnlock() + if i < 0 || i >= len(e.frameProverTries) { + return false + } + return e.frameProverTries[i].Contains(key) +} + func (e *DataClockConsensusEngine) runFramePruning() { defer e.wg.Done() // A full prover should _never_ do this - if e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) || + if e.FrameProverTrieContains(0, e.provingKeyAddress) || e.config.Engine.MaxFrames == -1 || e.config.Engine.FullProver { e.logger.Info("frame pruning not enabled") return @@ -105,7 +130,7 @@ func (e *DataClockConsensusEngine) runFramePruning() { func (e *DataClockConsensusEngine) runSync() { defer e.wg.Done() // small optimization, beacon should never collect for now: - if e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) { + if e.FrameProverTrieContains(0, e.provingKeyAddress) { return } @@ -147,7 +172,7 @@ func (e *DataClockConsensusEngine) runLoop() { } if runOnce { - if e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) { + if e.FrameProverTrieContains(0, e.provingKeyAddress) { dataFrame, err := e.dataTimeReel.Head() if err != nil { panic(err) @@ -165,7 +190,7 @@ func (e *DataClockConsensusEngine) runLoop() { e.validationFilterMx.Lock() e.validationFilter = make(map[string]struct{}, len(e.validationFilter)) e.validationFilterMx.Unlock() - if e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) { + if e.FrameProverTrieContains(0, e.provingKeyAddress) { if err = e.publishProof(dataFrame); err != nil { e.logger.Error("could not publish", zap.Error(err)) e.stateMx.Lock() @@ -191,7 +216,7 @@ func (e *DataClockConsensusEngine) processFrame( zap.Duration("frame_age", frametime.Since(dataFrame)), ) var err error - if !e.GetFrameProverTrie(0).Contains(e.provingKeyBytes) { + if !e.FrameProverTrieContains(0, e.provingKeyAddress) { select { case e.requestSyncCh <- struct{}{}: default: diff --git a/node/consensus/data/message_handler.go b/node/consensus/data/message_handler.go index 6a8ad83..91d3e83 100644 --- a/node/consensus/data/message_handler.go +++ b/node/consensus/data/message_handler.go @@ -182,8 +182,7 @@ func (e *DataClockConsensusEngine) handleClockFrame( return errors.Wrap(err, "handle clock frame data") } - trie := e.GetFrameProverTrie(0) - if !trie.Contains(addr.FillBytes(make([]byte, 32))) { + if !e.FrameProverTrieContains(0, addr.FillBytes(make([]byte, 32))) { e.logger.Debug( "prover not in trie at frame, address may be in fork", zap.Binary("address", address), @@ -370,7 +369,7 @@ func TokenRequestIdentifiers(transition *protobufs.TokenRequest) []string { func (e *DataClockConsensusEngine) handleTokenRequest( transition *protobufs.TokenRequest, ) error { - if e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) { + if e.FrameProverTrieContains(0, e.provingKeyAddress) { identifiers := TokenRequestIdentifiers(transition) e.stagedTransactionsMx.Lock() diff --git a/node/consensus/data/peer_messaging.go b/node/consensus/data/peer_messaging.go index d51deec..a8a991c 100644 --- a/node/consensus/data/peer_messaging.go +++ b/node/consensus/data/peer_messaging.go @@ -128,7 +128,7 @@ func (e *DataClockConsensusEngine) GetPreMidnightMintStatus( ctx context.Context, t *protobufs.PreMidnightMintStatusRequest, ) (*protobufs.PreMidnightMintResponse, error) { - if !e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) { + if !e.FrameProverTrieContains(0, e.provingKeyAddress) { return nil, errors.Wrap( errors.New("wrong destination"), "get pre midnight mint status", @@ -182,7 +182,7 @@ func (e *DataClockConsensusEngine) GetPreMidnightMintStatus( func (e *DataClockConsensusEngine) handleMint( t *protobufs.MintCoinRequest, ) ([]byte, error) { - if !e.GetFrameProverTrie(0).Contains(e.provingKeyAddress) { + if !e.FrameProverTrieContains(0, e.provingKeyAddress) { return nil, errors.Wrap(errors.New("wrong destination"), "handle mint") } @@ -243,7 +243,7 @@ func (e *DataClockConsensusEngine) handleMint( t.Proofs[0], []byte("pre-dusk"), ) && (!bytes.Equal(t.Proofs[1], make([]byte, 32)) || - time.Now().Unix() < 1730523600) && e.GetFrameProverTrie(0).Contains( + time.Now().Unix() < 1730523600) && e.FrameProverTrieContains(0, e.provingKeyAddress, ) { prevInput := []byte{} diff --git a/node/consensus/data/prover_lookup.go b/node/consensus/data/prover_lookup.go index 8f9ddc3..ca45b9a 100644 --- a/node/consensus/data/prover_lookup.go +++ b/node/consensus/data/prover_lookup.go @@ -55,13 +55,6 @@ func (e *DataClockConsensusEngine) IsInProverTrie(key []byte) bool { if err != nil { return false } - provingKeyAddress := h.FillBytes(make([]byte, 32)) - for _, tries := range e.GetFrameProverTries() { - if tries.Contains(provingKeyAddress) { - return true - } - } - - return false + return e.FrameProverTriesContains(provingKeyAddress) } diff --git a/node/execution/intrinsics/token/application/token_application.go b/node/execution/intrinsics/token/application/token_application.go index a493113..d7c57ca 100644 --- a/node/execution/intrinsics/token/application/token_application.go +++ b/node/execution/intrinsics/token/application/token_application.go @@ -5,7 +5,6 @@ import ( "crypto" "encoding/binary" "sync" - "sync/atomic" "github.com/iden3/go-iden3-crypto/poseidon" "github.com/pkg/errors" @@ -30,10 +29,6 @@ var TOKEN_ADDRESS = []byte{ } type TokenApplication struct { - MintTreeVerificationFailure uint64 - MintOutOfOrder uint64 - MintTooOld uint64 - Beacon []byte TokenOutputs *protobufs.TokenOutputs Tries []*tries.RollingFrecencyCritbitTrie @@ -193,7 +188,6 @@ func (a *TokenApplication) ApplyTransitions( } else if len(t.Mint.Proofs) >= 3 && currentFrameNumber > PROOF_FRAME_CUTOFF { frameNumber := binary.BigEndian.Uint64(t.Mint.Proofs[2]) if frameNumber < currentFrameNumber-2 { - atomic.AddUint64(&a.MintTooOld, 1) fails[i] = transition continue } diff --git a/node/execution/intrinsics/token/application/token_handle_mint.go b/node/execution/intrinsics/token/application/token_handle_mint.go index ebae60e..870396b 100644 --- a/node/execution/intrinsics/token/application/token_handle_mint.go +++ b/node/execution/intrinsics/token/application/token_handle_mint.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/binary" "math/big" - "sync/atomic" "github.com/iden3/go-iden3-crypto/poseidon" pcrypto "github.com/libp2p/go-libp2p/core/crypto" @@ -206,7 +205,6 @@ func (a *TokenApplication) handleMint( } if !verified { - atomic.AddUint64(&a.MintTreeVerificationFailure, 1) a.Logger.Debug( "tree verification failed", zap.String("peer_id", base58.Encode([]byte(peerId))), @@ -224,11 +222,6 @@ func (a *TokenApplication) handleMint( if previousFrame != nil { previousFrameNumber = previousFrame.FrameNumber } - if newFrameNumber < currentFrameNumber-2 { - atomic.AddUint64(&a.MintTooOld, 1) - } else { - atomic.AddUint64(&a.MintOutOfOrder, 1) - } a.Logger.Debug( "received out of order proofs, ignoring", zap.Error(err), diff --git a/node/execution/intrinsics/token/token_execution_engine.go b/node/execution/intrinsics/token/token_execution_engine.go index 107ab3c..b1288ec 100644 --- a/node/execution/intrinsics/token/token_execution_engine.go +++ b/node/execution/intrinsics/token/token_execution_engine.go @@ -473,7 +473,7 @@ func (e *TokenExecutionEngine) ProcessMessage( switch a.TypeUrl { case protobufs.TokenRequestType: - if e.clock.IsInProverTrie(e.proverPublicKey) { + if e.clock.FrameProverTriesContains(e.provingKeyAddress) { payload, err := proto.Marshal(a) if err != nil { return nil, errors.Wrap(err, "process message") From 7da27675dfb3d4b97fec5b697ad1821b38e83447 Mon Sep 17 00:00:00 2001 From: Cassandra Heart Date: Mon, 2 Dec 2024 02:55:58 -0600 Subject: [PATCH 07/14] update tripleratchet bindings and remove bad unwrap handling --- channel/channel_test.go | 241 ++++++++++++++++++ channel/go.mod | 13 + channel/go.sum | 71 ++++++ crates/channel/src/lib.rs | 75 +++--- crates/channel/src/protocols/doubleratchet.rs | 1 - crates/channel/src/protocols/tripleratchet.rs | 49 +++- 6 files changed, 409 insertions(+), 41 deletions(-) create mode 100644 channel/channel_test.go diff --git a/channel/channel_test.go b/channel/channel_test.go new file mode 100644 index 0000000..14cf04b --- /dev/null +++ b/channel/channel_test.go @@ -0,0 +1,241 @@ +package channel_test + +import ( + "bytes" + "crypto/rand" + "encoding/base64" + "fmt" + "sort" + "testing" + + "github.com/stretchr/testify/assert" + "source.quilibrium.com/quilibrium/monorepo/channel" + generated "source.quilibrium.com/quilibrium/monorepo/channel/generated/channel" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" +) + +type peer struct { + privKey *curves.ScalarEd448 + pubKey *curves.PointEd448 + pubKeyB64 string + identityKey *curves.ScalarEd448 + identityPubKey *curves.PointEd448 + signedPreKey *curves.ScalarEd448 + signedPrePubKey *curves.PointEd448 +} + +func generatePeer() *peer { + privKey := &curves.ScalarEd448{} + privKey = privKey.Random(rand.Reader).(*curves.ScalarEd448) + identityKey := &curves.ScalarEd448{} + identityKey = identityKey.Random(rand.Reader).(*curves.ScalarEd448) + signedPreKey := &curves.ScalarEd448{} + signedPreKey = signedPreKey.Random(rand.Reader).(*curves.ScalarEd448) + + pubkey := privKey.Point().Generator().Mul(privKey).(*curves.PointEd448) + pubKeyB64 := base64.StdEncoding.EncodeToString(pubkey.ToAffineCompressed()) + return &peer{ + privKey: privKey, + pubKey: pubkey, + pubKeyB64: pubKeyB64, + identityKey: identityKey, + identityPubKey: identityKey.Point().Generator().Mul(identityKey).(*curves.PointEd448), + signedPreKey: signedPreKey, + signedPrePubKey: signedPreKey.Point().Generator().Mul(signedPreKey).(*curves.PointEd448), + } +} + +func remapOutputs(maps map[string]map[string]string) map[string]map[string]string { + out := map[string]map[string]string{} + for k := range maps { + out[k] = map[string]string{} + } + + for k := range maps { + for ik, iv := range maps[k] { + out[ik][k] = iv + } + } + + return out +} + +func TestChannel(t *testing.T) { + peers := []*peer{} + for i := 0; i < 4; i++ { + peers = append(peers, generatePeer()) + } + + sort.Slice(peers, func(i, j int) bool { + return bytes.Compare(peers[i].pubKey.ToAffineCompressed(), peers[j].pubKey.ToAffineCompressed()) <= 0 + }) + + trs := map[string]*generated.TripleRatchetStateAndMetadata{} + + peerids := [][]byte{} + outs := map[string]map[string]string{} + for i := 0; i < 4; i++ { + outs[peers[i].pubKeyB64] = make(map[string]string) + peerids = append(peerids, + append( + append( + append([]byte{}, peers[i].pubKey.ToAffineCompressed()...), + peers[i].identityPubKey.ToAffineCompressed()..., + ), + peers[i].signedPrePubKey.ToAffineCompressed()..., + ), + ) + } + + for i := 0; i < 4; i++ { + otherPeerIds := [][]byte{} + for j := 0; j < 4; j++ { + if i != j { + otherPeerIds = append(otherPeerIds, peerids[j]) + } + } + + tr := channel.NewTripleRatchet( + otherPeerIds, + peers[i].privKey.Bytes(), + peers[i].identityKey.Bytes(), + peers[i].signedPreKey.Bytes(), + 2, + true, + ) + trs[peers[i].pubKeyB64] = &tr + outs[peers[i].pubKeyB64] = trs[peers[i].pubKeyB64].Metadata + } + + outs = remapOutputs(outs) + + for k := range trs { + for ik := range trs[k].Metadata { + delete(trs[k].Metadata, ik) + } + + for ik, iv := range outs[k] { + trs[k].Metadata[ik] = iv + } + } + + // round 1 + next := map[string]*generated.TripleRatchetStateAndMetadata{} + outs = map[string]map[string]string{} + for i := 0; i < 4; i++ { + tr := channel.TripleRatchetInitRound1( + *trs[peers[i].pubKeyB64], + ) + next[peers[i].pubKeyB64] = &tr + outs[peers[i].pubKeyB64] = next[peers[i].pubKeyB64].Metadata + } + + trs = next + outs = remapOutputs(outs) + + for k, _ := range trs { + for ik := range trs[k].Metadata { + delete(trs[k].Metadata, ik) + } + + for ik, iv := range outs[k] { + trs[k].Metadata[ik] = iv + } + } + + // round 2 + next = map[string]*generated.TripleRatchetStateAndMetadata{} + outs = map[string]map[string]string{} + for i := 0; i < 4; i++ { + tr := channel.TripleRatchetInitRound2( + *trs[peers[i].pubKeyB64], + ) + next[peers[i].pubKeyB64] = &tr + outs[peers[i].pubKeyB64] = next[peers[i].pubKeyB64].Metadata + } + + trs = next + outs = remapOutputs(outs) + + for k := range trs { + for ik := range trs[k].Metadata { + delete(trs[k].Metadata, ik) + } + + for ik, iv := range outs[k] { + trs[k].Metadata[ik] = iv + } + } + + // round 3 + next = map[string]*generated.TripleRatchetStateAndMetadata{} + outs = map[string]map[string]string{} + for i := 0; i < 4; i++ { + tr := channel.TripleRatchetInitRound3( + *trs[peers[i].pubKeyB64], + ) + next[peers[i].pubKeyB64] = &tr + outs[peers[i].pubKeyB64] = next[peers[i].pubKeyB64].Metadata + } + + trs = next + outs = remapOutputs(outs) + + for k := range trs { + for ik := range trs[k].Metadata { + delete(trs[k].Metadata, ik) + } + + for ik, iv := range outs[k] { + trs[k].Metadata[ik] = iv + } + } + + // round 4 + next = map[string]*generated.TripleRatchetStateAndMetadata{} + outs = map[string]map[string]string{} + for i := 0; i < 4; i++ { + tr := channel.TripleRatchetInitRound4( + *trs[peers[i].pubKeyB64], + ) + next[peers[i].pubKeyB64] = &tr + outs[peers[i].pubKeyB64] = next[peers[i].pubKeyB64].Metadata + } + + trs = next + outs = remapOutputs(outs) + + for k := range trs { + for ik := range trs[k].Metadata { + delete(trs[k].Metadata, ik) + } + + for ik, iv := range outs[k] { + trs[k].Metadata[ik] = iv + } + } + + for i := 0; i < 4; i++ { + send := channel.TripleRatchetEncrypt( + generated.TripleRatchetStateAndMessage{ + RatchetState: trs[peers[i].pubKeyB64].RatchetState, + Message: []byte(fmt.Sprintf("hi-%d", i)), + }, + ) + trs[peers[i].pubKeyB64].RatchetState = send.RatchetState + for j := 0; j < 4; j++ { + if i != j { + msg := channel.TripleRatchetDecrypt( + generated.TripleRatchetStateAndEnvelope{ + RatchetState: trs[peers[j].pubKeyB64].RatchetState, + Envelope: send.Envelope, + }, + ) + trs[peers[j].pubKeyB64].RatchetState = msg.RatchetState + if !bytes.Equal(msg.Message, []byte(fmt.Sprintf("hi-%d", i))) { + assert.FailNow(t, "mismatch messages") + } + } + } + } +} diff --git a/channel/go.mod b/channel/go.mod index c822d79..8121c98 100644 --- a/channel/go.mod +++ b/channel/go.mod @@ -8,6 +8,19 @@ replace source.quilibrium.com/quilibrium/monorepo/nekryptology => ../nekryptolog require github.com/stretchr/testify v1.9.0 require ( + filippo.io/edwards25519 v1.0.0-rc.1 // indirect + github.com/btcsuite/btcd v0.21.0-beta.0.20201114000516-e9c7a5ac6401 // indirect + github.com/bwesterb/go-ristretto v1.2.3 // indirect + github.com/consensys/gnark-crypto v0.5.3 // indirect + github.com/kr/pretty v0.2.1 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + +) + +require ( + github.com/cloudflare/circl v1.3.3 github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/crypto v0.24.0 // indirect diff --git a/channel/go.sum b/channel/go.sum index aadc4ec..647e2aa 100644 --- a/channel/go.sum +++ b/channel/go.sum @@ -1,13 +1,84 @@ +filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= +filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.21.0-beta.0.20201114000516-e9c7a5ac6401 h1:0tjUthKCaF8zwF9Qg7lfnep0xdo4n8WiFUfQPaMHX6g= +github.com/btcsuite/btcd v0.21.0-beta.0.20201114000516-e9c7a5ac6401/go.mod h1:Sv4JPQ3/M+teHz9Bo5jBpkNcP0x6r7rdihlNL/7tTAs= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/consensys/bavard v0.1.8-0.20210915155054-088da2f7f54a/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.5.3 h1:4xLFGZR3NWEH2zy+YzvzHicpToQR8FXFbfLNvpGB+rE= +github.com/consensys/gnark-crypto v0.5.3/go.mod h1:hOdPlWQV1gDLp7faZVeg8Y0iEPFaOUnCc4XeCCk96p0= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/crates/channel/src/lib.rs b/crates/channel/src/lib.rs index 931f558..00f9740 100644 --- a/crates/channel/src/lib.rs +++ b/crates/channel/src/lib.rs @@ -6,26 +6,33 @@ use protocols::{doubleratchet::{DoubleRatchetParticipant, P2PChannelEnvelope}, t pub(crate) mod protocols; +uniffi::include_scaffolding!("lib"); + +#[derive(Clone, PartialEq)] pub struct DoubleRatchetStateAndEnvelope { pub ratchet_state: String, pub envelope: String, } +#[derive(Clone, PartialEq)] pub struct DoubleRatchetStateAndMessage { pub ratchet_state: String, pub message: Vec, } +#[derive(Clone, PartialEq)] pub struct TripleRatchetStateAndMetadata { pub ratchet_state: String, pub metadata: HashMap, } +#[derive(Clone, PartialEq)] pub struct TripleRatchetStateAndEnvelope { pub ratchet_state: String, pub envelope: String, } +#[derive(Clone, PartialEq)] pub struct TripleRatchetStateAndMessage { pub ratchet_state: String, pub message: Vec, @@ -156,35 +163,35 @@ pub fn double_ratchet_decrypt(ratchet_state_and_envelope: DoubleRatchetStateAndE pub fn new_triple_ratchet(peers: &Vec>, peer_key: &Vec, identity_key: &Vec, signed_pre_key: &Vec, threshold: u64, async_dkg_ratchet: bool) -> TripleRatchetStateAndMetadata { if peer_key.len() != 56 { return TripleRatchetStateAndMetadata{ - ratchet_state: "".to_string(), + ratchet_state: "invalid peerkey".to_string(), metadata: HashMap::new(), }; } if identity_key.len() != 56 { return TripleRatchetStateAndMetadata{ - ratchet_state: "".to_string(), + ratchet_state: "invalid idk".to_string(), metadata: HashMap::new(), }; } if signed_pre_key.len() != 56 { return TripleRatchetStateAndMetadata{ - ratchet_state: "".to_string(), + ratchet_state: "invalid spk".to_string(), metadata: HashMap::new(), }; } if peers.len() < 3 { return TripleRatchetStateAndMetadata{ - ratchet_state: "".to_string(), + ratchet_state: "invalid peer count".to_string(), metadata: HashMap::new(), }; } if threshold > peers.len() as u64 { return TripleRatchetStateAndMetadata{ - ratchet_state: "".to_string(), + ratchet_state: "invalid threshold".to_string(), metadata: HashMap::new(), }; } @@ -205,7 +212,7 @@ pub fn new_triple_ratchet(peers: &Vec>, peer_key: &Vec, identity_key for pk in peers.iter() { if pk.len() != 171 { return TripleRatchetStateAndMetadata{ - ratchet_state: "".to_string(), + ratchet_state: "invalid peer key size".to_string(), metadata: HashMap::new(), }; } @@ -228,7 +235,7 @@ pub fn new_triple_ratchet(peers: &Vec>, peer_key: &Vec, identity_key if participant.is_err() { return TripleRatchetStateAndMetadata{ - ratchet_state: "".to_string(), + ratchet_state: participant.err().unwrap().to_string(), metadata: HashMap::new(), }; } @@ -239,7 +246,7 @@ pub fn new_triple_ratchet(peers: &Vec>, peer_key: &Vec, identity_key if participant_json.is_err() { return TripleRatchetStateAndMetadata{ - ratchet_state: "".to_string(), + ratchet_state: participant_json.err().unwrap().to_string(), metadata: HashMap::new(), }; } @@ -261,7 +268,7 @@ fn metadata_to_json(ratchet_state: &String, metadata: HashMap, P2PChanne let env = v.to_json(); if env.is_err() { return Err(TripleRatchetStateAndMetadata{ - ratchet_state: ratchet_state.to_string(), + ratchet_state: env.err().unwrap().to_string(), metadata: HashMap::new(), }); } @@ -276,9 +283,15 @@ fn json_to_metadata(ratchet_state_and_metadata: TripleRatchetStateAndMetadata, r for (k,v) in ratchet_state_and_metadata.metadata { let env = P2PChannelEnvelope::from_json(v); let kb = BASE64_STANDARD.decode(k); - if env.is_err() || kb.is_err() { + if env.is_err() { return Err(TripleRatchetStateAndMetadata{ - ratchet_state: ratchet_state.clone(), + ratchet_state: env.err().unwrap().to_string(), + metadata: HashMap::new(), + }); + } + if kb.is_err() { + return Err(TripleRatchetStateAndMetadata{ + ratchet_state: kb.err().unwrap().to_string(), metadata: HashMap::new(), }); } @@ -293,7 +306,7 @@ pub fn triple_ratchet_init_round_1(ratchet_state_and_metadata: TripleRatchetStat let tr = TripleRatchetParticipant::from_json(&ratchet_state); if tr.is_err() { return TripleRatchetStateAndMetadata{ - ratchet_state: ratchet_state, + ratchet_state: tr.err().unwrap().to_string(), metadata: HashMap::new(), }; } @@ -307,7 +320,7 @@ pub fn triple_ratchet_init_round_1(ratchet_state_and_metadata: TripleRatchetStat let result = trp.initialize(&metadata); if result.is_err() { return TripleRatchetStateAndMetadata{ - ratchet_state: ratchet_state, + ratchet_state: result.err().unwrap().to_string(), metadata: HashMap::new(), }; } @@ -321,7 +334,7 @@ pub fn triple_ratchet_init_round_1(ratchet_state_and_metadata: TripleRatchetStat let json = trp.to_json(); if json.is_err() { return TripleRatchetStateAndMetadata{ - ratchet_state: ratchet_state, + ratchet_state: json.err().unwrap().to_string(), metadata: HashMap::new(), }; } @@ -337,7 +350,7 @@ pub fn triple_ratchet_init_round_2(ratchet_state_and_metadata: TripleRatchetStat let tr = TripleRatchetParticipant::from_json(&ratchet_state); if tr.is_err() { return TripleRatchetStateAndMetadata{ - ratchet_state: ratchet_state, + ratchet_state: tr.err().unwrap().to_string(), metadata: HashMap::new(), }; } @@ -353,7 +366,7 @@ pub fn triple_ratchet_init_round_2(ratchet_state_and_metadata: TripleRatchetStat let r = trp.receive_poly_frag(&k, &v); if r.is_err() { return TripleRatchetStateAndMetadata{ - ratchet_state: ratchet_state, + ratchet_state: r.err().unwrap().to_string(), metadata: HashMap::new(), }; } @@ -372,7 +385,7 @@ pub fn triple_ratchet_init_round_2(ratchet_state_and_metadata: TripleRatchetStat let json = trp.to_json(); if json.is_err() { return TripleRatchetStateAndMetadata{ - ratchet_state: ratchet_state, + ratchet_state: json.err().unwrap().to_string(), metadata: HashMap::new(), }; } @@ -388,7 +401,7 @@ pub fn triple_ratchet_init_round_3(ratchet_state_and_metadata: TripleRatchetStat let tr = TripleRatchetParticipant::from_json(&ratchet_state); if tr.is_err() { return TripleRatchetStateAndMetadata{ - ratchet_state: ratchet_state, + ratchet_state: tr.err().unwrap().to_string(), metadata: HashMap::new(), }; } @@ -404,7 +417,7 @@ pub fn triple_ratchet_init_round_3(ratchet_state_and_metadata: TripleRatchetStat let r = trp.receive_commitment(&k, &v); if r.is_err() { return TripleRatchetStateAndMetadata{ - ratchet_state: ratchet_state, + ratchet_state: r.err().unwrap().to_string(), metadata: HashMap::new(), }; } @@ -423,7 +436,7 @@ pub fn triple_ratchet_init_round_3(ratchet_state_and_metadata: TripleRatchetStat let json = trp.to_json(); if json.is_err() { return TripleRatchetStateAndMetadata{ - ratchet_state: ratchet_state, + ratchet_state: json.err().unwrap().to_string(), metadata: HashMap::new(), }; } @@ -439,7 +452,7 @@ pub fn triple_ratchet_init_round_4(ratchet_state_and_metadata: TripleRatchetStat let tr = TripleRatchetParticipant::from_json(&ratchet_state); if tr.is_err() { return TripleRatchetStateAndMetadata{ - ratchet_state: ratchet_state, + ratchet_state: tr.err().unwrap().to_string(), metadata: HashMap::new(), }; } @@ -455,7 +468,7 @@ pub fn triple_ratchet_init_round_4(ratchet_state_and_metadata: TripleRatchetStat let r = trp.recombine(&k, &v); if r.is_err() { return TripleRatchetStateAndMetadata{ - ratchet_state: ratchet_state, + ratchet_state: r.err().unwrap().to_string(), metadata: HashMap::new(), }; } @@ -469,7 +482,7 @@ pub fn triple_ratchet_init_round_4(ratchet_state_and_metadata: TripleRatchetStat let json = trp.to_json(); if json.is_err() { return TripleRatchetStateAndMetadata{ - ratchet_state: ratchet_state, + ratchet_state: json.err().unwrap().to_string(), metadata: HashMap::new(), }; } @@ -485,7 +498,7 @@ pub fn triple_ratchet_encrypt(ratchet_state_and_message: TripleRatchetStateAndMe let tr = TripleRatchetParticipant::from_json(&ratchet_state); if tr.is_err() { return TripleRatchetStateAndEnvelope{ - ratchet_state: ratchet_state, + ratchet_state: tr.err().unwrap().to_string(), envelope: "".to_string(), }; } @@ -495,7 +508,7 @@ pub fn triple_ratchet_encrypt(ratchet_state_and_message: TripleRatchetStateAndMe if result.is_err() { return TripleRatchetStateAndEnvelope{ - ratchet_state: ratchet_state, + ratchet_state: result.err().unwrap().to_string(), envelope: "".to_string(), }; } @@ -505,7 +518,7 @@ pub fn triple_ratchet_encrypt(ratchet_state_and_message: TripleRatchetStateAndMe if envelope_json.is_err() { return TripleRatchetStateAndEnvelope{ - ratchet_state: ratchet_state, + ratchet_state: envelope_json.err().unwrap().to_string(), envelope: "".to_string(), }; } @@ -513,7 +526,7 @@ pub fn triple_ratchet_encrypt(ratchet_state_and_message: TripleRatchetStateAndMe let json = trp.to_json(); if json.is_err() { return TripleRatchetStateAndEnvelope{ - ratchet_state: ratchet_state, + ratchet_state: json.err().unwrap().to_string(), envelope: "".to_string(), }; } @@ -529,7 +542,7 @@ pub fn triple_ratchet_decrypt(ratchet_state_and_envelope: TripleRatchetStateAndE let tr = TripleRatchetParticipant::from_json(&ratchet_state); if tr.is_err() { return TripleRatchetStateAndMessage{ - ratchet_state: ratchet_state, + ratchet_state: tr.err().unwrap().to_string(), message: vec![], }; } @@ -538,7 +551,7 @@ pub fn triple_ratchet_decrypt(ratchet_state_and_envelope: TripleRatchetStateAndE let env = P2PChannelEnvelope::from_json(ratchet_state_and_envelope.envelope); if env.is_err() { return TripleRatchetStateAndMessage{ - ratchet_state: ratchet_state, + ratchet_state: env.err().unwrap().to_string(), message: vec![], }; } @@ -547,7 +560,7 @@ pub fn triple_ratchet_decrypt(ratchet_state_and_envelope: TripleRatchetStateAndE if result.is_err() { return TripleRatchetStateAndMessage{ - ratchet_state: ratchet_state, + ratchet_state: result.err().unwrap().to_string(), message: vec![], }; } @@ -557,7 +570,7 @@ pub fn triple_ratchet_decrypt(ratchet_state_and_envelope: TripleRatchetStateAndE let json = trp.to_json(); if json.is_err() { return TripleRatchetStateAndMessage{ - ratchet_state: ratchet_state, + ratchet_state: json.err().unwrap().to_string(), message: vec![], }; } diff --git a/crates/channel/src/protocols/doubleratchet.rs b/crates/channel/src/protocols/doubleratchet.rs index 34a0912..a828305 100644 --- a/crates/channel/src/protocols/doubleratchet.rs +++ b/crates/channel/src/protocols/doubleratchet.rs @@ -307,7 +307,6 @@ impl DoubleRatchetParticipant { } let (header, should_ratchet) = self.decrypt_header(&envelope.message_header, &self.current_receiving_header_key)?; - let (receiving_ephemeral_key, previous_receiving_chain_length, current_receiving_chain_length) = self.decode_header(&header)?; diff --git a/crates/channel/src/protocols/tripleratchet.rs b/crates/channel/src/protocols/tripleratchet.rs index 255fc8f..85eb169 100644 --- a/crates/channel/src/protocols/tripleratchet.rs +++ b/crates/channel/src/protocols/tripleratchet.rs @@ -408,13 +408,23 @@ impl TripleRatchetParticipant { pub fn initialize(&mut self, init_messages: &HashMap, P2PChannelEnvelope>) -> Result, P2PChannelEnvelope>, TripleRatchetError> { for (k, m) in init_messages { - let msg = self.peer_channels.get_mut(k).unwrap().ratchet_decrypt(m).unwrap(); - if msg != b"init" { + let channel = self.peer_channels.get_mut(k); + if channel.is_none() { + return Err(TripleRatchetError::InvalidData("Invalid peer channel".into())) + } + let msg = channel.unwrap().ratchet_decrypt(m); + if msg.is_err() { + return Err(TripleRatchetError::CryptoError(msg.err().unwrap().to_string())) + } + if msg.unwrap() != b"init" { return Err(TripleRatchetError::InvalidData("Invalid init message".into())); } } - self.dkg_ratchet.sample_polynomial(&mut OsRng); + let maybeerr = self.dkg_ratchet.sample_polynomial(&mut OsRng); + if maybeerr.is_err() { + return Err(TripleRatchetError::InvalidData(maybeerr.err().unwrap().to_string().into())) + } let result = self.dkg_ratchet.get_poly_frags().unwrap(); @@ -435,11 +445,18 @@ impl TripleRatchetParticipant { pub fn receive_poly_frag(&mut self, peer_id: &[u8], frag: &P2PChannelEnvelope) -> Result, P2PChannelEnvelope>>, TripleRatchetError> { - let b = self.peer_channels.get_mut(peer_id).unwrap().ratchet_decrypt(frag).unwrap(); + let channel = self.peer_channels.get_mut(peer_id); + if channel.is_none() { + return Err(TripleRatchetError::InvalidData("Invalid peer channel".into())) + } + let b = channel.unwrap().ratchet_decrypt(frag); + if b.is_err() { + return Err(TripleRatchetError::CryptoError(b.err().unwrap().to_string())) + } let result = self.dkg_ratchet.set_poly_frag_for_party( *self.peer_id_map.get(peer_id).unwrap(), - &b, + &b.unwrap(), ).unwrap(); if result.is_some() { @@ -457,11 +474,18 @@ impl TripleRatchetParticipant { pub fn receive_commitment(&mut self, peer_id: &[u8], zkcommit: &P2PChannelEnvelope) -> Result, P2PChannelEnvelope>>, TripleRatchetError> { - let b = self.peer_channels.get_mut(peer_id).unwrap().ratchet_decrypt(zkcommit).unwrap(); + let channel = self.peer_channels.get_mut(peer_id); + if channel.is_none() { + return Err(TripleRatchetError::InvalidData("Invalid peer channel".into())) + } + let b = channel.unwrap().ratchet_decrypt(zkcommit); + if b.is_err() { + return Err(TripleRatchetError::CryptoError(b.err().unwrap().to_string())) + } let result = self.dkg_ratchet.receive_commitments( *self.peer_id_map.get(peer_id).unwrap(), - &b, + &b.unwrap(), ).unwrap(); if let Some(reveal) = result { @@ -478,9 +502,16 @@ impl TripleRatchetParticipant { } pub fn recombine(&mut self, peer_id: &[u8], reveal: &P2PChannelEnvelope) -> Result<(), Box> { - let b = self.peer_channels.get_mut(peer_id).unwrap().ratchet_decrypt(reveal).unwrap(); + let channel = self.peer_channels.get_mut(peer_id); + if channel.is_none() { + return Err("Invalid peer channel".into()) + } + let b = channel.unwrap().ratchet_decrypt(reveal); + if b.is_err() { + return Err(Box::new(TripleRatchetError::CryptoError(b.err().unwrap().to_string()))) + } - let rev: FeldmanReveal = serde_json::from_slice(&b).unwrap(); + let rev: FeldmanReveal = serde_json::from_slice(&b.unwrap()).unwrap(); let done = self.dkg_ratchet.recombine( *self.peer_id_map.get(peer_id).unwrap(), From f5f7eb243b6b35b932d30d5624a43dfb2469d0f9 Mon Sep 17 00:00:00 2001 From: petricadaipegsp <155911522+petricadaipegsp@users.noreply.github.com> Date: Mon, 2 Dec 2024 22:00:43 +0100 Subject: [PATCH 08/14] Change message size limits (#394) * Increase message size limits * Lower soft max message size to 1MiB --- go-libp2p-blossomsub/pubsub.go | 4 ++-- node/consensus/data/data_clock_consensus_engine.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go-libp2p-blossomsub/pubsub.go b/go-libp2p-blossomsub/pubsub.go index efe9b14..69518a7 100644 --- a/go-libp2p-blossomsub/pubsub.go +++ b/go-libp2p-blossomsub/pubsub.go @@ -26,8 +26,8 @@ import ( logging "github.com/ipfs/go-log/v2" ) -// DefaultSoftMaxMessageSize is 10 MiB. -const DefaultSoftMaxMessageSize = 10 << 20 +// DefaultSoftMaxMessageSize is 1 MiB. +const DefaultSoftMaxMessageSize = 1 << 20 // DefaultHardMaxMessageSize is 20 MB. const DefaultHardMaxMessageSize = 10 << 21 diff --git a/node/consensus/data/data_clock_consensus_engine.go b/node/consensus/data/data_clock_consensus_engine.go index 327c0f9..5371ae3 100644 --- a/node/consensus/data/data_clock_consensus_engine.go +++ b/node/consensus/data/data_clock_consensus_engine.go @@ -333,8 +333,8 @@ func (e *DataClockConsensusEngine) Start() <-chan error { e.pubSub.Subscribe(e.infoFilter, e.handleInfoMessage) go func() { server := qgrpc.NewServer( - grpc.MaxSendMsgSize(20*1024*1024), - grpc.MaxRecvMsgSize(20*1024*1024), + grpc.MaxSendMsgSize(40*1024*1024), + grpc.MaxRecvMsgSize(40*1024*1024), ) protobufs.RegisterDataServiceServer(server, e) if err := e.pubSub.StartDirectChannelListener( From d1e65c1c920b7012fe6281485edef827cc8e00aa Mon Sep 17 00:00:00 2001 From: petricadaipegsp <155911522+petricadaipegsp@users.noreply.github.com> Date: Mon, 2 Dec 2024 23:25:10 +0100 Subject: [PATCH 09/14] Support frame fragmentation and dissemination (#396) * Add clock frame fragment message * Add clock frame fragment validation * Add clock frame fragmentation utilities * Add clock frame fragmentation message handling * Report publication errors * Publish info list after frame * Add frame publish configuration * Publish clock frame fragments * Update BlossomSub dashboard * Publish clock frame fragments in parallel --- client/go.mod | 4 +- client/go.sum | 10 +- dashboards/grafana/BlossomSub.json | 443 ++++++++++++++++- node/config/engine.go | 67 +++ node/consensus/data/broadcast_messaging.go | 113 ++++- .../data/data_clock_consensus_engine.go | 134 ++--- .../data/fragmentation/clock_frame.go | 371 ++++++++++++++ .../data/fragmentation/clock_frame_test.go | 414 ++++++++++++++++ node/consensus/data/fragmentation/hash.go | 10 + .../consensus/data/fragmentation/hash_test.go | 100 ++++ node/consensus/data/main_data_loop.go | 12 +- node/consensus/data/message_handler.go | 125 ++++- node/consensus/data/message_validators.go | 27 + node/consensus/data/token_handle_mint_test.go | 37 +- .../token/token_execution_engine.go | 12 +- node/go.mod | 5 +- node/go.sum | 10 +- node/protobufs/clock.pb.go | 467 ++++++++++++++---- node/protobufs/clock.proto | 27 + node/protobufs/protobufs.go | 1 + node/protobufs/validation.go | 112 +++++ node/protobufs/validation_test.go | 137 +++++ 22 files changed, 2426 insertions(+), 212 deletions(-) create mode 100644 node/consensus/data/fragmentation/clock_frame.go create mode 100644 node/consensus/data/fragmentation/clock_frame_test.go create mode 100644 node/consensus/data/fragmentation/hash.go create mode 100644 node/consensus/data/fragmentation/hash_test.go diff --git a/client/go.mod b/client/go.mod index cf7c94e..1ae2420 100644 --- a/client/go.mod +++ b/client/go.mod @@ -85,7 +85,7 @@ require ( github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/goprocess v0.1.4 // indirect github.com/klauspost/compress v1.17.8 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect @@ -164,7 +164,7 @@ require ( golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.25.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.21.0 // indirect + golang.org/x/sys v0.27.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gonum.org/v1/gonum v0.13.0 // indirect diff --git a/client/go.sum b/client/go.sum index 23e5817..3e21f86 100644 --- a/client/go.sum +++ b/client/go.sum @@ -248,8 +248,10 @@ github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= -github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/klauspost/reedsolomon v1.12.4 h1:5aDr3ZGoJbgu/8+j45KtUJxzYm8k08JGtB9Wx1VQ4OA= +github.com/klauspost/reedsolomon v1.12.4/go.mod h1:d3CzOMOt0JXGIFZm1StgkyF14EYr3xneR2rNWo7NcMU= github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -664,8 +666,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/dashboards/grafana/BlossomSub.json b/dashboards/grafana/BlossomSub.json index 400e769..ba29d10 100644 --- a/dashboards/grafana/BlossomSub.json +++ b/dashboards/grafana/BlossomSub.json @@ -192,6 +192,13 @@ "regex": "AAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABAA(.*)", "renamePattern": "Data Peer Announcements$1" } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEA(.*)", + "renamePattern": "Data Frame Fragments$1" + } } ], "type": "timeseries" @@ -323,6 +330,13 @@ "regex": "AAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABAA(.*)", "renamePattern": "Data Peer Announcements$1" } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEA(.*)", + "renamePattern": "Data Frame Fragments$1" + } } ], "type": "timeseries" @@ -454,6 +468,13 @@ "regex": "AAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABAA(.*)", "renamePattern": "Data Peer Announcements$1" } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEA(.*)", + "renamePattern": "Data Frame Fragments$1" + } } ], "type": "timeseries" @@ -585,6 +606,13 @@ "regex": "AAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABAA(.*)", "renamePattern": "Data Peer Announcements$1" } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEA(.*)", + "renamePattern": "Data Frame Fragments$1" + } } ], "type": "timeseries" @@ -894,6 +922,27 @@ "renamePattern": "Data Peer Announcements Shard 3$1" } }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA(.*)", + "renamePattern": "Data Frame Fragments Shard 1$1" + } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAA(.*)", + "renamePattern": "Data Frame Fragments Shard 2$1" + } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA(.*)", + "renamePattern": "Data Frame Fragments Shard 3$1" + } + }, { "id": "renameByRegex", "options": { @@ -1196,6 +1245,27 @@ "renamePattern": "Data Peer Announcements Shard 3$1" } }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA(.*)", + "renamePattern": "Data Frame Fragments Shard 1$1" + } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAA(.*)", + "renamePattern": "Data Frame Fragments Shard 2$1" + } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA(.*)", + "renamePattern": "Data Frame Fragments Shard 3$1" + } + }, { "id": "renameByRegex", "options": { @@ -1497,6 +1567,27 @@ "renamePattern": "Data Peer Announcements Shard 3$1" } }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA(.*)", + "renamePattern": "Data Frame Fragments Shard 1$1" + } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAA(.*)", + "renamePattern": "Data Frame Fragments Shard 2$1" + } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA(.*)", + "renamePattern": "Data Frame Fragments Shard 3$1" + } + }, { "id": "renameByRegex", "options": { @@ -1507,6 +1598,264 @@ ], "type": "timeseries" }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 23, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "min", + "max", + "mean" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(blossomsub_iwant_messages_count{job=~\"$job\", instance=~\"$host\", direction=\"drop\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "Dropped", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(blossomsub_iwant_messages_count{job=~\"$job\", instance=~\"$host\", direction=\"recv\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "Received", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(blossomsub_iwant_messages_count{job=~\"$job\", instance=~\"$host\", direction=\"send\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "Sent", + "range": true, + "refId": "C" + } + ], + "title": "IWANT message rates", + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 24, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "min", + "max", + "mean" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(blossomsub_ihave_messages_count{job=~\"$job\", instance=~\"$host\", direction=\"drop\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "Dropped", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(blossomsub_ihave_messages_count{job=~\"$job\", instance=~\"$host\", direction=\"recv\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "Received", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(blossomsub_ihave_messages_count{job=~\"$job\", instance=~\"$host\", direction=\"send\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "Sent", + "range": true, + "refId": "C" + } + ], + "title": "IHAVE message rates", + "type": "timeseries" + }, { "datasource": { "default": false, @@ -1570,7 +1919,7 @@ "h": 9, "w": 12, "x": 0, - "y": 47 + "y": 56 }, "id": 19, "options": { @@ -1698,7 +2047,7 @@ "h": 9, "w": 12, "x": 12, - "y": 47 + "y": 56 }, "id": 20, "options": { @@ -1825,7 +2174,7 @@ "h": 9, "w": 12, "x": 0, - "y": 56 + "y": 65 }, "id": 21, "options": { @@ -1953,7 +2302,7 @@ "h": 9, "w": 12, "x": 12, - "y": 56 + "y": 65 }, "id": 22, "options": { @@ -1982,7 +2331,7 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "rate(blossomsub_idontwant_messages_count{job=~\"$job\", instance=~\"$host\", direction=\"drop\"}[$__rate_interval])", + "expr": "sum(rate(blossomsub_idontwant_messages_count{job=~\"$job\", instance=~\"$host\", direction=\"drop\"}[$__rate_interval]))", "hide": false, "instant": false, "legendFormat": "Dropped", @@ -1995,7 +2344,7 @@ "uid": "${datasource}" }, "editorMode": "code", - "expr": "rate(blossomsub_idontwant_messages_count{job=~\"$job\", instance=~\"$host\", direction=\"recv\"}[$__rate_interval])", + "expr": "sum(rate(blossomsub_idontwant_messages_count{job=~\"$job\", instance=~\"$host\", direction=\"recv\"}[$__rate_interval]))", "hide": false, "instant": false, "legendFormat": "Received", @@ -2008,7 +2357,7 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "rate(blossomsub_idontwant_messages_count{job=~\"$job\", instance=~\"$host\", direction=\"send\"}[$__rate_interval])", + "expr": "sum(rate(blossomsub_idontwant_messages_count{job=~\"$job\", instance=~\"$host\", direction=\"send\"}[$__rate_interval]))", "hide": false, "instant": false, "legendFormat": "Sent", @@ -2025,7 +2374,7 @@ "h": 1, "w": 24, "x": 0, - "y": 65 + "y": 74 }, "id": 8, "panels": [], @@ -2093,7 +2442,7 @@ "h": 9, "w": 24, "x": 0, - "y": 66 + "y": 75 }, "id": 11, "options": { @@ -2194,6 +2543,27 @@ "renamePattern": "Data Peer Announcements Shard 3$1" } }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA(.*)", + "renamePattern": "Data Frame Fragments Shard 1$1" + } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAA(.*)", + "renamePattern": "Data Frame Fragments Shard 2$1" + } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA(.*)", + "renamePattern": "Data Frame Fragments Shard 3$1" + } + }, { "id": "renameByRegex", "options": { @@ -2266,7 +2636,7 @@ "h": 9, "w": 12, "x": 0, - "y": 75 + "y": 84 }, "id": 9, "options": { @@ -2367,6 +2737,27 @@ "renamePattern": "Data Peer Announcements Shard 3$1" } }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA(.*)", + "renamePattern": "Data Frame Fragments Shard 1$1" + } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAA(.*)", + "renamePattern": "Data Frame Fragments Shard 2$1" + } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA(.*)", + "renamePattern": "Data Frame Fragments Shard 3$1" + } + }, { "id": "renameByRegex", "options": { @@ -2439,7 +2830,7 @@ "h": 9, "w": 12, "x": 12, - "y": 75 + "y": 84 }, "id": 10, "options": { @@ -2540,6 +2931,27 @@ "renamePattern": "Data Peer Announcements Shard 3$1" } }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA(.*)", + "renamePattern": "Data Frame Fragments Shard 1$1" + } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAA(.*)", + "renamePattern": "Data Frame Fragments Shard 2$1" + } + }, + { + "id": "renameByRegex", + "options": { + "regex": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA(.*)", + "renamePattern": "Data Frame Fragments Shard 3$1" + } + }, { "id": "renameByRegex", "options": { @@ -2556,7 +2968,7 @@ "h": 1, "w": 24, "x": 0, - "y": 84 + "y": 93 }, "id": 6, "panels": [], @@ -2612,8 +3024,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" } ] }, @@ -2625,7 +3036,7 @@ "h": 9, "w": 24, "x": 0, - "y": 85 + "y": 94 }, "id": 7, "options": { @@ -2768,6 +3179,6 @@ "timezone": "browser", "title": "BlossomSub", "uid": "ee47pcfax962ob", - "version": 45, + "version": 55, "weekStart": "" } \ No newline at end of file diff --git a/node/config/engine.go b/node/config/engine.go index 3078f31..09b237a 100644 --- a/node/config/engine.go +++ b/node/config/engine.go @@ -2,6 +2,70 @@ package config import "time" +type FramePublishFragmentationReedSolomonConfig struct { + // The number of data shards to use for Reed-Solomon encoding and decoding. + DataShards int `yaml:"dataShards"` + // The number of parity shards to use for Reed-Solomon encoding and decoding. + ParityShards int `yaml:"parityShards"` +} + +// WithDefaults sets default values for any fields that are not set. +func (c FramePublishFragmentationReedSolomonConfig) WithDefaults() FramePublishFragmentationReedSolomonConfig { + cpy := c + if cpy.DataShards == 0 { + cpy.DataShards = 224 + } + if cpy.ParityShards == 0 { + cpy.ParityShards = 32 + } + return cpy +} + +type FramePublishFragmentationConfig struct { + // The algorithm to use for fragmenting and reassembling frames. + // Options: "reed-solomon". + Algorithm string `yaml:"algorithm"` + // The configuration for Reed-Solomon fragmentation. + ReedSolomon FramePublishFragmentationReedSolomonConfig `yaml:"reedSolomon"` +} + +// WithDefaults sets default values for any fields that are not set. +func (c FramePublishFragmentationConfig) WithDefaults() FramePublishFragmentationConfig { + cpy := c + if cpy.Algorithm == "" { + cpy.Algorithm = "reed-solomon" + } + cpy.ReedSolomon = cpy.ReedSolomon.WithDefaults() + return cpy +} + +type FramePublishConfig struct { + // The publish mode to use for the node. + // Options: "full", "fragmented", "dual", "threshold". + Mode string `yaml:"mode"` + // The threshold for switching between full and fragmented frame publishing. + Threshold int `yaml:"threshold"` + // The configuration for frame fragmentation. + Fragmentation FramePublishFragmentationConfig `yaml:"fragmentation"` + // The size of the ballast added to a frame. + // NOTE: This option exists solely for testing purposes and should not be + // modified in production. + BallastSize int `yaml:"ballastSize"` +} + +// WithDefaults sets default values for any fields that are not set. +func (c FramePublishConfig) WithDefaults() FramePublishConfig { + cpy := c + if cpy.Mode == "" { + cpy.Mode = "full" + } + if cpy.Threshold == 0 { + cpy.Threshold = 1 * 1024 * 1024 + } + cpy.Fragmentation = cpy.Fragmentation.WithDefaults() + return cpy +} + type EngineConfig struct { ProvingKeyId string `yaml:"provingKeyId"` Filter string `yaml:"filter"` @@ -36,4 +100,7 @@ type EngineConfig struct { Difficulty uint32 `yaml:"difficulty"` // Whether to allow GOMAXPROCS values above the number of physical cores. AllowExcessiveGOMAXPROCS bool `yaml:"allowExcessiveGOMAXPROCS"` + + // EXPERIMENTAL: The configuration for frame publishing. + FramePublish FramePublishConfig `yaml:"framePublish"` } diff --git a/node/consensus/data/broadcast_messaging.go b/node/consensus/data/broadcast_messaging.go index 6d0ed2a..312306b 100644 --- a/node/consensus/data/broadcast_messaging.go +++ b/node/consensus/data/broadcast_messaging.go @@ -1,7 +1,11 @@ package data import ( + "crypto" + "crypto/rand" + mrand "math/rand" "strings" + "sync" "time" "github.com/iden3/go-iden3-crypto/poseidon" @@ -11,6 +15,8 @@ import ( "google.golang.org/protobuf/types/known/anypb" "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb" "source.quilibrium.com/quilibrium/monorepo/node/config" + "source.quilibrium.com/quilibrium/monorepo/node/consensus/data/fragmentation" + qruntime "source.quilibrium.com/quilibrium/monorepo/node/internal/runtime" "source.quilibrium.com/quilibrium/monorepo/node/protobufs" ) @@ -27,6 +33,19 @@ func (e *DataClockConsensusEngine) handleFrameMessage( return nil } +func (e *DataClockConsensusEngine) handleFrameFragmentMessage( + message *pb.Message, +) error { + select { + case <-e.ctx.Done(): + return e.ctx.Err() + case e.frameFragmentMessageProcessorCh <- message: + default: + e.logger.Warn("dropping frame fragment message") + } + return nil +} + func (e *DataClockConsensusEngine) handleTxMessage( message *pb.Message, ) error { @@ -77,6 +96,95 @@ func (e *DataClockConsensusEngine) publishProof( ), reachability: reachability, } + e.peerMapMx.Unlock() + + cfg := e.config.Engine.FramePublish.WithDefaults() + if cfg.BallastSize > 0 { + frame = proto.Clone(frame).(*protobufs.ClockFrame) + frame.Padding = make([]byte, cfg.BallastSize) + } + + publishFragmented := func() error { + var splitter fragmentation.ClockFrameSplitter + switch cfg := cfg.Fragmentation; cfg.Algorithm { + case "reed-solomon": + var err error + splitter, err = fragmentation.NewReedSolomonClockFrameSplitter( + cfg.ReedSolomon.DataShards, + cfg.ReedSolomon.ParityShards, + ) + if err != nil { + return errors.Wrap(err, "creating reed-solomon splitter") + } + default: + return errors.Errorf("unsupported fragmentation algorithm: %s", cfg.Algorithm) + } + fragments, err := splitter.SplitClockFrame(frame) + if err != nil { + return errors.Wrap(err, "splitting clock frame") + } + mrand.Shuffle(len(fragments), func(i, j int) { + fragments[i], fragments[j] = fragments[j], fragments[i] + }) + sign := func(b []byte) ([]byte, error) { + return e.provingKey.Sign(rand.Reader, b, crypto.Hash(0)) + } + var wg sync.WaitGroup + defer wg.Wait() + throttle := make(chan struct{}, qruntime.WorkerCount(0, false)) + for _, fragment := range fragments { + throttle <- struct{}{} + wg.Add(1) + go func(fragment *protobufs.ClockFrameFragment) { + defer func() { <-throttle }() + defer wg.Done() + if err := fragment.SignED448(e.provingKeyBytes, sign); err != nil { + e.logger.Error("error signing clock frame fragment", zap.Error(err)) + return + } + if err := e.publishMessage(e.frameFragmentFilter, fragment); err != nil { + e.logger.Error("error publishing clock frame fragment", zap.Error(err)) + } + }(fragment) + } + return nil + } + publishFull := func() error { + if err := e.publishMessage(e.frameFilter, frame); err != nil { + e.logger.Error("error publishing clock frame", zap.Error(err)) + } + return nil + } + switch cfg.Mode { + case "full": + if err := publishFull(); err != nil { + return err + } + case "fragmented": + if err := publishFragmented(); err != nil { + return err + } + case "dual": + if err := publishFragmented(); err != nil { + return err + } + if err := publishFull(); err != nil { + return err + } + case "threshold": + if proto.Size(frame) >= cfg.Threshold { + if err := publishFragmented(); err != nil { + return err + } + } else { + if err := publishFull(); err != nil { + return err + } + } + default: + return errors.Errorf("unsupported frame publish mode: %s", cfg.Mode) + } + list := &protobufs.DataPeerListAnnounce{ Peer: &protobufs.DataPeer{ PeerId: nil, @@ -91,13 +199,10 @@ func (e *DataClockConsensusEngine) publishProof( ExternallyReachable: reachability, }, } - e.peerMapMx.Unlock() if err := e.publishMessage(e.infoFilter, list); err != nil { - e.logger.Debug("error publishing message", zap.Error(err)) + e.logger.Debug("error publishing data peer list announce", zap.Error(err)) } - e.publishMessage(e.frameFilter, frame) - return nil } diff --git a/node/consensus/data/data_clock_consensus_engine.go b/node/consensus/data/data_clock_consensus_engine.go index 5371ae3..66a8804 100644 --- a/node/consensus/data/data_clock_consensus_engine.go +++ b/node/consensus/data/data_clock_consensus_engine.go @@ -25,6 +25,7 @@ import ( "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb" "source.quilibrium.com/quilibrium/monorepo/node/config" "source.quilibrium.com/quilibrium/monorepo/node/consensus" + "source.quilibrium.com/quilibrium/monorepo/node/consensus/data/fragmentation" qtime "source.quilibrium.com/quilibrium/monorepo/node/consensus/time" qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto" "source.quilibrium.com/quilibrium/monorepo/node/execution" @@ -107,39 +108,42 @@ type DataClockConsensusEngine struct { currentReceivingSyncPeers int announcedJoin int - frameChan chan *protobufs.ClockFrame - executionEngines map[string]execution.ExecutionEngine - filter []byte - txFilter []byte - infoFilter []byte - frameFilter []byte - input []byte - parentSelector []byte - syncingStatus SyncStatusType - syncingTarget []byte - previousHead *protobufs.ClockFrame - engineMx sync.Mutex - dependencyMapMx sync.Mutex - stagedTransactions *protobufs.TokenRequests - stagedTransactionsSet map[string]struct{} - stagedTransactionsMx sync.Mutex - validationFilter map[string]struct{} - validationFilterMx sync.Mutex - peerMapMx sync.RWMutex - peerAnnounceMapMx sync.Mutex - lastKeyBundleAnnouncementFrame uint64 - peerMap map[string]*peerInfo - uncooperativePeersMap map[string]*peerInfo - frameMessageProcessorCh chan *pb.Message - txMessageProcessorCh chan *pb.Message - infoMessageProcessorCh chan *pb.Message - report *protobufs.SelfTestReport - clients []protobufs.DataIPCServiceClient - grpcRateLimiter *RateLimiter - previousFrameProven *protobufs.ClockFrame - previousTree *mt.MerkleTree - clientReconnectTest int - requestSyncCh chan struct{} + frameChan chan *protobufs.ClockFrame + executionEngines map[string]execution.ExecutionEngine + filter []byte + txFilter []byte + infoFilter []byte + frameFilter []byte + frameFragmentFilter []byte + input []byte + parentSelector []byte + syncingStatus SyncStatusType + syncingTarget []byte + previousHead *protobufs.ClockFrame + engineMx sync.Mutex + dependencyMapMx sync.Mutex + stagedTransactions *protobufs.TokenRequests + stagedTransactionsSet map[string]struct{} + stagedTransactionsMx sync.Mutex + validationFilter map[string]struct{} + validationFilterMx sync.Mutex + peerMapMx sync.RWMutex + peerAnnounceMapMx sync.Mutex + lastKeyBundleAnnouncementFrame uint64 + peerMap map[string]*peerInfo + uncooperativePeersMap map[string]*peerInfo + frameMessageProcessorCh chan *pb.Message + frameFragmentMessageProcessorCh chan *pb.Message + txMessageProcessorCh chan *pb.Message + infoMessageProcessorCh chan *pb.Message + report *protobufs.SelfTestReport + clients []protobufs.DataIPCServiceClient + grpcRateLimiter *RateLimiter + previousFrameProven *protobufs.ClockFrame + previousTree *mt.MerkleTree + clientReconnectTest int + requestSyncCh chan struct{} + clockFrameFragmentBuffer fragmentation.ClockFrameFragmentBuffer } var _ consensus.DataConsensusEngine = (*DataClockConsensusEngine)(nil) @@ -229,6 +233,14 @@ func NewDataClockConsensusEngine( rateLimit = 10 } + clockFrameFragmentBuffer, err := fragmentation.NewClockFrameFragmentCircularBuffer( + fragmentation.NewReedSolomonClockFrameFragmentBuffer, + 16, + ) + if err != nil { + panic(err) + } + ctx, cancel := context.WithCancel(context.Background()) e := &DataClockConsensusEngine{ ctx: ctx, @@ -251,30 +263,32 @@ func NewDataClockConsensusEngine( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, - currentReceivingSyncPeers: 0, - lastFrameReceivedAt: time.Time{}, - frameProverTries: []*tries.RollingFrecencyCritbitTrie{}, - inclusionProver: inclusionProver, - syncingStatus: SyncStatusNotSyncing, - peerMap: map[string]*peerInfo{}, - uncooperativePeersMap: map[string]*peerInfo{}, - minimumPeersRequired: minimumPeersRequired, - report: report, - frameProver: frameProver, - masterTimeReel: masterTimeReel, - dataTimeReel: dataTimeReel, - peerInfoManager: peerInfoManager, - frameMessageProcessorCh: make(chan *pb.Message, 65536), - txMessageProcessorCh: make(chan *pb.Message, 65536), - infoMessageProcessorCh: make(chan *pb.Message, 65536), - config: cfg, - preMidnightMint: map[string]struct{}{}, + currentReceivingSyncPeers: 0, + lastFrameReceivedAt: time.Time{}, + frameProverTries: []*tries.RollingFrecencyCritbitTrie{}, + inclusionProver: inclusionProver, + syncingStatus: SyncStatusNotSyncing, + peerMap: map[string]*peerInfo{}, + uncooperativePeersMap: map[string]*peerInfo{}, + minimumPeersRequired: minimumPeersRequired, + report: report, + frameProver: frameProver, + masterTimeReel: masterTimeReel, + dataTimeReel: dataTimeReel, + peerInfoManager: peerInfoManager, + frameMessageProcessorCh: make(chan *pb.Message, 65536), + frameFragmentMessageProcessorCh: make(chan *pb.Message, 65536), + txMessageProcessorCh: make(chan *pb.Message, 65536), + infoMessageProcessorCh: make(chan *pb.Message, 65536), + config: cfg, + preMidnightMint: map[string]struct{}{}, grpcRateLimiter: NewRateLimiter( rateLimit, time.Minute, ), - requestSyncCh: make(chan struct{}, 1), - validationFilter: map[string]struct{}{}, + requestSyncCh: make(chan struct{}, 1), + validationFilter: map[string]struct{}{}, + clockFrameFragmentBuffer: clockFrameFragmentBuffer, } logger.Info("constructing consensus engine") @@ -287,6 +301,7 @@ func NewDataClockConsensusEngine( e.txFilter = append([]byte{0x00}, e.filter...) e.infoFilter = append([]byte{0x00, 0x00}, e.filter...) e.frameFilter = append([]byte{0x00, 0x00, 0x00}, e.filter...) + e.frameFragmentFilter = append([]byte{0x00, 0x00, 0x00, 0x00}, e.filter...) e.input = seed e.provingKey = signer e.provingKeyType = keyType @@ -319,16 +334,19 @@ func (e *DataClockConsensusEngine) Start() <-chan error { panic(err) } - e.wg.Add(3) + e.wg.Add(4) go e.runFrameMessageHandler() + go e.runFrameFragmentMessageHandler() go e.runTxMessageHandler() go e.runInfoMessageHandler() e.logger.Info("subscribing to pubsub messages") e.pubSub.RegisterValidator(e.frameFilter, e.validateFrameMessage, true) + e.pubSub.RegisterValidator(e.frameFragmentFilter, e.validateFrameFragmentMessage, true) e.pubSub.RegisterValidator(e.txFilter, e.validateTxMessage, true) e.pubSub.RegisterValidator(e.infoFilter, e.validateInfoMessage, true) e.pubSub.Subscribe(e.frameFilter, e.handleFrameMessage) + e.pubSub.Subscribe(e.frameFragmentFilter, e.handleFrameFragmentMessage) e.pubSub.Subscribe(e.txFilter, e.handleTxMessage) e.pubSub.Subscribe(e.infoFilter, e.handleInfoMessage) go func() { @@ -504,7 +522,7 @@ func (e *DataClockConsensusEngine) Start() <-chan error { ) if err := e.publishMessage(e.infoFilter, list); err != nil { - e.logger.Debug("error publishing message", zap.Error(err)) + e.logger.Debug("error publishing data peer list announce", zap.Error(err)) } if thresholdBeforeConfirming > 0 { @@ -662,7 +680,9 @@ func (e *DataClockConsensusEngine) Stop(force bool) <-chan error { panic(err) } - e.publishMessage(e.txFilter, pause.TokenRequest()) + if err := e.publishMessage(e.txFilter, pause.TokenRequest()); err != nil { + e.logger.Warn("error publishing prover pause", zap.Error(err)) + } wg := sync.WaitGroup{} wg.Add(len(e.executionEngines)) @@ -684,9 +704,11 @@ func (e *DataClockConsensusEngine) Stop(force bool) <-chan error { } e.pubSub.Unsubscribe(e.frameFilter, false) + e.pubSub.Unsubscribe(e.frameFragmentFilter, false) e.pubSub.Unsubscribe(e.txFilter, false) e.pubSub.Unsubscribe(e.infoFilter, false) e.pubSub.UnregisterValidator(e.frameFilter) + e.pubSub.UnregisterValidator(e.frameFragmentFilter) e.pubSub.UnregisterValidator(e.txFilter) e.pubSub.UnregisterValidator(e.infoFilter) diff --git a/node/consensus/data/fragmentation/clock_frame.go b/node/consensus/data/fragmentation/clock_frame.go new file mode 100644 index 0000000..f0a3d53 --- /dev/null +++ b/node/consensus/data/fragmentation/clock_frame.go @@ -0,0 +1,371 @@ +package fragmentation + +import ( + "bytes" + "errors" + + "github.com/klauspost/reedsolomon" + "google.golang.org/protobuf/proto" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" +) + +// ClockFrameSplitter is an interface for splitting a ClockFrame into fragments. +type ClockFrameSplitter interface { + // SplitClockFrame splits a ClockFrame into fragments. + // The fragments are unsigned, and must be signed before being sent. + SplitClockFrame(frame *protobufs.ClockFrame) ([]*protobufs.ClockFrameFragment, error) +} + +type reedSolomonClockFrameSplitter struct { + dataShardCount int + parityShardCount int +} + +// NewReedSolomonClockFrameSplitter creates a new ReedSolomonClockFrameSplitter. +func NewReedSolomonClockFrameSplitter( + dataShardCount int, + parityShardCount int, +) (ClockFrameSplitter, error) { + if dataShardCount == 0 { + return nil, errors.New("dataShardCount must be greater than 0") + } + if parityShardCount == 0 { + return nil, errors.New("parityShardCount must be greater than 0") + } + if dataShardCount+parityShardCount > 256 { + return nil, errors.New("dataShardCount + parityShardCount must be less than or equal to 256") + } + return &reedSolomonClockFrameSplitter{ + dataShardCount: dataShardCount, + parityShardCount: parityShardCount, + }, nil +} + +// SplitClockFrame implements ClockFrameSplitter. +func (r *reedSolomonClockFrameSplitter) SplitClockFrame(frame *protobufs.ClockFrame) ([]*protobufs.ClockFrameFragment, error) { + bs, err := proto.Marshal(frame) + if err != nil { + return nil, err + } + fragmentSize := len(bs) / r.dataShardCount + if len(bs)%r.dataShardCount != 0 { + fragmentSize++ + } + if fragmentSize == 0 { + return nil, errors.New("ClockFrame is too small") + } + if n := fragmentSize % 64; n != 0 { + fragmentSize += 64 - n + } + shards := make([][]byte, r.dataShardCount+r.parityShardCount) + for i := 0; i < len(bs); i += fragmentSize { + shard := bs[i:] + if len(shard) > fragmentSize { + shard = shard[:fragmentSize] + } + shards[i/fragmentSize] = shard + } + for i := len(bs) / fragmentSize; i < r.dataShardCount; i++ { + if n := len(shards[i]); n < fragmentSize { + shards[i] = append(shards[i], make([]byte, fragmentSize-n)...) + } + } + for i := r.dataShardCount; i < r.dataShardCount+r.parityShardCount; i++ { + shards[i] = make([]byte, fragmentSize) + } + enc, err := reedsolomon.New( + r.dataShardCount, + r.parityShardCount, + reedsolomon.WithAutoGoroutines(fragmentSize), + ) + if err != nil { + return nil, err + } + if err := enc.Encode(shards); err != nil { + return nil, err + } + h := hash(bs) + fragments := make([]*protobufs.ClockFrameFragment, r.dataShardCount+r.parityShardCount) + for i, shard := range shards { + fragments[i] = &protobufs.ClockFrameFragment{ + Filter: frame.Filter, + FrameNumber: frame.FrameNumber, + Timestamp: frame.Timestamp, + FrameHash: h, + Encoding: &protobufs.ClockFrameFragment_ReedSolomon{ + ReedSolomon: &protobufs.ClockFrameFragment_ReedSolomonEncoding{ + FrameSize: uint64(len(bs)), + FragmentShard: uint64(i), + FragmentDataShardCount: uint64(r.dataShardCount), + FragmentParityShardCount: uint64(r.parityShardCount), + FragmentData: shard, + }, + }, + } + } + return fragments, nil +} + +// ClockFrameAssembler is an interface for assembling a ClockFrame from fragments. +type ClockFrameAssembler interface { + // AssembleClockFrame assembles a ClockFrame from fragments. + AssembleClockFrame(fragments []*protobufs.ClockFrameFragment) (*protobufs.ClockFrame, error) +} + +type reedSolomonClockFrameAssembler struct{} + +// NewReedSolomonClockFrameAssembler creates a new ReedSolomonClockFrameAssembler. +func NewReedSolomonClockFrameAssembler() ClockFrameAssembler { + return &reedSolomonClockFrameAssembler{} +} + +// AssembleClockFrame implements ClockFrameAssembler. +func (r *reedSolomonClockFrameAssembler) AssembleClockFrame(fragments []*protobufs.ClockFrameFragment) (*protobufs.ClockFrame, error) { + if len(fragments) == 0 { + return nil, errors.New("no fragments") + } + var ( + frameNumber uint64 + filter []byte + timestamp int64 + frameHash []byte + dataShardCount, parityShardCount int + fragmentSize int + frameSize int + ) + for _, fragment := range fragments { + if fragment == nil { + return nil, errors.New("fragment is nil") + } + switch { + case frameNumber == 0: + frameNumber = fragment.FrameNumber + case frameNumber != fragment.FrameNumber: + return nil, errors.New("inconsistent frame number") + case len(filter) == 0: + filter = fragment.Filter + case !bytes.Equal(filter, fragment.Filter): + return nil, errors.New("inconsistent filter") + case timestamp == 0: + timestamp = fragment.Timestamp + case timestamp != fragment.Timestamp: + return nil, errors.New("inconsistent timestamp") + case len(frameHash) == 0: + frameHash = fragment.FrameHash + case !bytes.Equal(frameHash, fragment.FrameHash): + return nil, errors.New("inconsistent frame hash") + } + fragment := fragment.GetReedSolomon() + if fragment == nil { + return nil, errors.New("fragment is not ReedSolomon") + } + switch { + case dataShardCount == 0: + dataShardCount = int(fragment.FragmentDataShardCount) + parityShardCount = int(fragment.FragmentParityShardCount) + case dataShardCount != int(fragment.FragmentDataShardCount): + return nil, errors.New("inconsistent data shard count") + case parityShardCount != int(fragment.FragmentParityShardCount): + return nil, errors.New("inconsistent parity shard count") + case dataShardCount+parityShardCount <= int(fragment.FragmentShard): + return nil, errors.New("shard out of bounds") + case fragmentSize == 0: + fragmentSize = len(fragment.FragmentData) + case len(fragment.FragmentData) != fragmentSize: + return nil, errors.New("inconsistent fragment size") + case frameSize == 0: + frameSize = int(fragment.FrameSize) + case int(fragment.FrameSize) != frameSize: + return nil, errors.New("inconsistent frame size") + } + } + shards := make([][]byte, dataShardCount+parityShardCount) + for _, fragment := range fragments { + fragment := fragment.GetReedSolomon() + shard := fragment.FragmentShard + if shards[shard] != nil { + return nil, errors.New("duplicate shard") + } + shards[shard] = fragment.FragmentData + } + enc, err := reedsolomon.New( + dataShardCount, + parityShardCount, + reedsolomon.WithAutoGoroutines(fragmentSize), + ) + if err != nil { + return nil, err + } + if err := enc.ReconstructData(shards); err != nil { + return nil, err + } + bs := make([]byte, 0, dataShardCount*fragmentSize) + for _, shard := range shards[:dataShardCount] { + bs = append(bs, shard...) + } + bs = bs[:frameSize] + if h := hash(bs); !bytes.Equal(h, frameHash) { + return nil, errors.New("frame hash mismatch") + } + frame := &protobufs.ClockFrame{} + if err := proto.Unmarshal(bs, frame); err != nil { + return nil, err + } + return frame, nil +} + +// ClockFrameFragmentBuffer is an interface for buffering ClockFrameFragments and assembling ClockFrames. +type ClockFrameFragmentBuffer interface { + // AccumulateClockFrameFragment accumulates a ClockFrameFragment. + // If sufficient fragments are available, the ClockFrame is returned. + // How fragments from different frames are handled is implementation-specific. + AccumulateClockFrameFragment(fragment *protobufs.ClockFrameFragment) (*protobufs.ClockFrame, error) +} + +type clockFrameFragmentCircularBuffer struct { + newBuffer func() ClockFrameFragmentBuffer + maxSize int + buffers map[[hashSize]byte]ClockFrameFragmentBuffer + keys [][hashSize]byte + built map[[hashSize]byte]struct{} + builtKeys [][hashSize]byte +} + +// NewClockFrameFragmentCircularBuffer creates a new ClockFrameFragmentBuffer. +// The newBuffer function is called to create a new ClockFrameFragmentBuffer. +// The maxSize parameter specifies the maximum number of buffers to keep. +// If maxSize buffers are already in use, the oldest buffer is removed. +func NewClockFrameFragmentCircularBuffer( + newBuffer func() ClockFrameFragmentBuffer, + maxSize int, +) (ClockFrameFragmentBuffer, error) { + if newBuffer == nil { + return nil, errors.New("newBuffer is nil") + } + if maxSize <= 0 { + return nil, errors.New("maxSize must be greater than 0") + } + return &clockFrameFragmentCircularBuffer{ + newBuffer: newBuffer, + maxSize: maxSize, + buffers: make(map[[hashSize]byte]ClockFrameFragmentBuffer, maxSize), + keys: make([][hashSize]byte, 0, maxSize), + built: make(map[[hashSize]byte]struct{}, maxSize), + builtKeys: make([][hashSize]byte, 0, maxSize), + }, nil +} + +// AccumulateClockFrameFragment implements ClockFrameFragmentBuffer. +func (c *clockFrameFragmentCircularBuffer) AccumulateClockFrameFragment(fragment *protobufs.ClockFrameFragment) (*protobufs.ClockFrame, error) { + if fragment == nil { + return nil, errors.New("fragment is nil") + } + if len(fragment.FrameHash) != hashSize { + return nil, errors.New("invalid frame hash size") + } + key := [hashSize]byte(fragment.FrameHash) + if _, ok := c.built[key]; ok { + return nil, nil + } + buffer, ok := c.buffers[key] + if !ok { + if len(c.buffers) == c.maxSize { + delete(c.buffers, c.keys[0]) + c.keys = append(c.keys[:0], c.keys[1:]...) + } + buffer = c.newBuffer() + c.buffers[key] = buffer + c.keys = append(c.keys, key) + } + frame, err := buffer.AccumulateClockFrameFragment(fragment) + if err != nil { + return nil, err + } + if frame != nil { + delete(c.buffers, key) + for i, k := range c.keys { + if k == key { + c.keys = append(c.keys[:i], c.keys[i+1:]...) + break + } + } + if len(c.built) == c.maxSize { + delete(c.built, c.builtKeys[0]) + c.builtKeys = append(c.builtKeys[:0], c.builtKeys[1:]...) + } + c.built[key] = struct{}{} + c.builtKeys = append(c.builtKeys, key) + } + return frame, nil +} + +type reedSolomonClockFrameFragmentBuffer struct { + fragments []*protobufs.ClockFrameFragment + have map[uint64]struct{} +} + +// NewReedSolomonClockFrameFragmentBuffer creates a new ReedSolomonClockFrameFragmentBuffer. +func NewReedSolomonClockFrameFragmentBuffer() ClockFrameFragmentBuffer { + return &reedSolomonClockFrameFragmentBuffer{ + fragments: make([]*protobufs.ClockFrameFragment, 0, 256), + have: make(map[uint64]struct{}, 256), + } +} + +// AccumulateClockFrameFragment implements ClockFrameFragmentBuffer. +func (r *reedSolomonClockFrameFragmentBuffer) AccumulateClockFrameFragment(fragment *protobufs.ClockFrameFragment) (*protobufs.ClockFrame, error) { + if fragment == nil { + return nil, errors.New("fragment is nil") + } + if fragment.GetReedSolomon() == nil { + return nil, errors.New("fragment is not ReedSolomon") + } + var templateRS *protobufs.ClockFrameFragment_ReedSolomonEncoding + if len(r.fragments) == 0 { + templateRS = fragment.GetReedSolomon() + } else { + template := r.fragments[0] + if !bytes.Equal(template.Filter, fragment.Filter) { + return nil, errors.New("inconsistent filter") + } + if template.FrameNumber != fragment.FrameNumber { + return nil, errors.New("inconsistent frame number") + } + if template.Timestamp != fragment.Timestamp { + return nil, errors.New("inconsistent timestamp") + } + if !bytes.Equal(template.FrameHash, fragment.FrameHash) { + return nil, errors.New("inconsistent frame hash") + } + templateRS = template.GetReedSolomon() + fragmentRS := fragment.GetReedSolomon() + if templateRS.FrameSize != fragmentRS.FrameSize { + return nil, errors.New("inconsistent frame size") + } + if templateRS.FragmentDataShardCount+templateRS.FragmentParityShardCount <= fragmentRS.FragmentShard { + return nil, errors.New("shard out of bounds") + } + if _, ok := r.have[fragmentRS.FragmentShard]; ok { + return nil, errors.New("duplicate shard") + } + if templateRS.FragmentDataShardCount != fragmentRS.FragmentDataShardCount { + return nil, errors.New("inconsistent data shard count") + } + if templateRS.FragmentParityShardCount != fragmentRS.FragmentParityShardCount { + return nil, errors.New("inconsistent parity shard count") + } + if len(templateRS.FragmentData) != len(fragmentRS.FragmentData) { + return nil, errors.New("inconsistent fragment size") + } + } + r.fragments = append(r.fragments, fragment) + r.have[templateRS.FragmentShard] = struct{}{} + if len(r.fragments) < int(templateRS.FragmentDataShardCount) { + return nil, nil + } + assembler := NewReedSolomonClockFrameAssembler() + frame, err := assembler.AssembleClockFrame(r.fragments) + r.fragments = r.fragments[:0] + clear(r.have) + return frame, err +} diff --git a/node/consensus/data/fragmentation/clock_frame_test.go b/node/consensus/data/fragmentation/clock_frame_test.go new file mode 100644 index 0000000..12fdcd6 --- /dev/null +++ b/node/consensus/data/fragmentation/clock_frame_test.go @@ -0,0 +1,414 @@ +package fragmentation_test + +import ( + "bytes" + "crypto/rand" + "fmt" + mrand "math/rand" + "slices" + "testing" + + "google.golang.org/protobuf/proto" + "source.quilibrium.com/quilibrium/monorepo/node/consensus/data/fragmentation" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" +) + +func BenchmarkReedSolomonClockFrameFragmentation(b *testing.B) { + frame := &protobufs.ClockFrame{ + Filter: bytes.Repeat([]byte{0x01}, 32), + FrameNumber: 123, + Timestamp: 456, + Padding: make([]byte, 20*1024*1024), + } + if _, err := rand.Read(frame.Padding); err != nil { + b.Fatal(err) + } + benchmarkCases := []struct { + dataShardCount int + parityShardCount int + }{ + { + dataShardCount: 4, + parityShardCount: 2, + }, + { + dataShardCount: 8, + parityShardCount: 4, + }, + { + dataShardCount: 16, + parityShardCount: 8, + }, + { + dataShardCount: 32, + parityShardCount: 16, + }, + { + dataShardCount: 48, + parityShardCount: 16, + }, + { + dataShardCount: 64, + parityShardCount: 32, + }, + { + dataShardCount: 128, + parityShardCount: 64, + }, + { + dataShardCount: 192, + parityShardCount: 64, + }, + { + dataShardCount: 224, + parityShardCount: 32, + }, + } + b.Run("Splitter", func(b *testing.B) { + for _, bc := range benchmarkCases { + b.Run(fmt.Sprintf("DS_%d/PS_%d", bc.dataShardCount, bc.parityShardCount), func(b *testing.B) { + for i := 0; i < b.N; i++ { + splitter, err := fragmentation.NewReedSolomonClockFrameSplitter(bc.dataShardCount, bc.parityShardCount) + if err != nil { + b.Fatal(err) + } + if _, err := splitter.SplitClockFrame(frame); err != nil { + b.Fatal(err) + } + } + }) + } + }) + b.Run("Assembler", func(b *testing.B) { + for _, bc := range benchmarkCases { + b.Run(fmt.Sprintf("DS_%d/PS_%d", bc.dataShardCount, bc.parityShardCount), func(b *testing.B) { + splitter, err := fragmentation.NewReedSolomonClockFrameSplitter(bc.dataShardCount, bc.parityShardCount) + if err != nil { + b.Fatal(err) + } + fragments, err := splitter.SplitClockFrame(frame) + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + assembler := fragmentation.NewReedSolomonClockFrameAssembler() + if _, err := assembler.AssembleClockFrame(fragments); err != nil { + b.Fatal(err) + } + } + }) + } + }) +} + +func TestReedSolomonClockFrameFragmentation(t *testing.T) { + splitter, err := fragmentation.NewReedSolomonClockFrameSplitter(4, 2) + if err != nil { + t.Fatal(err) + } + originalFrame := &protobufs.ClockFrame{ + Filter: bytes.Repeat([]byte{0x01}, 32), + FrameNumber: 123, + Timestamp: 456, + Padding: make([]byte, 20*1024*1024), + } + if _, err := rand.Read(originalFrame.Padding); err != nil { + t.Fatal(err) + } + fragments, err := splitter.SplitClockFrame(originalFrame) + if err != nil { + t.Fatal(err) + } + if len(fragments) != 6 { + t.Fatalf("fragment count mismatch: %d, expected %d", len(fragments), 5) + } + for _, fragment := range fragments { + if fragment.FrameNumber != 123 { + t.Fatalf("frame number mismatch: %d, expected %d", fragment.FrameNumber, 123) + } + if !bytes.Equal(fragment.Filter, bytes.Repeat([]byte{0x01}, 32)) { + t.Fatalf("filter mismatch") + } + if fragment.Timestamp != 456 { + t.Fatalf("timestamp mismatch: %d, expected %d", fragment.Timestamp, 456) + } + } + for _, tc := range []struct { + name string + erase []int + expectError bool + }{ + { + name: "no erasures", + erase: nil, + expectError: false, + }, + { + name: "one erasure", + erase: []int{0}, + expectError: false, + }, + { + name: "two erasures", + erase: []int{2, 0}, + expectError: false, + }, + { + name: "three erasures", + erase: []int{2, 4, 0}, + expectError: true, + }, + } { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + fragments := slices.Clone(fragments) + for _, idx := range tc.erase { + fragments[idx] = nil + } + for i, fragment := range fragments { + if fragment == nil { + fragments = append(fragments[:i], fragments[i+1:]...) + } + } + assembler := fragmentation.NewReedSolomonClockFrameAssembler() + assembledFrame, err := assembler.AssembleClockFrame(fragments) + switch { + case tc.expectError: + if err == nil { + t.Fatal("expected error") + } + return + case err != nil: + t.Fatal(err) + } + if !proto.Equal(assembledFrame, originalFrame) { + t.Fatalf("frame mismatch") + } + }) + } +} + +func TestClockFrameFragmentCircularBuffer(t *testing.T) { + t.Parallel() + splitter, err := fragmentation.NewReedSolomonClockFrameSplitter(4, 2) + if err != nil { + t.Fatal(err) + } + originalFrames := []*protobufs.ClockFrame{ + { + Filter: bytes.Repeat([]byte{0x01}, 32), + FrameNumber: 123, + Timestamp: 456, + Padding: make([]byte, 20*1024*1024), + }, + { + Filter: bytes.Repeat([]byte{0x02}, 32), + FrameNumber: 124, + Timestamp: 457, + Padding: make([]byte, 20*1024*1024), + }, + { + Filter: bytes.Repeat([]byte{0x03}, 32), + FrameNumber: 125, + Timestamp: 458, + Padding: make([]byte, 20*1024*1024), + }, + } + fragments := make([][]*protobufs.ClockFrameFragment, len(originalFrames)) + for i, originalFrame := range originalFrames { + if _, err := rand.Read(originalFrame.Padding); err != nil { + t.Fatal(err) + } + fragments[i], err = splitter.SplitClockFrame(originalFrame) + if err != nil { + t.Fatal(err) + } + } + allFragments := slices.Concat(fragments...) + mrand.Shuffle(len(allFragments), func(i, j int) { + allFragments[i], allFragments[j] = allFragments[j], allFragments[i] + }) + buffer, err := fragmentation.NewClockFrameFragmentCircularBuffer( + fragmentation.NewReedSolomonClockFrameFragmentBuffer, + 3, + ) + if err != nil { + t.Fatal(err) + } + var seen [3]bool + for _, fragment := range allFragments { + frame, err := buffer.AccumulateClockFrameFragment(fragment) + if err != nil { + t.Fatal(err) + } + if frame == nil { + continue + } + if !proto.Equal(frame, originalFrames[frame.FrameNumber-123]) { + t.Fatalf("frame mismatch") + } + if seen[frame.FrameNumber-123] { + t.Fatal("duplicate frame") + } + seen[frame.FrameNumber-123] = true + } + for i := range seen { + if !seen[i] { + t.Fatalf("missing frame: %d", i+123) + } + } + buffer, err = fragmentation.NewClockFrameFragmentCircularBuffer( + fragmentation.NewReedSolomonClockFrameFragmentBuffer, + 2, + ) + if err != nil { + t.Fatal(err) + } + clear(seen[:]) + for _, fragments := range fragments { + for _, fragment := range fragments { + frame, err := buffer.AccumulateClockFrameFragment(fragment) + if err != nil { + t.Fatal(err) + } + if frame == nil { + continue + } + if !proto.Equal(frame, originalFrames[frame.FrameNumber-123]) { + t.Fatalf("frame mismatch") + } + if seen[frame.FrameNumber-123] { + t.Fatal("duplicate frame") + } + seen[frame.FrameNumber-123] = true + } + } + for i := range seen { + if !seen[i] { + t.Fatalf("missing frame: %d", i+123) + } + } +} + +func TestReedSolomonClockFrameFragmentBuffer(t *testing.T) { + splitter, err := fragmentation.NewReedSolomonClockFrameSplitter(4, 2) + if err != nil { + t.Fatal(err) + } + originalFrame := &protobufs.ClockFrame{ + Filter: bytes.Repeat([]byte{0x01}, 32), + FrameNumber: 123, + Timestamp: 456, + Padding: make([]byte, 20*1024*1024), + } + if _, err := rand.Read(originalFrame.Padding); err != nil { + t.Fatal(err) + } + fragments, err := splitter.SplitClockFrame(originalFrame) + if err != nil { + t.Fatal(err) + } + for _, tc := range []struct { + name string + fragments []*protobufs.ClockFrameFragment + errorIdx int + frameIdx int + }{ + { + name: "one insert", + fragments: []*protobufs.ClockFrameFragment{ + fragments[0], + }, + errorIdx: -1, + frameIdx: -1, + }, + { + name: "two insert", + fragments: []*protobufs.ClockFrameFragment{ + fragments[0], fragments[2], + }, + errorIdx: -1, + frameIdx: -1, + }, + { + name: "three insert", + fragments: []*protobufs.ClockFrameFragment{ + fragments[0], fragments[4], fragments[2], + }, + errorIdx: -1, + frameIdx: -1, + }, + { + name: "four insert", + fragments: []*protobufs.ClockFrameFragment{ + fragments[0], fragments[4], fragments[1], fragments[2], + }, + errorIdx: -1, + frameIdx: 3, + }, + { + name: "one insert, one bogus", + fragments: []*protobufs.ClockFrameFragment{ + fragments[0], + { + FrameNumber: 123, + Filter: bytes.Repeat([]byte{0x01}, 32), + Timestamp: 456, + }, + }, + errorIdx: 1, + frameIdx: -1, + }, + { + name: "one insert, one duplicate", + fragments: []*protobufs.ClockFrameFragment{ + fragments[0], fragments[0], + }, + errorIdx: 1, + frameIdx: -1, + }, + { + name: "four insert, one bogus", + fragments: []*protobufs.ClockFrameFragment{ + fragments[0], fragments[2], fragments[4], + { + FrameNumber: 123, + Filter: bytes.Repeat([]byte{0x01}, 32), + Timestamp: 456, + }, + fragments[1], + }, + errorIdx: 3, + frameIdx: 4, + }, + } { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + buffer := fragmentation.NewReedSolomonClockFrameFragmentBuffer() + for i, fragment := range tc.fragments { + frame, err := buffer.AccumulateClockFrameFragment(fragment) + switch { + case tc.errorIdx == i: + if err == nil { + t.Fatal("expected error") + } + continue + case err != nil: + t.Fatal(err) + } + switch { + case tc.frameIdx == i: + if frame == nil { + t.Fatal("expected frame") + } + if !proto.Equal(frame, originalFrame) { + t.Fatalf("frame mismatch") + } + case frame != nil: + t.Fatal("unexpected frame") + } + } + }) + } +} diff --git a/node/consensus/data/fragmentation/hash.go b/node/consensus/data/fragmentation/hash.go new file mode 100644 index 0000000..c4f5c30 --- /dev/null +++ b/node/consensus/data/fragmentation/hash.go @@ -0,0 +1,10 @@ +package fragmentation + +import "crypto/sha256" + +const hashSize = 32 + +func hash(b []byte) []byte { + var h [hashSize]byte = sha256.Sum256(b) + return h[:] +} diff --git a/node/consensus/data/fragmentation/hash_test.go b/node/consensus/data/fragmentation/hash_test.go new file mode 100644 index 0000000..87e4e3b --- /dev/null +++ b/node/consensus/data/fragmentation/hash_test.go @@ -0,0 +1,100 @@ +package fragmentation_test + +import ( + "crypto/rand" + "crypto/sha256" + "testing" + + "golang.org/x/crypto/blake2b" + "golang.org/x/crypto/blake2s" + "golang.org/x/crypto/sha3" +) + +func BenchmarkHashFunctions(b *testing.B) { + data := make([]byte, 20*1024*1024) + if _, err := rand.Read(data); err != nil { + b.Fatal(err) + } + for _, bc := range []struct { + name string + f func([]byte) []byte + }{ + { + name: "SHA256-224", + f: func(data []byte) []byte { + b := sha256.Sum224(data) + return b[:] + }, + }, + { + name: "SHA256-256", + f: func(data []byte) []byte { + b := sha256.Sum256(data) + return b[:] + }, + }, + { + name: "SHA3-224", + f: func(data []byte) []byte { + b := sha3.Sum224(data) + return b[:] + }, + }, + { + name: "SHA3-256", + f: func(data []byte) []byte { + b := sha3.Sum256(data) + return b[:] + }, + }, + { + name: "SHA3-384", + f: func(data []byte) []byte { + b := sha3.Sum384(data) + return b[:] + }, + }, + { + name: "SHA3-512", + f: func(data []byte) []byte { + b := sha3.Sum512(data) + return b[:] + }, + }, + { + name: "BLAKE2b-256", + f: func(data []byte) []byte { + b := blake2b.Sum256(data) + return b[:] + }, + }, + { + name: "BLAKE2b-384", + f: func(data []byte) []byte { + b := blake2b.Sum384(data) + return b[:] + }, + }, + { + name: "BLAKE2b-512", + f: func(data []byte) []byte { + b := blake2b.Sum512(data) + return b[:] + }, + }, + { + name: "BLAKE2s-256", + f: func(data []byte) []byte { + b := blake2s.Sum256(data) + return b[:] + }, + }, + } { + b.Run(bc.name, func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = bc.f(data) + } + }) + } +} diff --git a/node/consensus/data/main_data_loop.go b/node/consensus/data/main_data_loop.go index 0dd9cbf..7167b2a 100644 --- a/node/consensus/data/main_data_loop.go +++ b/node/consensus/data/main_data_loop.go @@ -191,8 +191,8 @@ func (e *DataClockConsensusEngine) runLoop() { e.validationFilter = make(map[string]struct{}, len(e.validationFilter)) e.validationFilterMx.Unlock() if e.FrameProverTrieContains(0, e.provingKeyAddress) { - if err = e.publishProof(dataFrame); err != nil { - e.logger.Error("could not publish", zap.Error(err)) + if err := e.publishProof(dataFrame); err != nil { + e.logger.Error("could not publish proof", zap.Error(err)) e.stateMx.Lock() if e.state < consensus.EngineStateStopping { e.state = consensus.EngineStateCollecting @@ -375,7 +375,9 @@ func (e *DataClockConsensusEngine) processFrame( zap.Duration("frame_age", frametime.Since(latestFrame)), ) - e.publishMessage(e.txFilter, mint.TokenRequest()) + if err := e.publishMessage(e.txFilter, mint.TokenRequest()); err != nil { + e.logger.Error("could not publish mint", zap.Error(err)) + } if e.config.Engine.AutoMergeCoins { _, addrs, _, err := e.coinStore.GetCoinsForOwner( @@ -412,7 +414,9 @@ func (e *DataClockConsensusEngine) processFrame( return latestFrame } - e.publishMessage(e.txFilter, merge.TokenRequest()) + if err := e.publishMessage(e.txFilter, merge.TokenRequest()); err != nil { + e.logger.Warn("could not publish merge", zap.Error(err)) + } } } } diff --git a/node/consensus/data/message_handler.go b/node/consensus/data/message_handler.go index 91d3e83..3ea9d38 100644 --- a/node/consensus/data/message_handler.go +++ b/node/consensus/data/message_handler.go @@ -30,13 +30,13 @@ func (e *DataClockConsensusEngine) runFrameMessageHandler() { msg := &protobufs.Message{} if err := proto.Unmarshal(message.Data, msg); err != nil { - e.logger.Debug("bad message") + e.logger.Debug("cannot unmarshal data", zap.Error(err)) continue } a := &anypb.Any{} if err := proto.Unmarshal(msg.Payload, a); err != nil { - e.logger.Error("error while unmarshaling", zap.Error(err)) + e.logger.Debug("cannot unmarshal payload", zap.Error(err)) continue } @@ -46,7 +46,6 @@ func (e *DataClockConsensusEngine) runFrameMessageHandler() { message.From, msg.Address, a, - false, ); err != nil { e.logger.Debug("could not handle clock frame data", zap.Error(err)) } @@ -55,6 +54,41 @@ func (e *DataClockConsensusEngine) runFrameMessageHandler() { } } +func (e *DataClockConsensusEngine) runFrameFragmentMessageHandler() { + defer e.wg.Done() + for { + select { + case <-e.ctx.Done(): + return + case message := <-e.frameFragmentMessageProcessorCh: + e.logger.Debug("handling frame fragment message") + msg := &protobufs.Message{} + + if err := proto.Unmarshal(message.Data, msg); err != nil { + e.logger.Debug("cannot unmarshal data", zap.Error(err)) + continue + } + + a := &anypb.Any{} + if err := proto.Unmarshal(msg.Payload, a); err != nil { + e.logger.Debug("cannot unmarshal payload", zap.Error(err)) + continue + } + + switch a.TypeUrl { + case protobufs.ClockFrameFragmentType: + if err := e.handleClockFrameFragmentData( + message.From, + msg.Address, + a, + ); err != nil { + e.logger.Debug("could not handle clock frame fragment data", zap.Error(err)) + } + } + } + } +} + func (e *DataClockConsensusEngine) runTxMessageHandler() { defer e.wg.Done() for { @@ -66,12 +100,13 @@ func (e *DataClockConsensusEngine) runTxMessageHandler() { msg := &protobufs.Message{} if err := proto.Unmarshal(message.Data, msg); err != nil { - e.logger.Debug("bad message") + e.logger.Debug("could not unmarshal data", zap.Error(err)) continue } a := &anypb.Any{} if err := proto.Unmarshal(msg.Payload, a); err != nil { + e.logger.Debug("could not unmarshal payload", zap.Error(err)) continue } @@ -142,13 +177,13 @@ func (e *DataClockConsensusEngine) runInfoMessageHandler() { msg := &protobufs.Message{} if err := proto.Unmarshal(message.Data, msg); err != nil { - e.logger.Debug("bad message") + e.logger.Debug("could not unmarshal data", zap.Error(err)) continue } a := &anypb.Any{} if err := proto.Unmarshal(msg.Payload, a); err != nil { - e.logger.Error("error while unmarshaling", zap.Error(err)) + e.logger.Debug("could not unmarshal payload", zap.Error(err)) continue } @@ -224,35 +259,103 @@ func (e *DataClockConsensusEngine) handleClockFrame( return nil } +func (e *DataClockConsensusEngine) handleClockFrameFragment( + peerID []byte, + address []byte, + fragment *protobufs.ClockFrameFragment, +) error { + if fragment == nil { + return errors.Wrap(errors.New("fragment is nil"), "handle clock frame fragment") + } + + addr, err := poseidon.HashBytes( + fragment.GetPublicKeySignatureEd448().PublicKey.KeyValue, + ) + if err != nil { + return errors.Wrap(err, "handle clock frame fragment data") + } + + if !e.FrameProverTrieContains(0, addr.FillBytes(make([]byte, 32))) { + e.logger.Debug( + "prover not in trie at frame fragment, address may be in fork", + zap.Binary("address", address), + zap.Binary("filter", fragment.Filter), + zap.Uint64("frame_number", fragment.FrameNumber), + ) + return nil + } + + e.logger.Debug( + "got clock frame fragment", + zap.Binary("address", address), + zap.Binary("filter", fragment.Filter), + zap.Uint64("frame_number", fragment.FrameNumber), + ) + + frame, err := e.clockFrameFragmentBuffer.AccumulateClockFrameFragment(fragment) + if err != nil { + e.logger.Debug("could not accumulate clock frame fragment", zap.Error(err)) + return errors.Wrap(err, "handle clock frame fragment data") + } + if frame == nil { + return nil + } + + e.logger.Info( + "accumulated clock frame", + zap.Binary("address", address), + zap.Binary("filter", frame.Filter), + zap.Uint64("frame_number", frame.FrameNumber), + ) + + return e.handleClockFrame(peerID, address, frame) +} + func (e *DataClockConsensusEngine) handleClockFrameData( peerID []byte, address []byte, - any *anypb.Any, - isSync bool, + a *anypb.Any, ) error { if bytes.Equal(peerID, e.pubSub.GetPeerID()) { return nil } frame := &protobufs.ClockFrame{} - if err := any.UnmarshalTo(frame); err != nil { + if err := a.UnmarshalTo(frame); err != nil { return errors.Wrap(err, "handle clock frame data") } return e.handleClockFrame(peerID, address, frame) } +func (e *DataClockConsensusEngine) handleClockFrameFragmentData( + peerID []byte, + address []byte, + a *anypb.Any, +) error { + if bytes.Equal(peerID, e.pubSub.GetPeerID()) { + return nil + } + + fragment := &protobufs.ClockFrameFragment{} + if err := a.UnmarshalTo(fragment); err != nil { + return errors.Wrap(err, "handle clock frame fragment data") + } + + return e.handleClockFrameFragment(peerID, address, fragment) +} + func (e *DataClockConsensusEngine) handleDataPeerListAnnounce( peerID []byte, address []byte, - any *anypb.Any, + a *anypb.Any, ) error { if bytes.Equal(peerID, e.pubSub.GetPeerID()) { return nil } announce := &protobufs.DataPeerListAnnounce{} - if err := any.UnmarshalTo(announce); err != nil { + if err := a.UnmarshalTo(announce); err != nil { return errors.Wrap(err, "handle data peer list announce") } diff --git a/node/consensus/data/message_validators.go b/node/consensus/data/message_validators.go index 993eede..f06596d 100644 --- a/node/consensus/data/message_validators.go +++ b/node/consensus/data/message_validators.go @@ -37,6 +37,33 @@ func (e *DataClockConsensusEngine) validateFrameMessage(peerID peer.ID, message } } +func (e *DataClockConsensusEngine) validateFrameFragmentMessage(peerID peer.ID, message *pb.Message) p2p.ValidationResult { + msg := &protobufs.Message{} + if err := proto.Unmarshal(message.Data, msg); err != nil { + return p2p.ValidationResultReject + } + a := &anypb.Any{} + if err := proto.Unmarshal(msg.Payload, a); err != nil { + return p2p.ValidationResultReject + } + switch a.TypeUrl { + case protobufs.ClockFrameFragmentType: + fragment := &protobufs.ClockFrameFragment{} + if err := proto.Unmarshal(a.Value, fragment); err != nil { + return p2p.ValidationResultReject + } + if err := fragment.Validate(); err != nil { + return p2p.ValidationResultReject + } + if ts := time.UnixMilli(fragment.Timestamp); time.Since(ts) > 2*time.Minute { + return p2p.ValidationResultIgnore + } + return p2p.ValidationResultAccept + default: + return p2p.ValidationResultReject + } +} + func (e *DataClockConsensusEngine) validateTxMessage(peerID peer.ID, message *pb.Message) p2p.ValidationResult { msg := &protobufs.Message{} if err := proto.Unmarshal(message.Data, msg); err != nil { diff --git a/node/consensus/data/token_handle_mint_test.go b/node/consensus/data/token_handle_mint_test.go index 4bc9a90..6a12591 100644 --- a/node/consensus/data/token_handle_mint_test.go +++ b/node/consensus/data/token_handle_mint_test.go @@ -126,24 +126,25 @@ func TestHandlePreMidnightMint(t *testing.T) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, - currentReceivingSyncPeers: 0, - lastFrameReceivedAt: time.Time{}, - frameProverTries: []*tries.RollingFrecencyCritbitTrie{}, - inclusionProver: qcrypto.NewKZGInclusionProver(log), - syncingStatus: SyncStatusNotSyncing, - peerMap: map[string]*peerInfo{}, - uncooperativePeersMap: map[string]*peerInfo{}, - minimumPeersRequired: 0, - report: nil, - frameProver: qcrypto.NewWesolowskiFrameProver(log), - masterTimeReel: nil, - dataTimeReel: &qtime.DataTimeReel{}, - peerInfoManager: nil, - frameMessageProcessorCh: make(chan *pb.Message), - txMessageProcessorCh: make(chan *pb.Message), - infoMessageProcessorCh: make(chan *pb.Message), - config: nil, - preMidnightMint: map[string]struct{}{}, + currentReceivingSyncPeers: 0, + lastFrameReceivedAt: time.Time{}, + frameProverTries: []*tries.RollingFrecencyCritbitTrie{}, + inclusionProver: qcrypto.NewKZGInclusionProver(log), + syncingStatus: SyncStatusNotSyncing, + peerMap: map[string]*peerInfo{}, + uncooperativePeersMap: map[string]*peerInfo{}, + minimumPeersRequired: 0, + report: nil, + frameProver: qcrypto.NewWesolowskiFrameProver(log), + masterTimeReel: nil, + dataTimeReel: &qtime.DataTimeReel{}, + peerInfoManager: nil, + frameMessageProcessorCh: make(chan *pb.Message), + frameFragmentMessageProcessorCh: make(chan *pb.Message), + txMessageProcessorCh: make(chan *pb.Message), + infoMessageProcessorCh: make(chan *pb.Message), + config: nil, + preMidnightMint: map[string]struct{}{}, } d.dataTimeReel.SetHead(&protobufs.ClockFrame{ diff --git a/node/execution/intrinsics/token/token_execution_engine.go b/node/execution/intrinsics/token/token_execution_engine.go index b1288ec..49d0ebb 100644 --- a/node/execution/intrinsics/token/token_execution_engine.go +++ b/node/execution/intrinsics/token/token_execution_engine.go @@ -391,10 +391,12 @@ func NewTokenExecutionEngine( } } } - e.publishMessage( + if err := e.publishMessage( append([]byte{0x00}, e.intrinsicFilter...), resume.TokenRequest(), - ) + ); err != nil { + e.logger.Warn("error while publishing resume message", zap.Error(err)) + } } }() @@ -1437,10 +1439,12 @@ func (e *TokenExecutionEngine) AnnounceProverJoin() { panic(err) } - e.publishMessage( + if err := e.publishMessage( append([]byte{0x00}, e.intrinsicFilter...), join.TokenRequest(), - ) + ); err != nil { + e.logger.Warn("error publishing join message", zap.Error(err)) + } } func (e *TokenExecutionEngine) GetRingPosition() int { diff --git a/node/go.mod b/node/go.mod index 9da7c47..6978181 100644 --- a/node/go.mod +++ b/node/go.mod @@ -27,6 +27,7 @@ require ( github.com/cockroachdb/pebble v0.0.0-20231210175920-b4d301aeb46a github.com/deiu/rdf2go v0.0.0-20240619132609-81222e324bb9 github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 + github.com/klauspost/reedsolomon v1.12.4 github.com/libp2p/go-libp2p v0.35.4 github.com/libp2p/go-libp2p-kad-dht v0.23.0 github.com/shopspring/decimal v1.4.0 @@ -142,7 +143,7 @@ require ( github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/goprocess v0.1.4 // indirect github.com/klauspost/compress v1.17.8 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect @@ -199,7 +200,7 @@ require ( golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.25.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.21.0 + golang.org/x/sys v0.27.0 golang.org/x/text v0.16.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gonum.org/v1/gonum v0.13.0 // indirect diff --git a/node/go.sum b/node/go.sum index 888035b..12f568b 100644 --- a/node/go.sum +++ b/node/go.sum @@ -260,8 +260,10 @@ github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= -github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/klauspost/reedsolomon v1.12.4 h1:5aDr3ZGoJbgu/8+j45KtUJxzYm8k08JGtB9Wx1VQ4OA= +github.com/klauspost/reedsolomon v1.12.4/go.mod h1:d3CzOMOt0JXGIFZm1StgkyF14EYr3xneR2rNWo7NcMU= github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -693,8 +695,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/node/protobufs/clock.pb.go b/node/protobufs/clock.pb.go index a377ed9..68a3e85 100644 --- a/node/protobufs/clock.pb.go +++ b/node/protobufs/clock.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 -// protoc v3.21.12 +// protoc-gen-go v1.34.1 +// protoc v5.27.0 // source: clock.proto package protobufs @@ -78,6 +78,8 @@ type ClockFrame struct { // // *ClockFrame_PublicKeySignatureEd448 PublicKeySignature isClockFrame_PublicKeySignature `protobuf_oneof:"public_key_signature"` + // Padding is used in tests in order to simulate large clock frames. + Padding []byte `protobuf:"bytes,99,opt,name=padding,proto3" json:"padding,omitempty"` } func (x *ClockFrame) Reset() { @@ -182,6 +184,13 @@ func (x *ClockFrame) GetPublicKeySignatureEd448() *Ed448Signature { return nil } +func (x *ClockFrame) GetPadding() []byte { + if x != nil { + return x.Padding + } + return nil +} + type isClockFrame_PublicKeySignature interface { isClockFrame_PublicKeySignature() } @@ -192,6 +201,138 @@ type ClockFrame_PublicKeySignatureEd448 struct { func (*ClockFrame_PublicKeySignatureEd448) isClockFrame_PublicKeySignature() {} +// Represents a clock frame fragment for a given filter. Clock frame fragments +// are used to disseminate clock frame data across the network in a more +// efficient manner. This is particularly useful for large clock frames, where +// the frame data can be split into smaller fragments and sent across the +// network in parallel. +type ClockFrameFragment struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Filter []byte `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` + FrameNumber uint64 `protobuf:"varint,2,opt,name=frame_number,json=frameNumber,proto3" json:"frame_number,omitempty"` + Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + FrameHash []byte `protobuf:"bytes,4,opt,name=frame_hash,json=frameHash,proto3" json:"frame_hash,omitempty"` + // Types that are assignable to Encoding: + // + // *ClockFrameFragment_ReedSolomon + Encoding isClockFrameFragment_Encoding `protobuf_oneof:"encoding"` + // Types that are assignable to PublicKeySignature: + // + // *ClockFrameFragment_PublicKeySignatureEd448 + PublicKeySignature isClockFrameFragment_PublicKeySignature `protobuf_oneof:"public_key_signature"` +} + +func (x *ClockFrameFragment) Reset() { + *x = ClockFrameFragment{} + if protoimpl.UnsafeEnabled { + mi := &file_clock_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ClockFrameFragment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClockFrameFragment) ProtoMessage() {} + +func (x *ClockFrameFragment) ProtoReflect() protoreflect.Message { + mi := &file_clock_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClockFrameFragment.ProtoReflect.Descriptor instead. +func (*ClockFrameFragment) Descriptor() ([]byte, []int) { + return file_clock_proto_rawDescGZIP(), []int{1} +} + +func (x *ClockFrameFragment) GetFilter() []byte { + if x != nil { + return x.Filter + } + return nil +} + +func (x *ClockFrameFragment) GetFrameNumber() uint64 { + if x != nil { + return x.FrameNumber + } + return 0 +} + +func (x *ClockFrameFragment) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *ClockFrameFragment) GetFrameHash() []byte { + if x != nil { + return x.FrameHash + } + return nil +} + +func (m *ClockFrameFragment) GetEncoding() isClockFrameFragment_Encoding { + if m != nil { + return m.Encoding + } + return nil +} + +func (x *ClockFrameFragment) GetReedSolomon() *ClockFrameFragment_ReedSolomonEncoding { + if x, ok := x.GetEncoding().(*ClockFrameFragment_ReedSolomon); ok { + return x.ReedSolomon + } + return nil +} + +func (m *ClockFrameFragment) GetPublicKeySignature() isClockFrameFragment_PublicKeySignature { + if m != nil { + return m.PublicKeySignature + } + return nil +} + +func (x *ClockFrameFragment) GetPublicKeySignatureEd448() *Ed448Signature { + if x, ok := x.GetPublicKeySignature().(*ClockFrameFragment_PublicKeySignatureEd448); ok { + return x.PublicKeySignatureEd448 + } + return nil +} + +type isClockFrameFragment_Encoding interface { + isClockFrameFragment_Encoding() +} + +type ClockFrameFragment_ReedSolomon struct { + ReedSolomon *ClockFrameFragment_ReedSolomonEncoding `protobuf:"bytes,5,opt,name=reed_solomon,json=reedSolomon,proto3,oneof"` +} + +func (*ClockFrameFragment_ReedSolomon) isClockFrameFragment_Encoding() {} + +type isClockFrameFragment_PublicKeySignature interface { + isClockFrameFragment_PublicKeySignature() +} + +type ClockFrameFragment_PublicKeySignatureEd448 struct { + PublicKeySignatureEd448 *Ed448Signature `protobuf:"bytes,6,opt,name=public_key_signature_ed448,json=publicKeySignatureEd448,proto3,oneof"` +} + +func (*ClockFrameFragment_PublicKeySignatureEd448) isClockFrameFragment_PublicKeySignature() {} + type ClockFrameParentSelectors struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -204,7 +345,7 @@ type ClockFrameParentSelectors struct { func (x *ClockFrameParentSelectors) Reset() { *x = ClockFrameParentSelectors{} if protoimpl.UnsafeEnabled { - mi := &file_clock_proto_msgTypes[1] + mi := &file_clock_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -217,7 +358,7 @@ func (x *ClockFrameParentSelectors) String() string { func (*ClockFrameParentSelectors) ProtoMessage() {} func (x *ClockFrameParentSelectors) ProtoReflect() protoreflect.Message { - mi := &file_clock_proto_msgTypes[1] + mi := &file_clock_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -230,7 +371,7 @@ func (x *ClockFrameParentSelectors) ProtoReflect() protoreflect.Message { // Deprecated: Use ClockFrameParentSelectors.ProtoReflect.Descriptor instead. func (*ClockFrameParentSelectors) Descriptor() ([]byte, []int) { - return file_clock_proto_rawDescGZIP(), []int{1} + return file_clock_proto_rawDescGZIP(), []int{2} } func (x *ClockFrameParentSelectors) GetFrameNumber() uint64 { @@ -272,7 +413,7 @@ type ClockFramesRequest struct { func (x *ClockFramesRequest) Reset() { *x = ClockFramesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_clock_proto_msgTypes[2] + mi := &file_clock_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -285,7 +426,7 @@ func (x *ClockFramesRequest) String() string { func (*ClockFramesRequest) ProtoMessage() {} func (x *ClockFramesRequest) ProtoReflect() protoreflect.Message { - mi := &file_clock_proto_msgTypes[2] + mi := &file_clock_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -298,7 +439,7 @@ func (x *ClockFramesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ClockFramesRequest.ProtoReflect.Descriptor instead. func (*ClockFramesRequest) Descriptor() ([]byte, []int) { - return file_clock_proto_rawDescGZIP(), []int{2} + return file_clock_proto_rawDescGZIP(), []int{3} } func (x *ClockFramesRequest) GetFilter() []byte { @@ -347,7 +488,7 @@ type ClockFramesPreflight struct { func (x *ClockFramesPreflight) Reset() { *x = ClockFramesPreflight{} if protoimpl.UnsafeEnabled { - mi := &file_clock_proto_msgTypes[3] + mi := &file_clock_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -360,7 +501,7 @@ func (x *ClockFramesPreflight) String() string { func (*ClockFramesPreflight) ProtoMessage() {} func (x *ClockFramesPreflight) ProtoReflect() protoreflect.Message { - mi := &file_clock_proto_msgTypes[3] + mi := &file_clock_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -373,7 +514,7 @@ func (x *ClockFramesPreflight) ProtoReflect() protoreflect.Message { // Deprecated: Use ClockFramesPreflight.ProtoReflect.Descriptor instead. func (*ClockFramesPreflight) Descriptor() ([]byte, []int) { - return file_clock_proto_rawDescGZIP(), []int{3} + return file_clock_proto_rawDescGZIP(), []int{4} } func (x *ClockFramesPreflight) GetRangeParentSelectors() []*ClockFrameParentSelectors { @@ -404,7 +545,7 @@ type ClockFramesResponse struct { func (x *ClockFramesResponse) Reset() { *x = ClockFramesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_clock_proto_msgTypes[4] + mi := &file_clock_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -417,7 +558,7 @@ func (x *ClockFramesResponse) String() string { func (*ClockFramesResponse) ProtoMessage() {} func (x *ClockFramesResponse) ProtoReflect() protoreflect.Message { - mi := &file_clock_proto_msgTypes[4] + mi := &file_clock_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -430,7 +571,7 @@ func (x *ClockFramesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ClockFramesResponse.ProtoReflect.Descriptor instead. func (*ClockFramesResponse) Descriptor() ([]byte, []int) { - return file_clock_proto_rawDescGZIP(), []int{4} + return file_clock_proto_rawDescGZIP(), []int{5} } func (x *ClockFramesResponse) GetFilter() []byte { @@ -461,6 +602,85 @@ func (x *ClockFramesResponse) GetClockFrames() []*ClockFrame { return nil } +type ClockFrameFragment_ReedSolomonEncoding struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FrameSize uint64 `protobuf:"varint,1,opt,name=frame_size,json=frameSize,proto3" json:"frame_size,omitempty"` + FragmentShard uint64 `protobuf:"varint,2,opt,name=fragment_shard,json=fragmentShard,proto3" json:"fragment_shard,omitempty"` + FragmentDataShardCount uint64 `protobuf:"varint,3,opt,name=fragment_data_shard_count,json=fragmentDataShardCount,proto3" json:"fragment_data_shard_count,omitempty"` + FragmentParityShardCount uint64 `protobuf:"varint,4,opt,name=fragment_parity_shard_count,json=fragmentParityShardCount,proto3" json:"fragment_parity_shard_count,omitempty"` + FragmentData []byte `protobuf:"bytes,5,opt,name=fragment_data,json=fragmentData,proto3" json:"fragment_data,omitempty"` +} + +func (x *ClockFrameFragment_ReedSolomonEncoding) Reset() { + *x = ClockFrameFragment_ReedSolomonEncoding{} + if protoimpl.UnsafeEnabled { + mi := &file_clock_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ClockFrameFragment_ReedSolomonEncoding) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClockFrameFragment_ReedSolomonEncoding) ProtoMessage() {} + +func (x *ClockFrameFragment_ReedSolomonEncoding) ProtoReflect() protoreflect.Message { + mi := &file_clock_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClockFrameFragment_ReedSolomonEncoding.ProtoReflect.Descriptor instead. +func (*ClockFrameFragment_ReedSolomonEncoding) Descriptor() ([]byte, []int) { + return file_clock_proto_rawDescGZIP(), []int{1, 0} +} + +func (x *ClockFrameFragment_ReedSolomonEncoding) GetFrameSize() uint64 { + if x != nil { + return x.FrameSize + } + return 0 +} + +func (x *ClockFrameFragment_ReedSolomonEncoding) GetFragmentShard() uint64 { + if x != nil { + return x.FragmentShard + } + return 0 +} + +func (x *ClockFrameFragment_ReedSolomonEncoding) GetFragmentDataShardCount() uint64 { + if x != nil { + return x.FragmentDataShardCount + } + return 0 +} + +func (x *ClockFrameFragment_ReedSolomonEncoding) GetFragmentParityShardCount() uint64 { + if x != nil { + return x.FragmentParityShardCount + } + return 0 +} + +func (x *ClockFrameFragment_ReedSolomonEncoding) GetFragmentData() []byte { + if x != nil { + return x.FragmentData + } + return nil +} + var File_clock_proto protoreflect.FileDescriptor var file_clock_proto_rawDesc = []byte{ @@ -468,7 +688,7 @@ var file_clock_proto_rawDesc = []byte{ 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x1a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0a, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0xbc, 0x03, 0x0a, 0x0a, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, + 0x74, 0x6f, 0x22, 0xd6, 0x03, 0x0a, 0x0a, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, @@ -494,58 +714,99 @@ var file_clock_proto_rawDesc = []byte{ 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x48, 0x00, 0x52, 0x17, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x45, 0x64, 0x34, 0x34, 0x38, 0x42, 0x16, 0x0a, 0x14, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x22, 0x67, 0x0a, 0x19, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x21, - 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x94, 0x02, 0x0a, 0x12, 0x43, - 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x66, 0x72, 0x6f, - 0x6d, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x66, 0x72, 0x6f, 0x6d, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x4e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x6f, 0x5f, 0x66, 0x72, 0x61, 0x6d, - 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, - 0x74, 0x6f, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x27, 0x0a, - 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x69, 0x0a, 0x16, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x5f, - 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, - 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, - 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, - 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x14, 0x72, 0x61, 0x6e, - 0x67, 0x65, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x73, 0x22, 0x81, 0x01, 0x0a, 0x14, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, - 0x73, 0x50, 0x72, 0x65, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x12, 0x69, 0x0a, 0x16, 0x72, 0x61, - 0x6e, 0x67, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, - 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, - 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x52, - 0x14, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22, 0xca, 0x01, 0x0a, 0x13, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, - 0x72, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, - 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x66, 0x72, + 0x74, 0x75, 0x72, 0x65, 0x45, 0x64, 0x34, 0x34, 0x38, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x64, + 0x64, 0x69, 0x6e, 0x67, 0x18, 0x63, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x64, 0x64, + 0x69, 0x6e, 0x67, 0x42, 0x16, 0x0a, 0x14, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, + 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xfc, 0x04, 0x0a, 0x12, + 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, + 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x0f, 0x66, 0x72, 0x6f, 0x6d, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x6f, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x74, 0x6f, 0x46, 0x72, - 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x47, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, - 0x63, 0x6b, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x66, + 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x09, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x48, 0x61, 0x73, 0x68, 0x12, 0x65, 0x0a, 0x0c, 0x72, 0x65, + 0x65, 0x64, 0x5f, 0x73, 0x6f, 0x6c, 0x6f, 0x6d, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x40, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, + 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, + 0x65, 0x65, 0x64, 0x53, 0x6f, 0x6c, 0x6f, 0x6d, 0x6f, 0x6e, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, + 0x6e, 0x67, 0x48, 0x00, 0x52, 0x0b, 0x72, 0x65, 0x65, 0x64, 0x53, 0x6f, 0x6c, 0x6f, 0x6d, 0x6f, + 0x6e, 0x12, 0x66, 0x0a, 0x1a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x65, 0x64, 0x34, 0x34, 0x38, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, + 0x45, 0x64, 0x34, 0x34, 0x38, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x48, 0x01, + 0x52, 0x17, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x45, 0x64, 0x34, 0x34, 0x38, 0x1a, 0xfa, 0x01, 0x0a, 0x13, 0x52, 0x65, + 0x65, 0x64, 0x53, 0x6f, 0x6c, 0x6f, 0x6d, 0x6f, 0x6e, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, + 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x53, 0x69, 0x7a, 0x65, + 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x68, 0x61, + 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, + 0x6e, 0x74, 0x53, 0x68, 0x61, 0x72, 0x64, 0x12, 0x39, 0x0a, 0x19, 0x66, 0x72, 0x61, 0x67, 0x6d, + 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x66, 0x72, 0x61, 0x67, + 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x61, 0x74, 0x61, 0x53, 0x68, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x3d, 0x0a, 0x1b, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x70, + 0x61, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x5f, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, + 0x74, 0x50, 0x61, 0x72, 0x69, 0x74, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, + 0x6e, 0x74, 0x44, 0x61, 0x74, 0x61, 0x42, 0x0a, 0x0a, 0x08, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, + 0x6e, 0x67, 0x42, 0x16, 0x0a, 0x14, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, + 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x67, 0x0a, 0x19, 0x43, 0x6c, + 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, + 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, + 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x6f, 0x72, 0x22, 0x94, 0x02, 0x0a, 0x12, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, + 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, + 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x66, + 0x72, 0x6f, 0x6d, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x26, + 0x0a, 0x0f, 0x74, 0x6f, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x74, 0x6f, 0x46, 0x72, 0x61, 0x6d, 0x65, + 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, + 0x69, 0x0a, 0x16, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, + 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, - 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x0b, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, - 0x65, 0x73, 0x42, 0x3a, 0x5a, 0x38, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x71, 0x75, 0x69, - 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x71, 0x75, 0x69, 0x6c, - 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x6d, 0x6f, 0x6e, 0x6f, 0x72, 0x65, 0x70, 0x6f, 0x2f, - 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x73, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x46, 0x72, 0x61, 0x6d, 0x65, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x6f, 0x72, 0x73, 0x52, 0x14, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22, 0x81, 0x01, 0x0a, 0x14, 0x43, + 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x72, 0x65, 0x66, 0x6c, 0x69, + 0x67, 0x68, 0x74, 0x12, 0x69, 0x0a, 0x16, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x70, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, + 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x14, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22, 0xca, + 0x01, 0x0a, 0x13, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x2a, + 0x0a, 0x11, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x66, 0x72, 0x6f, 0x6d, 0x46, + 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x6f, + 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0d, 0x74, 0x6f, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x12, 0x47, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x66, 0x72, 0x61, 0x6d, + 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, + 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x0b, + 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x42, 0x3a, 0x5a, 0x38, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2f, + 0x6d, 0x6f, 0x6e, 0x6f, 0x72, 0x65, 0x70, 0x6f, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -560,27 +821,31 @@ func file_clock_proto_rawDescGZIP() []byte { return file_clock_proto_rawDescData } -var file_clock_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_clock_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_clock_proto_goTypes = []interface{}{ - (*ClockFrame)(nil), // 0: quilibrium.node.clock.pb.ClockFrame - (*ClockFrameParentSelectors)(nil), // 1: quilibrium.node.clock.pb.ClockFrameParentSelectors - (*ClockFramesRequest)(nil), // 2: quilibrium.node.clock.pb.ClockFramesRequest - (*ClockFramesPreflight)(nil), // 3: quilibrium.node.clock.pb.ClockFramesPreflight - (*ClockFramesResponse)(nil), // 4: quilibrium.node.clock.pb.ClockFramesResponse - (*InclusionAggregateProof)(nil), // 5: quilibrium.node.channel.pb.InclusionAggregateProof - (*Ed448Signature)(nil), // 6: quilibrium.node.keys.pb.Ed448Signature + (*ClockFrame)(nil), // 0: quilibrium.node.clock.pb.ClockFrame + (*ClockFrameFragment)(nil), // 1: quilibrium.node.clock.pb.ClockFrameFragment + (*ClockFrameParentSelectors)(nil), // 2: quilibrium.node.clock.pb.ClockFrameParentSelectors + (*ClockFramesRequest)(nil), // 3: quilibrium.node.clock.pb.ClockFramesRequest + (*ClockFramesPreflight)(nil), // 4: quilibrium.node.clock.pb.ClockFramesPreflight + (*ClockFramesResponse)(nil), // 5: quilibrium.node.clock.pb.ClockFramesResponse + (*ClockFrameFragment_ReedSolomonEncoding)(nil), // 6: quilibrium.node.clock.pb.ClockFrameFragment.ReedSolomonEncoding + (*InclusionAggregateProof)(nil), // 7: quilibrium.node.channel.pb.InclusionAggregateProof + (*Ed448Signature)(nil), // 8: quilibrium.node.keys.pb.Ed448Signature } var file_clock_proto_depIdxs = []int32{ - 5, // 0: quilibrium.node.clock.pb.ClockFrame.aggregate_proofs:type_name -> quilibrium.node.channel.pb.InclusionAggregateProof - 6, // 1: quilibrium.node.clock.pb.ClockFrame.public_key_signature_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature - 1, // 2: quilibrium.node.clock.pb.ClockFramesRequest.range_parent_selectors:type_name -> quilibrium.node.clock.pb.ClockFrameParentSelectors - 1, // 3: quilibrium.node.clock.pb.ClockFramesPreflight.range_parent_selectors:type_name -> quilibrium.node.clock.pb.ClockFrameParentSelectors - 0, // 4: quilibrium.node.clock.pb.ClockFramesResponse.clock_frames:type_name -> quilibrium.node.clock.pb.ClockFrame - 5, // [5:5] is the sub-list for method output_type - 5, // [5:5] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 7, // 0: quilibrium.node.clock.pb.ClockFrame.aggregate_proofs:type_name -> quilibrium.node.channel.pb.InclusionAggregateProof + 8, // 1: quilibrium.node.clock.pb.ClockFrame.public_key_signature_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature + 6, // 2: quilibrium.node.clock.pb.ClockFrameFragment.reed_solomon:type_name -> quilibrium.node.clock.pb.ClockFrameFragment.ReedSolomonEncoding + 8, // 3: quilibrium.node.clock.pb.ClockFrameFragment.public_key_signature_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature + 2, // 4: quilibrium.node.clock.pb.ClockFramesRequest.range_parent_selectors:type_name -> quilibrium.node.clock.pb.ClockFrameParentSelectors + 2, // 5: quilibrium.node.clock.pb.ClockFramesPreflight.range_parent_selectors:type_name -> quilibrium.node.clock.pb.ClockFrameParentSelectors + 0, // 6: quilibrium.node.clock.pb.ClockFramesResponse.clock_frames:type_name -> quilibrium.node.clock.pb.ClockFrame + 7, // [7:7] is the sub-list for method output_type + 7, // [7:7] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name } func init() { file_clock_proto_init() } @@ -604,7 +869,7 @@ func file_clock_proto_init() { } } file_clock_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ClockFrameParentSelectors); i { + switch v := v.(*ClockFrameFragment); i { case 0: return &v.state case 1: @@ -616,7 +881,7 @@ func file_clock_proto_init() { } } file_clock_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ClockFramesRequest); i { + switch v := v.(*ClockFrameParentSelectors); i { case 0: return &v.state case 1: @@ -628,7 +893,7 @@ func file_clock_proto_init() { } } file_clock_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ClockFramesPreflight); i { + switch v := v.(*ClockFramesRequest); i { case 0: return &v.state case 1: @@ -640,6 +905,18 @@ func file_clock_proto_init() { } } file_clock_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClockFramesPreflight); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_clock_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ClockFramesResponse); i { case 0: return &v.state @@ -651,17 +928,33 @@ func file_clock_proto_init() { return nil } } + file_clock_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClockFrameFragment_ReedSolomonEncoding); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_clock_proto_msgTypes[0].OneofWrappers = []interface{}{ (*ClockFrame_PublicKeySignatureEd448)(nil), } + file_clock_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*ClockFrameFragment_ReedSolomon)(nil), + (*ClockFrameFragment_PublicKeySignatureEd448)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_clock_proto_rawDesc, NumEnums: 0, - NumMessages: 5, + NumMessages: 7, NumExtensions: 0, NumServices: 0, }, diff --git a/node/protobufs/clock.proto b/node/protobufs/clock.proto index 5b8815e..63ce4a6 100644 --- a/node/protobufs/clock.proto +++ b/node/protobufs/clock.proto @@ -59,6 +59,33 @@ message ClockFrame { oneof public_key_signature { quilibrium.node.keys.pb.Ed448Signature public_key_signature_ed448 = 9; } + // Padding is used in tests in order to simulate large clock frames. + bytes padding = 99; +} + +// Represents a clock frame fragment for a given filter. Clock frame fragments +// are used to disseminate clock frame data across the network in a more +// efficient manner. This is particularly useful for large clock frames, where +// the frame data can be split into smaller fragments and sent across the +// network in parallel. +message ClockFrameFragment { + bytes filter = 1; + uint64 frame_number = 2; + int64 timestamp = 3; + bytes frame_hash = 4; + message ReedSolomonEncoding { + uint64 frame_size = 1; + uint64 fragment_shard = 2; + uint64 fragment_data_shard_count = 3; + uint64 fragment_parity_shard_count = 4; + bytes fragment_data = 5; + } + oneof encoding { + ReedSolomonEncoding reed_solomon = 5; + } + oneof public_key_signature { + quilibrium.node.keys.pb.Ed448Signature public_key_signature_ed448 = 6; + } } message ClockFrameParentSelectors { diff --git a/node/protobufs/protobufs.go b/node/protobufs/protobufs.go index 90638b6..ed9b2eb 100644 --- a/node/protobufs/protobufs.go +++ b/node/protobufs/protobufs.go @@ -37,6 +37,7 @@ const ( IdentityKeyType = ChannelPrefix + "IdentityKey" SignedPreKeyType = ChannelPrefix + "SignedPreKey" ClockFrameType = ClockPrefix + "ClockFrame" + ClockFrameFragmentType = ClockPrefix + "ClockFrameFragment" ClockFramesRequestType = ClockPrefix + "ClockFramesRequest" ClockFramesResponseType = ClockPrefix + "ClockFramesResponse" Ed448PublicKeyType = KeysPrefix + "Ed448PublicKey" diff --git a/node/protobufs/validation.go b/node/protobufs/validation.go index f4a7860..eb80801 100644 --- a/node/protobufs/validation.go +++ b/node/protobufs/validation.go @@ -1,6 +1,7 @@ package protobufs import ( + "crypto/sha256" "encoding/binary" "github.com/pkg/errors" @@ -10,6 +11,33 @@ type signatureMessage interface { signatureMessage() []byte } +var _ signatureMessage = (*ClockFrameFragment_ReedSolomonEncoding)(nil) + +func (c *ClockFrameFragment_ReedSolomonEncoding) signatureMessage() []byte { + payload := []byte("reed-solomon-fragment") + payload = binary.BigEndian.AppendUint64(payload, c.FrameSize) + payload = binary.BigEndian.AppendUint64(payload, c.FragmentShard) + payload = binary.BigEndian.AppendUint64(payload, c.FragmentDataShardCount) + payload = binary.BigEndian.AppendUint64(payload, c.FragmentParityShardCount) + h := sha256.Sum256(c.FragmentData) + payload = append(payload, h[:]...) + return payload +} + +var _ signatureMessage = (*ClockFrameFragment)(nil) + +func (c *ClockFrameFragment) signatureMessage() []byte { + payload := []byte("fragment") + payload = binary.BigEndian.AppendUint64(payload, c.FrameNumber) + payload = append(payload, c.Filter...) + payload = binary.BigEndian.AppendUint64(payload, uint64(c.Timestamp)) + payload = append(payload, c.FrameHash...) + if reedSolomon := c.GetReedSolomon(); reedSolomon != nil { + payload = append(payload, reedSolomon.signatureMessage()...) + } + return payload +} + var _ signatureMessage = (*TransferCoinRequest)(nil) func (t *TransferCoinRequest) signatureMessage() []byte { @@ -99,6 +127,21 @@ type SignedMessage interface { ValidateSignature() error } +var _ SignedMessage = (*ClockFrameFragment)(nil) + +// ValidateSignature checks the signature of the clock frame fragment. +func (c *ClockFrameFragment) ValidateSignature() error { + switch { + case c.GetPublicKeySignatureEd448() != nil: + if err := c.GetPublicKeySignatureEd448().verifyUnsafe(c.signatureMessage()); err != nil { + return errors.Wrap(err, "validate signature") + } + return nil + default: + return errors.New("invalid signature") + } +} + var _ SignedMessage = (*TransferCoinRequest)(nil) // ValidateSignature checks the signature of the transfer coin request. @@ -204,6 +247,61 @@ type ValidatableMessage interface { Validate() error } +var _ ValidatableMessage = (*ClockFrameFragment_ReedSolomonEncoding)(nil) + +// Validate checks the Reed-Solomon encoding. +func (c *ClockFrameFragment_ReedSolomonEncoding) Validate() error { + if c == nil { + return errors.New("nil Reed-Solomon encoding") + } + if c.FrameSize == 0 { + return errors.New("invalid frame size") + } + if c.FragmentDataShardCount == 0 { + return errors.New("invalid fragment data shard count") + } + if c.FragmentParityShardCount == 0 { + return errors.New("invalid fragment parity shard count") + } + if c.FragmentShard >= c.FragmentDataShardCount+c.FragmentParityShardCount { + return errors.New("invalid fragment shard") + } + if len(c.FragmentData) == 0 { + return errors.New("invalid fragment data") + } + return nil +} + +var _ ValidatableMessage = (*ClockFrameFragment)(nil) + +// Validate checks the clock frame fragment. +func (c *ClockFrameFragment) Validate() error { + if c == nil { + return errors.New("nil clock frame fragment") + } + if len(c.Filter) != 32 { + return errors.New("invalid filter") + } + if c.Timestamp == 0 { + return errors.New("invalid timestamp") + } + if n := len(c.FrameHash); n < 28 || n > 64 { + return errors.New("invalid frame hash") + } + switch { + case c.GetReedSolomon() != nil: + if err := c.GetReedSolomon().Validate(); err != nil { + return errors.Wrap(err, "reed-solomon encoding") + } + default: + return errors.New("missing encoding") + } + if err := c.ValidateSignature(); err != nil { + return errors.Wrap(err, "signature") + } + return nil +} + var _ ValidatableMessage = (*Ed448PublicKey)(nil) // Validate checks the Ed448 public key. @@ -573,6 +671,20 @@ func newED448Signature(publicKey, signature []byte) *Ed448Signature { } } +var _ SignableED448Message = (*ClockFrameFragment)(nil) + +// SignED448 signs the clock frame fragment with the given key. +func (c *ClockFrameFragment) SignED448(publicKey []byte, sign func([]byte) ([]byte, error)) error { + signature, err := sign(c.signatureMessage()) + if err != nil { + return errors.Wrap(err, "sign") + } + c.PublicKeySignature = &ClockFrameFragment_PublicKeySignatureEd448{ + PublicKeySignatureEd448: newED448Signature(publicKey, signature), + } + return nil +} + var _ SignableED448Message = (*TransferCoinRequest)(nil) // SignED448 signs the transfer coin request with the given key. diff --git a/node/protobufs/validation_test.go b/node/protobufs/validation_test.go index a10f9c1..2dc2f6f 100644 --- a/node/protobufs/validation_test.go +++ b/node/protobufs/validation_test.go @@ -41,6 +41,70 @@ func metaAppend[T any](bs ...[]T) []T { return result } +func TestClockFrameFragmentSignatureRoundtrip(t *testing.T) { + t.Parallel() + message := &protobufs.ClockFrameFragment{ + Filter: bytes.Repeat([]byte{0x01}, 32), + FrameNumber: 1, + Timestamp: 2, + FrameHash: bytes.Repeat([]byte{0x03}, 28), + Encoding: &protobufs.ClockFrameFragment_ReedSolomon{ + ReedSolomon: &protobufs.ClockFrameFragment_ReedSolomonEncoding{ + FrameSize: 3, + FragmentShard: 4, + FragmentDataShardCount: 5, + FragmentParityShardCount: 6, + FragmentData: bytes.Repeat([]byte{0x02}, 6), + }, + }, + PublicKeySignature: &protobufs.ClockFrameFragment_PublicKeySignatureEd448{ + PublicKeySignatureEd448: &protobufs.Ed448Signature{ + Signature: bytes.Repeat([]byte{0x02}, 114), + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: bytes.Repeat([]byte{0x03}, 57), + }, + }, + }, + } + if !bytes.Equal( + protobufs.SignatureMessageOf(message), + metaAppend( + []byte("fragment"), + []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + bytes.Repeat([]byte{0x01}, 32), + []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + bytes.Repeat([]byte{0x03}, 28), + metaAppend( + []byte("reed-solomon-fragment"), + []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05}, + []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, + []byte{ + 0x2e, 0xbd, 0x9a, 0x4e, 0x48, 0x8b, 0x47, 0x1c, + 0xd7, 0x0a, 0x25, 0xae, 0xcc, 0xb2, 0xdb, 0x50, + 0xaa, 0xbd, 0xa7, 0x3c, 0x92, 0xce, 0x8e, 0xe0, + 0xe2, 0x15, 0xcd, 0x89, 0x32, 0x0f, 0x6b, 0x9a, + }, + ), + ), + ) { + t.Fatal("unexpected signature message") + } + if err := message.ValidateSignature(); err == nil { + t.Fatal("expected error") + } + if err := message.SignED448(primaryPublicKeyBytes, primaryPrivateKey.Sign); err != nil { + t.Fatal(err) + } + if !bytes.Equal(message.GetPublicKeySignatureEd448().PublicKey.KeyValue, primaryPublicKeyBytes) { + t.Fatal("unexpected public key") + } + if err := message.ValidateSignature(); err != nil { + t.Fatal(err) + } +} + func TestTransferCoinRequestSignatureRoundtrip(t *testing.T) { t.Parallel() message := &protobufs.TransferCoinRequest{ @@ -422,6 +486,79 @@ func TestAnnounceProverResumeSignatureRoundtrip(t *testing.T) { } } +func TestClockFrameFragmentReedSolomonEncodingValidate(t *testing.T) { + t.Parallel() + if err := (*protobufs.ClockFrameFragment_ReedSolomonEncoding)(nil).Validate(); err == nil { + t.Fatal("expected error") + } + message := &protobufs.ClockFrameFragment_ReedSolomonEncoding{} + if err := message.Validate(); err == nil { + t.Fatal("expected error") + } + message.FrameSize = 1 + if err := message.Validate(); err == nil { + t.Fatal("expected error") + } + message.FragmentShard = 2 + if err := message.Validate(); err == nil { + t.Fatal("expected error") + } + message.FragmentDataShardCount = 3 + if err := message.Validate(); err == nil { + t.Fatal("expected error") + } + message.FragmentParityShardCount = 4 + if err := message.Validate(); err == nil { + t.Fatal("expected error") + } + message.FragmentData = bytes.Repeat([]byte{0x01}, 6) + if err := message.Validate(); err != nil { + t.Fatal(err) + } +} + +func TestClockFrameFragmentValidate(t *testing.T) { + t.Parallel() + if err := (*protobufs.ClockFrameFragment)(nil).Validate(); err == nil { + t.Fatal("expected error") + } + message := &protobufs.ClockFrameFragment{} + if err := message.Validate(); err == nil { + t.Fatal("expected error") + } + message.Filter = bytes.Repeat([]byte{0x01}, 32) + if err := message.Validate(); err == nil { + t.Fatal("expected error") + } + message.FrameNumber = 1 + if err := message.Validate(); err == nil { + t.Fatal("expected error") + } + message.Timestamp = 2 + if err := message.Validate(); err == nil { + t.Fatal("expected error") + } + message.FrameHash = bytes.Repeat([]byte{0x03}, 28) + if err := message.Validate(); err == nil { + t.Fatal("expected error") + } + message.Encoding = &protobufs.ClockFrameFragment_ReedSolomon{ + ReedSolomon: &protobufs.ClockFrameFragment_ReedSolomonEncoding{ + FrameSize: 2, + FragmentShard: 3, + FragmentDataShardCount: 4, + FragmentParityShardCount: 5, + FragmentData: bytes.Repeat([]byte{0x02}, 6), + }, + } + if err := message.SignED448(primaryPublicKeyBytes, primaryPrivateKey.Sign); err != nil { + t.Fatal(err) + } + if err := message.Validate(); err != nil { + t.Fatal(err) + } +} + func TestEd448PublicKeyValidate(t *testing.T) { t.Parallel() if err := (*protobufs.Ed448PublicKey)(nil).Validate(); err == nil { From cef7fb65cc10f6acd05a0866aa412f678565a941 Mon Sep 17 00:00:00 2001 From: petricadaipegsp <155911522+petricadaipegsp@users.noreply.github.com> Date: Tue, 3 Dec 2024 00:07:58 +0100 Subject: [PATCH 10/14] Avoid pooling large buffers (#399) * Revert buffer reuse * Use pool only for small messages --- go-libp2p-blossomsub/comm.go | 85 ++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 47 deletions(-) diff --git a/go-libp2p-blossomsub/comm.go b/go-libp2p-blossomsub/comm.go index e70cd7d..28d0f2d 100644 --- a/go-libp2p-blossomsub/comm.go +++ b/go-libp2p-blossomsub/comm.go @@ -56,10 +56,29 @@ func (p *PubSub) handleNewStream(s network.Stream) { p.inboundStreamsMx.Unlock() r := msgio.NewVarintReaderSize(s, p.hardMaxMessageSize) - for { - msgbytes, err := r.ReadMsg() + read := func() (*RPC, error) { + n, err := r.NextMsgLen() + if err != nil { + return nil, err + } + if n == 0 { + _, err := r.Read(nil) + return nil, err + } + buf := poolGet(n, p.softMaxMessageSize) + defer poolPut(buf, p.softMaxMessageSize) + if _, err := r.Read(buf); err != nil { + return nil, err + } + rpc := new(pb.RPC) + if err := rpc.Unmarshal(buf); err != nil { + return nil, err + } + return &RPC{RPC: rpc, from: peer}, nil + } + for { + rpc, err := read() if err != nil { - r.ReleaseMsg(msgbytes) if err != io.EOF { s.Reset() log.Debugf("error reading rpc from %s: %s", s.Conn().RemotePeer(), err) @@ -76,28 +95,10 @@ func (p *PubSub) handleNewStream(s network.Stream) { p.inboundStreamsMx.Unlock() return } - if len(msgbytes) == 0 { - r.ReleaseMsg(msgbytes) + if rpc == nil { continue } - rpc := &RPC{ - RPC: new(pb.RPC), - } - err = rpc.Unmarshal(msgbytes) - r.ReleaseMsg(msgbytes) - if err != nil { - s.Reset() - log.Warnf("bogus rpc from %s: %s", s.Conn().RemotePeer(), err) - p.inboundStreamsMx.Lock() - if p.inboundStreams[peer] == s { - delete(p.inboundStreams, peer) - } - p.inboundStreamsMx.Unlock() - return - } - - rpc.from = peer select { case p.incoming <- rpc: case <-p.ctx.Done(): @@ -169,11 +170,10 @@ func (p *PubSub) handlePeerDead(s network.Stream) { } func (p *PubSub) handleSendingMessages(ctx context.Context, s network.Stream, q *rpcQueue) { - getBuffer, returnLastBuffer := makeBufferSource() - defer returnLastBuffer() writeRPC := func(rpc *RPC) error { size := uint64(rpc.Size()) - buf := getBuffer(varint.UvarintSize(size) + int(size)) + buf := poolGet(varint.UvarintSize(size)+int(size), p.softMaxMessageSize) + defer poolPut(buf, p.softMaxMessageSize) n := binary.PutUvarint(buf, size) _, err := rpc.MarshalTo(buf[n:]) if err != nil { @@ -236,27 +236,18 @@ func copyRPC(rpc *RPC) *RPC { return res } -// makeBufferSource returns a function that can be used to allocate buffers of -// a given size, and a function that can be used to return the last buffer -// allocated. -// The returned function will attempt to reuse the last buffer allocated if -// the requested size is less than or equal to the capacity of the last buffer. -// If the requested size is greater than the capacity of the last buffer, the -// last buffer is returned to the pool and a new buffer is allocated. -// If the requested size is less than or equal to half the capacity of the last -// buffer, the last buffer is returned to the pool and a new buffer is allocated. -func makeBufferSource() (func(int) []byte, func()) { - b := pool.Get(0) - mk := func(n int) []byte { - if c := cap(b); c/2 < n && n <= c { - return b[:n] - } - pool.Put(b) - b = pool.Get(n) - return b +// poolGet returns a buffer of length n from the pool if n < limit, otherwise it allocates a new buffer. +func poolGet(n int, limit int) []byte { + if n >= limit { + return make([]byte, n) } - rt := func() { - pool.Put(b) - } - return mk, rt + return pool.Get(n) +} + +// poolPut returns a buffer to the pool if its length is less than limit. +func poolPut(buf []byte, limit int) { + if len(buf) >= limit { + return + } + pool.Put(buf) } From f6f87ce80b5d72df3998f253cd532369c3ab0d4b Mon Sep 17 00:00:00 2001 From: Cassandra Heart Date: Mon, 2 Dec 2024 16:27:59 -0600 Subject: [PATCH 11/14] bump version --- node/config/version.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/node/config/version.go b/node/config/version.go index 618338a..5519f44 100644 --- a/node/config/version.go +++ b/node/config/version.go @@ -13,15 +13,15 @@ func GetMinimumVersionCutoff() time.Time { // if there is something in the patch update that is needed to cut off unupgraded // peers. Be sure to update this to 0x00 for any new minor release func GetMinimumPatchVersion() byte { - return 0x02 + return 0x00 } func GetMinimumVersion() []byte { - return []byte{0x02, 0x00, 0x04} + return []byte{0x02, 0x00, 0x05} } func GetVersion() []byte { - return []byte{0x02, 0x00, 0x04} + return []byte{0x02, 0x00, 0x05} } func GetVersionString() string { @@ -43,9 +43,9 @@ func FormatVersion(version []byte) string { } func GetPatchNumber() byte { - return 0x02 + return 0x00 } func GetRCNumber() byte { - return 0x02 + return 0x00 } From 378d10469103a9b1539ab1fc4744c72926f2f47a Mon Sep 17 00:00:00 2001 From: Cassandra Heart Date: Tue, 3 Dec 2024 01:33:13 -0600 Subject: [PATCH 12/14] handle other half deletion cases --- node/store/clock.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/node/store/clock.go b/node/store/clock.go index 035d6cc..3a24de5 100644 --- a/node/store/clock.go +++ b/node/store/clock.go @@ -1064,8 +1064,7 @@ func (p *PebbleClockStore) DeleteDataClockFrameRange( for _, frame := range frames { err = p.deleteAggregateProofs(txn, frame) if err != nil { - txn.Abort() - return errors.Wrap(err, "delete data clock frame range") + continue } } @@ -1074,14 +1073,12 @@ func (p *PebbleClockStore) DeleteDataClockFrameRange( clockDataParentIndexKey(filter, i, bytes.Repeat([]byte{0xff}, 32)), ) if err != nil { - txn.Abort() - return errors.Wrap(err, "delete data clock frame range") + continue } err = txn.Delete(clockDataFrameKey(filter, i)) if err != nil { - txn.Abort() - return errors.Wrap(err, "delete data clock frame range") + continue } } From 63394edc9d23d2ddb10e42ec7e9753891790d09d Mon Sep 17 00:00:00 2001 From: petricadaipegsp <155911522+petricadaipegsp@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:26:19 +0100 Subject: [PATCH 13/14] Increase subscription buffer size (#400) --- go-libp2p-blossomsub/bitmask.go | 5 ++++- node/config/p2p.go | 1 + node/p2p/blossomsub.go | 25 +++++++++++++++++-------- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/go-libp2p-blossomsub/bitmask.go b/go-libp2p-blossomsub/bitmask.go index 0625ccf..2fa509b 100644 --- a/go-libp2p-blossomsub/bitmask.go +++ b/go-libp2p-blossomsub/bitmask.go @@ -13,6 +13,9 @@ import ( "github.com/libp2p/go-libp2p/core/peer" ) +// DefaultSubscriptionQueueSize is the default size of the subscription queue. +const DefaultSubscriptionQueueSize = 16384 + // ErrBitmaskClosed is returned if a Bitmask is utilized after it has been closed var ErrBitmaskClosed = errors.New("this Bitmask is closed, try opening a new one") @@ -167,7 +170,7 @@ func (t *Bitmask) Subscribe(opts ...SubOpt) (*Subscription, error) { } if sub.ch == nil { - sub.ch = make(chan *Message, 32) + sub.ch = make(chan *Message, DefaultSubscriptionQueueSize) } out := make(chan *Subscription, 1) diff --git a/node/config/p2p.go b/node/config/p2p.go index 2c98048..49d7306 100644 --- a/node/config/p2p.go +++ b/node/config/p2p.go @@ -53,4 +53,5 @@ type P2PConfig struct { PingAttempts int `yaml:"pingAttempts"` ValidateQueueSize int `yaml:"validateQueueSize"` ValidateWorkers int `yaml:"validateWorkers"` + SubscriptionQueueSize int `yaml:"subscriptionQueueSize"` } diff --git a/node/p2p/blossomsub.go b/node/p2p/blossomsub.go index a5ba56d..00e9056 100644 --- a/node/p2p/blossomsub.go +++ b/node/p2p/blossomsub.go @@ -82,10 +82,10 @@ type BlossomSub struct { signKey crypto.PrivKey peerScore map[string]*appScore peerScoreMx sync.Mutex - network uint8 bootstrap internal.PeerConnector discovery internal.PeerConnector reachability atomic.Pointer[network.Reachability] + p2pConfig config.P2PConfig } var _ PubSub = (*BlossomSub)(nil) @@ -160,7 +160,7 @@ func NewBlossomSubStreamer( bitmaskMap: make(map[string]*blossomsub.Bitmask), signKey: privKey, peerScore: make(map[string]*appScore), - network: p2pConfig.Network, + p2pConfig: *p2pConfig, } h, err := libp2p.New(opts...) @@ -314,7 +314,7 @@ func NewBlossomSub( bitmaskMap: make(map[string]*blossomsub.Bitmask), signKey: privKey, peerScore: make(map[string]*appScore), - network: p2pConfig.Network, + p2pConfig: *p2pConfig, } h, err := libp2p.New(opts...) @@ -493,7 +493,7 @@ func NewBlossomSub( )) params := toBlossomSubParams(p2pConfig) - rt := blossomsub.NewBlossomSubRouter(h, params, bs.network) + rt := blossomsub.NewBlossomSubRouter(h, params, bs.p2pConfig.Network) blossomOpts = append(blossomOpts, rt.WithDefaultTagTracer()) pubsub, err := blossomsub.NewBlossomSubWithRouter(ctx, h, rt, blossomOpts...) if err != nil { @@ -657,7 +657,7 @@ func (b *BlossomSub) Subscribe( b.logger.Info("subscribe to bitmask", zap.Binary("bitmask", bitmask)) subs := []*blossomsub.Subscription{} for _, bit := range bm { - sub, err := bit.Subscribe() + sub, err := bit.Subscribe(blossomsub.WithBufferSize(b.p2pConfig.SubscriptionQueueSize)) if err != nil { b.logger.Error("subscription failed", zap.Error(err)) return errors.Wrap(err, "subscribe") @@ -701,7 +701,9 @@ func (b *BlossomSub) Subscribe( } func (b *BlossomSub) Unsubscribe(bitmask []byte, raw bool) { - networkBitmask := append([]byte{b.network}, bitmask...) + // TODO: Fix this, it is broken - the bitmask parameter is not sliced, and the + // network is not pre-pended to the bitmask. + networkBitmask := append([]byte{b.p2pConfig.Network}, bitmask...) bm, ok := b.bitmaskMap[string(networkBitmask)] if !ok { return @@ -740,7 +742,9 @@ func (b *BlossomSub) GetPeerID() []byte { } func (b *BlossomSub) GetRandomPeer(bitmask []byte) ([]byte, error) { - networkBitmask := append([]byte{b.network}, bitmask...) + // TODO: Fix this, it is broken - the bitmask parameter is not sliced, and the + // network is not pre-pended to the bitmask. + networkBitmask := append([]byte{b.p2pConfig.Network}, bitmask...) peers := b.ps.ListPeers(networkBitmask) if len(peers) == 0 { return nil, errors.Wrap( @@ -875,6 +879,8 @@ func (b *BlossomSub) AddPeerScore(peerId []byte, scoreDelta int64) { func (b *BlossomSub) GetBitmaskPeers() map[string][]string { peers := map[string][]string{} + // TODO: Fix this, it is broken - the bitmask parameter is not sliced, and the + // network is not pre-pended to the bitmask. for _, k := range b.bitmaskMap { peers[fmt.Sprintf("%+x", k.Bitmask()[1:])] = []string{} @@ -931,7 +937,7 @@ func (b *BlossomSub) GetMultiaddrOfPeer(peerId []byte) string { } func (b *BlossomSub) GetNetwork() uint { - return uint(b.network) + return uint(b.p2pConfig.Network) } func (b *BlossomSub) StartDirectChannelListener( @@ -1165,6 +1171,9 @@ func withDefaults(p2pConfig *config.P2PConfig) *config.P2PConfig { if p2pConfig.ValidateWorkers == 0 { p2pConfig.ValidateWorkers = qruntime.WorkerCount(0, false) } + if p2pConfig.SubscriptionQueueSize == 0 { + p2pConfig.SubscriptionQueueSize = blossomsub.DefaultSubscriptionQueueSize + } return p2pConfig } From 667b2aa2bc9649e3ee6460cda26d285bdf854411 Mon Sep 17 00:00:00 2001 From: petricadaipegsp <155911522+petricadaipegsp@users.noreply.github.com> Date: Tue, 3 Dec 2024 12:00:48 +0100 Subject: [PATCH 14/14] Increase gossip history and length (#401) * Increase gossip history and length * Increase peer outbound queue size --- go-libp2p-blossomsub/blossomsub.go | 4 ++-- go-libp2p-blossomsub/pubsub.go | 3 +++ node/config/p2p.go | 1 + node/p2p/blossomsub.go | 4 ++++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/go-libp2p-blossomsub/blossomsub.go b/go-libp2p-blossomsub/blossomsub.go index 5888bfc..748c970 100644 --- a/go-libp2p-blossomsub/blossomsub.go +++ b/go-libp2p-blossomsub/blossomsub.go @@ -37,8 +37,8 @@ var ( BlossomSubDhi = 12 BlossomSubDscore = 4 BlossomSubDout = 2 - BlossomSubHistoryLength = 5 - BlossomSubHistoryGossip = 3 + BlossomSubHistoryLength = 9 + BlossomSubHistoryGossip = 6 BlossomSubDlazy = 6 BlossomSubGossipFactor = 0.25 BlossomSubGossipRetransmission = 3 diff --git a/go-libp2p-blossomsub/pubsub.go b/go-libp2p-blossomsub/pubsub.go index 69518a7..13e323e 100644 --- a/go-libp2p-blossomsub/pubsub.go +++ b/go-libp2p-blossomsub/pubsub.go @@ -32,6 +32,9 @@ const DefaultSoftMaxMessageSize = 1 << 20 // DefaultHardMaxMessageSize is 20 MB. const DefaultHardMaxMessageSize = 10 << 21 +// DefaultPeerOutboundQueueSize is the default size of the outbound message channel that we maintain for each peer. +const DefaultPeerOutboundQueueSize = 128 + var ( // TimeCacheDuration specifies how long a message ID will be remembered as seen. // Use WithSeenMessagesTTL to configure this per pubsub instance, instead of overriding the global default. diff --git a/node/config/p2p.go b/node/config/p2p.go index 49d7306..b6b54e5 100644 --- a/node/config/p2p.go +++ b/node/config/p2p.go @@ -54,4 +54,5 @@ type P2PConfig struct { ValidateQueueSize int `yaml:"validateQueueSize"` ValidateWorkers int `yaml:"validateWorkers"` SubscriptionQueueSize int `yaml:"subscriptionQueueSize"` + PeerOutboundQueueSize int `yaml:"peerOutboundQueueSize"` } diff --git a/node/p2p/blossomsub.go b/node/p2p/blossomsub.go index 00e9056..cfd1ad9 100644 --- a/node/p2p/blossomsub.go +++ b/node/p2p/blossomsub.go @@ -476,6 +476,7 @@ func NewBlossomSub( blossomOpts = append(blossomOpts, blossomsub.WithValidateQueueSize(p2pConfig.ValidateQueueSize), blossomsub.WithValidateWorkers(p2pConfig.ValidateWorkers), + blossomsub.WithPeerOutboundQueueSize(p2pConfig.PeerOutboundQueueSize), ) blossomOpts = append(blossomOpts, observability.WithPrometheusRawTracer()) blossomOpts = append(blossomOpts, blossomsub.WithPeerFilter(internal.NewStaticPeerFilter( @@ -1174,6 +1175,9 @@ func withDefaults(p2pConfig *config.P2PConfig) *config.P2PConfig { if p2pConfig.SubscriptionQueueSize == 0 { p2pConfig.SubscriptionQueueSize = blossomsub.DefaultSubscriptionQueueSize } + if p2pConfig.PeerOutboundQueueSize == 0 { + p2pConfig.PeerOutboundQueueSize = blossomsub.DefaultPeerOutboundQueueSize + } return p2pConfig }