Merge branch 'develop' into v2.0.4-p2

This commit is contained in:
Cassandra Heart 2024-11-27 20:40:13 -06:00
commit 796f42e834
No known key found for this signature in database
GPG Key ID: 6352152859385958
71 changed files with 5228 additions and 2328 deletions

View File

@ -37,7 +37,7 @@ var mergeCmd = &cobra.Command{
panic(err)
}
pub, err := privKey.GetPublic().Raw()
pubKeyBytes, err := privKey.GetPublic().Raw()
if err != nil {
panic(err)
}
@ -48,7 +48,7 @@ var mergeCmd = &cobra.Command{
addrBytes := addr.FillBytes(make([]byte, 32))
altAddr, err := poseidon.HashBytes([]byte(pub))
altAddr, err := poseidon.HashBytes([]byte(pubKeyBytes))
if err != nil {
panic(err)
}
@ -109,34 +109,20 @@ var mergeCmd = &cobra.Command{
}
}
// Create payload for merge operation
payload := []byte("merge")
for _, coinRef := range coinaddrs {
payload = append(payload, coinRef.Address...)
merge := &protobufs.MergeCoinRequest{
Coins: coinaddrs,
}
// Signing process
sig, err := privKey.Sign(payload)
if err != nil {
if err := merge.SignED448(pubKeyBytes, privKey.Sign); err != nil {
panic(err)
}
if err := merge.Validate(); err != nil {
panic(err)
}
// Send merge request
_, err = client.SendMessage(
context.Background(),
&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Merge{
Merge: &protobufs.MergeCoinRequest{
Coins: coinaddrs,
Signature: &protobufs.Ed448Signature{
Signature: sig,
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: pub,
},
},
},
},
},
merge.TokenRequest(),
)
if err != nil {
panic(err)

View File

@ -98,19 +98,19 @@ func publishMessage(
filter []byte,
message proto.Message,
) error {
any := &anypb.Any{}
if err := any.MarshalFrom(message); err != nil {
a := &anypb.Any{}
if err := a.MarshalFrom(message); err != nil {
return errors.Wrap(err, "publish message")
}
any.TypeUrl = strings.Replace(
any.TypeUrl,
a.TypeUrl = strings.Replace(
a.TypeUrl,
"type.googleapis.com",
"types.quilibrium.com",
1,
)
payload, err := proto.Marshal(any)
payload, err := proto.Marshal(a)
if err != nil {
return errors.Wrap(err, "publish message")
}

View File

@ -29,7 +29,6 @@ var splitCmd = &cobra.Command{
os.Exit(1)
}
payload := []byte("split")
coinaddrHex, _ := strings.CutPrefix(args[0], "0x")
coinaddr, err := hex.DecodeString(coinaddrHex)
if err != nil {
@ -38,7 +37,6 @@ var splitCmd = &cobra.Command{
coin := &protobufs.CoinRef{
Address: coinaddr,
}
payload = append(payload, coinaddr...)
conversionFactor, _ := new(big.Int).SetString("1DCD65000", 16)
amounts := [][]byte{}
@ -51,7 +49,6 @@ var splitCmd = &cobra.Command{
amount = amount.Mul(decimal.NewFromBigInt(conversionFactor, 0))
amountBytes := amount.BigInt().FillBytes(make([]byte, 32))
amounts = append(amounts, amountBytes)
payload = append(payload, amountBytes...)
}
conn, err := GetGRPCClient()
@ -61,37 +58,29 @@ var splitCmd = &cobra.Command{
defer conn.Close()
client := protobufs.NewNodeServiceClient(conn)
key, err := GetPrivKeyFromConfig(NodeConfig)
privKey, err := GetPrivKeyFromConfig(NodeConfig)
if err != nil {
panic(err)
}
pubKeyBytes, err := privKey.GetPublic().Raw()
if err != nil {
panic(err)
}
sig, err := key.Sign(payload)
if err != nil {
split := &protobufs.SplitCoinRequest{
OfCoin: coin,
Amounts: amounts,
}
if err := split.SignED448(pubKeyBytes, privKey.Sign); err != nil {
panic(err)
}
pub, err := key.GetPublic().Raw()
if err != nil {
if err := split.Validate(); err != nil {
panic(err)
}
_, err = client.SendMessage(
context.Background(),
&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Split{
Split: &protobufs.SplitCoinRequest{
OfCoin: coin,
Amounts: amounts,
Signature: &protobufs.Ed448Signature{
Signature: sig,
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: pub,
},
},
},
},
},
split.TokenRequest(),
)
if err != nil {
panic(err)

View File

@ -31,13 +31,16 @@ var transferCmd = &cobra.Command{
defer conn.Close()
client := protobufs.NewNodeServiceClient(conn)
key, err := GetPrivKeyFromConfig(NodeConfig)
privKey, err := GetPrivKeyFromConfig(NodeConfig)
if err != nil {
panic(err)
}
pubKeyBytes, err := privKey.GetPublic().Raw()
if err != nil {
panic(err)
}
var coinaddr *protobufs.CoinRef
payload := []byte("transfer")
toaddr := []byte{}
for i, arg := range args {
addrHex, _ := strings.CutPrefix(arg, "0x")
@ -53,42 +56,28 @@ var transferCmd = &cobra.Command{
coinaddr = &protobufs.CoinRef{
Address: addr,
}
payload = append(payload, addr...)
}
payload = append(payload, toaddr...)
sig, err := key.Sign(payload)
if err != nil {
transfer := &protobufs.TransferCoinRequest{
OfCoin: coinaddr,
ToAccount: &protobufs.AccountRef{
Account: &protobufs.AccountRef_ImplicitAccount{
ImplicitAccount: &protobufs.ImplicitAccount{
Address: toaddr,
},
},
},
}
if err := transfer.SignED448(pubKeyBytes, privKey.Sign); err != nil {
panic(err)
}
pub, err := key.GetPublic().Raw()
if err != nil {
if err := transfer.Validate(); err != nil {
panic(err)
}
_, err = client.SendMessage(
context.Background(),
&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Transfer{
Transfer: &protobufs.TransferCoinRequest{
OfCoin: coinaddr,
ToAccount: &protobufs.AccountRef{
Account: &protobufs.AccountRef_ImplicitAccount{
ImplicitAccount: &protobufs.ImplicitAccount{
Address: toaddr,
},
},
},
Signature: &protobufs.Ed448Signature{
Signature: sig,
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: pub,
},
},
},
},
},
transfer.TokenRequest(),
)
if err != nil {
panic(err)

View File

@ -1,8 +1,8 @@
module source.quilibrium.com/quilibrium/monorepo/client
go 1.21
go 1.22
toolchain go1.22.1
toolchain go1.22.5
replace source.quilibrium.com/quilibrium/monorepo/nekryptology => ../nekryptology
@ -14,6 +14,8 @@ 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

View File

@ -263,8 +263,6 @@ 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=

View File

@ -0,0 +1,18 @@
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

View File

@ -0,0 +1,20 @@
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 }}

View File

@ -0,0 +1,19 @@
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

View File

@ -0,0 +1,17 @@
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

View File

@ -0,0 +1,13 @@
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

View File

@ -0,0 +1,18 @@
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

21
go-buffer-pool/LICENSE Normal file
View File

@ -0,0 +1,21 @@
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.

View File

@ -0,0 +1,29 @@
### 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.

56
go-buffer-pool/README.md Normal file
View File

@ -0,0 +1,56 @@
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

302
go-buffer-pool/buffer.go Normal file
View File

@ -0,0 +1,302 @@
// 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 `<nil>` the buffer is a nil pointer.
func (b *Buffer) String() string {
if b == nil {
return "<nil>"
}
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]
}
}

View File

@ -0,0 +1,400 @@
// 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() != "<nil>" {
t.Errorf("expected <nil>; 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])
}
}
}

View File

@ -0,0 +1,3 @@
coverage:
range: "50...100"
comment: off

3
go-buffer-pool/go.mod Normal file
View File

@ -0,0 +1,3 @@
module github.com/libp2p/go-buffer-pool
go 1.22

103
go-buffer-pool/pool.go Normal file
View File

@ -0,0 +1,103 @@
// 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<<idx)[:uint32(length)]
}
// Put adds x to the pool.
func (p *BufferPool) Put(buf []byte) {
capacity := cap(buf)
if capacity == 0 || capacity > 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
}

185
go-buffer-pool/pool_test.go Normal file
View File

@ -0,0 +1,185 @@
// 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<<pow))
}
}
for _, b := range bufs {
p.Put(b)
}
}
})
}
func ExampleGet() {
buf := Get(100)
fmt.Println("length", len(buf))
fmt.Println("capacity", cap(buf))
Put(buf)
// Output:
// length 100
// capacity 128
}

View File

@ -0,0 +1,3 @@
{
"version": "v0.1.0"
}

119
go-buffer-pool/writer.go Normal file
View File

@ -0,0 +1,119 @@
package pool
import (
"bufio"
"io"
"sync"
)
const WriterBufferSize = 4096
var bufioWriterPool = sync.Pool{
New: func() interface{} {
return bufio.NewWriterSize(nil, WriterBufferSize)
},
}
// Writer is a buffered writer that returns its internal buffer in a pool when
// not in use.
type Writer struct {
W io.Writer
bufw *bufio.Writer
}
func (w *Writer) ensureBuffer() {
if w.bufw == nil {
w.bufw = bufioWriterPool.Get().(*bufio.Writer)
w.bufw.Reset(w.W)
}
}
// Write writes the given byte slice to the underlying connection.
//
// Note: Write won't return the write buffer to the pool even if it ends up
// being empty after the write. You must call Flush() to do that.
func (w *Writer) Write(b []byte) (int, error) {
if w.bufw == nil {
if len(b) >= 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
}

View File

@ -0,0 +1,91 @@
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)
}
}

View File

@ -40,6 +40,7 @@ var (
BlossomSubHistoryLength = 5
BlossomSubHistoryGossip = 3
BlossomSubDlazy = 6
BlossomSubGossipFactor = 0.25
BlossomSubGossipRetransmission = 3
BlossomSubBitmaskWidth = 256
BlossomSubHeartbeatInitialDelay = 100 * time.Millisecond
@ -116,9 +117,15 @@ type BlossomSubParams struct {
// Dlazy affects how many peers we will emit gossip to at each heartbeat.
// We will send gossip to at least Dlazy peers outside our mesh. The actual
// number may be less, depending on how many peers we're connected to.
// number may be more, depending on GossipFactor and how many peers we're
// connected to.
Dlazy int
// GossipFactor affects how many peers we will emit gossip to at each heartbeat.
// We will send gossip to GossipFactor * (total number of non-mesh peers), or
// Dlazy, whichever is greater.
GossipFactor float64
// GossipRetransmission controls how many times we will allow a peer to request
// the same message id through IWANT gossip before we start ignoring them. This is designed
// to prevent peers from spamming us with requests and wasting our resources.
@ -313,6 +320,7 @@ func DefaultBlossomSubParams() BlossomSubParams {
HistoryLength: BlossomSubHistoryLength,
HistoryGossip: BlossomSubHistoryGossip,
Dlazy: BlossomSubDlazy,
GossipFactor: BlossomSubGossipFactor,
GossipRetransmission: BlossomSubGossipRetransmission,
HeartbeatInitialDelay: BlossomSubHeartbeatInitialDelay,
HeartbeatInterval: BlossomSubHeartbeatInterval,
@ -693,62 +701,31 @@ func (bs *BlossomSubRouter) RemovePeer(p peer.ID) {
}
func (bs *BlossomSubRouter) EnoughPeers(bitmask []byte, suggested int) bool {
sliced := SliceBitmask(bitmask)
// bloom:
if len(sliced) != 1 {
// check all peers in the bitmask
peers := bs.p.getPeersInBitmask(bitmask)
if len(peers) == 0 {
return false
}
fsPeers, bsPeers := 0, 0
for _, p := range peers {
if !bs.feature(BlossomSubFeatureMesh, bs.peers[p]) {
fsPeers++
}
}
// BlossomSub peers
bsPeers = len(peers)
if suggested == 0 {
suggested = bs.params.Dlo
}
if fsPeers+bsPeers >= suggested || bsPeers >= bs.params.Dhi {
return true
}
return false
} else { // classic gossip
tmap, ok := bs.p.bitmasks[string(bitmask)]
if !ok {
return false
}
fsPeers, bsPeers := 0, 0
// floodsub peers
for p := range tmap {
if !bs.feature(BlossomSubFeatureMesh, bs.peers[p]) {
fsPeers++
}
}
// BlossomSub peers
bsPeers = len(bs.mesh[string(bitmask)])
if suggested == 0 {
suggested = bs.params.Dlo
}
if fsPeers+bsPeers >= suggested || bsPeers >= bs.params.Dhi {
return true
}
tmap, ok := bs.p.bitmasks[string(bitmask)]
if !ok {
return false
}
fsPeers, bsPeers := 0, 0
// floodsub peers
for p := range tmap {
if !bs.feature(BlossomSubFeatureMesh, bs.peers[p]) {
fsPeers++
}
}
// BlossomSub peers
bsPeers = len(bs.mesh[string(bitmask)])
if suggested == 0 {
suggested = bs.params.Dlo
}
if fsPeers+bsPeers >= suggested || bsPeers >= bs.params.Dhi {
return true
}
return false
}
func (bs *BlossomSubRouter) PeerScore(p peer.ID) float64 {
@ -943,6 +920,13 @@ func (bs *BlossomSubRouter) handleIWant(p peer.ID, ctl *pb.ControlMessage) []*pb
msgs := make([]*pb.Message, 0, len(ihave))
for _, msg := range ihave {
if peer.ID(msg.GetFrom()) == p {
continue
}
mid := bs.p.idGen.RawID(msg)
if _, ok := bs.unwanted[p][string(mid)]; ok {
continue
}
msgs = append(msgs, msg)
}
@ -1052,31 +1036,15 @@ func (bs *BlossomSubRouter) handlePrune(p peer.ID, ctl *pb.ControlMessage) {
for _, prune := range ctl.GetPrune() {
bitmask := prune.GetBitmask()
sliced := SliceBitmask(bitmask)
// bloom publish:
if len(sliced) != 1 {
// any peers in all slices of the bitmask?
peers := bs.p.getPeersInBitmask(bitmask)
if len(peers) == 0 {
return
}
peers, ok := bs.mesh[string(bitmask)]
if !ok {
continue
}
for _, p := range peers {
log.Debugf("PRUNE: Remove mesh link to %s in %s", p, bitmask)
bs.tracer.Prune(p, bitmask)
delete(bs.p.bitmasks[string(bitmask)], p)
}
} else { // classic gossip mesh
peers, ok := bs.mesh[string(bitmask)]
if !ok {
continue
}
if _, inMesh := peers[p]; inMesh {
log.Debugf("PRUNE: Remove mesh link to %s in %s", p, bitmask)
bs.tracer.Prune(p, bitmask)
delete(peers, p)
}
if _, inMesh := peers[p]; inMesh {
log.Debugf("PRUNE: Remove mesh link to %s in %s", p, bitmask)
bs.tracer.Prune(p, bitmask)
delete(peers, p)
}
// is there a backoff specified by the peer? if so obey it.
@ -1227,22 +1195,13 @@ func (bs *BlossomSubRouter) Publish(msg *Message) {
from := msg.ReceivedFrom
bitmask := msg.GetBitmask()
originalSender := peer.ID(msg.GetFrom())
mid := string(bs.p.idGen.ID(msg))
tosend := make(map[peer.ID]struct{})
var toSendAll []map[peer.ID]struct{}
for _, bitmask := range SliceBitmask(bitmask) {
tosend := make(map[peer.ID]struct{})
sliced := SliceBitmask(bitmask)
// bloom publish:
if len(sliced) != 1 {
// any peers in all slices of the bitmask?
peers := bs.p.getPeersInBitmask(bitmask)
if len(peers) == 0 {
return
}
for _, p := range peers {
tosend[p] = struct{}{}
}
} else { // classic gossip mesh
// any peers in the bitmask?
tmap, ok := bs.p.bitmasks[string(bitmask)]
if !ok {
@ -1296,21 +1255,27 @@ func (bs *BlossomSubRouter) Publish(msg *Message) {
tosend[p] = struct{}{}
}
}
delete(tosend, from)
delete(tosend, originalSender)
for p := range tosend {
if _, ok := bs.unwanted[p][mid]; ok {
delete(tosend, p)
}
}
if len(tosend) > 0 {
toSendAll = append(toSendAll, tosend)
}
}
if len(toSendAll) == 0 {
return
}
toSend := toSendAll[rand.Intn(len(toSendAll))]
out := rpcWithMessages(msg.Message)
for pid := range tosend {
if pid == from || pid == peer.ID(msg.GetFrom()) {
continue
}
mid := bs.p.idGen.ID(msg)
// Check if it has already received an IDONTWANT for the message.
// If so, don't send it to the peer
if _, ok := bs.unwanted[pid][string(mid)]; ok {
continue
}
for pid := range toSend {
bs.sendRPC(pid, out, false)
}
}
@ -1374,56 +1339,24 @@ func (bs *BlossomSubRouter) Join(bitmask []byte) {
}
func (bs *BlossomSubRouter) Leave(bitmask []byte) {
sliced := SliceBitmask(bitmask)
// bloom publish:
if len(sliced) != 1 {
// any peers in all slices of the bitmask?
peers := bs.p.getPeersInBitmask(bitmask)
if len(peers) == 0 {
return
}
gmap, ok := bs.mesh[string(bitmask)]
if !ok {
return
}
for _, s := range sliced {
_, ok := bs.mesh[string(s)]
if !ok {
continue
}
log.Debugf("LEAVE %s", bitmask)
bs.tracer.Leave(bitmask)
log.Debugf("LEAVE %s", bitmask)
bs.tracer.Leave(bitmask)
delete(bs.mesh, string(bitmask))
delete(bs.mesh, string(bitmask))
}
for _, p := range peers {
log.Debugf("LEAVE: Remove mesh link to %s in %s", p, bitmask)
bs.tracer.Prune(p, bitmask)
bs.sendPrune(p, bitmask, true)
// Add a backoff to this peer to prevent us from eagerly
// re-grafting this peer into our mesh if we rejoin this
// bitmask before the backoff period ends.
bs.addBackoff(p, bitmask, true)
}
} else { // classic gossip mesh
gmap, ok := bs.mesh[string(bitmask)]
if !ok {
return
}
log.Debugf("LEAVE %s", bitmask)
bs.tracer.Leave(bitmask)
delete(bs.mesh, string(bitmask))
for p := range gmap {
log.Debugf("LEAVE: Remove mesh link to %s in %s", p, bitmask)
bs.tracer.Prune(p, bitmask)
bs.sendPrune(p, bitmask, true)
// Add a backoff to this peer to prevent us from eagerly
// re-grafting this peer into our mesh if we rejoin this
// bitmask before the backoff period ends.
bs.addBackoff(p, bitmask, true)
}
for p := range gmap {
log.Debugf("LEAVE: Remove mesh link to %s in %s", p, bitmask)
bs.tracer.Prune(p, bitmask)
bs.sendPrune(p, bitmask, true)
// Add a backoff to this peer to prevent us from eagerly
// re-grafting this peer into our mesh if we rejoin this
// bitmask before the backoff period ends.
bs.addBackoff(p, bitmask, true)
}
}
@ -1469,18 +1402,18 @@ func (bs *BlossomSubRouter) sendRPC(p peer.ID, out *RPC, fast bool) {
}
// If we're below the max message size, go ahead and send
if out.Size() < bs.p.maxMessageSize {
if out.Size() < bs.p.softMaxMessageSize {
bs.doSendRPC(out, p, mch, fast)
return
}
outCopy := copyRPC(out)
// Potentially split the RPC into multiple RPCs that are below the max message size
outRPCs := appendOrMergeRPC(nil, bs.p.maxMessageSize, outCopy)
outRPCs := appendOrMergeRPC(nil, bs.p.softMaxMessageSize, outCopy)
for _, rpc := range outRPCs {
if rpc.Size() > bs.p.maxMessageSize {
if rpc.Size() > bs.p.hardMaxMessageSize {
// This should only happen if a single message/control is above the maxMessageSize.
bs.doDropRPC(out, p, fmt.Sprintf("Dropping oversized RPC. Size: %d, limit: %d. (Over by %d bytes)", rpc.Size(), bs.p.maxMessageSize, rpc.Size()-bs.p.maxMessageSize))
bs.doDropRPC(out, p, fmt.Sprintf("Dropping oversized RPC. Size: %d, limit: %d. (Over by %d bytes)", rpc.Size(), bs.p.hardMaxMessageSize, rpc.Size()-bs.p.hardMaxMessageSize))
continue
}
bs.doSendRPC(rpc, p, mch, fast)
@ -2070,6 +2003,8 @@ func (bs *BlossomSubRouter) emitGossip(bitmask []byte, exclude map[peer.ID]struc
}
target := bs.params.Dlazy
factor := int(bs.params.GossipFactor * float64(len(peers)))
target = max(target, factor)
if target > len(peers) {
target = len(peers)

View File

@ -1700,9 +1700,10 @@ func TestBlossomSubEnoughPeers(t *testing.T) {
}
// at this point we have no connections and no mesh, so EnoughPeers should return false
// NOTE: EnoughPeers operates with bloom filters, so we need to check for individual filters.
res := make(chan bool, 1)
psubs[0].eval <- func() {
res <- psubs[0].rt.EnoughPeers([]byte{0x00, 0x00, 0x81, 0x00}, 0)
res <- psubs[0].rt.EnoughPeers([]byte{0x00, 0x00, 0x80, 0x00}, 0)
}
enough := <-res
if enough {
@ -1715,7 +1716,7 @@ func TestBlossomSubEnoughPeers(t *testing.T) {
time.Sleep(5 * time.Second)
psubs[0].eval <- func() {
res <- psubs[0].rt.EnoughPeers([]byte{0x00, 0x00, 0x81, 0x00}, 0)
res <- psubs[0].rt.EnoughPeers([]byte{0x00, 0x00, 0x80, 0x00}, 0)
}
enough = <-res
if !enough {
@ -2199,11 +2200,12 @@ func TestBlossomSubLeaveBitmask(t *testing.T) {
leaveTime := time.Now()
done := make(chan struct{})
// NOTE: Leave operates with bloom filters, so we need to check for individual filters.
psubs[0].rt.(*BlossomSubRouter).p.eval <- func() {
defer close(done)
psubs[0].rt.Leave([]byte{0x00, 0x00, 0x81, 0x00})
psubs[0].rt.Leave([]byte{0x00, 0x00, 0x80, 0x00})
time.Sleep(time.Second)
peerMap := psubs[0].rt.(*BlossomSubRouter).backoff[string([]byte{0x00, 0x00, 0x81, 0x00})]
peerMap := psubs[0].rt.(*BlossomSubRouter).backoff[string([]byte{0x00, 0x00, 0x80, 0x00})]
if len(peerMap) != 1 {
t.Fatalf("No peer is populated in the backoff map for peer 0")
}
@ -2225,7 +2227,7 @@ func TestBlossomSubLeaveBitmask(t *testing.T) {
// for peer 0.
psubs[1].rt.(*BlossomSubRouter).p.eval <- func() {
defer close(done)
peerMap2 := psubs[1].rt.(*BlossomSubRouter).backoff[string([]byte{0x00, 0x00, 0x81, 0x00})]
peerMap2 := psubs[1].rt.(*BlossomSubRouter).backoff[string([]byte{0x00, 0x00, 0x80, 0x00})]
if len(peerMap2) != 1 {
t.Fatalf("No peer is populated in the backoff map for peer 1")
}
@ -2312,7 +2314,7 @@ func (sq *sybilSquatter) handleStream(s network.Stream) {
// send a subscription for test in the output stream to become candidate for GRAFT
// and then just read and ignore the incoming RPCs
r := msgio.NewVarintReaderSize(s, DefaultMaxMessageSize)
r := msgio.NewVarintReaderSize(s, DefaultHardMaxMessageSize)
w := msgio.NewVarintWriter(os)
truth := true
bitmask := []byte{0x00, 0x00, 0x81, 0x00}
@ -2532,7 +2534,7 @@ func TestBlossomSubRPCFragmentation(t *testing.T) {
// (nMessages * msgSize) / ps.maxMessageSize total RPCs containing the messages we sent IWANTs for.
// The actual number will probably be larger, since there's some overhead for the RPC itself, and
// we probably aren't packing each RPC to it's maximum size
minExpectedRPCS := (nMessages * msgSize) / ps.maxMessageSize
minExpectedRPCS := (nMessages * msgSize) / ps.softMaxMessageSize
if iwe.rpcsWithMessages < minExpectedRPCS {
t.Fatalf("expected to receive at least %d RPCs containing messages, got %d", minExpectedRPCS, iwe.rpcsWithMessages)
}
@ -2561,7 +2563,7 @@ func (iwe *iwantEverything) handleStream(s network.Stream) {
gossipMsgIdsReceived := make(map[string]struct{})
// send a subscription for test in the output stream to become candidate for gossip
r := msgio.NewVarintReaderSize(s, DefaultMaxMessageSize)
r := msgio.NewVarintReaderSize(s, DefaultHardMaxMessageSize)
w := msgio.NewVarintWriter(os)
truth := true
bitmasks := [][]byte{{0x00, 0x00, 0x80, 0x00}, {0x00, 0x00, 0x01, 0x00}}

View File

@ -55,7 +55,7 @@ func (p *PubSub) handleNewStream(s network.Stream) {
p.inboundStreams[peer] = s
p.inboundStreamsMx.Unlock()
r := msgio.NewVarintReaderSize(s, p.maxMessageSize)
r := msgio.NewVarintReaderSize(s, p.hardMaxMessageSize)
for {
msgbytes, err := r.ReadMsg()
if err != nil {

View File

@ -1,13 +1,15 @@
module source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub
go 1.21
go 1.22
toolchain go1.22.4
toolchain go1.22.5
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

View File

@ -140,8 +140,6 @@ 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=
@ -167,7 +165,6 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8=
@ -193,8 +190,6 @@ github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYg
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=
github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=
github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A=
github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk=
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
@ -463,7 +458,6 @@ golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@ -26,8 +26,11 @@ import (
logging "github.com/ipfs/go-log/v2"
)
// DefaultMaximumMessageSize is 10 MB.
const DefaultMaxMessageSize = 10 << 20
// DefaultSoftMaxMessageSize is 10 MiB.
const DefaultSoftMaxMessageSize = 10 << 20
// DefaultHardMaxMessageSize is 20 MB.
const DefaultHardMaxMessageSize = 10 << 21
var (
// TimeCacheDuration specifies how long a message ID will be remembered as seen.
@ -68,9 +71,12 @@ type PubSub struct {
peerFilter PeerFilter
// maxMessageSize is the maximum message size; it applies globally to all
// bitmasks.
maxMessageSize int
// softMaxMessageSize is the maximum size of a single message fragment that
// we will attempt to send.
softMaxMessageSize int
// hardMaxMessageSize is the maximum size of a single message fragment that
// we will accept.
hardMaxMessageSize int
// size of the outbound message channel that we maintain for each peer
peerOutboundQueueSize int
@ -265,7 +271,8 @@ func NewPubSub(ctx context.Context, h host.Host, rt PubSubRouter, opts ...Option
val: newValidation(),
peerFilter: DefaultPeerFilter,
disc: &discover{},
maxMessageSize: DefaultMaxMessageSize,
softMaxMessageSize: DefaultSoftMaxMessageSize,
hardMaxMessageSize: DefaultHardMaxMessageSize,
peerOutboundQueueSize: 32,
signID: h.ID(),
signKey: nil,
@ -520,9 +527,10 @@ func WithRawTracer(tracer RawTracer) Option {
// another type of locator, such that messages can be fetched on-demand, rather
// than being pushed proactively. Under this design, you'd use the pubsub layer
// as a signalling system, rather than a data delivery system.
func WithMaxMessageSize(maxMessageSize int) Option {
func WithMaxMessageSize(softMaxMessageSize, hardMaxMessageSize int) Option {
return func(ps *PubSub) error {
ps.maxMessageSize = maxMessageSize
ps.softMaxMessageSize = softMaxMessageSize
ps.hardMaxMessageSize = hardMaxMessageSize
return nil
}
}

View File

@ -251,7 +251,7 @@ func TestPBTracer(t *testing.T) {
}
defer f.Close()
r := msgio.NewVarintReaderSize(f, DefaultMaxMessageSize)
r := msgio.NewVarintReaderSize(f, DefaultHardMaxMessageSize)
for {
evt.Reset()

View File

@ -1,6 +1,8 @@
module github.com/libp2p/go-libp2p-kad-dht
go 1.21
go 1.22
toolchain go1.22.5
retract v0.24.3 // this includes a breaking change and should have been released as v0.25.0
@ -8,6 +10,8 @@ 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 (

View File

@ -246,10 +246,6 @@ 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=

View File

@ -1,9 +1,13 @@
module github.com/libp2p/go-libp2p
go 1.21
go 1.22
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

View File

@ -186,8 +186,6 @@ 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=

View File

@ -13,6 +13,7 @@ type P2PConfig struct {
HistoryLength int `yaml:"historyLength"`
HistoryGossip int `yaml:"historyGossip"`
DLazy int `yaml:"dLazy"`
GossipFactor float64 `yaml:"gossipFactor"`
GossipRetransmission int `yaml:"gossipRetransmission"`
HeartbeatInitialDelay time.Duration `yaml:"heartbeatInitialDelay"`
HeartbeatInterval time.Duration `yaml:"heartbeatInterval"`

View File

@ -6,7 +6,14 @@ import (
)
func GetMinimumVersionCutoff() time.Time {
return time.Date(2024, time.November, 2, 0, 0, 0, 0, time.UTC)
return time.Date(2024, time.November, 24, 0, 0, 0, 0, time.UTC)
}
// Gets the minimum patch version This should only be set in a release series
// 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
}
func GetMinimumVersion() []byte {
@ -36,9 +43,9 @@ func FormatVersion(version []byte) string {
}
func GetPatchNumber() byte {
return 0x01
return 0x02
}
func GetRCNumber() byte {
return 0x01
return 0x02
}

View File

@ -65,22 +65,24 @@ func (e *DataClockConsensusEngine) publishProof(
e.peerMapMx.Lock()
e.peerMap[string(e.pubSub.GetPeerID())] = &peerInfo{
peerId: e.pubSub.GetPeerID(),
multiaddr: "",
maxFrame: frame.FrameNumber,
version: config.GetVersion(),
timestamp: timestamp,
peerId: e.pubSub.GetPeerID(),
multiaddr: "",
maxFrame: frame.FrameNumber,
version: config.GetVersion(),
patchVersion: config.GetPatchNumber(),
timestamp: timestamp,
totalDistance: e.dataTimeReel.GetTotalDistance().FillBytes(
make([]byte, 256),
),
}
list := &protobufs.DataPeerListAnnounce{
Peer: &protobufs.DataPeer{
PeerId: nil,
Multiaddr: "",
MaxFrame: frame.FrameNumber,
Version: config.GetVersion(),
Timestamp: timestamp,
PeerId: nil,
Multiaddr: "",
MaxFrame: frame.FrameNumber,
Version: config.GetVersion(),
PatchVersion: []byte{config.GetPatchNumber()},
Timestamp: timestamp,
TotalDistance: e.dataTimeReel.GetTotalDistance().FillBytes(
make([]byte, 256),
),
@ -100,19 +102,19 @@ func (e *DataClockConsensusEngine) insertTxMessage(
filter []byte,
message proto.Message,
) error {
any := &anypb.Any{}
if err := any.MarshalFrom(message); err != nil {
a := &anypb.Any{}
if err := a.MarshalFrom(message); err != nil {
return errors.Wrap(err, "publish message")
}
any.TypeUrl = strings.Replace(
any.TypeUrl,
a.TypeUrl = strings.Replace(
a.TypeUrl,
"type.googleapis.com",
"types.quilibrium.com",
1,
)
payload, err := proto.Marshal(any)
payload, err := proto.Marshal(a)
if err != nil {
return errors.Wrap(err, "publish message")
}
@ -154,19 +156,19 @@ func (e *DataClockConsensusEngine) publishMessage(
filter []byte,
message proto.Message,
) error {
any := &anypb.Any{}
if err := any.MarshalFrom(message); err != nil {
a := &anypb.Any{}
if err := a.MarshalFrom(message); err != nil {
return errors.Wrap(err, "publish message")
}
any.TypeUrl = strings.Replace(
any.TypeUrl,
a.TypeUrl = strings.Replace(
a.TypeUrl,
"type.googleapis.com",
"types.quilibrium.com",
1,
)
payload, err := proto.Marshal(any)
payload, err := proto.Marshal(a)
if err != nil {
return errors.Wrap(err, "publish message")
}

View File

@ -21,12 +21,13 @@ import (
const defaultSyncTimeout = 4 * time.Second
func (e *DataClockConsensusEngine) collect(
enqueuedFrame *protobufs.ClockFrame,
) (*protobufs.ClockFrame, error) {
func (e *DataClockConsensusEngine) syncWithMesh() error {
e.logger.Info("collecting vdf proofs")
latest := enqueuedFrame
latest, err := e.dataTimeReel.Head()
if err != nil {
return errors.Wrap(err, "sync")
}
for {
candidates := e.GetAheadPeers(max(latest.FrameNumber, e.latestFrameReceived))
if len(candidates) == 0 {
@ -36,11 +37,16 @@ func (e *DataClockConsensusEngine) collect(
if candidate.MaxFrame <= max(latest.FrameNumber, e.latestFrameReceived) {
continue
}
var err error
latest, err = e.sync(latest, candidate.MaxFrame, candidate.PeerID)
head, err := e.dataTimeReel.Head()
if err != nil {
return errors.Wrap(err, "sync")
}
if latest.FrameNumber < head.FrameNumber {
latest = head
}
latest, err = e.syncWithPeer(latest, candidate.MaxFrame, candidate.PeerID)
if err != nil {
e.logger.Debug("error syncing frame", zap.Error(err))
continue
}
}
}
@ -51,7 +57,7 @@ func (e *DataClockConsensusEngine) collect(
zap.Duration("frame_age", frametime.Since(latest)),
)
return latest, nil
return nil
}
func (e *DataClockConsensusEngine) prove(
@ -268,7 +274,7 @@ func (e *DataClockConsensusEngine) GetAheadPeers(frameNumber uint64) []internal.
return internal.WeightedSampleWithoutReplacement(candidates, len(candidates))
}
func (e *DataClockConsensusEngine) sync(
func (e *DataClockConsensusEngine) syncWithPeer(
currentLatest *protobufs.ClockFrame,
maxFrame uint64,
peerId []byte,

View File

@ -3,7 +3,8 @@ package data
import (
"context"
"crypto"
"encoding/binary"
stderrors "errors"
"fmt"
"math/rand"
"sync"
@ -55,6 +56,7 @@ type peerInfo struct {
timestamp int64
lastSeen int64
version []byte
patchVersion byte
totalDistance []byte
}
@ -65,6 +67,7 @@ type DataClockConsensusEngine struct {
ctx context.Context
cancel context.CancelFunc
wg sync.WaitGroup
lastProven uint64
difficulty uint32
@ -118,6 +121,8 @@ type DataClockConsensusEngine struct {
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
@ -132,7 +137,7 @@ type DataClockConsensusEngine struct {
previousFrameProven *protobufs.ClockFrame
previousTree *mt.MerkleTree
clientReconnectTest int
requestSyncCh chan *protobufs.ClockFrame
requestSyncCh chan struct{}
}
var _ consensus.DataConsensusEngine = (*DataClockConsensusEngine)(nil)
@ -266,7 +271,8 @@ func NewDataClockConsensusEngine(
rateLimit,
time.Minute,
),
requestSyncCh: make(chan *protobufs.ClockFrame, 1),
requestSyncCh: make(chan struct{}, 1),
validationFilter: map[string]struct{}{},
}
logger.Info("constructing consensus engine")
@ -311,6 +317,7 @@ func (e *DataClockConsensusEngine) Start() <-chan error {
panic(err)
}
e.wg.Add(3)
go e.runFrameMessageHandler()
go e.runTxMessageHandler()
go e.runInfoMessageHandler()
@ -359,7 +366,9 @@ func (e *DataClockConsensusEngine) Start() <-chan error {
e.state = consensus.EngineStateCollecting
e.stateMx.Unlock()
e.wg.Add(1)
go func() {
defer e.wg.Done()
const baseDuration = 2 * time.Minute
const maxBackoff = 3
var currentBackoff = 0
@ -395,7 +404,9 @@ func (e *DataClockConsensusEngine) Start() <-chan error {
}
}()
e.wg.Add(1)
go func() {
defer e.wg.Done()
thresholdBeforeConfirming := 4
frame, err := e.dataTimeReel.Head()
if err != nil {
@ -422,11 +433,12 @@ func (e *DataClockConsensusEngine) Start() <-chan error {
timestamp := time.Now().UnixMilli()
list := &protobufs.DataPeerListAnnounce{
Peer: &protobufs.DataPeer{
PeerId: nil,
Multiaddr: "",
MaxFrame: frame.FrameNumber,
Version: config.GetVersion(),
Timestamp: timestamp,
PeerId: nil,
Multiaddr: "",
MaxFrame: frame.FrameNumber,
Version: config.GetVersion(),
PatchVersion: []byte{config.GetPatchNumber()},
Timestamp: timestamp,
TotalDistance: e.dataTimeReel.GetTotalDistance().FillBytes(
make([]byte, 256),
),
@ -442,11 +454,12 @@ func (e *DataClockConsensusEngine) Start() <-chan error {
e.peerMapMx.Lock()
e.peerMap[string(e.pubSub.GetPeerID())] = &peerInfo{
peerId: e.pubSub.GetPeerID(),
multiaddr: "",
maxFrame: frame.FrameNumber,
version: config.GetVersion(),
timestamp: timestamp,
peerId: e.pubSub.GetPeerID(),
multiaddr: "",
maxFrame: frame.FrameNumber,
version: config.GetVersion(),
patchVersion: config.GetPatchNumber(),
timestamp: timestamp,
totalDistance: e.dataTimeReel.GetTotalDistance().FillBytes(
make([]byte, 256),
),
@ -500,11 +513,14 @@ func (e *DataClockConsensusEngine) Start() <-chan error {
}
}()
e.wg.Add(3)
go e.runLoop()
go e.runSync()
go e.runFramePruning()
e.wg.Add(1)
go func() {
defer e.wg.Done()
select {
case <-e.ctx.Done():
return
@ -524,7 +540,9 @@ func (e *DataClockConsensusEngine) Start() <-chan error {
go e.runPreMidnightProofWorker()
e.wg.Add(1)
go func() {
defer e.wg.Done()
if len(e.config.Engine.DataWorkerMultiaddrs) != 0 {
e.clients, err = e.createParallelDataClientsFromList()
if err != nil {
@ -582,6 +600,7 @@ func (e *DataClockConsensusEngine) PerformTimeProof(
i := i
client := client
go func() {
defer wg.Done()
resp, err :=
client.client.CalculateChallengeProof(
e.ctx,
@ -595,7 +614,6 @@ func (e *DataClockConsensusEngine) PerformTimeProof(
)
if err != nil {
if status.Code(err) == codes.NotFound {
wg.Done()
return
}
}
@ -605,8 +623,6 @@ func (e *DataClockConsensusEngine) PerformTimeProof(
} else {
e.clients[client.index] = nil
}
wg.Done()
}()
}
wg.Wait()
@ -623,40 +639,32 @@ func (e *DataClockConsensusEngine) PerformTimeProof(
func (e *DataClockConsensusEngine) Stop(force bool) <-chan error {
e.logger.Info("stopping ceremony consensus engine")
e.cancel()
e.wg.Wait()
e.stateMx.Lock()
e.state = consensus.EngineStateStopping
e.stateMx.Unlock()
errChan := make(chan error)
msg := []byte("pause")
msg = binary.BigEndian.AppendUint64(msg, e.GetFrame().FrameNumber)
msg = append(msg, e.filter...)
sig, err := e.pubSub.SignMessage(msg)
if err != nil {
pause := &protobufs.AnnounceProverPause{
Filter: e.filter,
FrameNumber: e.GetFrame().FrameNumber,
}
if err := pause.SignED448(e.pubSub.GetPublicKey(), e.pubSub.SignMessage); err != nil {
panic(err)
}
if err := pause.Validate(); err != nil {
panic(err)
}
e.publishMessage(e.txFilter, &protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Pause{
Pause: &protobufs.AnnounceProverPause{
Filter: e.filter,
FrameNumber: e.GetFrame().FrameNumber,
PublicKeySignatureEd448: &protobufs.Ed448Signature{
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: e.pubSub.GetPublicKey(),
},
Signature: sig,
},
},
},
Timestamp: time.Now().UnixMilli(),
})
e.publishMessage(e.txFilter, pause.TokenRequest())
wg := sync.WaitGroup{}
wg.Add(len(e.executionEngines))
executionErrors := make(chan error, len(e.executionEngines))
for name := range e.executionEngines {
name := name
go func(name string) {
defer wg.Done()
frame, err := e.dataTimeReel.Head()
if err != nil {
panic(err)
@ -664,9 +672,8 @@ func (e *DataClockConsensusEngine) Stop(force bool) <-chan error {
err = <-e.UnregisterExecutor(name, frame.FrameNumber, force)
if err != nil {
errChan <- err
executionErrors <- err
}
wg.Done()
}(name)
}
@ -679,6 +686,7 @@ func (e *DataClockConsensusEngine) Stop(force bool) <-chan error {
e.logger.Info("waiting for execution engines to stop")
wg.Wait()
close(executionErrors)
e.logger.Info("execution engines stopped")
e.dataTimeReel.Stop()
@ -689,7 +697,12 @@ func (e *DataClockConsensusEngine) Stop(force bool) <-chan error {
e.engineMx.Lock()
defer e.engineMx.Unlock()
go func() {
errChan <- nil
var errs []error
for err := range executionErrors {
errs = append(errs, err)
}
err := stderrors.Join(errs...)
errChan <- err
}()
return errChan
}

View File

@ -43,6 +43,7 @@ func (
}
func (e *DataClockConsensusEngine) runFramePruning() {
defer e.wg.Done()
// A full prover should _never_ do this
if e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) ||
e.config.Engine.MaxFrames == -1 || e.config.Engine.FullProver {
@ -85,6 +86,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) {
return
@ -94,25 +96,19 @@ func (e *DataClockConsensusEngine) runSync() {
select {
case <-e.ctx.Done():
return
case enqueuedFrame := <-e.requestSyncCh:
if enqueuedFrame == nil {
var err error
enqueuedFrame, err = e.dataTimeReel.Head()
if err != nil {
panic(err)
}
}
case <-e.requestSyncCh:
if err := e.pubSub.Bootstrap(e.ctx); err != nil {
e.logger.Error("could not bootstrap", zap.Error(err))
}
if _, err := e.collect(enqueuedFrame); err != nil {
e.logger.Error("could not collect", zap.Error(err))
if err := e.syncWithMesh(); err != nil {
e.logger.Error("could not sync", zap.Error(err))
}
}
}
}
func (e *DataClockConsensusEngine) runLoop() {
defer e.wg.Done()
dataFrameCh := e.dataTimeReel.NewFrameCh()
runOnce := true
for {
@ -149,6 +145,9 @@ func (e *DataClockConsensusEngine) runLoop() {
case <-e.ctx.Done():
return
case dataFrame := <-dataFrameCh:
e.validationFilterMx.Lock()
e.validationFilter = make(map[string]struct{}, len(e.validationFilter))
e.validationFilterMx.Unlock()
if e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) {
if err = e.publishProof(dataFrame); err != nil {
e.logger.Error("could not publish", zap.Error(err))
@ -177,7 +176,7 @@ func (e *DataClockConsensusEngine) processFrame(
var err error
if !e.GetFrameProverTries()[0].Contains(e.provingKeyBytes) {
select {
case e.requestSyncCh <- dataFrame:
case e.requestSyncCh <- struct{}{}:
default:
}
}
@ -298,7 +297,7 @@ func (e *DataClockConsensusEngine) processFrame(
return latestFrame
}
modulo := len(outputs)
proofTree, payload, output, err := tries.PackOutputIntoPayloadAndProof(
proofTree, output, err := tries.PackOutputIntoPayloadAndProof(
outputs,
modulo,
latestFrame,
@ -314,11 +313,16 @@ func (e *DataClockConsensusEngine) processFrame(
e.previousFrameProven = latestFrame
e.previousTree = proofTree
sig, err := e.pubSub.SignMessage(
payload,
)
if err != nil {
panic(err)
mint := &protobufs.MintCoinRequest{
Proofs: output,
}
if err := mint.SignED448(e.pubSub.GetPublicKey(), e.pubSub.SignMessage); err != nil {
e.logger.Error("could not sign mint", zap.Error(err))
return latestFrame
}
if err := mint.Validate(); err != nil {
e.logger.Error("mint validation failed", zap.Error(err))
return latestFrame
}
e.logger.Info(
@ -329,20 +333,7 @@ func (e *DataClockConsensusEngine) processFrame(
zap.Duration("frame_age", frametime.Since(latestFrame)),
)
e.publishMessage(e.txFilter, &protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Mint{
Mint: &protobufs.MintCoinRequest{
Proofs: output,
Signature: &protobufs.Ed448Signature{
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: e.pubSub.GetPublicKey(),
},
Signature: sig,
},
},
},
Timestamp: time.Now().UnixMilli(),
})
e.publishMessage(e.txFilter, mint.TokenRequest())
if e.config.Engine.AutoMergeCoins {
_, addrs, _, err := e.coinStore.GetCoinsForOwner(
@ -357,33 +348,29 @@ func (e *DataClockConsensusEngine) processFrame(
}
if len(addrs) > 25 {
message := []byte("merge")
refs := []*protobufs.CoinRef{}
for _, addr := range addrs {
message = append(message, addr...)
refs = append(refs, &protobufs.CoinRef{
Address: addr,
})
}
sig, _ := e.pubSub.SignMessage(
message,
)
merge := &protobufs.MergeCoinRequest{
Coins: refs,
}
if err := merge.SignED448(
e.pubSub.GetPublicKey(),
e.pubSub.SignMessage,
); err != nil {
e.logger.Error("could not sign merge", zap.Error(err))
return latestFrame
}
if err := merge.Validate(); err != nil {
e.logger.Error("merge validation failed", zap.Error(err))
return latestFrame
}
e.publishMessage(e.txFilter, &protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Merge{
Merge: &protobufs.MergeCoinRequest{
Coins: refs,
Signature: &protobufs.Ed448Signature{
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: e.pubSub.GetPublicKey(),
},
Signature: sig,
},
},
},
Timestamp: time.Now().UnixMilli(),
})
e.publishMessage(e.txFilter, merge.TokenRequest())
}
}
}

View File

@ -2,6 +2,7 @@ package data
import (
"bytes"
"encoding/binary"
"fmt"
"sync"
"time"
@ -19,6 +20,7 @@ import (
)
func (e *DataClockConsensusEngine) runFrameMessageHandler() {
defer e.wg.Done()
for {
select {
case <-e.ctx.Done():
@ -32,31 +34,18 @@ func (e *DataClockConsensusEngine) runFrameMessageHandler() {
continue
}
any := &anypb.Any{}
if err := proto.Unmarshal(msg.Payload, any); err != nil {
a := &anypb.Any{}
if err := proto.Unmarshal(msg.Payload, a); err != nil {
e.logger.Error("error while unmarshaling", zap.Error(err))
continue
}
accepted := false
switch any.TypeUrl {
//expand for future message types
case protobufs.ClockFrameType:
accepted = true
default:
}
if !accepted {
e.pubSub.AddPeerScore(message.From, -100000)
continue
}
switch any.TypeUrl {
switch a.TypeUrl {
case protobufs.ClockFrameType:
if err := e.handleClockFrameData(
message.From,
msg.Address,
any,
a,
false,
); err != nil {
e.logger.Debug("could not handle clock frame data", zap.Error(err))
@ -67,6 +56,7 @@ func (e *DataClockConsensusEngine) runFrameMessageHandler() {
}
func (e *DataClockConsensusEngine) runTxMessageHandler() {
defer e.wg.Done()
for {
select {
case <-e.ctx.Done():
@ -80,21 +70,8 @@ func (e *DataClockConsensusEngine) runTxMessageHandler() {
continue
}
any := &anypb.Any{}
if err := proto.Unmarshal(msg.Payload, any); err != nil {
continue
}
accepted := false
switch any.TypeUrl {
//expand for future message types
case protobufs.TokenRequestType:
accepted = true
default:
}
if !accepted {
e.pubSub.AddPeerScore(message.From, -100000)
a := &anypb.Any{}
if err := proto.Unmarshal(msg.Payload, a); err != nil {
continue
}
@ -119,8 +96,8 @@ func (e *DataClockConsensusEngine) runTxMessageHandler() {
}
for _, appMessage := range messages {
appMsg := &anypb.Any{}
err := proto.Unmarshal(appMessage.Payload, appMsg)
a := &anypb.Any{}
err := proto.Unmarshal(appMessage.Payload, a)
if err != nil {
e.logger.Error(
"could not unmarshal app message",
@ -130,10 +107,10 @@ func (e *DataClockConsensusEngine) runTxMessageHandler() {
continue
}
switch appMsg.TypeUrl {
switch a.TypeUrl {
case protobufs.TokenRequestType:
t := &protobufs.TokenRequest{}
err := proto.Unmarshal(appMsg.Value, t)
err := proto.Unmarshal(a.Value, t)
if err != nil {
e.logger.Debug("could not unmarshal token request", zap.Error(err))
continue
@ -155,6 +132,7 @@ func (e *DataClockConsensusEngine) runTxMessageHandler() {
}
func (e *DataClockConsensusEngine) runInfoMessageHandler() {
defer e.wg.Done()
for {
select {
case <-e.ctx.Done():
@ -168,31 +146,18 @@ func (e *DataClockConsensusEngine) runInfoMessageHandler() {
continue
}
any := &anypb.Any{}
if err := proto.Unmarshal(msg.Payload, any); err != nil {
a := &anypb.Any{}
if err := proto.Unmarshal(msg.Payload, a); err != nil {
e.logger.Error("error while unmarshaling", zap.Error(err))
continue
}
accepted := false
switch any.TypeUrl {
//expand for future message types
case protobufs.DataPeerListAnnounceType:
accepted = true
default:
}
if !accepted {
e.pubSub.AddPeerScore(message.From, -100000)
continue
}
switch any.TypeUrl {
switch a.TypeUrl {
case protobufs.DataPeerListAnnounceType:
if err := e.handleDataPeerListAnnounce(
message.From,
msg.Address,
any,
a,
); err != nil {
e.logger.Debug("could not handle data peer list announce", zap.Error(err))
}
@ -305,6 +270,11 @@ func (e *DataClockConsensusEngine) handleDataPeerListAnnounce(
return nil
}
patchVersion := byte(0)
if len(p.PatchVersion) == 1 {
patchVersion = p.PatchVersion[0]
}
if p.Version != nil &&
bytes.Compare(p.Version, config.GetMinimumVersion()) < 0 &&
p.Timestamp > config.GetMinimumVersionCutoff().UnixMilli() {
@ -312,7 +282,7 @@ func (e *DataClockConsensusEngine) handleDataPeerListAnnounce(
"peer provided outdated version, penalizing app score",
zap.String("peer_id", peer.ID(peerID).String()),
)
e.pubSub.SetPeerScore(peerID, -1000000)
e.pubSub.AddPeerScore(peerID, -1000)
return nil
}
@ -323,7 +293,7 @@ func (e *DataClockConsensusEngine) handleDataPeerListAnnounce(
}
e.peerMapMx.RUnlock()
e.pubSub.SetPeerScore(peerID, 10)
e.pubSub.AddPeerScore(peerID, 10)
e.peerMapMx.RLock()
existing, ok := e.peerMap[string(peerID)]
@ -342,6 +312,7 @@ func (e *DataClockConsensusEngine) handleDataPeerListAnnounce(
lastSeen: time.Now().Unix(),
timestamp: p.Timestamp,
version: p.Version,
patchVersion: patchVersion,
totalDistance: p.TotalDistance,
}
e.peerMapMx.Unlock()
@ -349,7 +320,7 @@ func (e *DataClockConsensusEngine) handleDataPeerListAnnounce(
select {
case <-e.ctx.Done():
return nil
case e.requestSyncCh <- nil:
case e.requestSyncCh <- struct{}{}:
default:
}
@ -370,10 +341,12 @@ func TokenRequestIdentifiers(transition *protobufs.TokenRequest) []string {
return identifiers
case *protobufs.TokenRequest_Mint:
if len(t.Mint.Proofs) == 1 {
return []string{fmt.Sprintf("mint-%x", sha3.Sum512(t.Mint.Proofs[0]))}
return []string{fmt.Sprintf("mint-proof-%x", sha3.Sum512(t.Mint.Proofs[0]))}
} else if len(t.Mint.Proofs) >= 3 {
frameNumber := binary.BigEndian.Uint64(t.Mint.Proofs[2])
return []string{fmt.Sprintf("mint-sign-%d-%x", frameNumber, t.Mint.Signature.PublicKey.KeyValue)}
}
// Large proofs are currently not deduplicated.
return nil
return []string{fmt.Sprintf("mint-sign-%x", t.Mint.Signature.PublicKey.KeyValue)}
case *protobufs.TokenRequest_Announce:
identifiers := make([]string, len(t.Announce.GetPublicKeySignaturesEd448()))
for i, sig := range t.Announce.GetPublicKeySignaturesEd448() {

View File

@ -2,6 +2,7 @@ package data
import (
"encoding/binary"
"fmt"
"time"
"github.com/libp2p/go-libp2p/core/peer"
@ -51,6 +52,9 @@ func (e *DataClockConsensusEngine) validateTxMessage(peerID peer.ID, message *pb
if err := proto.Unmarshal(a.Value, tx); err != nil {
return p2p.ValidationResultReject
}
if err := tx.Validate(); err != nil {
return p2p.ValidationResultReject
}
if mint := tx.GetMint(); mint != nil {
if len(mint.Proofs) < 3 {
return p2p.ValidationResultReject
@ -61,18 +65,38 @@ func (e *DataClockConsensusEngine) validateTxMessage(peerID peer.ID, message *pb
if len(mint.Proofs[2]) != 8 {
return p2p.ValidationResultReject
}
// cheap hack for handling protobuf trickery: because protobufs can be
// serialized in infinite ways, message ids can be regenerated simply by
// modifying the data without affecting the underlying signed message.
// if this is encountered, go scorched earth on the sender a thank you
// message for destabilizing the network.
frameNumber := binary.BigEndian.Uint64(mint.Proofs[2])
id := fmt.Sprintf(
"mint-sign-%d-%x",
frameNumber,
mint.Signature.PublicKey.KeyValue,
)
e.validationFilterMx.Lock()
_, ok := e.validationFilter[id]
e.validationFilter[id] = struct{}{}
e.validationFilterMx.Unlock()
if ok {
e.pubSub.AddPeerScore(message.From, -1000000)
return p2p.ValidationResultIgnore
}
head, err := e.dataTimeReel.Head()
if err != nil {
panic(err)
}
if frameNumber := binary.BigEndian.Uint64(mint.Proofs[2]); frameNumber+2 < head.FrameNumber {
if frameNumber+2 < head.FrameNumber {
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.
// We avoid logging due to this reason.
return p2p.ValidationResultAccept
}
if ts := time.UnixMilli(tx.Timestamp); time.Since(ts) > 10*time.Minute {

View File

@ -186,6 +186,10 @@ func (e *DataClockConsensusEngine) handleMint(
return nil, errors.Wrap(errors.New("wrong destination"), "handle mint")
}
if err := t.Validate(); err != nil {
return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint")
}
returnAddr := []byte{}
e.preMidnightMintMx.Lock()
if _, active := e.preMidnightMint[string(
@ -211,17 +215,6 @@ func (e *DataClockConsensusEngine) handleMint(
return nil, errors.Wrap(errors.New("busy"), "handle mint")
}
if t == nil || t.Proofs == nil {
return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint")
}
payload := []byte("mint")
for _, p := range t.Proofs {
payload = append(payload, p...)
}
if err := t.Signature.Verify(payload); err != nil {
return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint")
}
pk, err := pcrypto.UnmarshalEd448PublicKey(
t.Signature.PublicKey.KeyValue,
)

View File

@ -36,6 +36,7 @@ type DataTimeReel struct {
ctx context.Context
cancel context.CancelFunc
wg sync.WaitGroup
filter []byte
engineConfig *config.EngineConfig
@ -175,6 +176,7 @@ func (d *DataTimeReel) Start() error {
d.headDistance, err = d.GetDistance(frame)
}
d.wg.Add(1)
go d.runLoop()
return nil
@ -253,6 +255,7 @@ func (d *DataTimeReel) BadFrameCh() <-chan *protobufs.ClockFrame {
func (d *DataTimeReel) Stop() {
d.cancel()
d.wg.Wait()
}
func (d *DataTimeReel) createGenesisFrame() (
@ -338,6 +341,7 @@ func (d *DataTimeReel) createGenesisFrame() (
// Main data consensus loop
func (d *DataTimeReel) runLoop() {
defer d.wg.Done()
for {
select {
case <-d.ctx.Done():

View File

@ -161,15 +161,12 @@ func (a *TokenApplication) ApplyTransitions(
i := i
switch t := transition.Request.(type) {
case *protobufs.TokenRequest_Mint:
if t == nil || t.Mint.Proofs == nil || t.Mint.Signature == nil {
if t == nil {
fails[i] = transition
continue
}
payload := []byte("mint")
for _, p := range t.Mint.Proofs {
payload = append(payload, p...)
}
if err := t.Mint.Signature.Verify(payload); err != nil {
if err := t.Mint.Validate(); err != nil {
fails[i] = transition
continue
}
@ -177,6 +174,7 @@ func (a *TokenApplication) ApplyTransitions(
t.Mint.Signature.PublicKey.KeyValue,
)
if err != nil {
fails[i] = transition
continue
}

View File

@ -16,19 +16,16 @@ func (a *TokenApplication) handleMerge(
lockMap map[string]struct{},
t *protobufs.MergeCoinRequest,
) ([]*protobufs.TokenOutput, error) {
if err := t.Validate(); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge")
}
newCoin := &protobufs.Coin{}
newTotal := new(big.Int)
newIntersection := make([]byte, 1024)
payload := []byte("merge")
if t == nil || t.Coins == nil || t.Signature == nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge")
}
addresses := [][]byte{}
for _, c := range t.Coins {
if c.Address == nil || len(c.Address) != 32 {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge")
}
if _, touched := lockMap[string(c.Address)]; touched {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge")
}
@ -40,14 +37,6 @@ func (a *TokenApplication) handleMerge(
}
addresses = append(addresses, c.Address)
payload = append(payload, c.Address...)
}
if t.Signature.PublicKey == nil ||
t.Signature.Signature == nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge")
}
if err := t.Signature.Verify(payload); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge")
}
addr, err := poseidon.HashBytes(t.Signature.PublicKey.KeyValue)

View File

@ -29,7 +29,7 @@ func (a *TokenApplication) handleMint(
frame *protobufs.ClockFrame,
parallelismMap map[int]uint64,
) ([]*protobufs.TokenOutput, error) {
if t == nil || t.Proofs == nil || t.Signature == nil {
if err := t.Validate(); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
}
@ -37,9 +37,7 @@ func (a *TokenApplication) handleMint(
for _, p := range t.Proofs {
payload = append(payload, p...)
}
if err := t.Signature.Verify(payload); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
}
pk, err := pcrypto.UnmarshalEd448PublicKey(
t.Signature.PublicKey.KeyValue,
)

View File

@ -13,36 +13,14 @@ func (a *TokenApplication) handleAnnounce(
[]*protobufs.TokenOutput,
error,
) {
var primary *protobufs.Ed448Signature
payload := []byte{}
if t == nil || t.PublicKeySignaturesEd448 == nil ||
len(t.PublicKeySignaturesEd448) == 0 {
if err := t.Validate(); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle announce")
}
for i, p := range t.PublicKeySignaturesEd448 {
for _, p := range t.PublicKeySignaturesEd448 {
if _, touched := lockMap[string(p.PublicKey.KeyValue)]; touched {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle announce")
}
if p.PublicKey == nil || p.Signature == nil ||
p.PublicKey.KeyValue == nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle announce")
}
if i == 0 {
primary = p
} else {
payload = append(payload, p.PublicKey.KeyValue...)
if err := p.Verify(primary.PublicKey.KeyValue); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle announce")
}
}
}
if primary == nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle announce")
}
if err := primary.Verify(payload); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle announce")
}
for _, p := range t.PublicKeySignaturesEd448[1:] {

View File

@ -1,8 +1,6 @@
package application
import (
"encoding/binary"
"github.com/iden3/go-iden3-crypto/poseidon"
pcrypto "github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
@ -50,25 +48,7 @@ func (a *TokenApplication) handleDataAnnounceProverJoin(
return nil, errors.Wrap(ErrInvalidStateTransition, "handle join")
}
payload := []byte("join")
if t == nil || t.PublicKeySignatureEd448 == nil {
a.Logger.Debug("invalid data for join")
return nil, errors.Wrap(ErrInvalidStateTransition, "handle join")
}
if t.PublicKeySignatureEd448.PublicKey == nil ||
t.PublicKeySignatureEd448.Signature == nil ||
t.PublicKeySignatureEd448.PublicKey.KeyValue == nil ||
t.Filter == nil || len(t.Filter) != 32 {
a.Logger.Debug(
"bad payload",
zap.Uint64("given_frame_number", t.FrameNumber),
zap.Uint64("current_frame_number", currentFrameNumber),
zap.Int("filter_length", len(t.Filter)),
)
if err := t.Validate(); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle join")
}
@ -79,13 +59,6 @@ func (a *TokenApplication) handleDataAnnounceProverJoin(
return nil, errors.Wrap(ErrInvalidStateTransition, "handle join")
}
payload = binary.BigEndian.AppendUint64(payload, t.FrameNumber)
payload = append(payload, t.Filter...)
if err := t.PublicKeySignatureEd448.Verify(payload); err != nil {
a.Logger.Debug("can't verify signature")
return nil, errors.Wrap(ErrInvalidStateTransition, "handle join")
}
address, err := a.getAddressFromSignature(t.PublicKeySignatureEd448)
if err != nil {

View File

@ -70,10 +70,6 @@ func TestHandleProverJoin(t *testing.T) {
}
addr := addrBI.FillBytes(make([]byte, 32))
payload := []byte("join")
payload = binary.BigEndian.AppendUint64(payload, 0)
payload = append(payload, bytes.Repeat([]byte{0xff}, 32)...)
sig, _ := privKey.Sign(payload)
wprover := qcrypto.NewWesolowskiFrameProver(app.Logger)
gen, _, err := wprover.CreateDataGenesisFrame(
p2p.GetBloomFilter(application.TOKEN_ADDRESS, 256, 3),
@ -87,24 +83,17 @@ func TestHandleProverJoin(t *testing.T) {
app.ClockStore.StageDataClockFrame(selbi.FillBytes(make([]byte, 32)), gen, txn)
app.ClockStore.CommitDataClockFrame(gen.Filter, 0, selbi.FillBytes(make([]byte, 32)), app.Tries, txn, false)
txn.Commit()
join := &protobufs.AnnounceProverJoin{
Filter: bytes.Repeat([]byte{0xff}, 32),
FrameNumber: 0,
}
assert.NoError(t, join.SignED448(pubkey, privKey.Sign))
assert.NoError(t, join.Validate())
app, success, fail, err := app.ApplyTransitions(
1,
&protobufs.TokenRequests{
Requests: []*protobufs.TokenRequest{
&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Join{
Join: &protobufs.AnnounceProverJoin{
Filter: bytes.Repeat([]byte{0xff}, 32),
FrameNumber: 0,
PublicKeySignatureEd448: &protobufs.Ed448Signature{
Signature: sig,
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: pubkey,
},
},
},
},
},
join.TokenRequest(),
},
},
false,
@ -121,24 +110,17 @@ func TestHandleProverJoin(t *testing.T) {
app.ClockStore.StageDataClockFrame(selbi.FillBytes(make([]byte, 32)), frame1, txn)
app.ClockStore.CommitDataClockFrame(frame1.Filter, 1, selbi.FillBytes(make([]byte, 32)), app.Tries, txn, false)
txn.Commit()
join = &protobufs.AnnounceProverJoin{
Filter: bytes.Repeat([]byte{0xff}, 32),
FrameNumber: 0,
}
assert.NoError(t, join.SignED448(pubkey, privKey.Sign))
assert.NoError(t, join.Validate())
_, success, fail, err = app.ApplyTransitions(
2,
&protobufs.TokenRequests{
Requests: []*protobufs.TokenRequest{
&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Join{
Join: &protobufs.AnnounceProverJoin{
Filter: bytes.Repeat([]byte{0xff}, 32),
FrameNumber: 0,
PublicKeySignatureEd448: &protobufs.Ed448Signature{
Signature: sig,
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: pubkey,
},
},
},
},
},
join.TokenRequest(),
},
},
false,
@ -175,7 +157,7 @@ func TestHandleProverJoin(t *testing.T) {
fmt.Printf("%x\n", individualChallenge)
out2, _ := wprover.CalculateChallengeProof(individualChallenge, 10000)
proofTree, payload, output, err := tries.PackOutputIntoPayloadAndProof(
proofTree, output, err := tries.PackOutputIntoPayloadAndProof(
[]merkletree.DataBlock{tries.NewProofLeaf(out1), tries.NewProofLeaf(out2)},
2,
frame2,
@ -183,22 +165,15 @@ func TestHandleProverJoin(t *testing.T) {
)
assert.NoError(t, err)
sig, _ = privKey.Sign(payload)
mint := &protobufs.MintCoinRequest{
Proofs: output,
}
assert.NoError(t, mint.SignED448(pubkey, privKey.Sign))
assert.NoError(t, mint.Validate())
app, success, _, err = app.ApplyTransitions(2, &protobufs.TokenRequests{
Requests: []*protobufs.TokenRequest{
&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Mint{
Mint: &protobufs.MintCoinRequest{
Proofs: output,
Signature: &protobufs.Ed448Signature{
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: pubkey,
},
Signature: sig,
},
},
},
},
mint.TokenRequest(),
},
}, false)
@ -240,7 +215,7 @@ func TestHandleProverJoin(t *testing.T) {
app.ClockStore.CommitDataClockFrame(frame3.Filter, 3, selbi.FillBytes(make([]byte, 32)), app.Tries, txn, false)
txn.Commit()
proofTree, payload, output, err = tries.PackOutputIntoPayloadAndProof(
proofTree, output, err = tries.PackOutputIntoPayloadAndProof(
[]merkletree.DataBlock{tries.NewProofLeaf(out1), tries.NewProofLeaf(out2)},
2,
frame3,
@ -248,22 +223,15 @@ func TestHandleProverJoin(t *testing.T) {
)
assert.NoError(t, err)
sig, _ = privKey.Sign(payload)
mint = &protobufs.MintCoinRequest{
Proofs: output,
}
assert.NoError(t, mint.SignED448(pubkey, privKey.Sign))
assert.NoError(t, mint.Validate())
app, success, _, err = app.ApplyTransitions(3, &protobufs.TokenRequests{
Requests: []*protobufs.TokenRequest{
&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Mint{
Mint: &protobufs.MintCoinRequest{
Proofs: output,
Signature: &protobufs.Ed448Signature{
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: pubkey,
},
Signature: sig,
},
},
},
},
mint.TokenRequest(),
},
}, false)
assert.NoError(t, err)

View File

@ -1,8 +1,6 @@
package application
import (
"encoding/binary"
"github.com/pkg/errors"
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
)
@ -19,17 +17,11 @@ func (a *TokenApplication) handleDataAnnounceProverLeave(
return nil, errors.Wrap(ErrInvalidStateTransition, "handle leave")
}
payload := []byte("leave")
if t == nil || t.PublicKeySignatureEd448 == nil {
if err := t.Validate(); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle leave")
}
if t.PublicKeySignatureEd448.PublicKey == nil ||
t.PublicKeySignatureEd448.Signature == nil ||
t.PublicKeySignatureEd448.PublicKey.KeyValue == nil ||
t.Filter == nil || len(t.Filter) != 32 ||
t.FrameNumber > currentFrameNumber {
if t.FrameNumber > currentFrameNumber {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle leave")
}
@ -39,13 +31,6 @@ func (a *TokenApplication) handleDataAnnounceProverLeave(
return nil, errors.Wrap(ErrInvalidStateTransition, "handle leave")
}
payload = binary.BigEndian.AppendUint64(payload, t.FrameNumber)
payload = append(payload, t.Filter...)
if err := t.PublicKeySignatureEd448.Verify(payload); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle leave")
}
address, err := a.getAddressFromSignature(t.PublicKeySignatureEd448)
if err != nil {
return nil, errors.Wrap(err, "handle leave")

View File

@ -1,8 +1,6 @@
package application
import (
"encoding/binary"
"github.com/pkg/errors"
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
)
@ -19,17 +17,11 @@ func (a *TokenApplication) handleDataAnnounceProverPause(
return nil, errors.Wrap(ErrInvalidStateTransition, "handle pause")
}
payload := []byte("pause")
if t == nil || t.PublicKeySignatureEd448 == nil {
if err := t.Validate(); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle pause")
}
if t.PublicKeySignatureEd448.PublicKey == nil ||
t.PublicKeySignatureEd448.Signature == nil ||
t.PublicKeySignatureEd448.PublicKey.KeyValue == nil ||
t.Filter == nil || len(t.Filter) != 32 ||
t.FrameNumber > currentFrameNumber {
if t.FrameNumber > currentFrameNumber {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle pause")
}
if _, touched := lockMap[string(
@ -38,13 +30,6 @@ func (a *TokenApplication) handleDataAnnounceProverPause(
return nil, errors.Wrap(ErrInvalidStateTransition, "handle pause")
}
payload = binary.BigEndian.AppendUint64(payload, t.FrameNumber)
payload = append(payload, t.Filter...)
if err := t.PublicKeySignatureEd448.Verify(payload); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle pause")
}
address, err := a.getAddressFromSignature(t.PublicKeySignatureEd448)
if err != nil {
return nil, errors.Wrap(err, "handle pause")

View File

@ -1,8 +1,6 @@
package application
import (
"encoding/binary"
"github.com/pkg/errors"
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
)
@ -19,17 +17,11 @@ func (a *TokenApplication) handleDataAnnounceProverResume(
return nil, errors.Wrap(ErrInvalidStateTransition, "handle resume")
}
payload := []byte("resume")
if t == nil || t.PublicKeySignatureEd448 == nil {
if err := t.Validate(); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle resume")
}
if t.PublicKeySignatureEd448.PublicKey == nil ||
t.PublicKeySignatureEd448.Signature == nil ||
t.PublicKeySignatureEd448.PublicKey.KeyValue == nil ||
t.Filter == nil || len(t.Filter) != 32 ||
t.FrameNumber > currentFrameNumber {
if t.FrameNumber > currentFrameNumber {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle resume")
}
@ -39,13 +31,6 @@ func (a *TokenApplication) handleDataAnnounceProverResume(
return nil, errors.Wrap(ErrInvalidStateTransition, "handle resume")
}
payload = binary.BigEndian.AppendUint64(payload, t.FrameNumber)
payload = append(payload, t.Filter...)
if err := t.PublicKeySignatureEd448.Verify(payload); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle resume")
}
address, err := a.getAddressFromSignature(t.PublicKeySignatureEd448)
if err != nil {
return nil, errors.Wrap(err, "handle resume")

View File

@ -16,13 +16,13 @@ func (a *TokenApplication) handleSplit(
lockMap map[string]struct{},
t *protobufs.SplitCoinRequest,
) ([]*protobufs.TokenOutput, error) {
newCoins := []*protobufs.Coin{}
newAmounts := []*big.Int{}
payload := []byte{}
if t.Signature == nil || t.OfCoin == nil || t.OfCoin.Address == nil ||
len(t.OfCoin.Address) != 32 {
if err := t.Validate(); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle split")
}
newCoins := []*protobufs.Coin{}
newAmounts := []*big.Int{}
coin, err := a.CoinStore.GetCoinByAddress(nil, t.OfCoin.Address)
if err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle split")
@ -32,24 +32,6 @@ func (a *TokenApplication) handleSplit(
return nil, errors.Wrap(ErrInvalidStateTransition, "handle split")
}
payload = append(payload, []byte("split")...)
payload = append(payload, t.OfCoin.Address...)
if len(t.Amounts) > 100 {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle split")
}
for _, a := range t.Amounts {
if len(a) > 32 {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle split")
}
payload = append(payload, a...)
}
if err := t.Signature.Verify(payload); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle split")
}
addr, err := poseidon.HashBytes(t.Signature.PublicKey.KeyValue)
if err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle split")

View File

@ -16,12 +16,7 @@ func (a *TokenApplication) handleTransfer(
lockMap map[string]struct{},
t *protobufs.TransferCoinRequest,
) ([]*protobufs.TokenOutput, error) {
payload := []byte("transfer")
if t == nil || t.Signature == nil || t.OfCoin == nil ||
t.OfCoin.Address == nil || len(t.OfCoin.Address) != 32 ||
t.ToAccount == nil || t.ToAccount.GetImplicitAccount() == nil ||
t.ToAccount.GetImplicitAccount().Address == nil ||
len(t.ToAccount.GetImplicitAccount().Address) != 32 {
if err := t.Validate(); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle transfer")
}
@ -34,16 +29,6 @@ func (a *TokenApplication) handleTransfer(
return nil, errors.Wrap(ErrInvalidStateTransition, "handle transfer")
}
payload = append(payload, t.OfCoin.Address...)
payload = append(
payload,
t.ToAccount.GetImplicitAccount().Address...,
)
if err := t.Signature.Verify(payload); err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle transfer")
}
addr, err := poseidon.HashBytes(t.Signature.PublicKey.KeyValue)
if err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle transfer")

View File

@ -4,7 +4,6 @@ import (
"bytes"
"context"
"crypto"
"encoding/binary"
"encoding/hex"
"math/big"
"slices"
@ -83,6 +82,7 @@ func (p PeerSeniorityItem) Priority() uint64 {
type TokenExecutionEngine struct {
ctx context.Context
cancel context.CancelFunc
wg sync.WaitGroup
logger *zap.Logger
clock *data.DataClockConsensusEngine
clockStore store.ClockStore
@ -341,7 +341,9 @@ func NewTokenExecutionEngine(
e.proverPublicKey = publicKeyBytes
e.provingKeyAddress = provingKeyAddress
e.wg.Add(1)
go func() {
defer e.wg.Done()
f, tries, err := e.clockStore.GetLatestDataClockFrame(e.intrinsicFilter)
if err != nil {
return
@ -361,11 +363,14 @@ func NewTokenExecutionEngine(
}
if shouldResume {
msg := []byte("resume")
msg = binary.BigEndian.AppendUint64(msg, f.FrameNumber)
msg = append(msg, e.intrinsicFilter...)
sig, err := e.pubSub.SignMessage(msg)
if err != nil {
resume := &protobufs.AnnounceProverResume{
Filter: e.intrinsicFilter,
FrameNumber: f.FrameNumber,
}
if err := resume.SignED448(e.pubSub.GetPublicKey(), e.pubSub.SignMessage); err != nil {
panic(err)
}
if err := resume.Validate(); err != nil {
panic(err)
}
@ -388,21 +393,7 @@ func NewTokenExecutionEngine(
}
e.publishMessage(
append([]byte{0x00}, e.intrinsicFilter...),
&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Resume{
Resume: &protobufs.AnnounceProverResume{
Filter: e.intrinsicFilter,
FrameNumber: f.FrameNumber,
PublicKeySignatureEd448: &protobufs.Ed448Signature{
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: e.pubSub.GetPublicKey(),
},
Signature: sig,
},
},
},
Timestamp: gotime.Now().UnixMilli(),
},
resume.TokenRequest(),
)
}
}()
@ -453,6 +444,7 @@ func (e *TokenExecutionEngine) Start() <-chan error {
// Stop implements ExecutionEngine
func (e *TokenExecutionEngine) Stop(force bool) <-chan error {
e.cancel()
e.wg.Wait()
errChan := make(chan error)
@ -469,20 +461,20 @@ func (e *TokenExecutionEngine) ProcessMessage(
message *protobufs.Message,
) ([]*protobufs.Message, error) {
if bytes.Equal(address, e.GetSupportedApplications()[0].Address) {
any := &anypb.Any{}
if err := proto.Unmarshal(message.Payload, any); err != nil {
a := &anypb.Any{}
if err := proto.Unmarshal(message.Payload, a); err != nil {
return nil, errors.Wrap(err, "process message")
}
e.logger.Debug(
"processing execution message",
zap.String("type", any.TypeUrl),
zap.String("type", a.TypeUrl),
)
switch any.TypeUrl {
switch a.TypeUrl {
case protobufs.TokenRequestType:
if e.clock.IsInProverTrie(e.proverPublicKey) {
payload, err := proto.Marshal(any)
payload, err := proto.Marshal(a)
if err != nil {
return nil, errors.Wrap(err, "process message")
}
@ -1109,19 +1101,19 @@ func (e *TokenExecutionEngine) publishMessage(
filter []byte,
message proto.Message,
) error {
any := &anypb.Any{}
if err := any.MarshalFrom(message); err != nil {
a := &anypb.Any{}
if err := a.MarshalFrom(message); err != nil {
return errors.Wrap(err, "publish message")
}
any.TypeUrl = strings.Replace(
any.TypeUrl,
a.TypeUrl = strings.Replace(
a.TypeUrl,
"type.googleapis.com",
"types.quilibrium.com",
1,
)
payload, err := proto.Marshal(any)
payload, err := proto.Marshal(a)
if err != nil {
return errors.Wrap(err, "publish message")
}
@ -1373,8 +1365,14 @@ func (e *TokenExecutionEngine) AnnounceProverMerge() *protobufs.AnnounceProverRe
currentHead.FrameNumber < application.PROOF_FRAME_CUTOFF {
return nil
}
keys := [][]byte{}
ksigs := [][]byte{}
var helpers []protobufs.ED448SignHelper = []protobufs.ED448SignHelper{
{
PublicKey: e.pubSub.GetPublicKey(),
Sign: e.pubSub.SignMessage,
},
}
if len(e.engineConfig.MultisigProverEnrollmentPaths) != 0 &&
e.GetSeniority().Cmp(GetAggregatedSeniority(
[]string{peer.ID(e.pubSub.GetPeerID()).String()},
@ -1401,86 +1399,46 @@ func (e *TokenExecutionEngine) AnnounceProverMerge() *protobufs.AnnounceProverRe
panic(errors.Wrap(err, "error unmarshaling peerkey"))
}
keys = append(keys, pubBytes)
sig, err := privKey.Sign(e.pubSub.GetPublicKey())
if err != nil {
panic(errors.Wrap(err, "error unmarshaling peerkey"))
}
ksigs = append(ksigs, sig)
helpers = append(helpers, protobufs.ED448SignHelper{
PublicKey: pubBytes,
Sign: privKey.Sign,
})
}
}
keyjoin := []byte{}
for _, k := range keys {
keyjoin = append(keyjoin, k...)
}
mainsig, err := e.pubSub.SignMessage(keyjoin)
if err != nil {
announce := &protobufs.AnnounceProverRequest{}
if err := announce.SignED448(helpers); err != nil {
panic(err)
}
announce := &protobufs.AnnounceProverRequest{
PublicKeySignaturesEd448: []*protobufs.Ed448Signature{},
}
announce.PublicKeySignaturesEd448 = append(
announce.PublicKeySignaturesEd448,
&protobufs.Ed448Signature{
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: e.pubSub.GetPublicKey(),
},
Signature: mainsig,
},
)
for i := range keys {
announce.PublicKeySignaturesEd448 = append(
announce.PublicKeySignaturesEd448,
&protobufs.Ed448Signature{
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: keys[i],
},
Signature: ksigs[i],
},
)
if err := announce.Validate(); err != nil {
panic(err)
}
return announce
}
func (e *TokenExecutionEngine) AnnounceProverJoin() {
msg := []byte("join")
head := e.GetFrame()
if head == nil ||
head.FrameNumber < application.PROOF_FRAME_CUTOFF {
return
}
msg = binary.BigEndian.AppendUint64(msg, head.FrameNumber)
msg = append(msg, bytes.Repeat([]byte{0xff}, 32)...)
sig, err := e.pubSub.SignMessage(msg)
if err != nil {
join := &protobufs.AnnounceProverJoin{
Filter: bytes.Repeat([]byte{0xff}, 32),
FrameNumber: head.FrameNumber,
Announce: e.AnnounceProverMerge(),
}
if err := join.SignED448(e.pubSub.GetPublicKey(), e.pubSub.SignMessage); err != nil {
panic(err)
}
if err := join.Validate(); err != nil {
panic(err)
}
e.publishMessage(
append([]byte{0x00}, e.intrinsicFilter...),
&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Join{
Join: &protobufs.AnnounceProverJoin{
Filter: bytes.Repeat([]byte{0xff}, 32),
FrameNumber: head.FrameNumber,
PublicKeySignatureEd448: &protobufs.Ed448Signature{
Signature: sig,
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: e.pubSub.GetPublicKey(),
},
},
Announce: e.AnnounceProverMerge(),
},
},
Timestamp: gotime.Now().UnixMilli(),
},
join.TokenRequest(),
)
}

View File

@ -1,8 +1,8 @@
module source.quilibrium.com/quilibrium/monorepo/node
go 1.21
go 1.22
toolchain go1.22.1
toolchain go1.22.5
// A necessary hack until source.quilibrium.com is open to all
replace source.quilibrium.com/quilibrium/monorepo/nekryptology => ../nekryptology
@ -15,6 +15,8 @@ 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

View File

@ -275,8 +275,6 @@ 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=

View File

@ -6,6 +6,7 @@ import (
"crypto/rand"
"encoding/hex"
"fmt"
"math"
"math/big"
"math/bits"
"net"
@ -60,8 +61,15 @@ const (
defaultPingTimeout = 5 * time.Second
defaultPingPeriod = 30 * time.Second
defaultPingAttempts = 3
DecayInterval = 10 * time.Second
AppDecay = .9
)
type appScore struct {
expire time.Time
score float64
}
type BlossomSub struct {
ps *blossomsub.PubSub
ctx context.Context
@ -70,7 +78,7 @@ type BlossomSub struct {
bitmaskMap map[string]*blossomsub.Bitmask
h host.Host
signKey crypto.PrivKey
peerScore map[string]int64
peerScore map[string]*appScore
peerScoreMx sync.Mutex
network uint8
bootstrap internal.PeerConnector
@ -148,7 +156,7 @@ func NewBlossomSubStreamer(
logger: logger,
bitmaskMap: make(map[string]*blossomsub.Bitmask),
signKey: privKey,
peerScore: make(map[string]int64),
peerScore: make(map[string]*appScore),
network: p2pConfig.Network,
}
@ -302,7 +310,7 @@ func NewBlossomSub(
logger: logger,
bitmaskMap: make(map[string]*blossomsub.Bitmask),
signKey: privKey,
peerScore: make(map[string]int64),
peerScore: make(map[string]*appScore),
network: p2pConfig.Network,
}
@ -443,7 +451,7 @@ func NewBlossomSub(
BehaviourPenaltyWeight: -10,
BehaviourPenaltyThreshold: 100,
BehaviourPenaltyDecay: .5,
DecayInterval: 10 * time.Second,
DecayInterval: DecayInterval,
DecayToZero: .1,
RetainScore: 60 * time.Minute,
AppSpecificScore: func(p peer.ID) float64 {
@ -493,6 +501,8 @@ func NewBlossomSub(
bs.h = h
bs.signKey = privKey
go bs.background(ctx)
return bs
}
@ -586,6 +596,39 @@ func resourceManager(highWatermark int, allowed []peer.AddrInfo) (
return mgr, nil
}
func (b *BlossomSub) background(ctx context.Context) {
refreshScores := time.NewTicker(DecayInterval)
defer refreshScores.Stop()
for {
select {
case <-refreshScores.C:
b.refreshScores()
case <-ctx.Done():
return
}
}
}
func (b *BlossomSub) refreshScores() {
b.peerScoreMx.Lock()
now := time.Now()
for p, pstats := range b.peerScore {
if now.After(pstats.expire) {
delete(b.peerScore, p)
continue
}
pstats.score *= AppDecay
if math.Abs(pstats.score) < .1 {
pstats.score = 0
}
}
b.peerScoreMx.Unlock()
}
func (b *BlossomSub) PublishToBitmask(bitmask []byte, data []byte) error {
return b.ps.Publish(b.ctx, bitmask, data)
}
@ -768,23 +811,37 @@ func (b *BlossomSub) DiscoverPeers(ctx context.Context) error {
func (b *BlossomSub) GetPeerScore(peerId []byte) int64 {
b.peerScoreMx.Lock()
score := b.peerScore[string(peerId)]
peerScore, ok := b.peerScore[string(peerId)]
if !ok {
b.peerScoreMx.Unlock()
return 0
}
score := peerScore.score
b.peerScoreMx.Unlock()
return score
return int64(score)
}
func (b *BlossomSub) SetPeerScore(peerId []byte, score int64) {
b.peerScoreMx.Lock()
b.peerScore[string(peerId)] = score
b.peerScore[string(peerId)] = &appScore{
score: float64(score),
expire: time.Now().Add(1 * time.Hour),
}
b.peerScoreMx.Unlock()
}
func (b *BlossomSub) AddPeerScore(peerId []byte, scoreDelta int64) {
b.peerScoreMx.Lock()
if _, ok := b.peerScore[string(peerId)]; !ok {
b.peerScore[string(peerId)] = scoreDelta
b.peerScore[string(peerId)] = &appScore{
score: float64(scoreDelta),
expire: time.Now().Add(1 * time.Hour),
}
} else {
b.peerScore[string(peerId)] = b.peerScore[string(peerId)] + scoreDelta
b.peerScore[string(peerId)] = &appScore{
score: b.peerScore[string(peerId)].score + float64(scoreDelta),
expire: time.Now().Add(1 * time.Hour),
}
}
b.peerScoreMx.Unlock()
}
@ -979,6 +1036,9 @@ func withDefaults(p2pConfig *config.P2PConfig) *config.P2PConfig {
if p2pConfig.DLazy == 0 {
p2pConfig.DLazy = blossomsub.BlossomSubDlazy
}
if p2pConfig.GossipFactor == 0 {
p2pConfig.GossipFactor = blossomsub.BlossomSubGossipFactor
}
if p2pConfig.GossipRetransmission == 0 {
p2pConfig.GossipRetransmission = blossomsub.BlossomSubGossipRetransmission
}
@ -1091,6 +1151,7 @@ func toBlossomSubParams(p2pConfig *config.P2PConfig) blossomsub.BlossomSubParams
HistoryLength: p2pConfig.HistoryLength,
HistoryGossip: p2pConfig.HistoryGossip,
Dlazy: p2pConfig.DLazy,
GossipFactor: p2pConfig.GossipFactor,
GossipRetransmission: p2pConfig.GossipRetransmission,
HeartbeatInitialDelay: p2pConfig.HeartbeatInitialDelay,
HeartbeatInterval: p2pConfig.HeartbeatInterval,

View File

@ -78,6 +78,7 @@ type DataPeer struct {
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"`
}
func (x *DataPeer) Reset() {
@ -154,6 +155,13 @@ func (x *DataPeer) GetTotalDistance() []byte {
return nil
}
func (x *DataPeer) GetPatchVersion() []byte {
if x != nil {
return x.PatchVersion
}
return nil
}
type DataCompressedSync struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -1087,7 +1095,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, 0xe0, 0x01, 0x0a, 0x08, 0x44, 0x61,
0x70, 0x65, 0x65, 0x72, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x85, 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,
@ -1099,204 +1107,206 @@ var file_data_proto_rawDesc = []byte{
0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x64, 0x69, 0x73, 0x74,
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, 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, 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, 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, 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,
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, 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, 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, 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, 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,
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,
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 (

View File

@ -26,6 +26,7 @@ message DataPeer {
reserved 7;
reserved "public_key";
bytes total_distance = 8;
bytes patch_version = 9;
}
message DataCompressedSync {

View File

@ -182,6 +182,11 @@ func (s *Ed448Signature) Verify(msg []byte) error {
return errors.Wrap(errors.New("invalid length for signature"), "verify")
}
return s.verifyUnsafe(msg)
}
// verifyUnsafe is used to verify a signature without checking the length of the public key and signature.
func (s *Ed448Signature) verifyUnsafe(msg []byte) error {
if !ed448.Verify(s.PublicKey.KeyValue, msg, s.Signature, "") {
return errors.Wrap(errors.New("invalid signature for public key"), "verify")
}

View File

@ -2,6 +2,7 @@ package protobufs
import (
"encoding/binary"
"time"
"github.com/iden3/go-iden3-crypto/poseidon"
pcrypto "github.com/libp2p/go-libp2p/core/crypto"
@ -22,14 +23,6 @@ func (t *TokenRequest) Priority() uint64 {
func (t *MintCoinRequest) RingAndParallelism(
ringCalc func(addr []byte) int,
) (int, uint32, error) {
payload := []byte("mint")
for _, p := range t.Proofs {
payload = append(payload, p...)
}
if err := t.Signature.Verify(payload); err != nil {
return -1, 0, errors.New("invalid")
}
pk, err := pcrypto.UnmarshalEd448PublicKey(
t.Signature.PublicKey.KeyValue,
)
@ -58,3 +51,93 @@ func (t *MintCoinRequest) RingAndParallelism(
return -1, 0, errors.New("invalid")
}
// TokenRequest returns the TokenRequest for the TransferCoinRequest.
func (t *TransferCoinRequest) TokenRequest() *TokenRequest {
return &TokenRequest{
Request: &TokenRequest_Transfer{
Transfer: t,
},
Timestamp: time.Now().UnixMilli(),
}
}
// TokenRequest returns the TokenRequest for the SplitCoinRequest.
func (t *SplitCoinRequest) TokenRequest() *TokenRequest {
return &TokenRequest{
Request: &TokenRequest_Split{
Split: t,
},
Timestamp: time.Now().UnixMilli(),
}
}
// TokenRequest returns the TokenRequest for the MergeCoinRequest.
func (t *MergeCoinRequest) TokenRequest() *TokenRequest {
return &TokenRequest{
Request: &TokenRequest_Merge{
Merge: t,
},
Timestamp: time.Now().UnixMilli(),
}
}
// TokenRequest returns the TokenRequest for the MintCoinRequest.
func (t *MintCoinRequest) TokenRequest() *TokenRequest {
return &TokenRequest{
Request: &TokenRequest_Mint{
Mint: t,
},
Timestamp: time.Now().UnixMilli(),
}
}
// TokenRequest returns the TokenRequest for the AnnounceProverRequest.
func (t *AnnounceProverRequest) TokenRequest() *TokenRequest {
return &TokenRequest{
Request: &TokenRequest_Announce{
Announce: t,
},
Timestamp: time.Now().UnixMilli(),
}
}
// TokenRequest returns the TokenRequest for the AnnounceProverJoin.
func (t *AnnounceProverJoin) TokenRequest() *TokenRequest {
return &TokenRequest{
Request: &TokenRequest_Join{
Join: t,
},
Timestamp: time.Now().UnixMilli(),
}
}
// TokenRequest returns the TokenRequest for the AnnounceProverLeave.
func (t *AnnounceProverLeave) TokenRequest() *TokenRequest {
return &TokenRequest{
Request: &TokenRequest_Leave{
Leave: t,
},
Timestamp: time.Now().UnixMilli(),
}
}
// TokenRequest returns the TokenRequest for the AnnounceProverPause.
func (t *AnnounceProverPause) TokenRequest() *TokenRequest {
return &TokenRequest{
Request: &TokenRequest_Pause{
Pause: t,
},
Timestamp: time.Now().UnixMilli(),
}
}
// TokenRequest returns the TokenRequest for the AnnounceProverResume.
func (t *AnnounceProverResume) TokenRequest() *TokenRequest {
return &TokenRequest{
Request: &TokenRequest_Resume{
Resume: t,
},
Timestamp: time.Now().UnixMilli(),
}
}

File diff suppressed because it is too large Load Diff

View File

@ -43,6 +43,7 @@ message PeerInfo {
bytes signature = 6;
bytes public_key = 7;
bytes total_distance = 8;
bytes patch_version = 9;
}
message PeerInfoResponse {

View File

@ -0,0 +1,700 @@
package protobufs
import (
"encoding/binary"
"github.com/pkg/errors"
)
type signatureMessage interface {
signatureMessage() []byte
}
var _ signatureMessage = (*TransferCoinRequest)(nil)
func (t *TransferCoinRequest) signatureMessage() []byte {
payload := []byte("transfer")
payload = append(payload, t.OfCoin.Address...)
payload = append(
payload,
t.ToAccount.GetImplicitAccount().Address...,
)
return payload
}
var _ signatureMessage = (*SplitCoinRequest)(nil)
func (t *SplitCoinRequest) signatureMessage() []byte {
payload := []byte("split")
payload = append(payload, t.OfCoin.Address...)
for _, a := range t.Amounts {
payload = append(payload, a...)
}
return payload
}
var _ signatureMessage = (*MergeCoinRequest)(nil)
func (t *MergeCoinRequest) signatureMessage() []byte {
payload := []byte("merge")
for _, c := range t.Coins {
payload = append(payload, c.Address...)
}
return payload
}
var _ signatureMessage = (*MintCoinRequest)(nil)
func (t *MintCoinRequest) signatureMessage() []byte {
payload := []byte("mint")
for _, p := range t.Proofs {
payload = append(payload, p...)
}
return payload
}
// NOTE: AnnounceProverRequest has a non-trivial signature payload.
var _ signatureMessage = (*AnnounceProverJoin)(nil)
func (t *AnnounceProverJoin) signatureMessage() []byte {
payload := []byte("join")
payload = binary.BigEndian.AppendUint64(payload, t.FrameNumber)
payload = append(payload, t.Filter...)
return payload
}
var _ signatureMessage = (*AnnounceProverLeave)(nil)
func (t *AnnounceProverLeave) signatureMessage() []byte {
payload := []byte("leave")
payload = binary.BigEndian.AppendUint64(payload, t.FrameNumber)
payload = append(payload, t.Filter...)
return payload
}
var _ signatureMessage = (*AnnounceProverPause)(nil)
func (t *AnnounceProverPause) signatureMessage() []byte {
payload := []byte("pause")
payload = binary.BigEndian.AppendUint64(payload, t.FrameNumber)
payload = append(payload, t.Filter...)
return payload
}
var _ signatureMessage = (*AnnounceProverResume)(nil)
func (t *AnnounceProverResume) signatureMessage() []byte {
payload := []byte("resume")
payload = binary.BigEndian.AppendUint64(payload, t.FrameNumber)
payload = append(payload, t.Filter...)
return payload
}
// SignedMessage is a message that has a signature.
type SignedMessage interface {
// ValidateSignature checks the signature of the message.
// The message contents are expected to be valid - validation
// of contents must precede validation of the signature.
ValidateSignature() error
}
var _ SignedMessage = (*TransferCoinRequest)(nil)
// ValidateSignature checks the signature of the transfer coin request.
func (t *TransferCoinRequest) ValidateSignature() error {
if err := t.Signature.verifyUnsafe(t.signatureMessage()); err != nil {
return errors.Wrap(err, "validate signature")
}
return nil
}
var _ SignedMessage = (*SplitCoinRequest)(nil)
// ValidateSignature checks the signature of the split coin request.
func (t *SplitCoinRequest) ValidateSignature() error {
if err := t.Signature.verifyUnsafe(t.signatureMessage()); err != nil {
return errors.Wrap(err, "validate signature")
}
return nil
}
var _ SignedMessage = (*MergeCoinRequest)(nil)
// ValidateSignature checks the signature of the merge coin request.
func (t *MergeCoinRequest) ValidateSignature() error {
if err := t.Signature.verifyUnsafe(t.signatureMessage()); err != nil {
return errors.Wrap(err, "validate signature")
}
return nil
}
var _ SignedMessage = (*MintCoinRequest)(nil)
// ValidateSignature checks the signature of the mint coin request.
func (t *MintCoinRequest) ValidateSignature() error {
if err := t.Signature.verifyUnsafe(t.signatureMessage()); err != nil {
return errors.Wrap(err, "validate signature")
}
return nil
}
var _ SignedMessage = (*AnnounceProverRequest)(nil)
// ValidateSignature checks the signature of the announce prover request.
func (t *AnnounceProverRequest) ValidateSignature() error {
payload := []byte{}
primary := t.PublicKeySignaturesEd448[0]
for _, p := range t.PublicKeySignaturesEd448[1:] {
payload = append(payload, p.PublicKey.KeyValue...)
if err := p.verifyUnsafe(primary.PublicKey.KeyValue); err != nil {
return errors.Wrap(err, "validate signature")
}
}
if err := primary.verifyUnsafe(payload); err != nil {
return errors.Wrap(err, "validate signature")
}
return nil
}
var _ SignedMessage = (*AnnounceProverJoin)(nil)
// ValidateSignature checks the signature of the announce prover join.
func (t *AnnounceProverJoin) ValidateSignature() error {
if err := t.PublicKeySignatureEd448.verifyUnsafe(t.signatureMessage()); err != nil {
return errors.Wrap(err, "validate signature")
}
return nil
}
var _ SignedMessage = (*AnnounceProverLeave)(nil)
// ValidateSignature checks the signature of the announce prover leave.
func (t *AnnounceProverLeave) ValidateSignature() error {
if err := t.PublicKeySignatureEd448.verifyUnsafe(t.signatureMessage()); err != nil {
return errors.Wrap(err, "validate signature")
}
return nil
}
var _ SignedMessage = (*AnnounceProverPause)(nil)
// ValidateSignature checks the signature of the announce prover pause.
func (t *AnnounceProverPause) ValidateSignature() error {
if err := t.PublicKeySignatureEd448.verifyUnsafe(t.signatureMessage()); err != nil {
return errors.Wrap(err, "validate signature")
}
return nil
}
var _ SignedMessage = (*AnnounceProverResume)(nil)
// ValidateSignature checks the signature of the announce prover resume.
func (t *AnnounceProverResume) ValidateSignature() error {
if err := t.PublicKeySignatureEd448.verifyUnsafe(t.signatureMessage()); err != nil {
return errors.Wrap(err, "validate signature")
}
return nil
}
// ValidatableMessage is a message that can be validated.
type ValidatableMessage interface {
// Validate checks the message contents.
// It will also verify signatures if the message is signed.
Validate() error
}
var _ ValidatableMessage = (*Ed448PublicKey)(nil)
// Validate checks the Ed448 public key.
func (e *Ed448PublicKey) Validate() error {
if e == nil {
return errors.New("nil Ed448 public key")
}
if len(e.KeyValue) != 57 {
return errors.New("invalid Ed448 public key")
}
return nil
}
var _ ValidatableMessage = (*Ed448Signature)(nil)
// Validate checks the Ed448 signature.
func (e *Ed448Signature) Validate() error {
if e == nil {
return errors.New("nil Ed448 signature")
}
if err := e.PublicKey.Validate(); err != nil {
return errors.Wrap(err, "public key")
}
if len(e.Signature) != 114 {
return errors.New("invalid Ed448 signature")
}
return nil
}
var _ ValidatableMessage = (*ImplicitAccount)(nil)
// Validate checks the implicit account.
func (i *ImplicitAccount) Validate() error {
if i == nil {
return errors.New("nil implicit account")
}
// TODO: Validate ImplicitType.
if len(i.Address) != 32 {
return errors.New("invalid implicit account")
}
// TODO: Validate Domain.
return nil
}
var _ ValidatableMessage = (*OriginatedAccountRef)(nil)
// Validate checks the originated account.
func (o *OriginatedAccountRef) Validate() error {
if o == nil {
return errors.New("nil originated account")
}
if len(o.Address) != 32 {
return errors.New("invalid originated account")
}
return nil
}
var _ ValidatableMessage = (*AccountRef)(nil)
// Validate checks the account reference.
func (a *AccountRef) Validate() error {
if a == nil {
return errors.New("nil account reference")
}
switch {
case a.GetImplicitAccount() != nil:
if err := a.GetImplicitAccount().Validate(); err != nil {
return errors.Wrap(err, "implicit account")
}
case a.GetOriginatedAccount() != nil:
if err := a.GetOriginatedAccount().Validate(); err != nil {
return errors.Wrap(err, "originated account")
}
default:
return errors.New("invalid account reference")
}
return nil
}
var _ ValidatableMessage = (*CoinRef)(nil)
// Validate checks the coin reference.
func (c *CoinRef) Validate() error {
if c == nil {
return errors.New("nil coin reference")
}
if len(c.Address) != 32 {
return errors.New("invalid coin reference")
}
return nil
}
var _ ValidatableMessage = (*AccountAllowanceRef)(nil)
// Validate checks the account allowance reference.
func (a *AccountAllowanceRef) Validate() error {
if a == nil {
return errors.New("nil account allowance reference")
}
if len(a.Address) != 32 {
return errors.New("invalid account allowance reference")
}
return nil
}
var _ ValidatableMessage = (*CoinAllowanceRef)(nil)
// Validate checks the coin allowance reference.
func (c *CoinAllowanceRef) Validate() error {
if c == nil {
return errors.New("nil coin allowance reference")
}
if len(c.Address) != 32 {
return errors.New("invalid coin allowance reference")
}
return nil
}
var _ ValidatableMessage = (*TokenRequest)(nil)
// Validate checks the token request.
func (t *TokenRequest) Validate() error {
if t == nil {
return errors.New("nil token request")
}
switch {
case t.GetTransfer() != nil:
return t.GetTransfer().Validate()
case t.GetSplit() != nil:
return t.GetSplit().Validate()
case t.GetMerge() != nil:
return t.GetMerge().Validate()
case t.GetMint() != nil:
return t.GetMint().Validate()
case t.GetAnnounce() != nil:
return t.GetAnnounce().Validate()
case t.GetJoin() != nil:
return t.GetJoin().Validate()
case t.GetLeave() != nil:
return t.GetLeave().Validate()
case t.GetPause() != nil:
return t.GetPause().Validate()
case t.GetResume() != nil:
return t.GetResume().Validate()
default:
return nil
}
}
var _ ValidatableMessage = (*TransferCoinRequest)(nil)
// Validate checks the transfer coin request.
func (t *TransferCoinRequest) Validate() error {
if t == nil {
return errors.New("nil transfer coin request")
}
if err := t.ToAccount.Validate(); err != nil {
return errors.Wrap(err, "to account")
}
// TODO: Validate RefundAccount.
if err := t.OfCoin.Validate(); err != nil {
return errors.Wrap(err, "of coin")
}
// TODO: Validate Expiry.
// TODO: Validate AccountAllowance.
// TODO: Validate CoinAllowance.
if err := t.Signature.Validate(); err != nil {
return errors.Wrap(err, "signature")
}
if err := t.ValidateSignature(); err != nil {
return errors.Wrap(err, "signature")
}
return nil
}
var _ ValidatableMessage = (*SplitCoinRequest)(nil)
// Validate checks the split coin request.
func (t *SplitCoinRequest) Validate() error {
if t == nil {
return errors.New("nil split coin request")
}
if err := t.OfCoin.Validate(); err != nil {
return errors.Wrap(err, "of coin")
}
if n := len(t.Amounts); n == 0 || n > 100 {
return errors.New("invalid amounts")
}
for _, a := range t.Amounts {
if n := len(a); n == 0 || n > 32 {
return errors.New("invalid amount")
}
}
// TODO: Validate AccountAllowance.
// TODO: Validate CoinAllowance.
if err := t.Signature.Validate(); err != nil {
return errors.Wrap(err, "signature")
}
if err := t.ValidateSignature(); err != nil {
return errors.Wrap(err, "signature")
}
return nil
}
var _ ValidatableMessage = (*MergeCoinRequest)(nil)
// Validate checks the merge coin request.
func (t *MergeCoinRequest) Validate() error {
if t == nil {
return errors.New("nil merge coin request")
}
if len(t.Coins) == 0 {
return errors.New("invalid coins")
}
for _, c := range t.Coins {
if err := c.Validate(); err != nil {
return errors.Wrap(err, "coin")
}
}
// TODO: Validate AccountAllowance.
// TODO: Validate CoinAllowance.
if err := t.Signature.Validate(); err != nil {
return errors.Wrap(err, "signature")
}
if err := t.ValidateSignature(); err != nil {
return errors.Wrap(err, "signature")
}
return nil
}
var _ ValidatableMessage = (*MintCoinRequest)(nil)
// Validate checks the mint coin request.
func (t *MintCoinRequest) Validate() error {
if t == nil {
return errors.New("nil mint coin request")
}
if len(t.Proofs) == 0 {
return errors.New("invalid proofs")
}
// TODO: Validate AccountAllowance.
if err := t.Signature.Validate(); err != nil {
return errors.Wrap(err, "signature")
}
if err := t.ValidateSignature(); err != nil {
return errors.Wrap(err, "signature")
}
return nil
}
var _ ValidatableMessage = (*AnnounceProverRequest)(nil)
// Validate checks the announce prover request.
func (t *AnnounceProverRequest) Validate() error {
if t == nil {
return errors.New("nil announce prover request")
}
if len(t.PublicKeySignaturesEd448) == 0 {
return errors.New("invalid public key signatures")
}
for _, p := range t.PublicKeySignaturesEd448 {
if err := p.Validate(); err != nil {
return errors.Wrap(err, "public key signature")
}
}
if err := t.ValidateSignature(); err != nil {
return errors.Wrap(err, "signature")
}
return nil
}
var _ ValidatableMessage = (*AnnounceProverJoin)(nil)
// Validate checks the announce prover join.
func (t *AnnounceProverJoin) Validate() error {
if t == nil {
return errors.New("nil announce prover join")
}
if len(t.Filter) != 32 {
return errors.New("invalid filter")
}
if announce := t.Announce; announce != nil {
if err := announce.Validate(); err != nil {
return errors.Wrap(err, "announce")
}
}
if err := t.PublicKeySignatureEd448.Validate(); err != nil {
return errors.Wrap(err, "public key signature")
}
if err := t.ValidateSignature(); err != nil {
return errors.Wrap(err, "signature")
}
return nil
}
var _ ValidatableMessage = (*AnnounceProverLeave)(nil)
// Validate checks the announce prover leave.
func (t *AnnounceProverLeave) Validate() error {
if t == nil {
return errors.New("nil announce prover leave")
}
if len(t.Filter) != 32 {
return errors.New("invalid filter")
}
if err := t.PublicKeySignatureEd448.Validate(); err != nil {
return errors.Wrap(err, "public key signature")
}
if err := t.ValidateSignature(); err != nil {
return errors.Wrap(err, "signature")
}
return nil
}
var _ ValidatableMessage = (*AnnounceProverPause)(nil)
// Validate checks the announce prover pause.
func (t *AnnounceProverPause) Validate() error {
if t == nil {
return errors.New("nil announce prover pause")
}
if len(t.Filter) != 32 {
return errors.New("invalid filter")
}
if err := t.PublicKeySignatureEd448.Validate(); err != nil {
return errors.Wrap(err, "public key signature")
}
if err := t.ValidateSignature(); err != nil {
return errors.Wrap(err, "signature")
}
return nil
}
var _ ValidatableMessage = (*AnnounceProverResume)(nil)
// Validate checks the announce prover resume.
func (t *AnnounceProverResume) Validate() error {
if t == nil {
return errors.New("nil announce prover resume")
}
if len(t.Filter) != 32 {
return errors.New("invalid filter")
}
if err := t.PublicKeySignatureEd448.Validate(); err != nil {
return errors.Wrap(err, "public key signature")
}
if err := t.ValidateSignature(); err != nil {
return errors.Wrap(err, "signature")
}
return nil
}
// SignableED448Message is a message that can be signed.
type SignableED448Message interface {
// SignED448 signs the message with the given key, modifying the message.
// The message contents are expected to be valid - message
// contents must be validated, or correctly constructed, before signing.
SignED448(publicKey []byte, sign func([]byte) ([]byte, error)) error
}
func newED448Signature(publicKey, signature []byte) *Ed448Signature {
return &Ed448Signature{
PublicKey: &Ed448PublicKey{
KeyValue: publicKey,
},
Signature: signature,
}
}
var _ SignableED448Message = (*TransferCoinRequest)(nil)
// SignED448 signs the transfer coin request with the given key.
func (t *TransferCoinRequest) SignED448(publicKey []byte, sign func([]byte) ([]byte, error)) error {
signature, err := sign(t.signatureMessage())
if err != nil {
return errors.Wrap(err, "sign")
}
t.Signature = newED448Signature(publicKey, signature)
return nil
}
var _ SignableED448Message = (*SplitCoinRequest)(nil)
// SignED448 signs the split coin request with the given key.
func (t *SplitCoinRequest) SignED448(publicKey []byte, sign func([]byte) ([]byte, error)) error {
signature, err := sign(t.signatureMessage())
if err != nil {
return errors.Wrap(err, "sign")
}
t.Signature = newED448Signature(publicKey, signature)
return nil
}
var _ SignableED448Message = (*MergeCoinRequest)(nil)
// SignED448 signs the merge coin request with the given key.
func (t *MergeCoinRequest) SignED448(publicKey []byte, sign func([]byte) ([]byte, error)) error {
signature, err := sign(t.signatureMessage())
if err != nil {
return errors.Wrap(err, "sign")
}
t.Signature = newED448Signature(publicKey, signature)
return nil
}
var _ SignableED448Message = (*MintCoinRequest)(nil)
// SignED448 signs the mint coin request with the given key.
func (t *MintCoinRequest) SignED448(publicKey []byte, sign func([]byte) ([]byte, error)) error {
signature, err := sign(t.signatureMessage())
if err != nil {
return errors.Wrap(err, "sign")
}
t.Signature = newED448Signature(publicKey, signature)
return nil
}
type ED448SignHelper struct {
PublicKey []byte
Sign func([]byte) ([]byte, error)
}
// SignED448 signs the announce prover request with the given keys.
func (t *AnnounceProverRequest) SignED448(helpers []ED448SignHelper) error {
if len(helpers) == 0 {
return errors.New("no keys")
}
payload := []byte{}
primary := helpers[0]
signatures := make([]*Ed448Signature, len(helpers))
for i, k := range helpers[1:] {
payload = append(payload, k.PublicKey...)
signature, err := k.Sign(primary.PublicKey)
if err != nil {
return errors.Wrap(err, "sign")
}
signatures[i+1] = newED448Signature(k.PublicKey, signature)
}
signature, err := primary.Sign(payload)
if err != nil {
return errors.Wrap(err, "sign")
}
signatures[0] = newED448Signature(primary.PublicKey, signature)
t.PublicKeySignaturesEd448 = signatures
return nil
}
var _ SignableED448Message = (*AnnounceProverJoin)(nil)
// SignED448 signs the announce prover join with the given key.
func (t *AnnounceProverJoin) SignED448(publicKey []byte, sign func([]byte) ([]byte, error)) error {
signature, err := sign(t.signatureMessage())
if err != nil {
return errors.Wrap(err, "sign")
}
t.PublicKeySignatureEd448 = newED448Signature(publicKey, signature)
return nil
}
var _ SignableED448Message = (*AnnounceProverLeave)(nil)
// SignED448 signs the announce prover leave with the given key.
func (t *AnnounceProverLeave) SignED448(publicKey []byte, sign func([]byte) ([]byte, error)) error {
signature, err := sign(t.signatureMessage())
if err != nil {
return errors.Wrap(err, "sign")
}
t.PublicKeySignatureEd448 = newED448Signature(publicKey, signature)
return nil
}
var _ SignableED448Message = (*AnnounceProverPause)(nil)
// SignED448 signs the announce prover pause with the given key.
func (t *AnnounceProverPause) SignED448(publicKey []byte, sign func([]byte) ([]byte, error)) error {
signature, err := sign(t.signatureMessage())
if err != nil {
return errors.Wrap(err, "sign")
}
t.PublicKeySignatureEd448 = newED448Signature(publicKey, signature)
return nil
}
var _ SignableED448Message = (*AnnounceProverResume)(nil)
// SignED448 signs the announce prover resume with the given key.
func (t *AnnounceProverResume) SignED448(publicKey []byte, sign func([]byte) ([]byte, error)) error {
signature, err := sign(t.signatureMessage())
if err != nil {
return errors.Wrap(err, "sign")
}
t.PublicKeySignatureEd448 = newED448Signature(publicKey, signature)
return nil
}

View File

@ -0,0 +1,5 @@
package protobufs
func SignatureMessageOf(m any) []byte {
return m.(signatureMessage).signatureMessage()
}

View File

@ -0,0 +1,914 @@
package protobufs_test
import (
"bytes"
"crypto/rand"
"testing"
"github.com/libp2p/go-libp2p/core/crypto"
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
)
func newPrivateKey() crypto.PrivKey {
privKey, _, err := crypto.GenerateEd448Key(rand.Reader)
if err != nil {
panic(err)
}
return privKey
}
func publicKeyBytesOf(privKey crypto.PrivKey) []byte {
b, err := privKey.GetPublic().Raw()
if err != nil {
panic(err)
}
return b
}
var (
primaryPrivateKey crypto.PrivKey = newPrivateKey()
primaryPublicKeyBytes []byte = publicKeyBytesOf(primaryPrivateKey)
secondaryPrivateKey crypto.PrivKey = newPrivateKey()
secondaryPublicKeyBytes []byte = publicKeyBytesOf(secondaryPrivateKey)
)
func metaAppend[T any](bs ...[]T) []T {
var result []T
for _, b := range bs {
result = append(result, b...)
}
return result
}
func TestTransferCoinRequestSignatureRoundtrip(t *testing.T) {
t.Parallel()
message := &protobufs.TransferCoinRequest{
OfCoin: &protobufs.CoinRef{
Address: bytes.Repeat([]byte{0x01}, 32),
},
ToAccount: &protobufs.AccountRef{
Account: &protobufs.AccountRef_ImplicitAccount{
ImplicitAccount: &protobufs.ImplicitAccount{
Address: bytes.Repeat([]byte{0x02}, 32),
},
},
},
Signature: &protobufs.Ed448Signature{
Signature: bytes.Repeat([]byte{0x03}, 114),
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: bytes.Repeat([]byte{0x04}, 57),
},
},
}
if !bytes.Equal(
protobufs.SignatureMessageOf(message),
metaAppend(
[]byte("transfer"),
bytes.Repeat([]byte{0x01}, 32),
bytes.Repeat([]byte{0x02}, 32),
),
) {
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.Signature.PublicKey.KeyValue, primaryPublicKeyBytes) {
t.Fatal("unexpected public key")
}
if err := message.ValidateSignature(); err != nil {
t.Fatal(err)
}
}
func TestSplitCoinRequestSignatureRoundtrip(t *testing.T) {
t.Parallel()
message := &protobufs.SplitCoinRequest{
OfCoin: &protobufs.CoinRef{
Address: bytes.Repeat([]byte{0x01}, 32),
},
Amounts: [][]byte{
bytes.Repeat([]byte{0x02}, 32),
bytes.Repeat([]byte{0x03}, 32),
},
Signature: &protobufs.Ed448Signature{
Signature: bytes.Repeat([]byte{0x04}, 114),
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: bytes.Repeat([]byte{0x05}, 57),
},
},
}
if !bytes.Equal(
protobufs.SignatureMessageOf(message),
metaAppend(
[]byte("split"),
bytes.Repeat([]byte{0x01}, 32),
bytes.Repeat([]byte{0x02}, 32),
bytes.Repeat([]byte{0x03}, 32),
),
) {
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.Signature.PublicKey.KeyValue, primaryPublicKeyBytes) {
t.Fatal("unexpected public key")
}
if err := message.ValidateSignature(); err != nil {
t.Fatal(err)
}
}
func TestMergeCoinRequestSignatureRoundtrip(t *testing.T) {
t.Parallel()
message := &protobufs.MergeCoinRequest{
Coins: []*protobufs.CoinRef{
{
Address: bytes.Repeat([]byte{0x01}, 32),
},
{
Address: bytes.Repeat([]byte{0x02}, 32),
},
},
Signature: &protobufs.Ed448Signature{
Signature: bytes.Repeat([]byte{0x03}, 114),
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: bytes.Repeat([]byte{0x04}, 57),
},
},
}
if !bytes.Equal(
protobufs.SignatureMessageOf(message),
metaAppend(
[]byte("merge"),
bytes.Repeat([]byte{0x01}, 32),
bytes.Repeat([]byte{0x02}, 32),
),
) {
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.Signature.PublicKey.KeyValue, primaryPublicKeyBytes) {
t.Fatal("unexpected public key")
}
if err := message.ValidateSignature(); err != nil {
t.Fatal(err)
}
}
func TestMintCoinRequestSignatureRoundtrip(t *testing.T) {
t.Parallel()
message := &protobufs.MintCoinRequest{
Proofs: [][]byte{
bytes.Repeat([]byte{0x01}, 32),
bytes.Repeat([]byte{0x02}, 32),
},
Signature: &protobufs.Ed448Signature{
Signature: bytes.Repeat([]byte{0x03}, 114),
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: bytes.Repeat([]byte{0x04}, 57),
},
},
}
if !bytes.Equal(
protobufs.SignatureMessageOf(message),
metaAppend(
[]byte("mint"),
bytes.Repeat([]byte{0x01}, 32),
bytes.Repeat([]byte{0x02}, 32),
),
) {
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.Signature.PublicKey.KeyValue, primaryPublicKeyBytes) {
t.Fatal("unexpected public key")
}
if err := message.ValidateSignature(); err != nil {
t.Fatal(err)
}
}
func TestAnnounceProverRequestSignatureRoundtrip(t *testing.T) {
t.Parallel()
message := &protobufs.AnnounceProverRequest{
PublicKeySignaturesEd448: []*protobufs.Ed448Signature{
{
Signature: bytes.Repeat([]byte{0x01}, 114),
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: bytes.Repeat([]byte{0x02}, 57),
},
},
{
Signature: bytes.Repeat([]byte{0x03}, 114),
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: bytes.Repeat([]byte{0x04}, 57),
},
},
},
}
if err := message.ValidateSignature(); err == nil {
t.Fatal("expected error")
}
if err := message.SignED448([]protobufs.ED448SignHelper{
{
PublicKey: primaryPublicKeyBytes,
Sign: primaryPrivateKey.Sign,
},
{
PublicKey: secondaryPublicKeyBytes,
Sign: secondaryPrivateKey.Sign,
},
}); err != nil {
t.Fatal(err)
}
if !bytes.Equal(message.PublicKeySignaturesEd448[0].PublicKey.KeyValue, primaryPublicKeyBytes) {
t.Fatal("unexpected public key")
}
if !bytes.Equal(message.PublicKeySignaturesEd448[1].PublicKey.KeyValue, secondaryPublicKeyBytes) {
t.Fatal("unexpected public key")
}
if err := message.ValidateSignature(); err != nil {
t.Fatal(err)
}
message = &protobufs.AnnounceProverRequest{
PublicKeySignaturesEd448: []*protobufs.Ed448Signature{
{
Signature: bytes.Repeat([]byte{0x01}, 114),
PublicKey: &protobufs.Ed448PublicKey{
KeyValue: bytes.Repeat([]byte{0x02}, 57),
},
},
},
}
if err := message.ValidateSignature(); err == nil {
t.Fatal("expected error")
}
if err := message.SignED448([]protobufs.ED448SignHelper{
{
PublicKey: primaryPublicKeyBytes,
Sign: primaryPrivateKey.Sign,
},
}); err != nil {
t.Fatal(err)
}
if !bytes.Equal(message.PublicKeySignaturesEd448[0].PublicKey.KeyValue, primaryPublicKeyBytes) {
t.Fatal("unexpected public key")
}
if err := message.ValidateSignature(); err != nil {
t.Fatal(err)
}
}
func TestAnnounceProverJoinSignatureRoundtrip(t *testing.T) {
t.Parallel()
message := &protobufs.AnnounceProverJoin{
Filter: bytes.Repeat([]byte{0x01}, 32),
FrameNumber: 1,
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("join"),
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
bytes.Repeat([]byte{0x01}, 32),
),
) {
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.PublicKeySignatureEd448.PublicKey.KeyValue, primaryPublicKeyBytes) {
t.Fatal("unexpected public key")
}
if err := message.ValidateSignature(); err != nil {
t.Fatal(err)
}
}
func TestAnnounceProverLeaveSignatureRoundtrip(t *testing.T) {
t.Parallel()
message := &protobufs.AnnounceProverLeave{
Filter: bytes.Repeat([]byte{0x01}, 32),
FrameNumber: 1,
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("leave"),
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
bytes.Repeat([]byte{0x01}, 32),
),
) {
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.PublicKeySignatureEd448.PublicKey.KeyValue, primaryPublicKeyBytes) {
t.Fatal("unexpected public key")
}
if err := message.ValidateSignature(); err != nil {
t.Fatal(err)
}
}
func TestAnnounceProverPauseSignatureRoundtrip(t *testing.T) {
t.Parallel()
message := &protobufs.AnnounceProverPause{
Filter: bytes.Repeat([]byte{0x01}, 32),
FrameNumber: 1,
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("pause"),
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
bytes.Repeat([]byte{0x01}, 32),
),
) {
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.PublicKeySignatureEd448.PublicKey.KeyValue, primaryPublicKeyBytes) {
t.Fatal("unexpected public key")
}
if err := message.ValidateSignature(); err != nil {
t.Fatal(err)
}
}
func TestAnnounceProverResumeSignatureRoundtrip(t *testing.T) {
t.Parallel()
message := &protobufs.AnnounceProverResume{
Filter: bytes.Repeat([]byte{0x01}, 32),
FrameNumber: 1,
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("resume"),
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
bytes.Repeat([]byte{0x01}, 32),
),
) {
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.PublicKeySignatureEd448.PublicKey.KeyValue, primaryPublicKeyBytes) {
t.Fatal("unexpected public key")
}
if err := message.ValidateSignature(); err != nil {
t.Fatal(err)
}
}
func TestEd448PublicKeyValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.Ed448PublicKey)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.Ed448PublicKey{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
message.KeyValue = bytes.Repeat([]byte{0x01}, 57)
if err := message.Validate(); err != nil {
t.Fatal(err)
}
}
func TestEd448SignatureValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.Ed448Signature)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.Ed448Signature{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
message.Signature = bytes.Repeat([]byte{0x01}, 114)
message.PublicKey = &protobufs.Ed448PublicKey{
KeyValue: bytes.Repeat([]byte{0x02}, 57),
}
if err := message.Validate(); err != nil {
t.Fatal(err)
}
}
func TestImplicitAccountValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.ImplicitAccount)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.ImplicitAccount{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
message.Address = bytes.Repeat([]byte{0x01}, 32)
if err := message.Validate(); err != nil {
t.Fatal(err)
}
}
func TestOriginatedAccountRefValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.OriginatedAccountRef)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.OriginatedAccountRef{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
message.Address = bytes.Repeat([]byte{0x01}, 32)
if err := message.Validate(); err != nil {
t.Fatal(err)
}
}
func TestAccountRefValidate(t *testing.T) {
t.Parallel()
message := &protobufs.AccountRef{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
message.Account = &protobufs.AccountRef_ImplicitAccount{
ImplicitAccount: &protobufs.ImplicitAccount{
Address: bytes.Repeat([]byte{0x01}, 32),
},
}
if err := message.Validate(); err != nil {
t.Fatal(err)
}
message.Account = &protobufs.AccountRef_OriginatedAccount{
OriginatedAccount: &protobufs.OriginatedAccountRef{
Address: bytes.Repeat([]byte{0x02}, 32),
},
}
if err := message.Validate(); err != nil {
t.Fatal(err)
}
}
func TestCoinRefValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.CoinRef)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.CoinRef{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
message.Address = bytes.Repeat([]byte{0x01}, 32)
if err := message.Validate(); err != nil {
t.Fatal(err)
}
}
func TestAccountAllowanceRefValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.AccountAllowanceRef)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.AccountAllowanceRef{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
message.Address = bytes.Repeat([]byte{0x01}, 32)
if err := message.Validate(); err != nil {
t.Fatal(err)
}
}
func TestCoinAllowanceRefValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.CoinAllowanceRef)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.CoinAllowanceRef{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
message.Address = bytes.Repeat([]byte{0x01}, 32)
if err := message.Validate(); err != nil {
t.Fatal(err)
}
}
func TestTransferCoinRequestValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.TransferCoinRequest)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.TransferCoinRequest{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Transfer{
Transfer: message,
},
}).Validate(); err == nil {
t.Fatal("expected error")
}
message.OfCoin = &protobufs.CoinRef{
Address: bytes.Repeat([]byte{0x01}, 32),
}
message.ToAccount = &protobufs.AccountRef{
Account: &protobufs.AccountRef_ImplicitAccount{
ImplicitAccount: &protobufs.ImplicitAccount{
Address: bytes.Repeat([]byte{0x02}, 32),
},
},
}
if err := message.SignED448(primaryPublicKeyBytes, primaryPrivateKey.Sign); err != nil {
t.Fatal(err)
}
if err := message.Validate(); err != nil {
t.Fatal(err)
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Transfer{
Transfer: message,
},
}).Validate(); err != nil {
t.Fatal(err)
}
}
func TestSplitCoinRequestValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.SplitCoinRequest)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.SplitCoinRequest{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Split{
Split: message,
},
}).Validate(); err == nil {
t.Fatal("expected error")
}
message.OfCoin = &protobufs.CoinRef{
Address: bytes.Repeat([]byte{0x01}, 32),
}
message.Amounts = [][]byte{
bytes.Repeat([]byte{0x02}, 32),
bytes.Repeat([]byte{0x03}, 32),
}
if err := message.SignED448(primaryPublicKeyBytes, primaryPrivateKey.Sign); err != nil {
t.Fatal(err)
}
if err := message.Validate(); err != nil {
t.Fatal(err)
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Split{
Split: message,
},
}).Validate(); err != nil {
t.Fatal(err)
}
}
func TestMergeCoinRequestValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.MergeCoinRequest)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.MergeCoinRequest{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Merge{
Merge: message,
},
}).Validate(); err == nil {
t.Fatal("expected error")
}
message.Coins = []*protobufs.CoinRef{
{
Address: bytes.Repeat([]byte{0x01}, 32),
},
{
Address: bytes.Repeat([]byte{0x02}, 32),
},
}
if err := message.SignED448(primaryPublicKeyBytes, primaryPrivateKey.Sign); err != nil {
t.Fatal(err)
}
if err := message.Validate(); err != nil {
t.Fatal(err)
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Merge{
Merge: message,
},
}).Validate(); err != nil {
t.Fatal(err)
}
}
func TestMintCoinRequestValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.MintCoinRequest)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.MintCoinRequest{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Mint{
Mint: message,
},
}).Validate(); err == nil {
t.Fatal("expected error")
}
message.Proofs = [][]byte{
bytes.Repeat([]byte{0x01}, 32),
bytes.Repeat([]byte{0x02}, 32),
}
if err := message.SignED448(primaryPublicKeyBytes, primaryPrivateKey.Sign); err != nil {
t.Fatal(err)
}
if err := message.Validate(); err != nil {
t.Fatal(err)
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Mint{
Mint: message,
},
}).Validate(); err != nil {
t.Fatal(err)
}
}
func TestAnnounceProverRequestValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.AnnounceProverRequest)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.AnnounceProverRequest{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Announce{
Announce: message,
},
}).Validate(); err == nil {
t.Fatal("expected error")
}
if err := message.SignED448([]protobufs.ED448SignHelper{
{
PublicKey: primaryPublicKeyBytes,
Sign: primaryPrivateKey.Sign,
},
{
PublicKey: secondaryPublicKeyBytes,
Sign: secondaryPrivateKey.Sign,
},
}); err != nil {
t.Fatal(err)
}
if err := message.Validate(); err != nil {
t.Fatal(err)
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Announce{
Announce: message,
},
}).Validate(); err != nil {
t.Fatal("expected error")
}
}
func TestAnnounceProverJoinValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.AnnounceProverJoin)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.AnnounceProverJoin{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Join{
Join: message,
},
}).Validate(); err == nil {
t.Fatal("expected error")
}
message.Filter = bytes.Repeat([]byte{0x01}, 32)
message.FrameNumber = 1
if err := message.SignED448(primaryPublicKeyBytes, primaryPrivateKey.Sign); err != nil {
t.Fatal(err)
}
if err := message.Validate(); err != nil {
t.Fatal(err)
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Join{
Join: message,
},
}).Validate(); err != nil {
t.Fatal(err)
}
announce := &protobufs.AnnounceProverRequest{}
message.Announce = announce
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Join{
Join: message,
},
}).Validate(); err == nil {
t.Fatal("expected error")
}
if err := announce.SignED448([]protobufs.ED448SignHelper{
{
PublicKey: primaryPublicKeyBytes,
Sign: primaryPrivateKey.Sign,
},
{
PublicKey: secondaryPublicKeyBytes,
Sign: secondaryPrivateKey.Sign,
},
}); err != nil {
t.Fatal(err)
}
if err := message.Validate(); err != nil {
t.Fatal(err)
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Join{
Join: message,
},
}).Validate(); err != nil {
t.Fatal(err)
}
}
func TestAnnounceProverLeaveValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.AnnounceProverLeave)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.AnnounceProverLeave{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Leave{
Leave: message,
},
}).Validate(); err == nil {
t.Fatal("expected error")
}
message.Filter = bytes.Repeat([]byte{0x01}, 32)
message.FrameNumber = 1
if err := message.SignED448(primaryPublicKeyBytes, primaryPrivateKey.Sign); err != nil {
t.Fatal(err)
}
if err := message.Validate(); err != nil {
t.Fatal(err)
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Leave{
Leave: message,
},
}).Validate(); err != nil {
t.Fatal(err)
}
}
func TestAnnounceProverPauseValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.AnnounceProverPause)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.AnnounceProverPause{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Pause{
Pause: message,
},
}).Validate(); err == nil {
t.Fatal("expected error")
}
message.Filter = bytes.Repeat([]byte{0x01}, 32)
message.FrameNumber = 1
if err := message.SignED448(primaryPublicKeyBytes, primaryPrivateKey.Sign); err != nil {
t.Fatal(err)
}
if err := message.Validate(); err != nil {
t.Fatal(err)
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Pause{
Pause: message,
},
}).Validate(); err != nil {
t.Fatal(err)
}
}
func TestAnnounceProverResumeValidate(t *testing.T) {
t.Parallel()
if err := (*protobufs.AnnounceProverResume)(nil).Validate(); err == nil {
t.Fatal("expected error")
}
message := &protobufs.AnnounceProverResume{}
if err := message.Validate(); err == nil {
t.Fatal("expected error")
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Resume{
Resume: message,
},
}).Validate(); err == nil {
t.Fatal("expected error")
}
message.Filter = bytes.Repeat([]byte{0x01}, 32)
message.FrameNumber = 1
if err := message.SignED448(primaryPublicKeyBytes, primaryPrivateKey.Sign); err != nil {
t.Fatal(err)
}
if err := message.Validate(); err != nil {
t.Fatal(err)
}
if err := (&protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Resume{
Resume: message,
},
}).Validate(); err != nil {
t.Fatal(err)
}
}

View File

@ -221,20 +221,20 @@ func (r *RPCServer) SendMessage(
) (*protobufs.SendMessageResponse, error) {
req.Timestamp = time.Now().UnixMilli()
any := &anypb.Any{}
if err := any.MarshalFrom(req); err != nil {
a := &anypb.Any{}
if err := a.MarshalFrom(req); err != nil {
return nil, errors.Wrap(err, "publish message")
}
// annoying protobuf any hack
any.TypeUrl = strings.Replace(
any.TypeUrl,
a.TypeUrl = strings.Replace(
a.TypeUrl,
"type.googleapis.com",
"types.quilibrium.com",
1,
)
payload, err := proto.Marshal(any)
payload, err := proto.Marshal(a)
if err != nil {
return nil, errors.Wrap(err, "publish message")
}

View File

@ -31,9 +31,9 @@ func PackOutputIntoPayloadAndProof(
modulo int,
frame *protobufs.ClockFrame,
previousTree *mt.MerkleTree,
) (*mt.MerkleTree, []byte, [][]byte, error) {
) (*mt.MerkleTree, [][]byte, error) {
if modulo != len(outputs) {
return nil, nil, nil, errors.Wrap(
return nil, nil, errors.Wrap(
errors.New("mismatch of outputs and prover size"),
"pack output into payload and proof",
)
@ -50,14 +50,9 @@ func PackOutputIntoPayloadAndProof(
outputs,
)
if err != nil {
return nil, nil, nil, errors.Wrap(err, "pack output into payload and proof")
return nil, nil, errors.Wrap(err, "pack output into payload and proof")
}
payload := []byte("mint")
payload = append(payload, tree.Root...)
payload = binary.BigEndian.AppendUint32(payload, uint32(modulo))
payload = binary.BigEndian.AppendUint64(payload, frame.FrameNumber)
output := [][]byte{
tree.Root,
binary.BigEndian.AppendUint32([]byte{}, uint32(modulo)),
@ -68,19 +63,14 @@ func PackOutputIntoPayloadAndProof(
hash := sha3.Sum256(frame.Output)
pick := BytesToUnbiasedMod(hash, uint64(modulo))
if uint64(modulo) < pick {
return nil, nil, nil, errors.Wrap(
return nil, nil, errors.Wrap(
errors.New("proof size mismatch"),
"pack output into payload and proof",
)
}
for _, sib := range previousTree.Proofs[int(pick)].Siblings {
payload = append(payload, sib...)
output = append(output, sib)
}
payload = binary.BigEndian.AppendUint32(
payload,
previousTree.Proofs[int(pick)].Path,
)
output = append(
output,
binary.BigEndian.AppendUint32(
@ -88,10 +78,9 @@ func PackOutputIntoPayloadAndProof(
previousTree.Proofs[int(pick)].Path,
),
)
payload = append(payload, previousTree.Leaves[int(pick)]...)
output = append(output, previousTree.Leaves[int(pick)])
}
return tree, payload, output, nil
return tree, output, nil
}
func UnpackAndVerifyOutput(