mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2025-04-04 19:36:54 +00:00
Compare commits
26 Commits
6c567a04c1
...
048b6459c3
Author | SHA1 | Date | |
---|---|---|---|
![]() |
048b6459c3 | ||
![]() |
e87ec00c89 | ||
![]() |
aec21504bc | ||
![]() |
763cf6d2ca | ||
![]() |
389ada9f28 | ||
![]() |
2f03d021c7 | ||
![]() |
b4051ccbc9 | ||
![]() |
ab065006b4 | ||
![]() |
025aa9baa4 | ||
![]() |
f640c09008 | ||
![]() |
819d49d659 | ||
![]() |
4292a7e3dc | ||
![]() |
9446375cb1 | ||
![]() |
3bf5521b36 | ||
![]() |
f90609fe83 | ||
![]() |
ac1b98dfda | ||
![]() |
a89d423c7a | ||
![]() |
e34467874b | ||
![]() |
adc55e5166 | ||
![]() |
6167530b15 | ||
![]() |
a48cf98b99 | ||
![]() |
15988c4546 | ||
![]() |
2479c9cc5f | ||
![]() |
f5e9c3b1d6 | ||
![]() |
d526ec63d0 | ||
![]() |
1a244f5154 |
796
Cargo.lock
generated
796
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -14,8 +14,10 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"crates/vdf",
|
||||
"crates/channel",
|
||||
"crates/classgroup",
|
||||
"crates/bls48581",
|
||||
"crates/rpm",
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
|
@ -40,7 +40,12 @@ RUN go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
|
||||
# Build and install qclient
|
||||
WORKDIR /opt/ceremonyclient/client
|
||||
|
||||
RUN go build -o qclient ./main.go
|
||||
RUN ./build.sh -o qclient && cp qclient /go/bin
|
||||
|
||||
# Allows exporting single binary
|
||||
FROM scratch as qclient
|
||||
COPY --from=build /go/bin/qclient /qclient
|
||||
ENTRYPOINT [ "/qclient" ]
|
||||
|
||||
# Allows exporting single binary
|
||||
FROM scratch AS node
|
||||
|
@ -38,16 +38,33 @@ tasks:
|
||||
- bls48581/generate.sh
|
||||
- node/build.sh -o build/arm64_macos/node
|
||||
|
||||
build_qclient_arm64_macos:
|
||||
desc: Build the QClient node binary for MacOS ARM. Outputs to client/build
|
||||
cmds:
|
||||
- vdf/generate.sh
|
||||
- bls48581/generate.sh
|
||||
- client/build.sh -o build/arm64_macos/qclient
|
||||
|
||||
build_node_arm64_linux:
|
||||
desc: Build the Quilibrium node binary for ARM64 Linux. Outputs to node/build.
|
||||
cmds:
|
||||
- docker build --platform linux/arm64 -f Dockerfile.source --output node/build/arm64_linux --target=node .
|
||||
|
||||
build_qclient_arm64_linux:
|
||||
desc: Build the QClient node binary for ARM64 Linux. Outputs to client/build.
|
||||
cmds:
|
||||
- docker build --platform linux/arm64 -f Dockerfile.source --output client/build/arm64_linux --target=qclient .
|
||||
|
||||
build_node_amd64_linux:
|
||||
desc: Build the Quilibrium node binary for AMD64 Linux. Outputs to node/build.
|
||||
cmds:
|
||||
- docker build --platform linux/amd64 -f Dockerfile.source --output node/build/amd64_linux --target=node .
|
||||
|
||||
build_qclient_amd64_linux:
|
||||
desc: Build the QClient node binary for AMD64 Linux. Outputs to node/build.
|
||||
cmds:
|
||||
- docker build --platform linux/amd64 -f Dockerfile.source --output client/build/amd64_linux --target=qclient .
|
||||
|
||||
build:source:
|
||||
desc: Build the Quilibrium docker image from source.
|
||||
cmds:
|
||||
|
9
channel/README.md
Normal file
9
channel/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Channel
|
||||
|
||||
Wrapper for the Rust implementation of Channel in [crates/channel](../crates/channel).
|
||||
|
||||
## Generate Go bindings
|
||||
|
||||
```sh
|
||||
go generate
|
||||
```
|
88
channel/channel.go
Normal file
88
channel/channel.go
Normal file
@ -0,0 +1,88 @@
|
||||
package channel
|
||||
|
||||
import (
|
||||
generated "source.quilibrium.com/quilibrium/monorepo/channel/generated/channel"
|
||||
)
|
||||
|
||||
//go:generate ./generate.sh
|
||||
|
||||
func NewDoubleRatchet(
|
||||
sessionKey []uint8,
|
||||
sendingHeaderKey []uint8,
|
||||
nextReceivingHeaderKey []uint8,
|
||||
isSender bool,
|
||||
sendingEphemeralPrivateKey []uint8,
|
||||
receivingEphemeralKey []uint8,
|
||||
) string {
|
||||
return generated.NewDoubleRatchet(
|
||||
sessionKey,
|
||||
sendingHeaderKey,
|
||||
nextReceivingHeaderKey,
|
||||
isSender,
|
||||
sendingEphemeralPrivateKey,
|
||||
receivingEphemeralKey,
|
||||
)
|
||||
}
|
||||
|
||||
func NewTripleRatchet(
|
||||
peers [][]uint8,
|
||||
peerKey []uint8,
|
||||
identityKey []uint8,
|
||||
signedPreKey []uint8,
|
||||
threshold uint64,
|
||||
asyncDkgRatchet bool,
|
||||
) generated.TripleRatchetStateAndMetadata {
|
||||
return generated.NewTripleRatchet(
|
||||
peers,
|
||||
peerKey,
|
||||
identityKey,
|
||||
signedPreKey,
|
||||
threshold,
|
||||
asyncDkgRatchet,
|
||||
)
|
||||
}
|
||||
|
||||
func DoubleRatchetEncrypt(
|
||||
ratchetStateAndMessage generated.DoubleRatchetStateAndMessage,
|
||||
) generated.DoubleRatchetStateAndEnvelope {
|
||||
return generated.DoubleRatchetEncrypt(ratchetStateAndMessage)
|
||||
}
|
||||
|
||||
func DoubleRatchetDecrypt(
|
||||
ratchetStateAndEnvelope generated.DoubleRatchetStateAndEnvelope,
|
||||
) generated.DoubleRatchetStateAndMessage {
|
||||
return generated.DoubleRatchetDecrypt(ratchetStateAndEnvelope)
|
||||
}
|
||||
|
||||
func TripleRatchetInitRound1(
|
||||
ratchetStateAndMetadata generated.TripleRatchetStateAndMetadata,
|
||||
) generated.TripleRatchetStateAndMetadata {
|
||||
return generated.TripleRatchetInitRound1(ratchetStateAndMetadata)
|
||||
}
|
||||
func TripleRatchetInitRound2(
|
||||
ratchetStateAndMetadata generated.TripleRatchetStateAndMetadata,
|
||||
) generated.TripleRatchetStateAndMetadata {
|
||||
return generated.TripleRatchetInitRound2(ratchetStateAndMetadata)
|
||||
}
|
||||
func TripleRatchetInitRound3(
|
||||
ratchetStateAndMetadata generated.TripleRatchetStateAndMetadata,
|
||||
) generated.TripleRatchetStateAndMetadata {
|
||||
return generated.TripleRatchetInitRound3(ratchetStateAndMetadata)
|
||||
}
|
||||
func TripleRatchetInitRound4(
|
||||
ratchetStateAndMetadata generated.TripleRatchetStateAndMetadata,
|
||||
) generated.TripleRatchetStateAndMetadata {
|
||||
return generated.TripleRatchetInitRound4(ratchetStateAndMetadata)
|
||||
}
|
||||
|
||||
func TripleRatchetEncrypt(
|
||||
ratchetStateAndMessage generated.TripleRatchetStateAndMessage,
|
||||
) generated.TripleRatchetStateAndEnvelope {
|
||||
return generated.TripleRatchetEncrypt(ratchetStateAndMessage)
|
||||
}
|
||||
|
||||
func TripleRatchetDecrypt(
|
||||
ratchetStateAndEnvelope generated.TripleRatchetStateAndEnvelope,
|
||||
) generated.TripleRatchetStateAndMessage {
|
||||
return generated.TripleRatchetDecrypt(ratchetStateAndEnvelope)
|
||||
}
|
14
channel/generate.sh
Executable file
14
channel/generate.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
|
||||
ROOT_DIR="${ROOT_DIR:-$( cd "$(dirname "$(realpath "$( dirname "${BASH_SOURCE[0]}" )")")" >/dev/null 2>&1 && pwd )}"
|
||||
|
||||
RUST_CHANNEL_PACKAGE="$ROOT_DIR/crates/channel"
|
||||
BINDINGS_DIR="$ROOT_DIR/channel"
|
||||
|
||||
# Build the Rust Channel package in release mode
|
||||
cargo build -p channel --release
|
||||
|
||||
# Generate Go bindings
|
||||
pushd "$RUST_CHANNEL_PACKAGE" > /dev/null
|
||||
uniffi-bindgen-go src/lib.udl -o "$BINDINGS_DIR"/generated
|
8
channel/generated/channel/channel.c
Normal file
8
channel/generated/channel/channel.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include <channel.h>
|
||||
|
||||
// This file exists beacause of
|
||||
// https://github.com/golang/go/issues/11263
|
||||
|
||||
void cgo_rust_task_callback_bridge_channel(RustTaskCallback cb, const void * taskData, int8_t status) {
|
||||
cb(taskData, status);
|
||||
}
|
954
channel/generated/channel/channel.go
Normal file
954
channel/generated/channel/channel.go
Normal file
@ -0,0 +1,954 @@
|
||||
package channel
|
||||
|
||||
// #include <channel.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type RustBuffer = C.RustBuffer
|
||||
|
||||
type RustBufferI interface {
|
||||
AsReader() *bytes.Reader
|
||||
Free()
|
||||
ToGoBytes() []byte
|
||||
Data() unsafe.Pointer
|
||||
Len() int
|
||||
Capacity() int
|
||||
}
|
||||
|
||||
func RustBufferFromExternal(b RustBufferI) RustBuffer {
|
||||
return RustBuffer{
|
||||
capacity: C.int(b.Capacity()),
|
||||
len: C.int(b.Len()),
|
||||
data: (*C.uchar)(b.Data()),
|
||||
}
|
||||
}
|
||||
|
||||
func (cb RustBuffer) Capacity() int {
|
||||
return int(cb.capacity)
|
||||
}
|
||||
|
||||
func (cb RustBuffer) Len() int {
|
||||
return int(cb.len)
|
||||
}
|
||||
|
||||
func (cb RustBuffer) Data() unsafe.Pointer {
|
||||
return unsafe.Pointer(cb.data)
|
||||
}
|
||||
|
||||
func (cb RustBuffer) AsReader() *bytes.Reader {
|
||||
b := unsafe.Slice((*byte)(cb.data), C.int(cb.len))
|
||||
return bytes.NewReader(b)
|
||||
}
|
||||
|
||||
func (cb RustBuffer) Free() {
|
||||
rustCall(func(status *C.RustCallStatus) bool {
|
||||
C.ffi_channel_rustbuffer_free(cb, status)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
func (cb RustBuffer) ToGoBytes() []byte {
|
||||
return C.GoBytes(unsafe.Pointer(cb.data), C.int(cb.len))
|
||||
}
|
||||
|
||||
func stringToRustBuffer(str string) RustBuffer {
|
||||
return bytesToRustBuffer([]byte(str))
|
||||
}
|
||||
|
||||
func bytesToRustBuffer(b []byte) RustBuffer {
|
||||
if len(b) == 0 {
|
||||
return RustBuffer{}
|
||||
}
|
||||
// We can pass the pointer along here, as it is pinned
|
||||
// for the duration of this call
|
||||
foreign := C.ForeignBytes{
|
||||
len: C.int(len(b)),
|
||||
data: (*C.uchar)(unsafe.Pointer(&b[0])),
|
||||
}
|
||||
|
||||
return rustCall(func(status *C.RustCallStatus) RustBuffer {
|
||||
return C.ffi_channel_rustbuffer_from_bytes(foreign, status)
|
||||
})
|
||||
}
|
||||
|
||||
type BufLifter[GoType any] interface {
|
||||
Lift(value RustBufferI) GoType
|
||||
}
|
||||
|
||||
type BufLowerer[GoType any] interface {
|
||||
Lower(value GoType) RustBuffer
|
||||
}
|
||||
|
||||
type FfiConverter[GoType any, FfiType any] interface {
|
||||
Lift(value FfiType) GoType
|
||||
Lower(value GoType) FfiType
|
||||
}
|
||||
|
||||
type BufReader[GoType any] interface {
|
||||
Read(reader io.Reader) GoType
|
||||
}
|
||||
|
||||
type BufWriter[GoType any] interface {
|
||||
Write(writer io.Writer, value GoType)
|
||||
}
|
||||
|
||||
type FfiRustBufConverter[GoType any, FfiType any] interface {
|
||||
FfiConverter[GoType, FfiType]
|
||||
BufReader[GoType]
|
||||
}
|
||||
|
||||
func LowerIntoRustBuffer[GoType any](bufWriter BufWriter[GoType], value GoType) RustBuffer {
|
||||
// This might be not the most efficient way but it does not require knowing allocation size
|
||||
// beforehand
|
||||
var buffer bytes.Buffer
|
||||
bufWriter.Write(&buffer, value)
|
||||
|
||||
bytes, err := io.ReadAll(&buffer)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("reading written data: %w", err))
|
||||
}
|
||||
return bytesToRustBuffer(bytes)
|
||||
}
|
||||
|
||||
func LiftFromRustBuffer[GoType any](bufReader BufReader[GoType], rbuf RustBufferI) GoType {
|
||||
defer rbuf.Free()
|
||||
reader := rbuf.AsReader()
|
||||
item := bufReader.Read(reader)
|
||||
if reader.Len() > 0 {
|
||||
// TODO: Remove this
|
||||
leftover, _ := io.ReadAll(reader)
|
||||
panic(fmt.Errorf("Junk remaining in buffer after lifting: %s", string(leftover)))
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func rustCallWithError[U any](converter BufLifter[error], callback func(*C.RustCallStatus) U) (U, error) {
|
||||
var status C.RustCallStatus
|
||||
returnValue := callback(&status)
|
||||
err := checkCallStatus(converter, status)
|
||||
|
||||
return returnValue, err
|
||||
}
|
||||
|
||||
func checkCallStatus(converter BufLifter[error], status C.RustCallStatus) error {
|
||||
switch status.code {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return converter.Lift(status.errorBuf)
|
||||
case 2:
|
||||
// when the rust code sees a panic, it tries to construct a rustbuffer
|
||||
// with the message. but if that code panics, then it just sends back
|
||||
// an empty buffer.
|
||||
if status.errorBuf.len > 0 {
|
||||
panic(fmt.Errorf("%s", FfiConverterStringINSTANCE.Lift(status.errorBuf)))
|
||||
} else {
|
||||
panic(fmt.Errorf("Rust panicked while handling Rust panic"))
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown status code: %d", status.code)
|
||||
}
|
||||
}
|
||||
|
||||
func checkCallStatusUnknown(status C.RustCallStatus) error {
|
||||
switch status.code {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
panic(fmt.Errorf("function not returning an error returned an error"))
|
||||
case 2:
|
||||
// when the rust code sees a panic, it tries to construct a rustbuffer
|
||||
// with the message. but if that code panics, then it just sends back
|
||||
// an empty buffer.
|
||||
if status.errorBuf.len > 0 {
|
||||
panic(fmt.Errorf("%s", FfiConverterStringINSTANCE.Lift(status.errorBuf)))
|
||||
} else {
|
||||
panic(fmt.Errorf("Rust panicked while handling Rust panic"))
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown status code: %d", status.code)
|
||||
}
|
||||
}
|
||||
|
||||
func rustCall[U any](callback func(*C.RustCallStatus) U) U {
|
||||
returnValue, err := rustCallWithError(nil, callback)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return returnValue
|
||||
}
|
||||
|
||||
func writeInt8(writer io.Writer, value int8) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeUint8(writer io.Writer, value uint8) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeInt16(writer io.Writer, value int16) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeUint16(writer io.Writer, value uint16) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeInt32(writer io.Writer, value int32) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeUint32(writer io.Writer, value uint32) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeInt64(writer io.Writer, value int64) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeUint64(writer io.Writer, value uint64) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeFloat32(writer io.Writer, value float32) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeFloat64(writer io.Writer, value float64) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func readInt8(reader io.Reader) int8 {
|
||||
var result int8
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readUint8(reader io.Reader) uint8 {
|
||||
var result uint8
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readInt16(reader io.Reader) int16 {
|
||||
var result int16
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readUint16(reader io.Reader) uint16 {
|
||||
var result uint16
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readInt32(reader io.Reader) int32 {
|
||||
var result int32
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readUint32(reader io.Reader) uint32 {
|
||||
var result uint32
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readInt64(reader io.Reader) int64 {
|
||||
var result int64
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readUint64(reader io.Reader) uint64 {
|
||||
var result uint64
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readFloat32(reader io.Reader) float32 {
|
||||
var result float32
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readFloat64(reader io.Reader) float64 {
|
||||
var result float64
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
uniffiCheckChecksums()
|
||||
}
|
||||
|
||||
func uniffiCheckChecksums() {
|
||||
// Get the bindings contract version from our ComponentInterface
|
||||
bindingsContractVersion := 24
|
||||
// Get the scaffolding contract version by calling the into the dylib
|
||||
scaffoldingContractVersion := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint32_t {
|
||||
return C.ffi_channel_uniffi_contract_version(uniffiStatus)
|
||||
})
|
||||
if bindingsContractVersion != int(scaffoldingContractVersion) {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("channel: UniFFI contract version mismatch")
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_channel_checksum_func_double_ratchet_decrypt(uniffiStatus)
|
||||
})
|
||||
if checksum != 57128 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("channel: uniffi_channel_checksum_func_double_ratchet_decrypt: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_channel_checksum_func_double_ratchet_encrypt(uniffiStatus)
|
||||
})
|
||||
if checksum != 10167 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("channel: uniffi_channel_checksum_func_double_ratchet_encrypt: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_channel_checksum_func_new_double_ratchet(uniffiStatus)
|
||||
})
|
||||
if checksum != 21249 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("channel: uniffi_channel_checksum_func_new_double_ratchet: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_channel_checksum_func_new_triple_ratchet(uniffiStatus)
|
||||
})
|
||||
if checksum != 11118 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("channel: uniffi_channel_checksum_func_new_triple_ratchet: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_channel_checksum_func_triple_ratchet_decrypt(uniffiStatus)
|
||||
})
|
||||
if checksum != 56417 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("channel: uniffi_channel_checksum_func_triple_ratchet_decrypt: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_channel_checksum_func_triple_ratchet_encrypt(uniffiStatus)
|
||||
})
|
||||
if checksum != 63768 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("channel: uniffi_channel_checksum_func_triple_ratchet_encrypt: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_channel_checksum_func_triple_ratchet_init_round_1(uniffiStatus)
|
||||
})
|
||||
if checksum != 48593 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("channel: uniffi_channel_checksum_func_triple_ratchet_init_round_1: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_channel_checksum_func_triple_ratchet_init_round_2(uniffiStatus)
|
||||
})
|
||||
if checksum != 55359 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("channel: uniffi_channel_checksum_func_triple_ratchet_init_round_2: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_channel_checksum_func_triple_ratchet_init_round_3(uniffiStatus)
|
||||
})
|
||||
if checksum != 50330 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("channel: uniffi_channel_checksum_func_triple_ratchet_init_round_3: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_channel_checksum_func_triple_ratchet_init_round_4(uniffiStatus)
|
||||
})
|
||||
if checksum != 58513 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("channel: uniffi_channel_checksum_func_triple_ratchet_init_round_4: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type FfiConverterUint8 struct{}
|
||||
|
||||
var FfiConverterUint8INSTANCE = FfiConverterUint8{}
|
||||
|
||||
func (FfiConverterUint8) Lower(value uint8) C.uint8_t {
|
||||
return C.uint8_t(value)
|
||||
}
|
||||
|
||||
func (FfiConverterUint8) Write(writer io.Writer, value uint8) {
|
||||
writeUint8(writer, value)
|
||||
}
|
||||
|
||||
func (FfiConverterUint8) Lift(value C.uint8_t) uint8 {
|
||||
return uint8(value)
|
||||
}
|
||||
|
||||
func (FfiConverterUint8) Read(reader io.Reader) uint8 {
|
||||
return readUint8(reader)
|
||||
}
|
||||
|
||||
type FfiDestroyerUint8 struct{}
|
||||
|
||||
func (FfiDestroyerUint8) Destroy(_ uint8) {}
|
||||
|
||||
type FfiConverterUint64 struct{}
|
||||
|
||||
var FfiConverterUint64INSTANCE = FfiConverterUint64{}
|
||||
|
||||
func (FfiConverterUint64) Lower(value uint64) C.uint64_t {
|
||||
return C.uint64_t(value)
|
||||
}
|
||||
|
||||
func (FfiConverterUint64) Write(writer io.Writer, value uint64) {
|
||||
writeUint64(writer, value)
|
||||
}
|
||||
|
||||
func (FfiConverterUint64) Lift(value C.uint64_t) uint64 {
|
||||
return uint64(value)
|
||||
}
|
||||
|
||||
func (FfiConverterUint64) Read(reader io.Reader) uint64 {
|
||||
return readUint64(reader)
|
||||
}
|
||||
|
||||
type FfiDestroyerUint64 struct{}
|
||||
|
||||
func (FfiDestroyerUint64) Destroy(_ uint64) {}
|
||||
|
||||
type FfiConverterBool struct{}
|
||||
|
||||
var FfiConverterBoolINSTANCE = FfiConverterBool{}
|
||||
|
||||
func (FfiConverterBool) Lower(value bool) C.int8_t {
|
||||
if value {
|
||||
return C.int8_t(1)
|
||||
}
|
||||
return C.int8_t(0)
|
||||
}
|
||||
|
||||
func (FfiConverterBool) Write(writer io.Writer, value bool) {
|
||||
if value {
|
||||
writeInt8(writer, 1)
|
||||
} else {
|
||||
writeInt8(writer, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func (FfiConverterBool) Lift(value C.int8_t) bool {
|
||||
return value != 0
|
||||
}
|
||||
|
||||
func (FfiConverterBool) Read(reader io.Reader) bool {
|
||||
return readInt8(reader) != 0
|
||||
}
|
||||
|
||||
type FfiDestroyerBool struct{}
|
||||
|
||||
func (FfiDestroyerBool) Destroy(_ bool) {}
|
||||
|
||||
type FfiConverterString struct{}
|
||||
|
||||
var FfiConverterStringINSTANCE = FfiConverterString{}
|
||||
|
||||
func (FfiConverterString) Lift(rb RustBufferI) string {
|
||||
defer rb.Free()
|
||||
reader := rb.AsReader()
|
||||
b, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("reading reader: %w", err))
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (FfiConverterString) Read(reader io.Reader) string {
|
||||
length := readInt32(reader)
|
||||
buffer := make([]byte, length)
|
||||
read_length, err := reader.Read(buffer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if read_length != int(length) {
|
||||
panic(fmt.Errorf("bad read length when reading string, expected %d, read %d", length, read_length))
|
||||
}
|
||||
return string(buffer)
|
||||
}
|
||||
|
||||
func (FfiConverterString) Lower(value string) RustBuffer {
|
||||
return stringToRustBuffer(value)
|
||||
}
|
||||
|
||||
func (FfiConverterString) Write(writer io.Writer, value string) {
|
||||
if len(value) > math.MaxInt32 {
|
||||
panic("String is too large to fit into Int32")
|
||||
}
|
||||
|
||||
writeInt32(writer, int32(len(value)))
|
||||
write_length, err := io.WriteString(writer, value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if write_length != len(value) {
|
||||
panic(fmt.Errorf("bad write length when writing string, expected %d, written %d", len(value), write_length))
|
||||
}
|
||||
}
|
||||
|
||||
type FfiDestroyerString struct{}
|
||||
|
||||
func (FfiDestroyerString) Destroy(_ string) {}
|
||||
|
||||
type DoubleRatchetStateAndEnvelope struct {
|
||||
RatchetState string
|
||||
Envelope string
|
||||
}
|
||||
|
||||
func (r *DoubleRatchetStateAndEnvelope) Destroy() {
|
||||
FfiDestroyerString{}.Destroy(r.RatchetState)
|
||||
FfiDestroyerString{}.Destroy(r.Envelope)
|
||||
}
|
||||
|
||||
type FfiConverterTypeDoubleRatchetStateAndEnvelope struct{}
|
||||
|
||||
var FfiConverterTypeDoubleRatchetStateAndEnvelopeINSTANCE = FfiConverterTypeDoubleRatchetStateAndEnvelope{}
|
||||
|
||||
func (c FfiConverterTypeDoubleRatchetStateAndEnvelope) Lift(rb RustBufferI) DoubleRatchetStateAndEnvelope {
|
||||
return LiftFromRustBuffer[DoubleRatchetStateAndEnvelope](c, rb)
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeDoubleRatchetStateAndEnvelope) Read(reader io.Reader) DoubleRatchetStateAndEnvelope {
|
||||
return DoubleRatchetStateAndEnvelope{
|
||||
FfiConverterStringINSTANCE.Read(reader),
|
||||
FfiConverterStringINSTANCE.Read(reader),
|
||||
}
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeDoubleRatchetStateAndEnvelope) Lower(value DoubleRatchetStateAndEnvelope) RustBuffer {
|
||||
return LowerIntoRustBuffer[DoubleRatchetStateAndEnvelope](c, value)
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeDoubleRatchetStateAndEnvelope) Write(writer io.Writer, value DoubleRatchetStateAndEnvelope) {
|
||||
FfiConverterStringINSTANCE.Write(writer, value.RatchetState)
|
||||
FfiConverterStringINSTANCE.Write(writer, value.Envelope)
|
||||
}
|
||||
|
||||
type FfiDestroyerTypeDoubleRatchetStateAndEnvelope struct{}
|
||||
|
||||
func (_ FfiDestroyerTypeDoubleRatchetStateAndEnvelope) Destroy(value DoubleRatchetStateAndEnvelope) {
|
||||
value.Destroy()
|
||||
}
|
||||
|
||||
type DoubleRatchetStateAndMessage struct {
|
||||
RatchetState string
|
||||
Message []uint8
|
||||
}
|
||||
|
||||
func (r *DoubleRatchetStateAndMessage) Destroy() {
|
||||
FfiDestroyerString{}.Destroy(r.RatchetState)
|
||||
FfiDestroyerSequenceUint8{}.Destroy(r.Message)
|
||||
}
|
||||
|
||||
type FfiConverterTypeDoubleRatchetStateAndMessage struct{}
|
||||
|
||||
var FfiConverterTypeDoubleRatchetStateAndMessageINSTANCE = FfiConverterTypeDoubleRatchetStateAndMessage{}
|
||||
|
||||
func (c FfiConverterTypeDoubleRatchetStateAndMessage) Lift(rb RustBufferI) DoubleRatchetStateAndMessage {
|
||||
return LiftFromRustBuffer[DoubleRatchetStateAndMessage](c, rb)
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeDoubleRatchetStateAndMessage) Read(reader io.Reader) DoubleRatchetStateAndMessage {
|
||||
return DoubleRatchetStateAndMessage{
|
||||
FfiConverterStringINSTANCE.Read(reader),
|
||||
FfiConverterSequenceUint8INSTANCE.Read(reader),
|
||||
}
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeDoubleRatchetStateAndMessage) Lower(value DoubleRatchetStateAndMessage) RustBuffer {
|
||||
return LowerIntoRustBuffer[DoubleRatchetStateAndMessage](c, value)
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeDoubleRatchetStateAndMessage) Write(writer io.Writer, value DoubleRatchetStateAndMessage) {
|
||||
FfiConverterStringINSTANCE.Write(writer, value.RatchetState)
|
||||
FfiConverterSequenceUint8INSTANCE.Write(writer, value.Message)
|
||||
}
|
||||
|
||||
type FfiDestroyerTypeDoubleRatchetStateAndMessage struct{}
|
||||
|
||||
func (_ FfiDestroyerTypeDoubleRatchetStateAndMessage) Destroy(value DoubleRatchetStateAndMessage) {
|
||||
value.Destroy()
|
||||
}
|
||||
|
||||
type TripleRatchetStateAndEnvelope struct {
|
||||
RatchetState string
|
||||
Envelope string
|
||||
}
|
||||
|
||||
func (r *TripleRatchetStateAndEnvelope) Destroy() {
|
||||
FfiDestroyerString{}.Destroy(r.RatchetState)
|
||||
FfiDestroyerString{}.Destroy(r.Envelope)
|
||||
}
|
||||
|
||||
type FfiConverterTypeTripleRatchetStateAndEnvelope struct{}
|
||||
|
||||
var FfiConverterTypeTripleRatchetStateAndEnvelopeINSTANCE = FfiConverterTypeTripleRatchetStateAndEnvelope{}
|
||||
|
||||
func (c FfiConverterTypeTripleRatchetStateAndEnvelope) Lift(rb RustBufferI) TripleRatchetStateAndEnvelope {
|
||||
return LiftFromRustBuffer[TripleRatchetStateAndEnvelope](c, rb)
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeTripleRatchetStateAndEnvelope) Read(reader io.Reader) TripleRatchetStateAndEnvelope {
|
||||
return TripleRatchetStateAndEnvelope{
|
||||
FfiConverterStringINSTANCE.Read(reader),
|
||||
FfiConverterStringINSTANCE.Read(reader),
|
||||
}
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeTripleRatchetStateAndEnvelope) Lower(value TripleRatchetStateAndEnvelope) RustBuffer {
|
||||
return LowerIntoRustBuffer[TripleRatchetStateAndEnvelope](c, value)
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeTripleRatchetStateAndEnvelope) Write(writer io.Writer, value TripleRatchetStateAndEnvelope) {
|
||||
FfiConverterStringINSTANCE.Write(writer, value.RatchetState)
|
||||
FfiConverterStringINSTANCE.Write(writer, value.Envelope)
|
||||
}
|
||||
|
||||
type FfiDestroyerTypeTripleRatchetStateAndEnvelope struct{}
|
||||
|
||||
func (_ FfiDestroyerTypeTripleRatchetStateAndEnvelope) Destroy(value TripleRatchetStateAndEnvelope) {
|
||||
value.Destroy()
|
||||
}
|
||||
|
||||
type TripleRatchetStateAndMessage struct {
|
||||
RatchetState string
|
||||
Message []uint8
|
||||
}
|
||||
|
||||
func (r *TripleRatchetStateAndMessage) Destroy() {
|
||||
FfiDestroyerString{}.Destroy(r.RatchetState)
|
||||
FfiDestroyerSequenceUint8{}.Destroy(r.Message)
|
||||
}
|
||||
|
||||
type FfiConverterTypeTripleRatchetStateAndMessage struct{}
|
||||
|
||||
var FfiConverterTypeTripleRatchetStateAndMessageINSTANCE = FfiConverterTypeTripleRatchetStateAndMessage{}
|
||||
|
||||
func (c FfiConverterTypeTripleRatchetStateAndMessage) Lift(rb RustBufferI) TripleRatchetStateAndMessage {
|
||||
return LiftFromRustBuffer[TripleRatchetStateAndMessage](c, rb)
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeTripleRatchetStateAndMessage) Read(reader io.Reader) TripleRatchetStateAndMessage {
|
||||
return TripleRatchetStateAndMessage{
|
||||
FfiConverterStringINSTANCE.Read(reader),
|
||||
FfiConverterSequenceUint8INSTANCE.Read(reader),
|
||||
}
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeTripleRatchetStateAndMessage) Lower(value TripleRatchetStateAndMessage) RustBuffer {
|
||||
return LowerIntoRustBuffer[TripleRatchetStateAndMessage](c, value)
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeTripleRatchetStateAndMessage) Write(writer io.Writer, value TripleRatchetStateAndMessage) {
|
||||
FfiConverterStringINSTANCE.Write(writer, value.RatchetState)
|
||||
FfiConverterSequenceUint8INSTANCE.Write(writer, value.Message)
|
||||
}
|
||||
|
||||
type FfiDestroyerTypeTripleRatchetStateAndMessage struct{}
|
||||
|
||||
func (_ FfiDestroyerTypeTripleRatchetStateAndMessage) Destroy(value TripleRatchetStateAndMessage) {
|
||||
value.Destroy()
|
||||
}
|
||||
|
||||
type TripleRatchetStateAndMetadata struct {
|
||||
RatchetState string
|
||||
Metadata map[string]string
|
||||
}
|
||||
|
||||
func (r *TripleRatchetStateAndMetadata) Destroy() {
|
||||
FfiDestroyerString{}.Destroy(r.RatchetState)
|
||||
FfiDestroyerMapStringString{}.Destroy(r.Metadata)
|
||||
}
|
||||
|
||||
type FfiConverterTypeTripleRatchetStateAndMetadata struct{}
|
||||
|
||||
var FfiConverterTypeTripleRatchetStateAndMetadataINSTANCE = FfiConverterTypeTripleRatchetStateAndMetadata{}
|
||||
|
||||
func (c FfiConverterTypeTripleRatchetStateAndMetadata) Lift(rb RustBufferI) TripleRatchetStateAndMetadata {
|
||||
return LiftFromRustBuffer[TripleRatchetStateAndMetadata](c, rb)
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeTripleRatchetStateAndMetadata) Read(reader io.Reader) TripleRatchetStateAndMetadata {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
FfiConverterStringINSTANCE.Read(reader),
|
||||
FfiConverterMapStringStringINSTANCE.Read(reader),
|
||||
}
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeTripleRatchetStateAndMetadata) Lower(value TripleRatchetStateAndMetadata) RustBuffer {
|
||||
return LowerIntoRustBuffer[TripleRatchetStateAndMetadata](c, value)
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeTripleRatchetStateAndMetadata) Write(writer io.Writer, value TripleRatchetStateAndMetadata) {
|
||||
FfiConverterStringINSTANCE.Write(writer, value.RatchetState)
|
||||
FfiConverterMapStringStringINSTANCE.Write(writer, value.Metadata)
|
||||
}
|
||||
|
||||
type FfiDestroyerTypeTripleRatchetStateAndMetadata struct{}
|
||||
|
||||
func (_ FfiDestroyerTypeTripleRatchetStateAndMetadata) Destroy(value TripleRatchetStateAndMetadata) {
|
||||
value.Destroy()
|
||||
}
|
||||
|
||||
type FfiConverterSequenceUint8 struct{}
|
||||
|
||||
var FfiConverterSequenceUint8INSTANCE = FfiConverterSequenceUint8{}
|
||||
|
||||
func (c FfiConverterSequenceUint8) Lift(rb RustBufferI) []uint8 {
|
||||
return LiftFromRustBuffer[[]uint8](c, rb)
|
||||
}
|
||||
|
||||
func (c FfiConverterSequenceUint8) Read(reader io.Reader) []uint8 {
|
||||
length := readInt32(reader)
|
||||
if length == 0 {
|
||||
return nil
|
||||
}
|
||||
result := make([]uint8, 0, length)
|
||||
for i := int32(0); i < length; i++ {
|
||||
result = append(result, FfiConverterUint8INSTANCE.Read(reader))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (c FfiConverterSequenceUint8) Lower(value []uint8) RustBuffer {
|
||||
return LowerIntoRustBuffer[[]uint8](c, value)
|
||||
}
|
||||
|
||||
func (c FfiConverterSequenceUint8) Write(writer io.Writer, value []uint8) {
|
||||
if len(value) > math.MaxInt32 {
|
||||
panic("[]uint8 is too large to fit into Int32")
|
||||
}
|
||||
|
||||
writeInt32(writer, int32(len(value)))
|
||||
for _, item := range value {
|
||||
FfiConverterUint8INSTANCE.Write(writer, item)
|
||||
}
|
||||
}
|
||||
|
||||
type FfiDestroyerSequenceUint8 struct{}
|
||||
|
||||
func (FfiDestroyerSequenceUint8) Destroy(sequence []uint8) {
|
||||
for _, value := range sequence {
|
||||
FfiDestroyerUint8{}.Destroy(value)
|
||||
}
|
||||
}
|
||||
|
||||
type FfiConverterSequenceSequenceUint8 struct{}
|
||||
|
||||
var FfiConverterSequenceSequenceUint8INSTANCE = FfiConverterSequenceSequenceUint8{}
|
||||
|
||||
func (c FfiConverterSequenceSequenceUint8) Lift(rb RustBufferI) [][]uint8 {
|
||||
return LiftFromRustBuffer[[][]uint8](c, rb)
|
||||
}
|
||||
|
||||
func (c FfiConverterSequenceSequenceUint8) Read(reader io.Reader) [][]uint8 {
|
||||
length := readInt32(reader)
|
||||
if length == 0 {
|
||||
return nil
|
||||
}
|
||||
result := make([][]uint8, 0, length)
|
||||
for i := int32(0); i < length; i++ {
|
||||
result = append(result, FfiConverterSequenceUint8INSTANCE.Read(reader))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (c FfiConverterSequenceSequenceUint8) Lower(value [][]uint8) RustBuffer {
|
||||
return LowerIntoRustBuffer[[][]uint8](c, value)
|
||||
}
|
||||
|
||||
func (c FfiConverterSequenceSequenceUint8) Write(writer io.Writer, value [][]uint8) {
|
||||
if len(value) > math.MaxInt32 {
|
||||
panic("[][]uint8 is too large to fit into Int32")
|
||||
}
|
||||
|
||||
writeInt32(writer, int32(len(value)))
|
||||
for _, item := range value {
|
||||
FfiConverterSequenceUint8INSTANCE.Write(writer, item)
|
||||
}
|
||||
}
|
||||
|
||||
type FfiDestroyerSequenceSequenceUint8 struct{}
|
||||
|
||||
func (FfiDestroyerSequenceSequenceUint8) Destroy(sequence [][]uint8) {
|
||||
for _, value := range sequence {
|
||||
FfiDestroyerSequenceUint8{}.Destroy(value)
|
||||
}
|
||||
}
|
||||
|
||||
type FfiConverterMapStringString struct{}
|
||||
|
||||
var FfiConverterMapStringStringINSTANCE = FfiConverterMapStringString{}
|
||||
|
||||
func (c FfiConverterMapStringString) Lift(rb RustBufferI) map[string]string {
|
||||
return LiftFromRustBuffer[map[string]string](c, rb)
|
||||
}
|
||||
|
||||
func (_ FfiConverterMapStringString) Read(reader io.Reader) map[string]string {
|
||||
result := make(map[string]string)
|
||||
length := readInt32(reader)
|
||||
for i := int32(0); i < length; i++ {
|
||||
key := FfiConverterStringINSTANCE.Read(reader)
|
||||
value := FfiConverterStringINSTANCE.Read(reader)
|
||||
result[key] = value
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (c FfiConverterMapStringString) Lower(value map[string]string) RustBuffer {
|
||||
return LowerIntoRustBuffer[map[string]string](c, value)
|
||||
}
|
||||
|
||||
func (_ FfiConverterMapStringString) Write(writer io.Writer, mapValue map[string]string) {
|
||||
if len(mapValue) > math.MaxInt32 {
|
||||
panic("map[string]string is too large to fit into Int32")
|
||||
}
|
||||
|
||||
writeInt32(writer, int32(len(mapValue)))
|
||||
for key, value := range mapValue {
|
||||
FfiConverterStringINSTANCE.Write(writer, key)
|
||||
FfiConverterStringINSTANCE.Write(writer, value)
|
||||
}
|
||||
}
|
||||
|
||||
type FfiDestroyerMapStringString struct{}
|
||||
|
||||
func (_ FfiDestroyerMapStringString) Destroy(mapValue map[string]string) {
|
||||
for key, value := range mapValue {
|
||||
FfiDestroyerString{}.Destroy(key)
|
||||
FfiDestroyerString{}.Destroy(value)
|
||||
}
|
||||
}
|
||||
|
||||
func DoubleRatchetDecrypt(ratchetStateAndEnvelope DoubleRatchetStateAndEnvelope) DoubleRatchetStateAndMessage {
|
||||
return FfiConverterTypeDoubleRatchetStateAndMessageINSTANCE.Lift(rustCall(func(_uniffiStatus *C.RustCallStatus) RustBufferI {
|
||||
return C.uniffi_channel_fn_func_double_ratchet_decrypt(FfiConverterTypeDoubleRatchetStateAndEnvelopeINSTANCE.Lower(ratchetStateAndEnvelope), _uniffiStatus)
|
||||
}))
|
||||
}
|
||||
|
||||
func DoubleRatchetEncrypt(ratchetStateAndMessage DoubleRatchetStateAndMessage) DoubleRatchetStateAndEnvelope {
|
||||
return FfiConverterTypeDoubleRatchetStateAndEnvelopeINSTANCE.Lift(rustCall(func(_uniffiStatus *C.RustCallStatus) RustBufferI {
|
||||
return C.uniffi_channel_fn_func_double_ratchet_encrypt(FfiConverterTypeDoubleRatchetStateAndMessageINSTANCE.Lower(ratchetStateAndMessage), _uniffiStatus)
|
||||
}))
|
||||
}
|
||||
|
||||
func NewDoubleRatchet(sessionKey []uint8, sendingHeaderKey []uint8, nextReceivingHeaderKey []uint8, isSender bool, sendingEphemeralPrivateKey []uint8, receivingEphemeralKey []uint8) string {
|
||||
return FfiConverterStringINSTANCE.Lift(rustCall(func(_uniffiStatus *C.RustCallStatus) RustBufferI {
|
||||
return C.uniffi_channel_fn_func_new_double_ratchet(FfiConverterSequenceUint8INSTANCE.Lower(sessionKey), FfiConverterSequenceUint8INSTANCE.Lower(sendingHeaderKey), FfiConverterSequenceUint8INSTANCE.Lower(nextReceivingHeaderKey), FfiConverterBoolINSTANCE.Lower(isSender), FfiConverterSequenceUint8INSTANCE.Lower(sendingEphemeralPrivateKey), FfiConverterSequenceUint8INSTANCE.Lower(receivingEphemeralKey), _uniffiStatus)
|
||||
}))
|
||||
}
|
||||
|
||||
func NewTripleRatchet(peers [][]uint8, peerKey []uint8, identityKey []uint8, signedPreKey []uint8, threshold uint64, asyncDkgRatchet bool) TripleRatchetStateAndMetadata {
|
||||
return FfiConverterTypeTripleRatchetStateAndMetadataINSTANCE.Lift(rustCall(func(_uniffiStatus *C.RustCallStatus) RustBufferI {
|
||||
return C.uniffi_channel_fn_func_new_triple_ratchet(FfiConverterSequenceSequenceUint8INSTANCE.Lower(peers), FfiConverterSequenceUint8INSTANCE.Lower(peerKey), FfiConverterSequenceUint8INSTANCE.Lower(identityKey), FfiConverterSequenceUint8INSTANCE.Lower(signedPreKey), FfiConverterUint64INSTANCE.Lower(threshold), FfiConverterBoolINSTANCE.Lower(asyncDkgRatchet), _uniffiStatus)
|
||||
}))
|
||||
}
|
||||
|
||||
func TripleRatchetDecrypt(ratchetStateAndEnvelope TripleRatchetStateAndEnvelope) TripleRatchetStateAndMessage {
|
||||
return FfiConverterTypeTripleRatchetStateAndMessageINSTANCE.Lift(rustCall(func(_uniffiStatus *C.RustCallStatus) RustBufferI {
|
||||
return C.uniffi_channel_fn_func_triple_ratchet_decrypt(FfiConverterTypeTripleRatchetStateAndEnvelopeINSTANCE.Lower(ratchetStateAndEnvelope), _uniffiStatus)
|
||||
}))
|
||||
}
|
||||
|
||||
func TripleRatchetEncrypt(ratchetStateAndMessage TripleRatchetStateAndMessage) TripleRatchetStateAndEnvelope {
|
||||
return FfiConverterTypeTripleRatchetStateAndEnvelopeINSTANCE.Lift(rustCall(func(_uniffiStatus *C.RustCallStatus) RustBufferI {
|
||||
return C.uniffi_channel_fn_func_triple_ratchet_encrypt(FfiConverterTypeTripleRatchetStateAndMessageINSTANCE.Lower(ratchetStateAndMessage), _uniffiStatus)
|
||||
}))
|
||||
}
|
||||
|
||||
func TripleRatchetInitRound1(ratchetStateAndMetadata TripleRatchetStateAndMetadata) TripleRatchetStateAndMetadata {
|
||||
return FfiConverterTypeTripleRatchetStateAndMetadataINSTANCE.Lift(rustCall(func(_uniffiStatus *C.RustCallStatus) RustBufferI {
|
||||
return C.uniffi_channel_fn_func_triple_ratchet_init_round_1(FfiConverterTypeTripleRatchetStateAndMetadataINSTANCE.Lower(ratchetStateAndMetadata), _uniffiStatus)
|
||||
}))
|
||||
}
|
||||
|
||||
func TripleRatchetInitRound2(ratchetStateAndMetadata TripleRatchetStateAndMetadata) TripleRatchetStateAndMetadata {
|
||||
return FfiConverterTypeTripleRatchetStateAndMetadataINSTANCE.Lift(rustCall(func(_uniffiStatus *C.RustCallStatus) RustBufferI {
|
||||
return C.uniffi_channel_fn_func_triple_ratchet_init_round_2(FfiConverterTypeTripleRatchetStateAndMetadataINSTANCE.Lower(ratchetStateAndMetadata), _uniffiStatus)
|
||||
}))
|
||||
}
|
||||
|
||||
func TripleRatchetInitRound3(ratchetStateAndMetadata TripleRatchetStateAndMetadata) TripleRatchetStateAndMetadata {
|
||||
return FfiConverterTypeTripleRatchetStateAndMetadataINSTANCE.Lift(rustCall(func(_uniffiStatus *C.RustCallStatus) RustBufferI {
|
||||
return C.uniffi_channel_fn_func_triple_ratchet_init_round_3(FfiConverterTypeTripleRatchetStateAndMetadataINSTANCE.Lower(ratchetStateAndMetadata), _uniffiStatus)
|
||||
}))
|
||||
}
|
||||
|
||||
func TripleRatchetInitRound4(ratchetStateAndMetadata TripleRatchetStateAndMetadata) TripleRatchetStateAndMetadata {
|
||||
return FfiConverterTypeTripleRatchetStateAndMetadataINSTANCE.Lift(rustCall(func(_uniffiStatus *C.RustCallStatus) RustBufferI {
|
||||
return C.uniffi_channel_fn_func_triple_ratchet_init_round_4(FfiConverterTypeTripleRatchetStateAndMetadataINSTANCE.Lower(ratchetStateAndMetadata), _uniffiStatus)
|
||||
}))
|
||||
}
|
475
channel/generated/channel/channel.h
Normal file
475
channel/generated/channel/channel.h
Normal file
@ -0,0 +1,475 @@
|
||||
|
||||
|
||||
// This file was autogenerated by some hot garbage in the `uniffi` crate.
|
||||
// Trust me, you don't want to mess with it!
|
||||
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// The following structs are used to implement the lowest level
|
||||
// of the FFI, and thus useful to multiple uniffied crates.
|
||||
// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H.
|
||||
#ifdef UNIFFI_SHARED_H
|
||||
// We also try to prevent mixing versions of shared uniffi header structs.
|
||||
// If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V6
|
||||
#ifndef UNIFFI_SHARED_HEADER_V6
|
||||
#error Combining helper code from multiple versions of uniffi is not supported
|
||||
#endif // ndef UNIFFI_SHARED_HEADER_V6
|
||||
#else
|
||||
#define UNIFFI_SHARED_H
|
||||
#define UNIFFI_SHARED_HEADER_V6
|
||||
// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️
|
||||
// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V6 in this file. ⚠️
|
||||
|
||||
typedef struct RustBuffer {
|
||||
int32_t capacity;
|
||||
int32_t len;
|
||||
uint8_t *data;
|
||||
} RustBuffer;
|
||||
|
||||
typedef int32_t (*ForeignCallback)(uint64_t, int32_t, uint8_t *, int32_t, RustBuffer *);
|
||||
|
||||
// Task defined in Rust that Go executes
|
||||
typedef void (*RustTaskCallback)(const void *, int8_t);
|
||||
|
||||
// Callback to execute Rust tasks using a Go routine
|
||||
//
|
||||
// Args:
|
||||
// executor: ForeignExecutor lowered into a uint64_t value
|
||||
// delay: Delay in MS
|
||||
// task: RustTaskCallback to call
|
||||
// task_data: data to pass the task callback
|
||||
typedef int8_t (*ForeignExecutorCallback)(uint64_t, uint32_t, RustTaskCallback, void *);
|
||||
|
||||
typedef struct ForeignBytes {
|
||||
int32_t len;
|
||||
const uint8_t *data;
|
||||
} ForeignBytes;
|
||||
|
||||
// Error definitions
|
||||
typedef struct RustCallStatus {
|
||||
int8_t code;
|
||||
RustBuffer errorBuf;
|
||||
} RustCallStatus;
|
||||
|
||||
// Continuation callback for UniFFI Futures
|
||||
typedef void (*RustFutureContinuation)(void * , int8_t);
|
||||
|
||||
// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️
|
||||
// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V6 in this file. ⚠️
|
||||
#endif // def UNIFFI_SHARED_H
|
||||
|
||||
// Needed because we can't execute the callback directly from go.
|
||||
void cgo_rust_task_callback_bridge_channel(RustTaskCallback, const void *, int8_t);
|
||||
|
||||
int8_t uniffiForeignExecutorCallbackchannel(uint64_t, uint32_t, RustTaskCallback, void*);
|
||||
|
||||
void uniffiFutureContinuationCallbackchannel(void*, int8_t);
|
||||
|
||||
RustBuffer uniffi_channel_fn_func_double_ratchet_decrypt(
|
||||
RustBuffer ratchet_state_and_envelope,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer uniffi_channel_fn_func_double_ratchet_encrypt(
|
||||
RustBuffer ratchet_state_and_message,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer uniffi_channel_fn_func_new_double_ratchet(
|
||||
RustBuffer session_key,
|
||||
RustBuffer sending_header_key,
|
||||
RustBuffer next_receiving_header_key,
|
||||
int8_t is_sender,
|
||||
RustBuffer sending_ephemeral_private_key,
|
||||
RustBuffer receiving_ephemeral_key,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer uniffi_channel_fn_func_new_triple_ratchet(
|
||||
RustBuffer peers,
|
||||
RustBuffer peer_key,
|
||||
RustBuffer identity_key,
|
||||
RustBuffer signed_pre_key,
|
||||
uint64_t threshold,
|
||||
int8_t async_dkg_ratchet,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer uniffi_channel_fn_func_triple_ratchet_decrypt(
|
||||
RustBuffer ratchet_state_and_envelope,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer uniffi_channel_fn_func_triple_ratchet_encrypt(
|
||||
RustBuffer ratchet_state_and_message,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer uniffi_channel_fn_func_triple_ratchet_init_round_1(
|
||||
RustBuffer ratchet_state_and_metadata,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer uniffi_channel_fn_func_triple_ratchet_init_round_2(
|
||||
RustBuffer ratchet_state_and_metadata,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer uniffi_channel_fn_func_triple_ratchet_init_round_3(
|
||||
RustBuffer ratchet_state_and_metadata,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer uniffi_channel_fn_func_triple_ratchet_init_round_4(
|
||||
RustBuffer ratchet_state_and_metadata,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer ffi_channel_rustbuffer_alloc(
|
||||
int32_t size,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer ffi_channel_rustbuffer_from_bytes(
|
||||
ForeignBytes bytes,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rustbuffer_free(
|
||||
RustBuffer buf,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer ffi_channel_rustbuffer_reserve(
|
||||
RustBuffer buf,
|
||||
int32_t additional,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_continuation_callback_set(
|
||||
RustFutureContinuation callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_poll_u8(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_cancel_u8(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_free_u8(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint8_t ffi_channel_rust_future_complete_u8(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_poll_i8(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_cancel_i8(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_free_i8(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
int8_t ffi_channel_rust_future_complete_i8(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_poll_u16(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_cancel_u16(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_free_u16(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t ffi_channel_rust_future_complete_u16(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_poll_i16(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_cancel_i16(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_free_i16(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
int16_t ffi_channel_rust_future_complete_i16(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_poll_u32(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_cancel_u32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_free_u32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint32_t ffi_channel_rust_future_complete_u32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_poll_i32(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_cancel_i32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_free_i32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
int32_t ffi_channel_rust_future_complete_i32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_poll_u64(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_cancel_u64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_free_u64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint64_t ffi_channel_rust_future_complete_u64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_poll_i64(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_cancel_i64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_free_i64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
int64_t ffi_channel_rust_future_complete_i64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_poll_f32(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_cancel_f32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_free_f32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
float ffi_channel_rust_future_complete_f32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_poll_f64(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_cancel_f64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_free_f64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
double ffi_channel_rust_future_complete_f64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_poll_pointer(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_cancel_pointer(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_free_pointer(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void* ffi_channel_rust_future_complete_pointer(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_poll_rust_buffer(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_cancel_rust_buffer(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_free_rust_buffer(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer ffi_channel_rust_future_complete_rust_buffer(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_poll_void(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_cancel_void(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_free_void(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_channel_rust_future_complete_void(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_channel_checksum_func_double_ratchet_decrypt(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_channel_checksum_func_double_ratchet_encrypt(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_channel_checksum_func_new_double_ratchet(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_channel_checksum_func_new_triple_ratchet(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_channel_checksum_func_triple_ratchet_decrypt(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_channel_checksum_func_triple_ratchet_encrypt(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_channel_checksum_func_triple_ratchet_init_round_1(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_channel_checksum_func_triple_ratchet_init_round_2(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_channel_checksum_func_triple_ratchet_init_round_3(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_channel_checksum_func_triple_ratchet_init_round_4(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint32_t ffi_channel_uniffi_contract_version(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
|
||||
|
17
channel/go.mod
Normal file
17
channel/go.mod
Normal file
@ -0,0 +1,17 @@
|
||||
module source.quilibrium.com/quilibrium/monorepo/channel
|
||||
|
||||
go 1.20
|
||||
|
||||
// A necessary hack until source.quilibrium.com is open to all
|
||||
replace source.quilibrium.com/quilibrium/monorepo/nekryptology => ../nekryptology
|
||||
|
||||
require github.com/stretchr/testify v1.9.0
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/crypto v0.24.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
source.quilibrium.com/quilibrium/monorepo/nekryptology v0.0.0-00010101000000-000000000000 // indirect
|
||||
)
|
13
channel/go.sum
Normal file
13
channel/go.sum
Normal file
@ -0,0 +1,13 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
17
channel/test.sh
Executable file
17
channel/test.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
|
||||
# Run tests for the channel package. Takes care of linking the native Channel library.
|
||||
# Assumes that the Channel library has been built by running the generate.sh script in the same directory.
|
||||
|
||||
ROOT_DIR="${ROOT_DIR:-$( cd "$(dirname "$(realpath "$( dirname "${BASH_SOURCE[0]}" )")")" >/dev/null 2>&1 && pwd )}"
|
||||
|
||||
NODE_DIR="$ROOT_DIR/channel"
|
||||
BINARIES_DIR="$ROOT_DIR/target/release"
|
||||
|
||||
# Link the native Channel library and execute tests
|
||||
pushd "$NODE_DIR" > /dev/null
|
||||
CGO_LDFLAGS="-L$BINARIES_DIR -lchannel -ldl" \
|
||||
CGO_ENABLED=1 \
|
||||
GOEXPERIMENT=arenas \
|
||||
go test "$@"
|
35
client/build.sh
Executable file
35
client/build.sh
Executable file
@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
|
||||
# This script builds the node binary for the current platform and statically links it with VDF static lib.
|
||||
# Assumes that the VDF library has been built by running the generate.sh script in the `../vdf` directory.
|
||||
|
||||
ROOT_DIR="${ROOT_DIR:-$( cd "$(dirname "$(realpath "$( dirname "${BASH_SOURCE[0]}" )")")" >/dev/null 2>&1 && pwd )}"
|
||||
|
||||
CLIENT_DIR="$ROOT_DIR/client"
|
||||
BINARIES_DIR="$ROOT_DIR/target/release"
|
||||
|
||||
pushd "$CLIENT_DIR" > /dev/null
|
||||
|
||||
export CGO_ENABLED=1
|
||||
|
||||
os_type="$(uname)"
|
||||
case "$os_type" in
|
||||
"Darwin")
|
||||
# Check if the architecture is ARM
|
||||
if [[ "$(uname -m)" == "arm64" ]]; then
|
||||
# MacOS ld doesn't support -Bstatic and -Bdynamic, so it's important that there is only a static version of the library
|
||||
go build -ldflags "-linkmode 'external' -extldflags '-L$BINARIES_DIR -lvdf -lbls48581 -ldl -lm'" "$@"
|
||||
else
|
||||
echo "Unsupported platform"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
"Linux")
|
||||
go build -ldflags "-linkmode 'external' -extldflags '-L$BINARIES_DIR -Wl,-Bstatic -lvdf -lbls48581 -Wl,-Bdynamic -ldl -lm'" "$@"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported platform"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
@ -2,8 +2,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -18,18 +16,7 @@ var acceptCmd = &cobra.Command{
|
||||
PendingTransaction - the address of the pending transfer
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 1 {
|
||||
fmt.Println("invalid command")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
_, ok := new(big.Int).SetString(args[0], 0)
|
||||
if !ok {
|
||||
fmt.Println("invalid PendingTransaction")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("25 QUIL (Coin 0x2688997f2776ab5993894ed04fcdac05577cf2494ddfedf356ebf8bd3de464ab)")
|
||||
fmt.Println("command not yet available")
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ var allCmd = &cobra.Command{
|
||||
Use: "all",
|
||||
Short: "Mints all available token rewards",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("1520.381923 QUIL (Coin 0x162ad88c319060b4f5ea6dbf9a0c2cd82d3d70dfc22d5fc99ca5371083d68416)")
|
||||
fmt.Println("command not yet available")
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,50 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/iden3/go-iden3-crypto/poseidon"
|
||||
"github.com/spf13/cobra"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||
)
|
||||
|
||||
var balanceCmd = &cobra.Command{
|
||||
Use: "balance",
|
||||
Short: "Lists the total balance of tokens in the managing account",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("1545.381923 QUIL (Account 0x026a5cf3d486b8e8733060d6ce0060074616f0f925671a0886faef744412dc8a)")
|
||||
conn, err := GetGRPCClient()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := protobufs.NewNodeServiceClient(conn)
|
||||
peerId := GetPeerIDFromConfig(NodeConfig)
|
||||
addr, err := poseidon.HashBytes([]byte(peerId))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
addrBytes := addr.FillBytes(make([]byte, 32))
|
||||
info, err := client.GetTokenInfo(
|
||||
context.Background(),
|
||||
&protobufs.GetTokenInfoRequest{
|
||||
Address: addrBytes,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if info.OwnedTokens == nil {
|
||||
panic("invalid response from RPC")
|
||||
}
|
||||
tokens := new(big.Int).SetBytes(info.OwnedTokens)
|
||||
conversionFactor, _ := new(big.Int).SetString("1DCD65000", 16)
|
||||
r := new(big.Rat).SetFrac(tokens, conversionFactor)
|
||||
fmt.Println("Total balance:", r.FloatString(12), "QUIL")
|
||||
},
|
||||
}
|
||||
|
||||
|
51764
client/cmd/bridged.json
Normal file
51764
client/cmd/bridged.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,17 +1,59 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/iden3/go-iden3-crypto/poseidon"
|
||||
"github.com/spf13/cobra"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||
)
|
||||
|
||||
var coinsCmd = &cobra.Command{
|
||||
Use: "coins",
|
||||
Short: "Lists all coins under control of the managing account",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("25.0 QUIL (Coin 0x1148092cdce78c721835601ef39f9c2cd8b48b7787cbea032dd3913a4106a58d)")
|
||||
fmt.Println("1520.381923 QUIL (Coin 0x162ad88c319060b4f5ea6dbf9a0c2cd82d3d70dfc22d5fc99ca5371083d68416)")
|
||||
conn, err := GetGRPCClient()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := protobufs.NewNodeServiceClient(conn)
|
||||
peerId := GetPeerIDFromConfig(NodeConfig)
|
||||
addr, err := poseidon.HashBytes([]byte(peerId))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
addrBytes := addr.FillBytes(make([]byte, 32))
|
||||
resp, err := client.GetTokensByAccount(
|
||||
context.Background(),
|
||||
&protobufs.GetTokensByAccountRequest{
|
||||
Address: addrBytes,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if len(resp.Coins) != len(resp.FrameNumbers) {
|
||||
panic("invalid response from RPC")
|
||||
}
|
||||
|
||||
for i, coin := range resp.Coins {
|
||||
amount := new(big.Int).SetBytes(coin.Amount)
|
||||
conversionFactor, _ := new(big.Int).SetString("1DCD65000", 16)
|
||||
r := new(big.Rat).SetFrac(amount, conversionFactor)
|
||||
addr, err := token.GetAddressOfCoin(coin, resp.FrameNumbers[i])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(r.FloatString(12), "QUIL (Coin 0x", hex.EncodeToString(addr), ")")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
12
client/cmd/config.go
Normal file
12
client/cmd/config.go
Normal file
@ -0,0 +1,12 @@
|
||||
package cmd
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
var configCmd = &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "Performs a configuration operation",
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(configCmd)
|
||||
}
|
@ -10,13 +10,10 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/cloudflare/circl/sign/ed448"
|
||||
"github.com/iden3/go-iden3-crypto/poseidon"
|
||||
libP2pCrypto "github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/mr-tron/base58"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
||||
)
|
||||
|
||||
@ -25,10 +22,9 @@ var crossMintCmd = &cobra.Command{
|
||||
Short: "Signs a payload from the Quilibrium bridge to mint tokens on Ethereum L1 and prints the result to stdout",
|
||||
Long: `Signs a payload from the Quilibrium bridge to mint tokens on Ethereum L1 and prints the result to stdout":
|
||||
|
||||
cross-mint <Payload> [<Voucher File Path>]
|
||||
cross-mint <Payload>
|
||||
|
||||
Payload – the hex-encoded payload from the Quilibrium bridge with optional 0x-prefix, must be specified
|
||||
Voucher File Path – (optional) the path to a voucher private key, from the initial KZG ceremony
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) < 1 {
|
||||
@ -41,63 +37,7 @@ var crossMintCmd = &cobra.Command{
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if len(args) == 2 {
|
||||
rawVoucherHex, err := os.ReadFile(args[1])
|
||||
if err != nil {
|
||||
fmt.Printf("invalid file: %s\n", args[1])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
rawVoucherKey, err := hex.DecodeString(string(rawVoucherHex))
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "cross mint"))
|
||||
}
|
||||
|
||||
ed448Key := ed448.PrivateKey(rawVoucherKey)
|
||||
|
||||
result, err := CrossMint(&CrossMintArgs{
|
||||
Payload: args[0],
|
||||
PeerKey: ed448Key,
|
||||
ProvingKey: ed448Key,
|
||||
})
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "error cross minting"))
|
||||
}
|
||||
|
||||
pubkeyBytes := ed448Key.Public().(ed448.PublicKey)
|
||||
|
||||
addr, err := poseidon.HashBytes(pubkeyBytes)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "error cross minting"))
|
||||
}
|
||||
|
||||
addrBytes := addr.Bytes()
|
||||
addrBytes = append(make([]byte, 32-len(addrBytes)), addrBytes...)
|
||||
|
||||
// Print the result
|
||||
fmt.Println("Voucher ID: " + base58.Encode(addrBytes))
|
||||
|
||||
jsonResult, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "error marshaling result to json"))
|
||||
}
|
||||
fmt.Println(string(jsonResult))
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
_, err := os.Stat(configDirectory)
|
||||
if os.IsNotExist(err) {
|
||||
fmt.Printf("config directory doesn't exist: %s\n", configDirectory)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
config, err := config.LoadConfig(configDirectory, "")
|
||||
if err != nil {
|
||||
fmt.Printf("invalid config directory: %s\n", configDirectory)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
rawPeerKey, err := hex.DecodeString(config.P2P.PeerPrivKey)
|
||||
rawPeerKey, err := hex.DecodeString(NodeConfig.P2P.PeerPrivKey)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "cross mint"))
|
||||
}
|
||||
@ -117,10 +57,10 @@ var crossMintCmd = &cobra.Command{
|
||||
// `config.Key.KeyStoreFile.Path` defaults to `.config/keys.yml`.
|
||||
// We do our best here to make sure the configuration value is taken into
|
||||
// account if it was changed.
|
||||
if !filepath.IsAbs(config.Key.KeyStoreFile.Path) {
|
||||
config.Key.KeyStoreFile.Path = filepath.Join(
|
||||
if !filepath.IsAbs(NodeConfig.Key.KeyStoreFile.Path) {
|
||||
NodeConfig.Key.KeyStoreFile.Path = filepath.Join(
|
||||
configDirectory,
|
||||
filepath.Base(config.Key.KeyStoreFile.Path),
|
||||
filepath.Base(NodeConfig.Key.KeyStoreFile.Path),
|
||||
)
|
||||
}
|
||||
|
||||
@ -129,8 +69,8 @@ var crossMintCmd = &cobra.Command{
|
||||
panic(errors.Wrap(err, "cross mint"))
|
||||
}
|
||||
|
||||
fileKeyManager := keys.NewFileKeyManager(config.Key, logger)
|
||||
provingKey, err := fileKeyManager.GetSigningKey(config.Engine.ProvingKeyId)
|
||||
fileKeyManager := keys.NewFileKeyManager(NodeConfig.Key, logger)
|
||||
provingKey, err := fileKeyManager.GetSigningKey(NodeConfig.Engine.ProvingKeyId)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "cross mint"))
|
||||
}
|
||||
|
1049
client/cmd/first_retro.json
Normal file
1049
client/cmd/first_retro.json
Normal file
File diff suppressed because it is too large
Load Diff
181103
client/cmd/fourth_retro.json
Normal file
181103
client/cmd/fourth_retro.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,42 +1,77 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||
)
|
||||
|
||||
var mergeCmd = &cobra.Command{
|
||||
Use: "merge",
|
||||
Short: "Merges two coins",
|
||||
Long: `Merges two coins:
|
||||
Short: "Merges multiple coins",
|
||||
Long: `Merges multiple coins:
|
||||
|
||||
merge <LeftCoin> <RightCoin>
|
||||
|
||||
LeftCoin - the first coin address
|
||||
RightCoin - the second coin address
|
||||
merge <Coin Addresses>...
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
fmt.Println("invalid command")
|
||||
os.Exit(1)
|
||||
conn, err := GetGRPCClient()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := protobufs.NewNodeServiceClient(conn)
|
||||
key, err := GetPrivKeyFromConfig(NodeConfig)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, ok := new(big.Int).SetString(args[0], 0)
|
||||
if !ok {
|
||||
fmt.Println("invalid LeftCoin")
|
||||
os.Exit(1)
|
||||
coinaddrs := []*protobufs.CoinRef{}
|
||||
payload := []byte("merge")
|
||||
for _, arg := range args {
|
||||
coinaddrHex, _ := strings.CutPrefix(arg, "0x")
|
||||
coinaddr, err := hex.DecodeString(coinaddrHex)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
coinaddrs = append(coinaddrs, &protobufs.CoinRef{
|
||||
Address: coinaddr,
|
||||
})
|
||||
payload = append(payload, coinaddr...)
|
||||
}
|
||||
|
||||
_, ok = new(big.Int).SetString(args[1], 0)
|
||||
if !ok {
|
||||
fmt.Println("invalid Rightcoin")
|
||||
os.Exit(1)
|
||||
sig, err := key.Sign(payload)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println("1545.381923 QUIL (Coin 0x151f4ae225e20759077e1724e4c5d0feae26c477fd10d728dfea962eec79b83f)")
|
||||
pub, err := key.GetPublic().Raw()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, 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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -2,10 +2,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -19,22 +16,7 @@ var mutualReceiveCmd = &cobra.Command{
|
||||
ExpectedAmount - the amount expected in the transfer
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 1 {
|
||||
fmt.Println("invalid command")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
amount := args[len(args)-1]
|
||||
_, err := decimal.NewFromString(amount)
|
||||
if err != nil {
|
||||
fmt.Println("invalid ExpectedAmount")
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("Rendezvous: 0x2ad567e4fc1ac335a8d3d6077de2ee998aff996b51936da04ee1b0f5dc196a4f")
|
||||
fmt.Printf("Awaiting sender... ")
|
||||
time.Sleep(2 * time.Second)
|
||||
fmt.Println("OK")
|
||||
fmt.Println(amount + " QUIL (Coin 0x0525c76ecdc6ef21c2eb75df628b52396adcf402ba26a518ac395db8f5874a82)")
|
||||
fmt.Println("command not yet available")
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -22,15 +20,7 @@ var mutualTransferCmd = &cobra.Command{
|
||||
Either Amount or OfCoin must be specified
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
fmt.Println("invalid command")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("Confirming rendezvous... ")
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
fmt.Println("OK")
|
||||
fmt.Println("50 QUIL (Coin [private])")
|
||||
fmt.Println("command not yet available")
|
||||
},
|
||||
}
|
||||
|
||||
|
12
client/cmd/prover.go
Normal file
12
client/cmd/prover.go
Normal file
@ -0,0 +1,12 @@
|
||||
package cmd
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
var proverCmd = &cobra.Command{
|
||||
Use: "prover",
|
||||
Short: "Performs a configuration operation for given prover info",
|
||||
}
|
||||
|
||||
func init() {
|
||||
configCmd.AddCommand(proverCmd)
|
||||
}
|
299
client/cmd/proverMerge.go
Normal file
299
client/cmd/proverMerge.go
Normal file
@ -0,0 +1,299 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/spf13/cobra"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||
)
|
||||
|
||||
var proverConfigMergeCmd = &cobra.Command{
|
||||
Use: "merge",
|
||||
Short: "Merges config data for prover seniority",
|
||||
Long: `Merges config data for prover seniority:
|
||||
|
||||
merge <Primary Config Path> [<Additional Config Paths>...]
|
||||
|
||||
Use with --dry-run to evaluate seniority score, this may take a while...
|
||||
`,
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
if len(args) <= 1 {
|
||||
fmt.Println("missing configs")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
primaryConfig, err := config.LoadConfig(args[0], "", true)
|
||||
if err != nil {
|
||||
fmt.Printf("invalid config directory: %s\n", args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
otherPaths := []string{}
|
||||
peerIds := []string{GetPeerIDFromConfig(primaryConfig).String()}
|
||||
for _, p := range args[1:] {
|
||||
if !path.IsAbs(p) {
|
||||
fmt.Printf("%s is not an absolute path\n", p)
|
||||
}
|
||||
cfg, err := config.LoadConfig(p, "", true)
|
||||
if err != nil {
|
||||
fmt.Printf("invalid config directory: %s\n", p)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
peerId := GetPeerIDFromConfig(cfg).String()
|
||||
peerIds = append(peerIds, peerId)
|
||||
otherPaths = append(otherPaths, p)
|
||||
}
|
||||
|
||||
if DryRun {
|
||||
bridged := []*BridgedPeerJson{}
|
||||
firstRetro := []*FirstRetroJson{}
|
||||
secondRetro := []*SecondRetroJson{}
|
||||
thirdRetro := []*ThirdRetroJson{}
|
||||
fourthRetro := []*FourthRetroJson{}
|
||||
|
||||
err = json.Unmarshal(bridgedPeersJsonBinary, &bridged)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(firstRetroJsonBinary, &firstRetro)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(secondRetroJsonBinary, &secondRetro)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(thirdRetroJsonBinary, &thirdRetro)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(fourthRetroJsonBinary, &fourthRetro)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bridgedAddrs := map[string]struct{}{}
|
||||
|
||||
bridgeTotal := decimal.Zero
|
||||
for _, b := range bridged {
|
||||
amt, err := decimal.NewFromString(b.Amount)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bridgeTotal = bridgeTotal.Add(amt)
|
||||
bridgedAddrs[b.Identifier] = struct{}{}
|
||||
}
|
||||
|
||||
highestFirst := uint64(0)
|
||||
highestSecond := uint64(0)
|
||||
highestThird := uint64(0)
|
||||
highestFourth := uint64(0)
|
||||
|
||||
for _, f := range firstRetro {
|
||||
found := false
|
||||
for _, p := range peerIds {
|
||||
if p != f.PeerId {
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
}
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
// these don't have decimals so we can shortcut
|
||||
max := 157208
|
||||
actual, err := strconv.Atoi(f.Reward)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
s := uint64(10 * 6 * 60 * 24 * 92 / (max / actual))
|
||||
if s > uint64(highestFirst) {
|
||||
highestFirst = s
|
||||
}
|
||||
}
|
||||
|
||||
for _, f := range secondRetro {
|
||||
found := false
|
||||
for _, p := range peerIds {
|
||||
if p != f.PeerId {
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
}
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
amt := uint64(0)
|
||||
if f.JanPresence {
|
||||
amt += (10 * 6 * 60 * 24 * 31)
|
||||
}
|
||||
|
||||
if f.FebPresence {
|
||||
amt += (10 * 6 * 60 * 24 * 29)
|
||||
}
|
||||
|
||||
if f.MarPresence {
|
||||
amt += (10 * 6 * 60 * 24 * 31)
|
||||
}
|
||||
|
||||
if f.AprPresence {
|
||||
amt += (10 * 6 * 60 * 24 * 30)
|
||||
}
|
||||
|
||||
if f.MayPresence {
|
||||
amt += (10 * 6 * 60 * 24 * 31)
|
||||
}
|
||||
|
||||
if amt > uint64(highestSecond) {
|
||||
highestSecond = amt
|
||||
}
|
||||
}
|
||||
|
||||
for _, f := range thirdRetro {
|
||||
found := false
|
||||
for _, p := range peerIds {
|
||||
if p != f.PeerId {
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
}
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
s := uint64(10 * 6 * 60 * 24 * 30)
|
||||
if s > uint64(highestThird) {
|
||||
highestThird = s
|
||||
}
|
||||
}
|
||||
|
||||
for _, f := range fourthRetro {
|
||||
found := false
|
||||
for _, p := range peerIds {
|
||||
if p != f.PeerId {
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
}
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
s := uint64(10 * 6 * 60 * 24 * 31)
|
||||
if s > uint64(highestFourth) {
|
||||
highestFourth = s
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Effective seniority score: %d\n", highestFirst+highestSecond+highestThird+highestFourth)
|
||||
} else {
|
||||
for _, p := range args[1:] {
|
||||
primaryConfig.Engine.MultisigProverEnrollmentPaths = append(
|
||||
primaryConfig.Engine.MultisigProverEnrollmentPaths,
|
||||
p,
|
||||
)
|
||||
}
|
||||
err := config.SaveConfig(args[0], primaryConfig)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func GetPrivKeyFromConfig(cfg *config.Config) (crypto.PrivKey, error) {
|
||||
peerPrivKey, err := hex.DecodeString(cfg.P2P.PeerPrivKey)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "error unmarshaling peerkey"))
|
||||
}
|
||||
|
||||
privKey, err := crypto.UnmarshalEd448PrivateKey(peerPrivKey)
|
||||
return privKey, err
|
||||
}
|
||||
|
||||
func GetPeerIDFromConfig(cfg *config.Config) peer.ID {
|
||||
peerPrivKey, err := hex.DecodeString(cfg.P2P.PeerPrivKey)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "error unmarshaling peerkey"))
|
||||
}
|
||||
|
||||
privKey, err := crypto.UnmarshalEd448PrivateKey(peerPrivKey)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "error unmarshaling peerkey"))
|
||||
}
|
||||
|
||||
pub := privKey.GetPublic()
|
||||
id, err := peer.IDFromPublicKey(pub)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "error getting peer id"))
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
type BridgedPeerJson struct {
|
||||
Amount string `json:"amount"`
|
||||
Identifier string `json:"identifier"`
|
||||
Variant string `json:"variant"`
|
||||
}
|
||||
|
||||
type FirstRetroJson struct {
|
||||
PeerId string `json:"peerId"`
|
||||
Reward string `json:"reward"`
|
||||
}
|
||||
|
||||
type SecondRetroJson struct {
|
||||
PeerId string `json:"peerId"`
|
||||
Reward string `json:"reward"`
|
||||
JanPresence bool `json:"janPresence"`
|
||||
FebPresence bool `json:"febPresence"`
|
||||
MarPresence bool `json:"marPresence"`
|
||||
AprPresence bool `json:"aprPresence"`
|
||||
MayPresence bool `json:"mayPresence"`
|
||||
}
|
||||
|
||||
type ThirdRetroJson struct {
|
||||
PeerId string `json:"peerId"`
|
||||
Reward string `json:"reward"`
|
||||
}
|
||||
|
||||
type FourthRetroJson struct {
|
||||
PeerId string `json:"peerId"`
|
||||
Reward string `json:"reward"`
|
||||
}
|
||||
|
||||
//go:embed bridged.json
|
||||
var bridgedPeersJsonBinary []byte
|
||||
|
||||
//go:embed first_retro.json
|
||||
var firstRetroJsonBinary []byte
|
||||
|
||||
//go:embed second_retro.json
|
||||
var secondRetroJsonBinary []byte
|
||||
|
||||
//go:embed third_retro.json
|
||||
var thirdRetroJsonBinary []byte
|
||||
|
||||
//go:embed fourth_retro.json
|
||||
var fourthRetroJsonBinary []byte
|
||||
|
||||
func init() {
|
||||
proverCmd.AddCommand(proverConfigMergeCmd)
|
||||
}
|
139
client/cmd/proverPause.go
Normal file
139
client/cmd/proverPause.go
Normal file
@ -0,0 +1,139 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
|
||||
"github.com/iden3/go-iden3-crypto/poseidon"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
"source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token/application"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||
)
|
||||
|
||||
var proverPauseCmd = &cobra.Command{
|
||||
Use: "pause",
|
||||
Short: "Pauses a prover",
|
||||
Long: `Pauses a prover (use in emergency when a worker isn't coming back online):
|
||||
|
||||
pause <Filter>
|
||||
|
||||
Filter – the hex bitstring of the filter to pause for
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 1 {
|
||||
panic("invalid arguments")
|
||||
}
|
||||
|
||||
logger, err := zap.NewProduction()
|
||||
pubsub := p2p.NewBlossomSub(NodeConfig.P2P, logger)
|
||||
intrinsicFilter := p2p.GetBloomFilter(application.TOKEN_ADDRESS, 256, 3)
|
||||
pubsub.Subscribe(
|
||||
intrinsicFilter,
|
||||
func(message *pb.Message) error { return nil },
|
||||
)
|
||||
key, err := GetPrivKeyFromConfig(NodeConfig)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
payload := []byte("pause")
|
||||
filterHex, _ := strings.CutPrefix(args[0], "0x")
|
||||
filter, err := hex.DecodeString(filterHex)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
payload = append(payload, filter...)
|
||||
|
||||
sig, err := key.Sign(payload)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pub, err := key.GetPublic().Raw()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = publishMessage(
|
||||
key,
|
||||
pubsub,
|
||||
intrinsicFilter,
|
||||
&protobufs.AnnounceProverPause{
|
||||
Filter: filter,
|
||||
PublicKeySignatureEd448: &protobufs.Ed448Signature{
|
||||
Signature: sig,
|
||||
PublicKey: &protobufs.Ed448PublicKey{
|
||||
KeyValue: pub,
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func publishMessage(
|
||||
key crypto.PrivKey,
|
||||
pubsub p2p.PubSub,
|
||||
filter []byte,
|
||||
message proto.Message,
|
||||
) error {
|
||||
any := &anypb.Any{}
|
||||
if err := any.MarshalFrom(message); err != nil {
|
||||
return errors.Wrap(err, "publish message")
|
||||
}
|
||||
|
||||
any.TypeUrl = strings.Replace(
|
||||
any.TypeUrl,
|
||||
"type.googleapis.com",
|
||||
"types.quilibrium.com",
|
||||
1,
|
||||
)
|
||||
|
||||
payload, err := proto.Marshal(any)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "publish message")
|
||||
}
|
||||
|
||||
h, err := poseidon.HashBytes(payload)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "publish message")
|
||||
}
|
||||
|
||||
pub, err := key.GetPublic().Raw()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "publish message")
|
||||
}
|
||||
|
||||
pbi, err := poseidon.HashBytes(pub)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "publish message")
|
||||
}
|
||||
|
||||
provingKeyAddress := pbi.FillBytes(make([]byte, 32))
|
||||
|
||||
msg := &protobufs.Message{
|
||||
Hash: h.Bytes(),
|
||||
Address: provingKeyAddress,
|
||||
Payload: payload,
|
||||
}
|
||||
data, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "publish message")
|
||||
}
|
||||
return pubsub.PublishToBitmask(filter, data)
|
||||
}
|
||||
|
||||
func init() {
|
||||
proverCmd.AddCommand(proverPauseCmd)
|
||||
}
|
@ -2,8 +2,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -18,18 +16,7 @@ var rejectCmd = &cobra.Command{
|
||||
PendingTransaction - the address of the pending transfer
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 1 {
|
||||
fmt.Println("invalid command")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
_, ok := new(big.Int).SetString(args[0], 0)
|
||||
if !ok {
|
||||
fmt.Println("invalid PendingTransaction")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("25 QUIL (PendingTransaction 0x27fff099dee515ece193d2af09b164864e4bb60c19eb6719b5bc981f92151009)")
|
||||
fmt.Println("command not yet available")
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,118 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/cloudflare/circl/sign/ed448"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
mn "github.com/multiformats/go-multiaddr/net"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/crypto/sha3"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||
)
|
||||
|
||||
var configDirectory string
|
||||
var signatureCheck bool = true
|
||||
var NodeConfig *config.Config
|
||||
var simulateFail bool
|
||||
var LightNode bool = false
|
||||
var DryRun bool = false
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "qclient",
|
||||
Short: "Quilibrium RPC Client",
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
if signatureCheck {
|
||||
ex, err := os.Executable()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
b, err := os.ReadFile(ex)
|
||||
if err != nil {
|
||||
fmt.Println(
|
||||
"Error encountered during signature check – are you running this " +
|
||||
"from source? (use --signature-check=false)",
|
||||
)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
checksum := sha3.Sum256(b)
|
||||
digest, err := os.ReadFile(ex + ".dgst")
|
||||
if err != nil {
|
||||
fmt.Println("Digest file not found")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
parts := strings.Split(string(digest), " ")
|
||||
if len(parts) != 2 {
|
||||
fmt.Println("Invalid digest file format")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
digestBytes, err := hex.DecodeString(parts[1][:64])
|
||||
if err != nil {
|
||||
fmt.Println("Invalid digest file format")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if !bytes.Equal(checksum[:], digestBytes) {
|
||||
fmt.Println("Invalid digest for node")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
count := 0
|
||||
|
||||
for i := 1; i <= len(config.Signatories); i++ {
|
||||
signatureFile := fmt.Sprintf(ex+".dgst.sig.%d", i)
|
||||
sig, err := os.ReadFile(signatureFile)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
pubkey, _ := hex.DecodeString(config.Signatories[i-1])
|
||||
if !ed448.Verify(pubkey, digest, sig, "") {
|
||||
fmt.Printf("Failed signature check for signatory #%d\n", i)
|
||||
os.Exit(1)
|
||||
}
|
||||
count++
|
||||
}
|
||||
|
||||
if count < len(config.Signatories)/2+len(config.Signatories)%2 {
|
||||
fmt.Printf("Quorum on signatures not met")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("Signature check passed")
|
||||
} else {
|
||||
fmt.Println("Signature check bypassed, be sure you know what you're doing")
|
||||
}
|
||||
|
||||
_, err := os.Stat(configDirectory)
|
||||
if os.IsNotExist(err) {
|
||||
fmt.Printf("config directory doesn't exist: %s\n", configDirectory)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
NodeConfig, err = config.LoadConfig(configDirectory, "", false)
|
||||
if err != nil {
|
||||
fmt.Printf("invalid config directory: %s\n", configDirectory)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if NodeConfig.ListenGRPCMultiaddr == "" {
|
||||
fmt.Println("gRPC not enabled, using light node")
|
||||
LightNode = true
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
@ -21,6 +122,34 @@ func Execute() {
|
||||
}
|
||||
}
|
||||
|
||||
func GetGRPCClient() (*grpc.ClientConn, error) {
|
||||
addr := "rpc.quilibrium.com:8337"
|
||||
credentials := credentials.NewTLS(&tls.Config{InsecureSkipVerify: false})
|
||||
if !LightNode {
|
||||
ma, err := multiaddr.NewMultiaddr(NodeConfig.ListenGRPCMultiaddr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, addr, err = mn.DialArgs(ma)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
credentials = insecure.NewCredentials()
|
||||
}
|
||||
|
||||
return grpc.Dial(
|
||||
addr,
|
||||
grpc.WithTransportCredentials(
|
||||
credentials,
|
||||
),
|
||||
grpc.WithDefaultCallOptions(
|
||||
grpc.MaxCallSendMsgSize(600*1024*1024),
|
||||
grpc.MaxCallRecvMsgSize(600*1024*1024),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.PersistentFlags().StringVar(
|
||||
&configDirectory,
|
||||
@ -28,4 +157,16 @@ func init() {
|
||||
".config/",
|
||||
"config directory (default is .config/)",
|
||||
)
|
||||
rootCmd.PersistentFlags().BoolVar(
|
||||
&DryRun,
|
||||
"dry-run",
|
||||
false,
|
||||
"runs the command (if applicable) without actually mutating state (printing effect output)",
|
||||
)
|
||||
rootCmd.PersistentFlags().BoolVar(
|
||||
&signatureCheck,
|
||||
"signature-check",
|
||||
true,
|
||||
"bypass signature check (not recommended for binaries)",
|
||||
)
|
||||
}
|
||||
|
138554
client/cmd/second_retro.json
Normal file
138554
client/cmd/second_retro.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,52 +1,101 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/spf13/cobra"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||
)
|
||||
|
||||
var splitCmd = &cobra.Command{
|
||||
Use: "split",
|
||||
Short: "Splits a coin into two coins",
|
||||
Long: `Splits a coin into two coins:
|
||||
Short: "Splits a coin into multiple coins",
|
||||
Long: `Splits a coin into multiple coins:
|
||||
|
||||
split <OfCoin> <LeftAmount> <RightAmount>
|
||||
split <OfCoin> <Amounts>...
|
||||
|
||||
OfCoin - the address of the coin to split
|
||||
LeftAmount - the first half of the split amount
|
||||
RightAmount - the second half of the split amount
|
||||
Amounts - the sets of amounts to split
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 3 {
|
||||
if len(args) < 3 {
|
||||
fmt.Println("invalid command")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
_, ok := new(big.Int).SetString(args[0], 0)
|
||||
if !ok {
|
||||
fmt.Println("invalid OfCoin")
|
||||
os.Exit(1)
|
||||
payload := []byte("split")
|
||||
coinaddrHex, _ := strings.CutPrefix(args[0], "0x")
|
||||
coinaddr, err := hex.DecodeString(coinaddrHex)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
coin := &protobufs.CoinRef{
|
||||
Address: coinaddr,
|
||||
}
|
||||
payload = append(payload, coinaddr...)
|
||||
|
||||
conversionFactor, _ := new(big.Int).SetString("1DCD65000", 16)
|
||||
amounts := [][]byte{}
|
||||
for _, amt := range args[1:] {
|
||||
amount, err := decimal.NewFromString(amt)
|
||||
if err != nil {
|
||||
fmt.Println("invalid amount")
|
||||
os.Exit(1)
|
||||
}
|
||||
amount.Mul(decimal.NewFromBigInt(conversionFactor, 0))
|
||||
amountBytes := amount.BigInt().FillBytes(make([]byte, 32))
|
||||
amounts = append(amounts, amountBytes)
|
||||
payload = append(payload, amountBytes...)
|
||||
}
|
||||
|
||||
leftAmount := args[1]
|
||||
_, err := decimal.NewFromString(leftAmount)
|
||||
conn, err := GetGRPCClient()
|
||||
if err != nil {
|
||||
fmt.Println("invalid LeftAmount")
|
||||
os.Exit(1)
|
||||
panic(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := protobufs.NewNodeServiceClient(conn)
|
||||
key, err := GetPrivKeyFromConfig(NodeConfig)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
rightAmount := args[2]
|
||||
_, err = decimal.NewFromString(rightAmount)
|
||||
sig, err := key.Sign(payload)
|
||||
if err != nil {
|
||||
fmt.Println("invalid RightAmount")
|
||||
os.Exit(1)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pub, err := key.GetPublic().Raw()
|
||||
if 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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(leftAmount + " QUIL (Coin 0x024479f49f03dc53fd702198cd9b548c9e96004e19ef6a4e9c5211a9795ba34d)")
|
||||
fmt.Println(rightAmount + " QUIL (Coin 0x0140e01731256793bba03914f3844d645fbece26553acdea8ac4de4d84f91690)")
|
||||
},
|
||||
}
|
||||
|
||||
|
191064
client/cmd/third_retro.json
Normal file
191064
client/cmd/third_retro.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,12 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"strconv"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/spf13/cobra"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||
)
|
||||
|
||||
var transferCmd = &cobra.Command{
|
||||
@ -15,75 +14,84 @@ var transferCmd = &cobra.Command{
|
||||
Short: "Creates a pending transfer of coin",
|
||||
Long: `Creates a pending transfer of coin:
|
||||
|
||||
transfer <ToAccount> [<RefundAccount>] [<Expiry>] (<Amount>|<OfCoin>)
|
||||
transfer <ToAccount> <OfCoin>
|
||||
|
||||
ToAccount – account address, must be specified
|
||||
RefundAccount - account address to receive coin if rejected (if omitted, uses sender address)
|
||||
Expiry – unix epoch time in seconds where the ToAccount can no longer claim (if omitted, does not expire)
|
||||
Amount – the amount to send, splitting/merging and sending as needed
|
||||
OfCoin – the address of the coin to send in whole
|
||||
|
||||
Either Amount or OfCoin must be specified
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) < 2 || len(args) > 4 {
|
||||
fmt.Println("invalid command")
|
||||
os.Exit(1)
|
||||
if len(args) != 2 {
|
||||
panic("invalid arguments")
|
||||
}
|
||||
|
||||
_, ok := new(big.Int).SetString(args[0], 0)
|
||||
if !ok {
|
||||
fmt.Println("invalid ToAccount")
|
||||
os.Exit(1)
|
||||
conn, err := GetGRPCClient()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := protobufs.NewNodeServiceClient(conn)
|
||||
key, err := GetPrivKeyFromConfig(NodeConfig)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
refundAccount := "0x23c0f371e9faa7be4ffedd616361e0c9aeb776ae4d7f3a37605ecbfa40a55a90"
|
||||
// expiry := int64(9999999999)
|
||||
var err error
|
||||
|
||||
if len(args) >= 3 {
|
||||
if len(args[len(args)-2]) != 66 {
|
||||
_, err = strconv.ParseInt(args[len(args)-2], 10, 0)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
refundAccount = args[1]
|
||||
}
|
||||
}
|
||||
|
||||
if refundAccount[0] != '0' || refundAccount[1] != 'x' {
|
||||
_, ok := new(big.Int).SetString(refundAccount, 0)
|
||||
if !ok {
|
||||
fmt.Println("invalid refund account")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
ofCoin := ""
|
||||
amount := ""
|
||||
if len(args[len(args)-1]) == 66 {
|
||||
ofCoin = args[len(args)-1]
|
||||
_, ok := new(big.Int).SetString(ofCoin, 0)
|
||||
if !ok {
|
||||
fmt.Println("invalid OfCoin")
|
||||
os.Exit(1)
|
||||
}
|
||||
switch ofCoin {
|
||||
case "0x1148092cdce78c721835601ef39f9c2cd8b48b7787cbea032dd3913a4106a58d":
|
||||
fmt.Println("25.0 QUIL (Pending Transaction 0x0382e4da0c7c0133a1b53453b05096272b80c1575c6828d0211c4e371f7c81bb)")
|
||||
case "0x162ad88c319060b4f5ea6dbf9a0c2cd82d3d70dfc22d5fc99ca5371083d68416":
|
||||
fmt.Println("1520.381923 QUIL (Pending Transaction 0x0382e4da0c7c0133a1b53453b05096272b80c1575c6828d0211c4e371f7c81bb)")
|
||||
}
|
||||
} else {
|
||||
amount = args[len(args)-1]
|
||||
_, err := decimal.NewFromString(amount)
|
||||
var coinaddr *protobufs.CoinRef
|
||||
payload := []byte("transfer")
|
||||
toaddr := []byte{}
|
||||
for i, arg := range args {
|
||||
addrHex, _ := strings.CutPrefix(arg, "0x")
|
||||
addr, err := hex.DecodeString(addrHex)
|
||||
if err != nil {
|
||||
fmt.Println("invalid Amount")
|
||||
os.Exit(1)
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(amount + " QUIL (Pending Transaction 0x0382e4da0c7c0133a1b53453b05096272b80c1575c6828d0211c4e371f7c81bb)")
|
||||
if i == 0 {
|
||||
toaddr = addr
|
||||
continue
|
||||
}
|
||||
|
||||
coinaddr = &protobufs.CoinRef{
|
||||
Address: addr,
|
||||
}
|
||||
payload = append(payload, addr...)
|
||||
}
|
||||
payload = append(payload, toaddr...)
|
||||
|
||||
sig, err := key.Sign(payload)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pub, err := key.GetPublic().Raw()
|
||||
if 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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
159
client/go.mod
159
client/go.mod
@ -4,43 +4,190 @@ go 1.21
|
||||
|
||||
toolchain go1.22.1
|
||||
|
||||
replace source.quilibrium.com/quilibrium/monorepo/nekryptology => ../nekryptology
|
||||
|
||||
replace source.quilibrium.com/quilibrium/monorepo/bls48581 => ../bls48581
|
||||
|
||||
replace source.quilibrium.com/quilibrium/monorepo/vdf => ../vdf
|
||||
|
||||
replace github.com/multiformats/go-multiaddr => ../go-multiaddr
|
||||
|
||||
replace github.com/multiformats/go-multiaddr-dns => ../go-multiaddr-dns
|
||||
|
||||
replace github.com/libp2p/go-libp2p => ../go-libp2p
|
||||
|
||||
replace github.com/libp2p/go-libp2p-kad-dht => ../go-libp2p-kad-dht
|
||||
|
||||
replace github.com/libp2p/go-libp2p-gostream => ../go-libp2p-gostream
|
||||
|
||||
replace source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub => ../go-libp2p-blossomsub
|
||||
|
||||
replace source.quilibrium.com/quilibrium/monorepo/node => ../node
|
||||
|
||||
replace source.quilibrium.com/quilibrium/monorepo/nekryptology => ../nekryptology
|
||||
replace github.com/cockroachdb/pebble => ../pebble
|
||||
|
||||
require (
|
||||
github.com/iden3/go-iden3-crypto v0.0.15
|
||||
github.com/iden3/go-iden3-crypto v0.0.16
|
||||
github.com/mr-tron/base58 v1.2.0
|
||||
github.com/multiformats/go-multiaddr v0.12.4
|
||||
github.com/stretchr/testify v1.9.0
|
||||
golang.org/x/crypto v0.24.0
|
||||
google.golang.org/grpc v1.58.2
|
||||
source.quilibrium.com/quilibrium/monorepo/node v0.0.0-00010101000000-000000000000
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
|
||||
github.com/DataDog/zstd v1.4.5 // indirect
|
||||
github.com/benbjohnson/clock v1.3.5 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/btcsuite/btcd v0.21.0-beta.0.20201114000516-e9c7a5ac6401 // indirect
|
||||
github.com/bwesterb/go-ristretto v1.2.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cockroachdb/errors v1.11.1 // indirect
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
|
||||
github.com/cockroachdb/pebble v0.0.0-20231210175920-b4d301aeb46a // indirect
|
||||
github.com/cockroachdb/redact v1.1.5 // indirect
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
|
||||
github.com/consensys/gnark-crypto v0.5.3 // indirect
|
||||
github.com/containerd/cgroups v1.1.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/elastic/gosigar v0.14.2 // indirect
|
||||
github.com/flynn/noise v1.1.0 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/getsentry/sentry-go v0.18.0 // indirect
|
||||
github.com/go-logr/logr v1.3.0 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect
|
||||
github.com/google/uuid v1.4.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/huin/goupnp v1.3.0 // indirect
|
||||
github.com/ipfs/boxo v0.10.0 // indirect
|
||||
github.com/ipfs/go-cid v0.4.1 // indirect
|
||||
github.com/ipfs/go-datastore v0.6.0 // indirect
|
||||
github.com/ipfs/go-log v1.0.5 // indirect
|
||||
github.com/ipfs/go-log/v2 v2.5.1 // indirect
|
||||
github.com/ipld/go-ipld-prime v0.20.0 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
|
||||
github.com/jbenet/goprocess v0.1.4 // indirect
|
||||
github.com/klauspost/compress v1.17.8 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/koron/go-ssdp v0.0.4 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
||||
github.com/libp2p/go-cidranger v1.1.0 // indirect
|
||||
github.com/libp2p/go-flow-metrics v0.1.0 // indirect
|
||||
github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect
|
||||
github.com/libp2p/go-libp2p-gostream v0.6.0 // indirect
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.23.0 // indirect
|
||||
github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect
|
||||
github.com/libp2p/go-libp2p-record v0.2.0 // indirect
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.7.2 // indirect
|
||||
github.com/libp2p/go-msgio v0.3.0 // indirect
|
||||
github.com/libp2p/go-nat v0.2.0 // indirect
|
||||
github.com/libp2p/go-netroute v0.2.1 // indirect
|
||||
github.com/libp2p/go-reuseport v0.4.0 // indirect
|
||||
github.com/libp2p/go-yamux/v4 v4.0.1 // indirect
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/miekg/dns v1.1.58 // indirect
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
|
||||
github.com/minio/sha256-simd v1.0.1 // indirect
|
||||
github.com/multiformats/go-base32 v0.1.0 // indirect
|
||||
github.com/multiformats/go-base36 v0.2.0 // indirect
|
||||
github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
|
||||
github.com/multiformats/go-multibase v0.2.0 // indirect
|
||||
github.com/multiformats/go-multicodec v0.9.0 // indirect
|
||||
github.com/multiformats/go-multihash v0.2.3 // indirect
|
||||
github.com/multiformats/go-multistream v0.5.0 // indirect
|
||||
github.com/multiformats/go-varint v0.0.7 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.15.0 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.2.0 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/pion/datachannel v1.5.6 // indirect
|
||||
github.com/pion/dtls/v2 v2.2.11 // indirect
|
||||
github.com/pion/ice/v2 v2.3.25 // indirect
|
||||
github.com/pion/interceptor v0.1.29 // indirect
|
||||
github.com/pion/logging v0.2.2 // indirect
|
||||
github.com/pion/mdns v0.0.12 // indirect
|
||||
github.com/pion/randutil v0.1.0 // indirect
|
||||
github.com/pion/rtcp v1.2.14 // indirect
|
||||
github.com/pion/rtp v1.8.6 // indirect
|
||||
github.com/pion/sctp v1.8.16 // indirect
|
||||
github.com/pion/sdp/v3 v3.0.9 // indirect
|
||||
github.com/pion/srtp/v2 v2.0.18 // indirect
|
||||
github.com/pion/stun v0.6.1 // indirect
|
||||
github.com/pion/transport/v2 v2.2.5 // indirect
|
||||
github.com/pion/turn/v2 v2.1.6 // indirect
|
||||
github.com/pion/webrtc/v3 v3.2.40 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/polydawn/refmt v0.89.0 // indirect
|
||||
github.com/prometheus/client_golang v1.19.1 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.48.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/quic-go v0.44.0 // indirect
|
||||
github.com/quic-go/webtransport-go v0.8.0 // indirect
|
||||
github.com/raulk/go-watchdog v1.3.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.10.0 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/otel v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.16.0 // indirect
|
||||
go.uber.org/dig v1.17.1 // indirect
|
||||
go.uber.org/fx v1.22.1 // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.24.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
gonum.org/v1/gonum v0.13.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/blake3 v1.2.1 // indirect
|
||||
source.quilibrium.com/quilibrium/monorepo/bls48581 v0.0.0-00010101000000-000000000000 // indirect
|
||||
source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub v0.0.0-00010101000000-000000000000 // indirect
|
||||
source.quilibrium.com/quilibrium/monorepo/nekryptology v0.0.0-00010101000000-000000000000 // indirect
|
||||
source.quilibrium.com/quilibrium/monorepo/vdf v0.0.0-00010101000000-000000000000 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cloudflare/circl v1.3.8
|
||||
github.com/cloudflare/circl v1.3.9
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/libp2p/go-libp2p v0.35.1
|
||||
github.com/libp2p/go-libp2p v0.35.4
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/shopspring/decimal v1.4.0
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
go.uber.org/zap v1.27.0
|
||||
google.golang.org/protobuf v1.34.1 // indirect
|
||||
source.quilibrium.com/quilibrium/monorepo/node v1.14.17
|
||||
)
|
||||
|
664
client/go.sum
664
client/go.sum
@ -1,6 +1,27 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
|
||||
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
|
||||
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
|
||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
||||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
|
||||
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
|
||||
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
|
||||
github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btcd v0.21.0-beta.0.20201114000516-e9c7a5ac6401 h1:0tjUthKCaF8zwF9Qg7lfnep0xdo4n8WiFUfQPaMHX6g=
|
||||
github.com/btcsuite/btcd v0.21.0-beta.0.20201114000516-e9c7a5ac6401/go.mod h1:Sv4JPQ3/M+teHz9Bo5jBpkNcP0x6r7rdihlNL/7tTAs=
|
||||
@ -14,131 +35,758 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku
|
||||
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
||||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
|
||||
github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE=
|
||||
github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4=
|
||||
github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
|
||||
github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8=
|
||||
github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw=
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
|
||||
github.com/cockroachdb/metamorphic v0.0.0-20231108215700-4ba948b56895 h1:XANOgPYtvELQ/h4IrmPAohXqe2pWA8Bwhejr3VQoZsA=
|
||||
github.com/cockroachdb/metamorphic v0.0.0-20231108215700-4ba948b56895/go.mod h1:aPd7gM9ov9M8v32Yy5NJrDyOcD8z642dqs+F0CeNXfA=
|
||||
github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
|
||||
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
|
||||
github.com/consensys/bavard v0.1.8-0.20210915155054-088da2f7f54a/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
|
||||
github.com/consensys/gnark-crypto v0.5.3 h1:4xLFGZR3NWEH2zy+YzvzHicpToQR8FXFbfLNvpGB+rE=
|
||||
github.com/consensys/gnark-crypto v0.5.3/go.mod h1:hOdPlWQV1gDLp7faZVeg8Y0iEPFaOUnCc4XeCCk96p0=
|
||||
github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
|
||||
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
|
||||
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
|
||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU=
|
||||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
|
||||
github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4=
|
||||
github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
|
||||
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
|
||||
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
|
||||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0=
|
||||
github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
|
||||
github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo=
|
||||
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/iden3/go-iden3-crypto v0.0.15 h1:4MJYlrot1l31Fzlo2sF56u7EVFeHHJkxGXXZCtESgK4=
|
||||
github.com/iden3/go-iden3-crypto v0.0.15/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E=
|
||||
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
||||
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
||||
github.com/iden3/go-iden3-crypto v0.0.16 h1:zN867xiz6HgErXVIV/6WyteGcOukE9gybYTorBMEdsk=
|
||||
github.com/iden3/go-iden3-crypto v0.0.16/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/ipfs/boxo v0.10.0 h1:tdDAxq8jrsbRkYoF+5Rcqyeb91hgWe2hp7iLu7ORZLY=
|
||||
github.com/ipfs/boxo v0.10.0/go.mod h1:Fg+BnfxZ0RPzR0nOodzdIq3A7KgoWAOWsEIImrIQdBM=
|
||||
github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
|
||||
github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=
|
||||
github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk=
|
||||
github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk=
|
||||
github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8=
|
||||
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
|
||||
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
|
||||
github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8=
|
||||
github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ=
|
||||
github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8=
|
||||
github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo=
|
||||
github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g=
|
||||
github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY=
|
||||
github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
|
||||
github.com/ipld/go-ipld-prime v0.20.0 h1:Ud3VwE9ClxpO2LkCYP7vWPc0Fo+dYdYzgxUJZ3uRG4g=
|
||||
github.com/ipld/go-ipld-prime v0.20.0/go.mod h1:PzqZ/ZR981eKbgdr3y2DJYeD/8bgMawdGVlJDE8kK+M=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk=
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk=
|
||||
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
|
||||
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0=
|
||||
github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
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/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=
|
||||
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=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
|
||||
github.com/libp2p/go-libp2p-kbucket v0.6.3 h1:p507271wWzpy2f1XxPzCQG9NiN6R6lHL9GiSErbQQo0=
|
||||
github.com/libp2p/go-libp2p-kbucket v0.6.3/go.mod h1:RCseT7AH6eJWxxk2ol03xtP9pEHetYSPXOaJnOiD8i0=
|
||||
github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0=
|
||||
github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk=
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.7.2 h1:xJMFyhQ3Iuqnk9Q2dYE1eUTzsah7NLw3Qs2zjUV78T0=
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.7.2/go.mod h1:cN4mJAD/7zfPKXBcs9ze31JGYAZgzdABEm+q/hkswb8=
|
||||
github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA=
|
||||
github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg=
|
||||
github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0=
|
||||
github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM=
|
||||
github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk=
|
||||
github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk=
|
||||
github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU=
|
||||
github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ=
|
||||
github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s=
|
||||
github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU=
|
||||
github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ=
|
||||
github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
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.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=
|
||||
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms=
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc=
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU=
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc=
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
|
||||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
|
||||
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
|
||||
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
|
||||
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
|
||||
github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE=
|
||||
github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=
|
||||
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 v0.12.4 h1:rrKqpY9h+n80EwhhC/kkcunCZZ7URIF8yN1WEUt2Hvc=
|
||||
github.com/multiformats/go-multiaddr v0.12.4/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII=
|
||||
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=
|
||||
github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
|
||||
github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
|
||||
github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg=
|
||||
github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k=
|
||||
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
|
||||
github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U=
|
||||
github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=
|
||||
github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE=
|
||||
github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA=
|
||||
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||
github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
|
||||
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
|
||||
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
|
||||
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
|
||||
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
|
||||
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
|
||||
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||
github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg=
|
||||
github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4=
|
||||
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
|
||||
github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks=
|
||||
github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE=
|
||||
github.com/pion/ice/v2 v2.3.25 h1:M5rJA07dqhi3nobJIg+uPtcVjFECTrhcR3n0ns8kDZs=
|
||||
github.com/pion/ice/v2 v2.3.25/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw=
|
||||
github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M=
|
||||
github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4=
|
||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
||||
github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8=
|
||||
github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk=
|
||||
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
||||
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||
github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
|
||||
github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE=
|
||||
github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
|
||||
github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
|
||||
github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw=
|
||||
github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
|
||||
github.com/pion/sctp v1.8.13/go.mod h1:YKSgO/bO/6aOMP9LCie1DuD7m+GamiK2yIiPM6vH+GA=
|
||||
github.com/pion/sctp v1.8.16 h1:PKrMs+o9EMLRvFfXq59WFsC+V8mN1wnKzqrv+3D/gYY=
|
||||
github.com/pion/sctp v1.8.16/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE=
|
||||
github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY=
|
||||
github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M=
|
||||
github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo=
|
||||
github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA=
|
||||
github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4=
|
||||
github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8=
|
||||
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
|
||||
github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc=
|
||||
github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
|
||||
github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
|
||||
github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc=
|
||||
github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
|
||||
github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0=
|
||||
github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4=
|
||||
github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0=
|
||||
github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY=
|
||||
github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc=
|
||||
github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY=
|
||||
github.com/pion/webrtc/v3 v3.2.40 h1:Wtfi6AZMQg+624cvCXUuSmrKWepSB7zfgYDOYqsSOVU=
|
||||
github.com/pion/webrtc/v3 v3.2.40/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4=
|
||||
github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0=
|
||||
github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek=
|
||||
github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg=
|
||||
github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM=
|
||||
github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk=
|
||||
github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
||||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
||||
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
|
||||
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
|
||||
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
|
||||
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
|
||||
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
|
||||
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
|
||||
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
|
||||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
|
||||
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
|
||||
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
|
||||
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
|
||||
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
|
||||
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
|
||||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
||||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
||||
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
|
||||
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
|
||||
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
|
||||
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=
|
||||
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
|
||||
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
|
||||
go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
|
||||
go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
|
||||
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
|
||||
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc=
|
||||
go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
|
||||
go.uber.org/fx v1.22.1 h1:nvvln7mwyT5s1q201YE29V/BFrGor6vMiDNpU/78Mys=
|
||||
go.uber.org/fx v1.22.1/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48=
|
||||
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20230725012225-302865e7556b/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/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=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.13.0 h1:a0T3bh+7fhRyqeNbiC3qVHYmkiQgit3wnNan/2c0HMM=
|
||||
gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU=
|
||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
|
||||
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g=
|
||||
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
|
||||
google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
|
||||
lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
|
||||
lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
|
||||
rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
|
||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
|
@ -12,5 +12,13 @@ hex = "0.4.3"
|
||||
serde_json = "1.0.117"
|
||||
uniffi = { version= "0.25", features = ["cli"]}
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.4", features = ["html_reports"] }
|
||||
rand = "0.8.5"
|
||||
|
||||
[build-dependencies]
|
||||
uniffi = { version = "0.25", features = [ "build" ] }
|
||||
|
||||
[[bench]]
|
||||
name = "bench_bls"
|
||||
harness = false
|
20
crates/bls48581/benches/bench_bls.rs
Normal file
20
crates/bls48581/benches/bench_bls.rs
Normal file
@ -0,0 +1,20 @@
|
||||
use rand::Rng;
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
bls48581::init();
|
||||
let mut bytes = vec![0u8; 65536];
|
||||
rand::thread_rng().fill(&mut bytes[..]);
|
||||
|
||||
let mut group = c.benchmark_group("commit");
|
||||
group.sample_size(10);
|
||||
group.bench_function("commit 16", |b| b.iter(|| black_box(bls48581::commit_raw(&bytes, 16))));
|
||||
group.bench_function("commit 128", |b| b.iter(|| black_box(bls48581::commit_raw(&bytes, 128))));
|
||||
group.bench_function("commit 256", |b| b.iter(|| black_box(bls48581::commit_raw(&bytes, 256))));
|
||||
group.bench_function("commit 1024", |b| b.iter(|| black_box(bls48581::commit_raw(&bytes, 1024))));
|
||||
group.bench_function("commit 65536", |b| b.iter(|| black_box(bls48581::commit_raw(&bytes, 65536))));
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
criterion_main!(benches);
|
@ -49,35 +49,18 @@ fn recurse_fft(
|
||||
fft_width: u64,
|
||||
inverse: bool,
|
||||
) {
|
||||
let M = &big::BIG::new_ints(&rom::CURVE_ORDER);
|
||||
let roots = if inverse {
|
||||
&bls::singleton().ReverseRootsOfUnityBLS48581[&fft_width]
|
||||
} else {
|
||||
&bls::singleton().RootsOfUnityBLS48581[&fft_width]
|
||||
};
|
||||
|
||||
if out.len() <= 16 {
|
||||
let l = out.len() as u64;
|
||||
for i in 0..l {
|
||||
let mut last = big::BIG::modmul(
|
||||
&values[offset as usize],
|
||||
&roots[0],
|
||||
&big::BIG::new_ints(&rom::CURVE_ORDER),
|
||||
);
|
||||
|
||||
for j in 1..l {
|
||||
let mid = big::BIG::modmul(
|
||||
&values[(offset + j * stride) as usize],
|
||||
&roots[((i * j) % l) as usize * roots_stride as usize],
|
||||
&big::BIG::new_ints(&rom::CURVE_ORDER),
|
||||
);
|
||||
last = big::BIG::modadd(
|
||||
&last,
|
||||
&mid,
|
||||
&big::BIG::new_ints(&rom::CURVE_ORDER),
|
||||
);
|
||||
}
|
||||
out[i as usize] = last;
|
||||
}
|
||||
if out.len() == 1 {
|
||||
// optimization: we're working in bls48-581, the first roots of unity
|
||||
// value is always 1 no matter the fft width, so we can skip the
|
||||
// multiplication:
|
||||
out[0] = values[offset as usize].clone();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -107,26 +90,26 @@ fn recurse_fft(
|
||||
|
||||
// cha cha now, y'all
|
||||
for i in 0..half {
|
||||
let mul = big::BIG::modmul(
|
||||
&out[(i + half) as usize],
|
||||
&roots[(i * roots_stride) as usize],
|
||||
&big::BIG::new_ints(&rom::CURVE_ORDER),
|
||||
);
|
||||
let mul_add = big::BIG::modadd(
|
||||
&out[i as usize],
|
||||
&mul,
|
||||
&big::BIG::new_ints(&rom::CURVE_ORDER),
|
||||
);
|
||||
out[(i + half) as usize] = big::BIG::modadd(
|
||||
&out[i as usize],
|
||||
&big::BIG::modneg(&mul, &big::BIG::new_ints(&rom::CURVE_ORDER)),
|
||||
&big::BIG::new_ints(&rom::CURVE_ORDER),
|
||||
);
|
||||
out[i as usize] = mul_add;
|
||||
let mul = big::BIG::modmul(
|
||||
&out[(i + half) as usize],
|
||||
&roots[(i * roots_stride) as usize],
|
||||
&big::BIG::new_ints(&rom::CURVE_ORDER),
|
||||
);
|
||||
let mul_add = big::BIG::modadd(
|
||||
&out[i as usize],
|
||||
&mul,
|
||||
&big::BIG::new_ints(&rom::CURVE_ORDER),
|
||||
);
|
||||
out[(i + half) as usize] = big::BIG::modadd(
|
||||
&out[i as usize],
|
||||
&big::BIG::modneg(&mul, &big::BIG::new_ints(&rom::CURVE_ORDER)),
|
||||
&big::BIG::new_ints(&rom::CURVE_ORDER),
|
||||
);
|
||||
out[i as usize] = mul_add;
|
||||
}
|
||||
}
|
||||
|
||||
fn fft(
|
||||
pub fn fft(
|
||||
values: &[big::BIG],
|
||||
fft_width: u64,
|
||||
inverse: bool,
|
||||
@ -183,21 +166,8 @@ fn recurse_fft_g1(
|
||||
&bls::singleton().RootsOfUnityBLS48581[&fft_width]
|
||||
};
|
||||
|
||||
if out.len() <= 16 {
|
||||
let l = out.len() as u64;
|
||||
for i in 0..l {
|
||||
let mut last = ecp::ECP::mul(&values[offset as usize].clone(), &roots[0]);
|
||||
|
||||
for j in 1..l {
|
||||
let mid = ecp::ECP::mul(
|
||||
&values[(offset + j * stride) as usize].clone(),
|
||||
&roots[((i * j) % l) as usize * roots_stride as usize],
|
||||
);
|
||||
&last.add(&mid);
|
||||
}
|
||||
|
||||
out[i as usize] = last.clone();
|
||||
}
|
||||
if out.len() == 1 {
|
||||
out[0] = values[offset as usize].clone();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -227,7 +197,9 @@ fn recurse_fft_g1(
|
||||
|
||||
// cha cha now, y'all
|
||||
for i in 0..half {
|
||||
let mul = out[(i + half) as usize].clone().mul(&roots[(i * roots_stride) as usize].clone());
|
||||
let mul = out[(i + half) as usize].clone().mul(
|
||||
&roots[(i * roots_stride) as usize].clone(),
|
||||
);
|
||||
let mut mul_add = out[i as usize].clone();
|
||||
mul_add.add(&mul.clone());
|
||||
out[(i + half) as usize] = out[i as usize].clone();
|
||||
@ -236,7 +208,7 @@ fn recurse_fft_g1(
|
||||
}
|
||||
}
|
||||
|
||||
fn fft_g1(
|
||||
pub fn fft_g1(
|
||||
values: &[ecp::ECP],
|
||||
fft_width: u64,
|
||||
inverse: bool,
|
||||
@ -291,7 +263,7 @@ fn bytes_to_polynomial(
|
||||
let size = bytes.len() / 64;
|
||||
let trunc_last = bytes.len() % 64 > 0;
|
||||
|
||||
let mut poly = Vec::new();
|
||||
let mut poly = Vec::with_capacity(size + (if trunc_last { 1 } else { 0 }));
|
||||
|
||||
for i in 0..size {
|
||||
let scalar = big::BIG::frombytes(&bytes[i * 64..(i + 1) * 64]);
|
||||
@ -306,8 +278,8 @@ fn bytes_to_polynomial(
|
||||
return poly;
|
||||
}
|
||||
|
||||
fn point_linear_combination(
|
||||
points: &Vec<&ecp::ECP>,
|
||||
pub fn point_linear_combination(
|
||||
points: &[ecp::ECP],
|
||||
scalars: &Vec<big::BIG>,
|
||||
) -> Result<ecp::ECP, Box<dyn Error>> {
|
||||
if points.len() != scalars.len() {
|
||||
@ -318,14 +290,7 @@ fn point_linear_combination(
|
||||
).into());
|
||||
}
|
||||
|
||||
let mut result = ecp::ECP::new();
|
||||
|
||||
for (i, point) in points.iter().enumerate() {
|
||||
let c = point.clone();
|
||||
let p = c.mul(&scalars[i]);
|
||||
|
||||
&result.add(&p);
|
||||
}
|
||||
let result = ecp::ECP::muln(points.len(), points, scalars.as_slice());
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
@ -362,7 +327,7 @@ pub fn commit_raw(
|
||||
poly.push(big::BIG::new());
|
||||
}
|
||||
match point_linear_combination(
|
||||
&bls::singleton().FFTBLS48581[&poly_size].iter().collect(),
|
||||
&bls::singleton().FFTBLS48581[&poly_size],
|
||||
&poly,
|
||||
) {
|
||||
Ok(commit) => {
|
||||
@ -398,7 +363,7 @@ pub fn prove_raw(
|
||||
subz = big::BIG::modadd(&subz, &big::BIG::modneg(&z, &big::BIG::new_ints(&rom::CURVE_ORDER)), &big::BIG::new_ints(&rom::CURVE_ORDER));
|
||||
let mut subzinv = subz.clone();
|
||||
subzinv.invmodp(&big::BIG::new_ints(&rom::CURVE_ORDER));
|
||||
let mut o = big::BIG::new_int(1);
|
||||
let o = big::BIG::new_int(1);
|
||||
let mut oinv = o.clone();
|
||||
oinv.invmodp(&big::BIG::new_ints(&rom::CURVE_ORDER));
|
||||
let divisors: Vec<big::BIG> = vec![
|
||||
@ -440,7 +405,7 @@ pub fn prove_raw(
|
||||
}
|
||||
|
||||
match point_linear_combination(
|
||||
&bls::singleton().CeremonyBLS48581G1[..(poly_size as usize - 1)].iter().collect(),
|
||||
&bls::singleton().CeremonyBLS48581G1[..(poly_size as usize - 1)],
|
||||
&out,
|
||||
) {
|
||||
Ok(proof) => {
|
||||
@ -471,7 +436,29 @@ pub fn verify_raw(
|
||||
let y = big::BIG::frombytes(data);
|
||||
|
||||
let c = ecp::ECP::frombytes(commit);
|
||||
if c.is_infinity() || c.equals(&ecp::ECP::generator()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let p = ecp::ECP::frombytes(proof);
|
||||
if p.is_infinity() || p.equals(&ecp::ECP::generator()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if poly_size > 1024 {
|
||||
let mut xc = c.clone();
|
||||
xc.sub(&bls::singleton().FFTBLS48581[&poly_size][index as usize].clone().mul(&y));
|
||||
let mut check = c.clone();
|
||||
check.neg();
|
||||
let yp = &bls::singleton().CeremonyBLS48581G2[1].clone().mul(&y);
|
||||
let mut r = pair8::initmp();
|
||||
pair8::another(&mut r, &bls::singleton().CeremonyBLS48581G2[1], &check);
|
||||
pair8::another(&mut r, &yp, &bls::singleton().FFTBLS48581[&poly_size][index as usize]);
|
||||
pair8::another(&mut r, &bls::singleton().CeremonyBLS48581G2[1], &xc);
|
||||
let mut v = pair8::miller(&mut r);
|
||||
v = pair8::fexp(&v);
|
||||
return v.isunity();
|
||||
}
|
||||
|
||||
return verify(
|
||||
&c,
|
||||
@ -484,3 +471,28 @@ pub fn verify_raw(
|
||||
pub fn init() {
|
||||
bls::singleton();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ecp::ECP;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn fft_matches_fft_g1_when_raised() {
|
||||
init();
|
||||
let mut rand = rand::RAND::new();
|
||||
let mut v = vec![big::BIG::new(); 16];
|
||||
let mut vp = vec![ECP::new(); 16];
|
||||
for i in 0..16 {
|
||||
v[i] = big::BIG::random(&mut rand);
|
||||
vp[i] = ECP::generator().mul(&v[i]);
|
||||
}
|
||||
let scalars = fft(v.as_slice(), 16, false).unwrap();
|
||||
let points = fft_g1(vp.as_slice(), 16, false).unwrap();
|
||||
for (i, s) in scalars.iter().enumerate() {
|
||||
let sp = ECP::generator().mul(&s);
|
||||
assert!(points[i].equals(&sp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
7
crates/channel/Cargo.lock
generated
Normal file
7
crates/channel/Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "channel"
|
||||
version = "0.1.0"
|
34
crates/channel/Cargo.toml
Normal file
34
crates/channel/Cargo.toml
Normal file
@ -0,0 +1,34 @@
|
||||
[package]
|
||||
name = "channel"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib", "staticlib"]
|
||||
name = "channel"
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.22.1"
|
||||
hex = "0.4.3"
|
||||
serde_json = "1.0.117"
|
||||
ed448-goldilocks-plus = "0.11.2"
|
||||
rand = "0.8.5"
|
||||
sha2 = "0.10.8"
|
||||
hkdf = "0.12.4"
|
||||
aes-gcm = "0.10.3"
|
||||
thiserror = "1.0.63"
|
||||
hmac = "0.12.1"
|
||||
serde = "1.0.208"
|
||||
lazy_static = "1.5.0"
|
||||
uniffi = { version= "0.25", features = ["cli"]}
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.4", features = ["html_reports"] }
|
||||
rand = "0.8.5"
|
||||
|
||||
[build-dependencies]
|
||||
uniffi = { version = "0.25", features = [ "build" ] }
|
||||
|
||||
[[bench]]
|
||||
name = "bench_channel"
|
||||
harness = false
|
9
crates/channel/benches/bench_channel.rs
Normal file
9
crates/channel/benches/bench_channel.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use rand::Rng;
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
|
||||
}
|
||||
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
criterion_main!(benches);
|
5
crates/channel/build.rs
Normal file
5
crates/channel/build.rs
Normal file
@ -0,0 +1,5 @@
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
uniffi::generate_scaffolding("src/lib.udl").expect("uniffi generation failed");
|
||||
}
|
991
crates/channel/src/lib.rs
Normal file
991
crates/channel/src/lib.rs
Normal file
@ -0,0 +1,991 @@
|
||||
use base64::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use ed448_goldilocks_plus::{elliptic_curve::group::GroupEncoding, EdwardsPoint, Scalar};
|
||||
use protocols::{doubleratchet::{DoubleRatchetParticipant, P2PChannelEnvelope}, tripleratchet::{PeerInfo, TripleRatchetParticipant}};
|
||||
|
||||
pub(crate) mod protocols;
|
||||
|
||||
pub struct DoubleRatchetStateAndEnvelope {
|
||||
pub ratchet_state: String,
|
||||
pub envelope: String,
|
||||
}
|
||||
|
||||
pub struct DoubleRatchetStateAndMessage {
|
||||
pub ratchet_state: String,
|
||||
pub message: Vec<u8>,
|
||||
}
|
||||
|
||||
pub struct TripleRatchetStateAndMetadata {
|
||||
pub ratchet_state: String,
|
||||
pub metadata: HashMap<String, String>,
|
||||
}
|
||||
|
||||
pub struct TripleRatchetStateAndEnvelope {
|
||||
pub ratchet_state: String,
|
||||
pub envelope: String,
|
||||
}
|
||||
|
||||
pub struct TripleRatchetStateAndMessage {
|
||||
pub ratchet_state: String,
|
||||
pub message: Vec<u8>,
|
||||
}
|
||||
|
||||
pub fn new_double_ratchet(session_key: &Vec<u8>, sending_header_key: &Vec<u8>, next_receiving_header_key: &Vec<u8>, is_sender: bool, sending_ephemeral_private_key: &Vec<u8>, receiving_ephemeral_key: &Vec<u8>) -> String {
|
||||
if sending_ephemeral_private_key.len() != 56 {
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
if receiving_ephemeral_key.len() != 57 {
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
let mut sending_ephemeral_private_key_bytes = [0u8; 56];
|
||||
sending_ephemeral_private_key_bytes.copy_from_slice(&sending_ephemeral_private_key);
|
||||
|
||||
let mut receiving_ephemeral_key_bytes = [0u8; 57];
|
||||
receiving_ephemeral_key_bytes.copy_from_slice(&receiving_ephemeral_key);
|
||||
|
||||
let sending_key = Scalar::from_bytes(&sending_ephemeral_private_key_bytes.into());
|
||||
let receiving_key = EdwardsPoint::from_bytes(&receiving_ephemeral_key_bytes.into()).into_option();
|
||||
if receiving_key.is_none() {
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
let participant = DoubleRatchetParticipant::new(
|
||||
&session_key,
|
||||
&sending_header_key,
|
||||
&next_receiving_header_key,
|
||||
true,
|
||||
sending_key,
|
||||
receiving_key.unwrap(),
|
||||
);
|
||||
|
||||
if participant.is_err() {
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
let json = participant.unwrap().to_json();
|
||||
if json.is_err() {
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
return json.unwrap();
|
||||
}
|
||||
|
||||
pub fn double_ratchet_encrypt(ratchet_state_and_message: DoubleRatchetStateAndMessage) -> DoubleRatchetStateAndEnvelope {
|
||||
let ratchet_state = ratchet_state_and_message.ratchet_state.clone();
|
||||
let participant = DoubleRatchetParticipant::from_json(ratchet_state.clone());
|
||||
|
||||
if participant.is_err() {
|
||||
return DoubleRatchetStateAndEnvelope{
|
||||
ratchet_state: ratchet_state,
|
||||
envelope: "".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
let mut dr = participant.unwrap();
|
||||
let envelope = dr.ratchet_encrypt(&ratchet_state_and_message.message);
|
||||
|
||||
if envelope.is_err() {
|
||||
return DoubleRatchetStateAndEnvelope{
|
||||
ratchet_state: ratchet_state,
|
||||
envelope: "".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
let participant_json = dr.to_json();
|
||||
if participant_json.is_err() {
|
||||
return DoubleRatchetStateAndEnvelope{
|
||||
ratchet_state: ratchet_state,
|
||||
envelope: "".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
let envelope_json = envelope.unwrap().to_json();
|
||||
if envelope_json.is_err() {
|
||||
return DoubleRatchetStateAndEnvelope{
|
||||
ratchet_state: ratchet_state,
|
||||
envelope: "".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
return DoubleRatchetStateAndEnvelope{
|
||||
ratchet_state: participant_json.unwrap(),
|
||||
envelope: envelope_json.unwrap(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn double_ratchet_decrypt(ratchet_state_and_envelope: DoubleRatchetStateAndEnvelope) -> DoubleRatchetStateAndMessage {
|
||||
let ratchet_state = ratchet_state_and_envelope.ratchet_state.clone();
|
||||
let participant = DoubleRatchetParticipant::from_json(ratchet_state.clone());
|
||||
let envelope = P2PChannelEnvelope::from_json(ratchet_state_and_envelope.envelope);
|
||||
|
||||
if participant.is_err() || envelope.is_err() {
|
||||
return DoubleRatchetStateAndMessage{
|
||||
ratchet_state: ratchet_state,
|
||||
message: vec![],
|
||||
};
|
||||
}
|
||||
|
||||
let mut dr = participant.unwrap();
|
||||
let message = dr.ratchet_decrypt(&envelope.unwrap());
|
||||
|
||||
if message.is_err() {
|
||||
return DoubleRatchetStateAndMessage{
|
||||
ratchet_state: ratchet_state,
|
||||
message: vec![],
|
||||
};
|
||||
}
|
||||
|
||||
let participant_json = dr.to_json();
|
||||
if participant_json.is_err() {
|
||||
return DoubleRatchetStateAndMessage{
|
||||
ratchet_state: ratchet_state,
|
||||
message: vec![],
|
||||
};
|
||||
}
|
||||
|
||||
return DoubleRatchetStateAndMessage{
|
||||
ratchet_state: participant_json.unwrap(),
|
||||
message: message.unwrap(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn new_triple_ratchet(peers: &Vec<Vec<u8>>, peer_key: &Vec<u8>, identity_key: &Vec<u8>, signed_pre_key: &Vec<u8>, threshold: u64, async_dkg_ratchet: bool) -> TripleRatchetStateAndMetadata {
|
||||
if peer_key.len() != 56 {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: "".to_string(),
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
if identity_key.len() != 56 {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: "".to_string(),
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
if signed_pre_key.len() != 56 {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: "".to_string(),
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
if peers.len() < 3 {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: "".to_string(),
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
if threshold > peers.len() as u64 {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: "".to_string(),
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
let mut peer_key_bytes = [0u8; 56];
|
||||
peer_key_bytes.copy_from_slice(&peer_key);
|
||||
|
||||
let mut identity_key_bytes = [0u8; 56];
|
||||
identity_key_bytes.copy_from_slice(&identity_key);
|
||||
|
||||
let mut signed_pre_key_bytes = [0u8; 56];
|
||||
signed_pre_key_bytes.copy_from_slice(&signed_pre_key);
|
||||
|
||||
let peer_key_scalar = Scalar::from_bytes(&peer_key_bytes.into());
|
||||
let identity_key_scalar = Scalar::from_bytes(&identity_key_bytes.into());
|
||||
let signed_pre_key_scalar = Scalar::from_bytes(&signed_pre_key_bytes.into());
|
||||
let mut peerinfos = Vec::<PeerInfo>::new();
|
||||
for pk in peers.iter() {
|
||||
if pk.len() != 171 {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: "".to_string(),
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
peerinfos.push(PeerInfo{
|
||||
public_key: pk[..57].into(),
|
||||
identity_public_key: pk[57..114].into(),
|
||||
signed_pre_public_key: pk[114..].into(),
|
||||
});
|
||||
}
|
||||
|
||||
let participant = TripleRatchetParticipant::new(
|
||||
&peerinfos,
|
||||
peer_key_scalar,
|
||||
identity_key_scalar,
|
||||
signed_pre_key_scalar,
|
||||
threshold as usize,
|
||||
async_dkg_ratchet,
|
||||
);
|
||||
|
||||
if participant.is_err() {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: "".to_string(),
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
let (tr, metadata) = participant.unwrap();
|
||||
|
||||
let participant_json = tr.to_json();
|
||||
|
||||
if participant_json.is_err() {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: "".to_string(),
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
let metadata_json = match metadata_to_json(&String::from(""), metadata) {
|
||||
Ok(value) => value,
|
||||
Err(value) => return value,
|
||||
};
|
||||
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: participant_json.unwrap(),
|
||||
metadata: metadata_json,
|
||||
};
|
||||
}
|
||||
|
||||
fn metadata_to_json(ratchet_state: &String, metadata: HashMap<Vec<u8>, P2PChannelEnvelope>) -> Result<HashMap<String, String>, TripleRatchetStateAndMetadata> {
|
||||
let mut metadata_json = HashMap::<String, String>::new();
|
||||
for (k,v) in metadata {
|
||||
let env = v.to_json();
|
||||
if env.is_err() {
|
||||
return Err(TripleRatchetStateAndMetadata{
|
||||
ratchet_state: ratchet_state.to_string(),
|
||||
metadata: HashMap::new(),
|
||||
});
|
||||
}
|
||||
|
||||
metadata_json.insert(BASE64_STANDARD.encode(k), env.unwrap());
|
||||
}
|
||||
Ok(metadata_json)
|
||||
}
|
||||
|
||||
fn json_to_metadata(ratchet_state_and_metadata: TripleRatchetStateAndMetadata, ratchet_state: &String) -> Result<HashMap<Vec<u8>, P2PChannelEnvelope>, TripleRatchetStateAndMetadata> {
|
||||
let mut metadata = HashMap::<Vec<u8>, P2PChannelEnvelope>::new();
|
||||
for (k,v) in ratchet_state_and_metadata.metadata {
|
||||
let env = P2PChannelEnvelope::from_json(v);
|
||||
let kb = BASE64_STANDARD.decode(k);
|
||||
if env.is_err() || kb.is_err() {
|
||||
return Err(TripleRatchetStateAndMetadata{
|
||||
ratchet_state: ratchet_state.clone(),
|
||||
metadata: HashMap::new(),
|
||||
});
|
||||
}
|
||||
|
||||
metadata.insert(kb.unwrap(), env.unwrap());
|
||||
}
|
||||
Ok(metadata)
|
||||
}
|
||||
|
||||
pub fn triple_ratchet_init_round_1(ratchet_state_and_metadata: TripleRatchetStateAndMetadata) -> TripleRatchetStateAndMetadata {
|
||||
let ratchet_state = ratchet_state_and_metadata.ratchet_state.clone();
|
||||
let tr = TripleRatchetParticipant::from_json(&ratchet_state);
|
||||
if tr.is_err() {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: ratchet_state,
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
let metadata = match json_to_metadata(ratchet_state_and_metadata, &ratchet_state) {
|
||||
Ok(value) => value,
|
||||
Err(value) => return value,
|
||||
};
|
||||
|
||||
let mut trp = tr.unwrap();
|
||||
let result = trp.initialize(&metadata);
|
||||
if result.is_err() {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: ratchet_state,
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
let metadata = result.unwrap();
|
||||
let metadata_json = match metadata_to_json(&ratchet_state, metadata) {
|
||||
Ok(value) => value,
|
||||
Err(value) => return value,
|
||||
};
|
||||
|
||||
let json = trp.to_json();
|
||||
if json.is_err() {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: ratchet_state,
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: json.unwrap(),
|
||||
metadata: metadata_json,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn triple_ratchet_init_round_2(ratchet_state_and_metadata: TripleRatchetStateAndMetadata) -> TripleRatchetStateAndMetadata {
|
||||
let ratchet_state = ratchet_state_and_metadata.ratchet_state.clone();
|
||||
let tr = TripleRatchetParticipant::from_json(&ratchet_state);
|
||||
if tr.is_err() {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: ratchet_state,
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
let metadata = match json_to_metadata(ratchet_state_and_metadata, &ratchet_state) {
|
||||
Ok(value) => value,
|
||||
Err(value) => return value,
|
||||
};
|
||||
|
||||
let mut trp = tr.unwrap();
|
||||
let mut result = HashMap::<Vec<u8>, P2PChannelEnvelope>::new();
|
||||
for (k, v) in metadata {
|
||||
let r = trp.receive_poly_frag(&k, &v);
|
||||
if r.is_err() {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: ratchet_state,
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
let opt = r.unwrap();
|
||||
if opt.is_some() {
|
||||
result = opt.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
let metadata_json = match metadata_to_json(&ratchet_state, result) {
|
||||
Ok(value) => value,
|
||||
Err(value) => return value,
|
||||
};
|
||||
|
||||
let json = trp.to_json();
|
||||
if json.is_err() {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: ratchet_state,
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: json.unwrap(),
|
||||
metadata: metadata_json,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn triple_ratchet_init_round_3(ratchet_state_and_metadata: TripleRatchetStateAndMetadata) -> TripleRatchetStateAndMetadata {
|
||||
let ratchet_state = ratchet_state_and_metadata.ratchet_state.clone();
|
||||
let tr = TripleRatchetParticipant::from_json(&ratchet_state);
|
||||
if tr.is_err() {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: ratchet_state,
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
let metadata = match json_to_metadata(ratchet_state_and_metadata, &ratchet_state) {
|
||||
Ok(value) => value,
|
||||
Err(value) => return value,
|
||||
};
|
||||
|
||||
let mut trp = tr.unwrap();
|
||||
let mut result = HashMap::<Vec<u8>, P2PChannelEnvelope>::new();
|
||||
for (k, v) in metadata {
|
||||
let r = trp.receive_commitment(&k, &v);
|
||||
if r.is_err() {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: ratchet_state,
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
let opt = r.unwrap();
|
||||
if opt.is_some() {
|
||||
result = opt.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
let metadata_json = match metadata_to_json(&ratchet_state, result) {
|
||||
Ok(value) => value,
|
||||
Err(value) => return value,
|
||||
};
|
||||
|
||||
let json = trp.to_json();
|
||||
if json.is_err() {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: ratchet_state,
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: json.unwrap(),
|
||||
metadata: metadata_json,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn triple_ratchet_init_round_4(ratchet_state_and_metadata: TripleRatchetStateAndMetadata) -> TripleRatchetStateAndMetadata {
|
||||
let ratchet_state = ratchet_state_and_metadata.ratchet_state.clone();
|
||||
let tr = TripleRatchetParticipant::from_json(&ratchet_state);
|
||||
if tr.is_err() {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: ratchet_state,
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
let metadata = match json_to_metadata(ratchet_state_and_metadata, &ratchet_state) {
|
||||
Ok(value) => value,
|
||||
Err(value) => return value,
|
||||
};
|
||||
|
||||
let mut trp = tr.unwrap();
|
||||
let mut result = HashMap::<Vec<u8>, P2PChannelEnvelope>::new();
|
||||
for (k, v) in metadata {
|
||||
let r = trp.recombine(&k, &v);
|
||||
if r.is_err() {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: ratchet_state,
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let metadata_json = match metadata_to_json(&ratchet_state, result) {
|
||||
Ok(value) => value,
|
||||
Err(value) => return value,
|
||||
};
|
||||
|
||||
let json = trp.to_json();
|
||||
if json.is_err() {
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: ratchet_state,
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
return TripleRatchetStateAndMetadata{
|
||||
ratchet_state: json.unwrap(),
|
||||
metadata: metadata_json,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn triple_ratchet_encrypt(ratchet_state_and_message: TripleRatchetStateAndMessage) -> TripleRatchetStateAndEnvelope {
|
||||
let ratchet_state = ratchet_state_and_message.ratchet_state.clone();
|
||||
let tr = TripleRatchetParticipant::from_json(&ratchet_state);
|
||||
if tr.is_err() {
|
||||
return TripleRatchetStateAndEnvelope{
|
||||
ratchet_state: ratchet_state,
|
||||
envelope: "".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
let mut trp = tr.unwrap();
|
||||
let result = trp.ratchet_encrypt(&ratchet_state_and_message.message);
|
||||
|
||||
if result.is_err() {
|
||||
return TripleRatchetStateAndEnvelope{
|
||||
ratchet_state: ratchet_state,
|
||||
envelope: "".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
let envelope = result.unwrap();
|
||||
let envelope_json = envelope.to_json();
|
||||
|
||||
if envelope_json.is_err() {
|
||||
return TripleRatchetStateAndEnvelope{
|
||||
ratchet_state: ratchet_state,
|
||||
envelope: "".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
let json = trp.to_json();
|
||||
if json.is_err() {
|
||||
return TripleRatchetStateAndEnvelope{
|
||||
ratchet_state: ratchet_state,
|
||||
envelope: "".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
return TripleRatchetStateAndEnvelope{
|
||||
ratchet_state: json.unwrap(),
|
||||
envelope: envelope_json.unwrap(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn triple_ratchet_decrypt(ratchet_state_and_envelope: TripleRatchetStateAndEnvelope) -> TripleRatchetStateAndMessage {
|
||||
let ratchet_state = ratchet_state_and_envelope.ratchet_state.clone();
|
||||
let tr = TripleRatchetParticipant::from_json(&ratchet_state);
|
||||
if tr.is_err() {
|
||||
return TripleRatchetStateAndMessage{
|
||||
ratchet_state: ratchet_state,
|
||||
message: vec![],
|
||||
};
|
||||
}
|
||||
|
||||
let mut trp = tr.unwrap();
|
||||
let env = P2PChannelEnvelope::from_json(ratchet_state_and_envelope.envelope);
|
||||
if env.is_err() {
|
||||
return TripleRatchetStateAndMessage{
|
||||
ratchet_state: ratchet_state,
|
||||
message: vec![],
|
||||
};
|
||||
}
|
||||
|
||||
let result = trp.ratchet_decrypt(&env.unwrap());
|
||||
|
||||
if result.is_err() {
|
||||
return TripleRatchetStateAndMessage{
|
||||
ratchet_state: ratchet_state,
|
||||
message: vec![],
|
||||
};
|
||||
}
|
||||
|
||||
let message = result.unwrap().0;
|
||||
|
||||
let json = trp.to_json();
|
||||
if json.is_err() {
|
||||
return TripleRatchetStateAndMessage{
|
||||
ratchet_state: ratchet_state,
|
||||
message: vec![],
|
||||
};
|
||||
}
|
||||
|
||||
return TripleRatchetStateAndMessage{
|
||||
ratchet_state: json.unwrap(),
|
||||
message: message,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::*;
|
||||
use ed448_goldilocks_plus::{Scalar, elliptic_curve::Group, EdwardsPoint};
|
||||
use protocols::{doubleratchet::P2PChannelEnvelope, tripleratchet::{PeerInfo, TripleRatchetParticipant}};
|
||||
|
||||
#[test]
|
||||
fn test_four_party_triple_ratchet_communication() {
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut keys: Vec<(Scalar, Scalar, Scalar)> = (0..4)
|
||||
.map(|_| (Scalar::random(&mut rng), Scalar::random(&mut rng), Scalar::random(&mut rng)))
|
||||
.collect();
|
||||
|
||||
keys.sort_by(|a, b| (a.0 * EdwardsPoint::generator()).compress().to_bytes().cmp(&(b.0 * EdwardsPoint::generator()).compress().to_bytes()));
|
||||
|
||||
let mut peer_infos: Vec<PeerInfo> = keys
|
||||
.iter()
|
||||
.map(|(peer_key, identity_key, signed_pre_key)| PeerInfo {
|
||||
public_key: (peer_key * EdwardsPoint::generator()).compress().to_bytes().to_vec(),
|
||||
identity_public_key: (identity_key * EdwardsPoint::generator()).compress().to_bytes().to_vec(),
|
||||
signed_pre_public_key: (signed_pre_key * EdwardsPoint::generator()).compress().to_bytes().to_vec(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
// mirror the internal order so we can use by index:
|
||||
peer_infos.sort_by(|a, b| a.public_key.cmp(&b.public_key));
|
||||
|
||||
let mut participants: Vec<TripleRatchetParticipant> = Vec::new();
|
||||
let mut init_messages: HashMap<Vec<u8>, HashMap<Vec<u8>, P2PChannelEnvelope>> = HashMap::new();
|
||||
let mut frag_messages: HashMap<Vec<u8>, HashMap<Vec<u8>, P2PChannelEnvelope>> = HashMap::new();
|
||||
let mut commitment_messages: HashMap<Vec<u8>, HashMap<Vec<u8>, P2PChannelEnvelope>> = HashMap::new();
|
||||
let mut reveal_messages: HashMap<Vec<u8>, HashMap<Vec<u8>, P2PChannelEnvelope>> = HashMap::new();
|
||||
|
||||
for i in 0..4 {
|
||||
init_messages.insert(peer_infos[i].public_key.clone(), HashMap::new());
|
||||
frag_messages.insert(peer_infos[i].public_key.clone(), HashMap::new());
|
||||
commitment_messages.insert(peer_infos[i].public_key.clone(), HashMap::new());
|
||||
reveal_messages.insert(peer_infos[i].public_key.clone(), HashMap::new());
|
||||
}
|
||||
|
||||
for i in 0..4 {
|
||||
let other_peers: Vec<PeerInfo> = peer_infos.iter().enumerate()
|
||||
.filter(|&(j, _)| j != i)
|
||||
.map(|(_, peer)| peer.clone())
|
||||
.collect();
|
||||
|
||||
let (participant, init_msg) = TripleRatchetParticipant::new(
|
||||
&other_peers,
|
||||
keys[i].0.clone(),
|
||||
keys[i].1.clone(),
|
||||
keys[i].2.clone(),
|
||||
3,
|
||||
false,
|
||||
).unwrap();
|
||||
|
||||
participants.push(participant);
|
||||
|
||||
for (j, env) in init_msg.iter() {
|
||||
init_messages.get_mut(j).unwrap().insert(peer_infos[i].public_key.clone(), env.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Exchange initial messages and get frags:
|
||||
for i in 0..4 {
|
||||
let result = participants[i].initialize(&init_messages[&peer_infos[i].public_key.clone()]).unwrap();
|
||||
for (j, env) in result.iter() {
|
||||
frag_messages.get_mut(j).unwrap().insert(peer_infos[i].public_key.clone(), env.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Exchange frags and receive commitments once all frags have been distributed:
|
||||
for i in 0..4 {
|
||||
for (p, envelope) in frag_messages[&peer_infos[i].public_key.clone()].iter() {
|
||||
if let Some(out) = participants[i].receive_poly_frag(&p, envelope).unwrap() {
|
||||
for (j, env) in out.iter() {
|
||||
commitment_messages.get_mut(j).unwrap().insert(peer_infos[i].public_key.clone(), env.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Exchange commitments and produce reveals:
|
||||
for i in 0..4 {
|
||||
for (p, envelope) in commitment_messages[&peer_infos[i].public_key.clone()].iter() {
|
||||
if let Some(reveal_msg) = participants[i].receive_commitment(&p, envelope).unwrap() {
|
||||
for (j, env) in reveal_msg.iter() {
|
||||
reveal_messages.get_mut(j).unwrap().insert(peer_infos[i].public_key.clone(), env.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect reveals and confirm zkpoks are valid, produce group key:
|
||||
for i in 0..4 {
|
||||
for (j, env) in reveal_messages[&peer_infos[i].public_key.clone()].iter() {
|
||||
participants[i].recombine(j, &env.clone()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Test sending and receiving messages
|
||||
let test_messages = [
|
||||
"hello there",
|
||||
"general kenobi",
|
||||
"you are a bold one",
|
||||
"*mechanical laughter*",
|
||||
];
|
||||
|
||||
for (i, message) in test_messages.iter().enumerate() {
|
||||
let encrypted = participants[i].ratchet_encrypt(message.as_bytes()).unwrap();
|
||||
for j in 0..4 {
|
||||
if i != j {
|
||||
let decrypted = participants[j].ratchet_decrypt(&encrypted).unwrap();
|
||||
assert_eq!(message.as_bytes(), decrypted.0.as_slice(), "Message decryption failed for Participant {}", j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _ in 0..5 {
|
||||
for i in 0..4 {
|
||||
let message1 = format!("test 1 {}", i + 1);
|
||||
let message2 = format!("test 2 {}", i + 1);
|
||||
let encrypted1 = participants[i].ratchet_encrypt(message1.as_bytes()).unwrap();
|
||||
let encrypted2 = participants[i].ratchet_encrypt(message2.as_bytes()).unwrap();
|
||||
|
||||
for j in 0..4 {
|
||||
if i != j {
|
||||
let decrypted1 = participants[j].ratchet_decrypt(&encrypted1).unwrap();
|
||||
assert_eq!(message1.as_bytes(), decrypted1.0.as_slice(), "Round message decryption failed for Participant {}", j);
|
||||
let decrypted2 = participants[j].ratchet_decrypt(&encrypted2).unwrap();
|
||||
assert_eq!(message2.as_bytes(), decrypted2.0.as_slice(), "Round message decryption failed for Participant {}", j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_four_party_triple_ratchet_communication_with_serialization_each_step() {
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut keys: Vec<(Scalar, Scalar, Scalar)> = (0..4)
|
||||
.map(|_| (Scalar::random(&mut rng), Scalar::random(&mut rng), Scalar::random(&mut rng)))
|
||||
.collect();
|
||||
|
||||
keys.sort_by(|a, b| (a.0 * EdwardsPoint::generator()).compress().to_bytes().cmp(&(b.0 * EdwardsPoint::generator()).compress().to_bytes()));
|
||||
|
||||
let mut peer_infos: Vec<PeerInfo> = keys
|
||||
.iter()
|
||||
.map(|(peer_key, identity_key, signed_pre_key)| PeerInfo {
|
||||
public_key: (peer_key * EdwardsPoint::generator()).compress().to_bytes().to_vec(),
|
||||
identity_public_key: (identity_key * EdwardsPoint::generator()).compress().to_bytes().to_vec(),
|
||||
signed_pre_public_key: (signed_pre_key * EdwardsPoint::generator()).compress().to_bytes().to_vec(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
// mirror the internal order so we can use by index:
|
||||
peer_infos.sort_by(|a, b| a.public_key.cmp(&b.public_key));
|
||||
|
||||
let mut participants: Vec<TripleRatchetParticipant> = Vec::new();
|
||||
let mut init_messages: HashMap<Vec<u8>, HashMap<Vec<u8>, P2PChannelEnvelope>> = HashMap::new();
|
||||
let mut frag_messages: HashMap<Vec<u8>, HashMap<Vec<u8>, P2PChannelEnvelope>> = HashMap::new();
|
||||
let mut commitment_messages: HashMap<Vec<u8>, HashMap<Vec<u8>, P2PChannelEnvelope>> = HashMap::new();
|
||||
let mut reveal_messages: HashMap<Vec<u8>, HashMap<Vec<u8>, P2PChannelEnvelope>> = HashMap::new();
|
||||
|
||||
for i in 0..4 {
|
||||
init_messages.insert(peer_infos[i].public_key.clone(), HashMap::new());
|
||||
frag_messages.insert(peer_infos[i].public_key.clone(), HashMap::new());
|
||||
commitment_messages.insert(peer_infos[i].public_key.clone(), HashMap::new());
|
||||
reveal_messages.insert(peer_infos[i].public_key.clone(), HashMap::new());
|
||||
}
|
||||
|
||||
for i in 0..4 {
|
||||
let other_peers: Vec<PeerInfo> = peer_infos.iter().enumerate()
|
||||
.filter(|&(j, _)| j != i)
|
||||
.map(|(_, peer)| peer.clone())
|
||||
.collect();
|
||||
|
||||
let (participant, init_msg) = TripleRatchetParticipant::new(
|
||||
&other_peers,
|
||||
keys[i].0.clone(),
|
||||
keys[i].1.clone(),
|
||||
keys[i].2.clone(),
|
||||
3,
|
||||
false,
|
||||
).unwrap();
|
||||
|
||||
for (j, env) in init_msg.iter() {
|
||||
init_messages.get_mut(j).unwrap().insert(peer_infos[i].public_key.clone(), env.clone());
|
||||
}
|
||||
|
||||
let participant_json = participant.to_json();
|
||||
if participant_json.is_err() {
|
||||
panic!("bad json");
|
||||
}
|
||||
participants.push(TripleRatchetParticipant::from_json(&participant_json.unwrap()).unwrap());
|
||||
}
|
||||
|
||||
// Exchange initial messages and get frags:
|
||||
for i in 0..4 {
|
||||
let result = participants[i].initialize(&init_messages[&peer_infos[i].public_key.clone()]).unwrap();
|
||||
for (j, env) in result.iter() {
|
||||
frag_messages.get_mut(j).unwrap().insert(peer_infos[i].public_key.clone(), env.clone());
|
||||
}
|
||||
|
||||
let participant_json = participants[i].to_json();
|
||||
participants[i] = TripleRatchetParticipant::from_json(&participant_json.unwrap()).unwrap();
|
||||
}
|
||||
|
||||
// Exchange frags and receive commitments once all frags have been distributed:
|
||||
for i in 0..4 {
|
||||
for (p, envelope) in frag_messages[&peer_infos[i].public_key.clone()].iter() {
|
||||
if let Some(out) = participants[i].receive_poly_frag(&p, envelope).unwrap() {
|
||||
for (j, env) in out.iter() {
|
||||
commitment_messages.get_mut(j).unwrap().insert(peer_infos[i].public_key.clone(), env.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let participant_json = participants[i].to_json();
|
||||
participants[i] = TripleRatchetParticipant::from_json(&participant_json.unwrap()).unwrap();
|
||||
}
|
||||
|
||||
// Exchange commitments and produce reveals:
|
||||
for i in 0..4 {
|
||||
for (p, envelope) in commitment_messages[&peer_infos[i].public_key.clone()].iter() {
|
||||
if let Some(reveal_msg) = participants[i].receive_commitment(&p, envelope).unwrap() {
|
||||
for (j, env) in reveal_msg.iter() {
|
||||
reveal_messages.get_mut(j).unwrap().insert(peer_infos[i].public_key.clone(), env.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let participant_json = participants[i].to_json();
|
||||
participants[i] = TripleRatchetParticipant::from_json(&participant_json.unwrap()).unwrap();
|
||||
}
|
||||
|
||||
// Collect reveals and confirm zkpoks are valid, produce group key:
|
||||
for i in 0..4 {
|
||||
for (j, env) in reveal_messages[&peer_infos[i].public_key.clone()].iter() {
|
||||
participants[i].recombine(j, &env.clone()).unwrap();
|
||||
|
||||
let participant_json = participants[i].to_json();
|
||||
participants[i] = TripleRatchetParticipant::from_json(&participant_json.unwrap()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Test sending and receiving messages
|
||||
let test_messages = [
|
||||
"hello there",
|
||||
"general kenobi",
|
||||
"you are a bold one",
|
||||
"*mechanical laughter*",
|
||||
];
|
||||
|
||||
for (i, message) in test_messages.iter().enumerate() {
|
||||
let encrypted = participants[i].ratchet_encrypt(message.as_bytes()).unwrap();
|
||||
for j in 0..4 {
|
||||
if i != j {
|
||||
let decrypted = participants[j].ratchet_decrypt(&encrypted).unwrap();
|
||||
assert_eq!(message.as_bytes(), decrypted.0.as_slice(), "Message decryption failed for Participant {}", j);
|
||||
}
|
||||
}
|
||||
|
||||
let participant_json = participants[i].to_json();
|
||||
participants[i] = TripleRatchetParticipant::from_json(&participant_json.unwrap()).unwrap();
|
||||
}
|
||||
|
||||
for _ in 0..5 {
|
||||
for i in 0..4 {
|
||||
let message1 = format!("test 1 {}", i + 1);
|
||||
let message2 = format!("test 2 {}", i + 1);
|
||||
let encrypted1 = participants[i].ratchet_encrypt(message1.as_bytes()).unwrap();
|
||||
let encrypted2 = participants[i].ratchet_encrypt(message2.as_bytes()).unwrap();
|
||||
|
||||
for j in 0..4 {
|
||||
if i != j {
|
||||
let decrypted1 = participants[j].ratchet_decrypt(&encrypted1).unwrap();
|
||||
assert_eq!(message1.as_bytes(), decrypted1.0.as_slice(), "Round message decryption failed for Participant {}", j);
|
||||
let decrypted2 = participants[j].ratchet_decrypt(&encrypted2).unwrap();
|
||||
assert_eq!(message2.as_bytes(), decrypted2.0.as_slice(), "Round message decryption failed for Participant {}", j);
|
||||
}
|
||||
}
|
||||
|
||||
let participant_json = participants[i].to_json();
|
||||
participants[i] = TripleRatchetParticipant::from_json(&participant_json.unwrap()).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_four_party_async_triple_ratchet_communication() {
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut keys: Vec<(Scalar, Scalar, Scalar)> = (0..4)
|
||||
.map(|_| (Scalar::random(&mut rng), Scalar::random(&mut rng), Scalar::random(&mut rng)))
|
||||
.collect();
|
||||
|
||||
keys.sort_by(|a, b| (a.0 * EdwardsPoint::generator()).compress().to_bytes().cmp(&(b.0 * EdwardsPoint::generator()).compress().to_bytes()));
|
||||
|
||||
let mut peer_infos: Vec<PeerInfo> = keys
|
||||
.iter()
|
||||
.map(|(peer_key, identity_key, signed_pre_key)| PeerInfo {
|
||||
public_key: (peer_key * EdwardsPoint::generator()).compress().to_bytes().to_vec(),
|
||||
identity_public_key: (identity_key * EdwardsPoint::generator()).compress().to_bytes().to_vec(),
|
||||
signed_pre_public_key: (signed_pre_key * EdwardsPoint::generator()).compress().to_bytes().to_vec(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
// mirror the internal order so we can use by index:
|
||||
peer_infos.sort_by(|a, b| a.public_key.cmp(&b.public_key));
|
||||
|
||||
let mut participants: Vec<TripleRatchetParticipant> = Vec::new();
|
||||
let mut init_messages: HashMap<Vec<u8>, HashMap<Vec<u8>, P2PChannelEnvelope>> = HashMap::new();
|
||||
let mut frag_messages: HashMap<Vec<u8>, HashMap<Vec<u8>, P2PChannelEnvelope>> = HashMap::new();
|
||||
let mut commitment_messages: HashMap<Vec<u8>, HashMap<Vec<u8>, P2PChannelEnvelope>> = HashMap::new();
|
||||
let mut reveal_messages: HashMap<Vec<u8>, HashMap<Vec<u8>, P2PChannelEnvelope>> = HashMap::new();
|
||||
|
||||
for i in 0..4 {
|
||||
init_messages.insert(peer_infos[i].public_key.clone(), HashMap::new());
|
||||
frag_messages.insert(peer_infos[i].public_key.clone(), HashMap::new());
|
||||
commitment_messages.insert(peer_infos[i].public_key.clone(), HashMap::new());
|
||||
reveal_messages.insert(peer_infos[i].public_key.clone(), HashMap::new());
|
||||
}
|
||||
|
||||
for i in 0..4 {
|
||||
let other_peers: Vec<PeerInfo> = peer_infos.iter().enumerate()
|
||||
.filter(|&(j, _)| j != i)
|
||||
.map(|(_, peer)| peer.clone())
|
||||
.collect();
|
||||
|
||||
let (participant, init_msg) = TripleRatchetParticipant::new(
|
||||
&other_peers,
|
||||
keys[i].0.clone(),
|
||||
keys[i].1.clone(),
|
||||
keys[i].2.clone(),
|
||||
2,
|
||||
true,
|
||||
).unwrap();
|
||||
|
||||
participants.push(participant);
|
||||
|
||||
for (j, env) in init_msg.iter() {
|
||||
init_messages.get_mut(j).unwrap().insert(peer_infos[i].public_key.clone(), env.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Exchange initial messages and get frags:
|
||||
for i in 0..4 {
|
||||
let result = participants[i].initialize(&init_messages[&peer_infos[i].public_key.clone()]).unwrap();
|
||||
for (j, env) in result.iter() {
|
||||
frag_messages.get_mut(j).unwrap().insert(peer_infos[i].public_key.clone(), env.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Exchange frags and receive commitments once all frags have been distributed:
|
||||
for i in 0..4 {
|
||||
for (p, envelope) in frag_messages[&peer_infos[i].public_key.clone()].iter() {
|
||||
if let Some(out) = participants[i].receive_poly_frag(&p, envelope).unwrap() {
|
||||
for (j, env) in out.iter() {
|
||||
commitment_messages.get_mut(j).unwrap().insert(peer_infos[i].public_key.clone(), env.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Exchange commitments and produce reveals:
|
||||
for i in 0..4 {
|
||||
for (p, envelope) in commitment_messages[&peer_infos[i].public_key.clone()].iter() {
|
||||
if let Some(reveal_msg) = participants[i].receive_commitment(&p, envelope).unwrap() {
|
||||
for (j, env) in reveal_msg.iter() {
|
||||
reveal_messages.get_mut(j).unwrap().insert(peer_infos[i].public_key.clone(), env.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect reveals and confirm zkpoks are valid, produce group key:
|
||||
for i in 0..4 {
|
||||
for (j, env) in reveal_messages[&peer_infos[i].public_key.clone()].iter() {
|
||||
participants[i].recombine(j, &env.clone()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Test sending and receiving messages
|
||||
let test_messages = [
|
||||
"hello there",
|
||||
"general kenobi",
|
||||
"you are a bold one",
|
||||
"*mechanical laughter*",
|
||||
];
|
||||
|
||||
for (i, message) in test_messages.iter().enumerate() {
|
||||
let encrypted = participants[i].ratchet_encrypt(message.as_bytes()).unwrap();
|
||||
for j in 0..4 {
|
||||
if i != j {
|
||||
let decrypted = participants[j].ratchet_decrypt(&encrypted).unwrap();
|
||||
assert_eq!(message.as_bytes(), decrypted.0.as_slice(), "Message decryption failed for Participant {}", j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _ in 0..5 {
|
||||
for i in 0..4 {
|
||||
let message1 = format!("test 1 {}", i + 1);
|
||||
let message2 = format!("test 2 {}", i + 1);
|
||||
let encrypted1 = participants[i].ratchet_encrypt(message1.as_bytes()).unwrap();
|
||||
let encrypted2 = participants[i].ratchet_encrypt(message2.as_bytes()).unwrap();
|
||||
|
||||
for j in 0..4 {
|
||||
if i != j {
|
||||
let decrypted1 = participants[j].ratchet_decrypt(&encrypted1).unwrap();
|
||||
assert_eq!(message1.as_bytes(), decrypted1.0.as_slice(), "Round message decryption failed for Participant {}", j);
|
||||
let decrypted2 = participants[j].ratchet_decrypt(&encrypted2).unwrap();
|
||||
assert_eq!(message2.as_bytes(), decrypted2.0.as_slice(), "Round message decryption failed for Participant {}", j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
38
crates/channel/src/lib.udl
Normal file
38
crates/channel/src/lib.udl
Normal file
@ -0,0 +1,38 @@
|
||||
namespace channel {
|
||||
string new_double_ratchet([ByRef] sequence<u8> session_key, [ByRef] sequence<u8> sending_header_key, [ByRef] sequence<u8> next_receiving_header_key, boolean is_sender, [ByRef] sequence<u8> sending_ephemeral_private_key, [ByRef] sequence<u8> receiving_ephemeral_key);
|
||||
DoubleRatchetStateAndEnvelope double_ratchet_encrypt(DoubleRatchetStateAndMessage ratchet_state_and_message);
|
||||
DoubleRatchetStateAndMessage double_ratchet_decrypt(DoubleRatchetStateAndEnvelope ratchet_state_and_envelope);
|
||||
|
||||
TripleRatchetStateAndMetadata new_triple_ratchet([ByRef] sequence<sequence<u8>> peers, [ByRef] sequence<u8> peer_key, [ByRef] sequence<u8> identity_key, [ByRef] sequence<u8> signed_pre_key, u64 threshold, boolean async_dkg_ratchet);
|
||||
TripleRatchetStateAndMetadata triple_ratchet_init_round_1(TripleRatchetStateAndMetadata ratchet_state_and_metadata);
|
||||
TripleRatchetStateAndMetadata triple_ratchet_init_round_2(TripleRatchetStateAndMetadata ratchet_state_and_metadata);
|
||||
TripleRatchetStateAndMetadata triple_ratchet_init_round_3(TripleRatchetStateAndMetadata ratchet_state_and_metadata);
|
||||
TripleRatchetStateAndMetadata triple_ratchet_init_round_4(TripleRatchetStateAndMetadata ratchet_state_and_metadata);
|
||||
TripleRatchetStateAndEnvelope triple_ratchet_encrypt(TripleRatchetStateAndMessage ratchet_state_and_message);
|
||||
TripleRatchetStateAndMessage triple_ratchet_decrypt(TripleRatchetStateAndEnvelope ratchet_state_and_envelope);
|
||||
};
|
||||
|
||||
dictionary DoubleRatchetStateAndEnvelope {
|
||||
string ratchet_state;
|
||||
string envelope;
|
||||
};
|
||||
|
||||
dictionary DoubleRatchetStateAndMessage {
|
||||
string ratchet_state;
|
||||
sequence<u8> message;
|
||||
};
|
||||
|
||||
dictionary TripleRatchetStateAndMetadata {
|
||||
string ratchet_state;
|
||||
record<string, string> metadata;
|
||||
};
|
||||
|
||||
dictionary TripleRatchetStateAndEnvelope {
|
||||
string ratchet_state;
|
||||
string envelope;
|
||||
};
|
||||
|
||||
dictionary TripleRatchetStateAndMessage {
|
||||
string ratchet_state;
|
||||
sequence<u8> message;
|
||||
};
|
622
crates/channel/src/protocols/doubleratchet.rs
Normal file
622
crates/channel/src/protocols/doubleratchet.rs
Normal file
@ -0,0 +1,622 @@
|
||||
use base64::prelude::*;
|
||||
use ed448_goldilocks_plus::elliptic_curve::group::GroupEncoding;
|
||||
use ed448_goldilocks_plus::elliptic_curve::ops::MulByGenerator;
|
||||
use ed448_goldilocks_plus::{subtle, CompressedEdwardsY, EdwardsPoint, Scalar};
|
||||
use rand::rngs::OsRng;
|
||||
use rand::RngCore;
|
||||
use sha2::Sha512;
|
||||
use hkdf::Hkdf;
|
||||
use aes_gcm::{Aes256Gcm, Nonce};
|
||||
use aes_gcm::aead::{Aead, Payload};
|
||||
use std::collections::HashMap;
|
||||
use std::error;
|
||||
use subtle::ConstantTimeEq;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
const DOUBLE_RATCHET_PROTOCOL_VERSION: u16 = 1;
|
||||
const DOUBLE_RATCHET_PROTOCOL: u16 = 1 << 8 + DOUBLE_RATCHET_PROTOCOL_VERSION;
|
||||
|
||||
const CHAIN_KEY: u8 = 0x01;
|
||||
const MESSAGE_KEY: u8 = 0x02;
|
||||
const AEAD_KEY: u8 = 0x03;
|
||||
|
||||
pub struct DoubleRatchetParticipant {
|
||||
sending_ephemeral_private_key: Scalar,
|
||||
receiving_ephemeral_key: EdwardsPoint,
|
||||
root_key: Vec<u8>,
|
||||
sending_chain_key: Vec<u8>,
|
||||
current_sending_header_key: Vec<u8>,
|
||||
current_receiving_header_key: Vec<u8>,
|
||||
next_sending_header_key: Vec<u8>,
|
||||
next_receiving_header_key: Vec<u8>,
|
||||
receiving_chain_key: Vec<u8>,
|
||||
current_sending_chain_length: u32,
|
||||
previous_sending_chain_length: u32,
|
||||
current_receiving_chain_length: u32,
|
||||
previous_receiving_chain_length: u32,
|
||||
skipped_keys_map: HashMap<Vec<u8>, HashMap<u32, Vec<u8>>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct DoubleRatchetParticipantJson {
|
||||
pub sending_ephemeral_private_key: String,
|
||||
pub receiving_ephemeral_key: String,
|
||||
pub root_key: String,
|
||||
pub sending_chain_key: String,
|
||||
pub current_sending_header_key: String,
|
||||
pub current_receiving_header_key: String,
|
||||
pub next_sending_header_key: String,
|
||||
pub next_receiving_header_key: String,
|
||||
pub receiving_chain_key: String,
|
||||
pub current_sending_chain_length: u32,
|
||||
pub previous_sending_chain_length: u32,
|
||||
pub current_receiving_chain_length: u32,
|
||||
pub previous_receiving_chain_length: u32,
|
||||
pub skipped_keys_map: HashMap<String, HashMap<u32, String>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MessageCiphertext {
|
||||
pub ciphertext: Vec<u8>,
|
||||
pub initialization_vector: Vec<u8>,
|
||||
pub associated_data: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct P2PChannelEnvelope {
|
||||
pub protocol_identifier: u16,
|
||||
pub message_header: MessageCiphertext,
|
||||
pub message_body: MessageCiphertext,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct P2PChannelEnvelopeJson {
|
||||
pub protocol_identifier: u16,
|
||||
pub message_header: MessageCiphertextJson,
|
||||
pub message_body: MessageCiphertextJson,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct MessageCiphertextJson {
|
||||
pub ciphertext: String,
|
||||
pub initialization_vector: String,
|
||||
pub associated_data: Option<String>,
|
||||
}
|
||||
|
||||
impl P2PChannelEnvelope {
|
||||
pub fn to_json(&self) -> Result<String, serde_json::Error> {
|
||||
let envelope = P2PChannelEnvelopeJson{
|
||||
protocol_identifier: self.protocol_identifier,
|
||||
message_header: MessageCiphertextJson{
|
||||
ciphertext: BASE64_STANDARD.encode(&self.message_header.ciphertext),
|
||||
initialization_vector: BASE64_STANDARD.encode(&self.message_header.initialization_vector),
|
||||
associated_data: self.message_header.associated_data.clone().map(|a| BASE64_STANDARD.encode(a)),
|
||||
},
|
||||
message_body: MessageCiphertextJson{
|
||||
ciphertext: BASE64_STANDARD.encode(&self.message_body.ciphertext),
|
||||
initialization_vector: BASE64_STANDARD.encode(&self.message_body.initialization_vector),
|
||||
associated_data: self.message_body.associated_data.clone().map(|a| BASE64_STANDARD.encode(a)),
|
||||
},
|
||||
};
|
||||
|
||||
serde_json::to_string(&envelope)
|
||||
}
|
||||
|
||||
pub fn from_json(envelope_json: String) -> Result<P2PChannelEnvelope, Box<dyn std::error::Error>> {
|
||||
let envelope: Result<P2PChannelEnvelopeJson, serde_json::Error> = serde_json::from_str(&envelope_json);
|
||||
if envelope.is_err() {
|
||||
return Err(Box::new(envelope.unwrap_err()));
|
||||
}
|
||||
|
||||
let e = envelope.unwrap();
|
||||
let header_ciphertext = BASE64_STANDARD.decode(e.message_header.ciphertext)?;
|
||||
let header_initialization_vector = BASE64_STANDARD.decode(e.message_header.initialization_vector)?;
|
||||
let header_associated_data = e.message_header.associated_data.map(|a| BASE64_STANDARD.decode(a)).transpose()?;
|
||||
let ciphertext = BASE64_STANDARD.decode(e.message_body.ciphertext)?;
|
||||
let initialization_vector = BASE64_STANDARD.decode(e.message_body.initialization_vector)?;
|
||||
let associated_data = e.message_body.associated_data.map(|a| BASE64_STANDARD.decode(a)).transpose()?;
|
||||
|
||||
Ok(P2PChannelEnvelope{
|
||||
protocol_identifier: e.protocol_identifier,
|
||||
message_header: MessageCiphertext{
|
||||
ciphertext: header_ciphertext,
|
||||
initialization_vector: header_initialization_vector,
|
||||
associated_data: header_associated_data,
|
||||
},
|
||||
message_body: MessageCiphertext{
|
||||
ciphertext: ciphertext,
|
||||
initialization_vector: initialization_vector,
|
||||
associated_data: associated_data,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl DoubleRatchetParticipant {
|
||||
pub fn new(
|
||||
session_key: &[u8],
|
||||
sending_header_key: &[u8],
|
||||
next_receiving_header_key: &[u8],
|
||||
is_sender: bool,
|
||||
sending_ephemeral_private_key: Scalar,
|
||||
receiving_ephemeral_key: EdwardsPoint,
|
||||
) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let mut participant = DoubleRatchetParticipant {
|
||||
sending_ephemeral_private_key,
|
||||
receiving_ephemeral_key,
|
||||
root_key: vec![],
|
||||
sending_chain_key: vec![],
|
||||
current_sending_header_key: sending_header_key.to_vec(),
|
||||
current_receiving_header_key: vec![],
|
||||
next_sending_header_key: vec![],
|
||||
next_receiving_header_key: next_receiving_header_key.to_vec(),
|
||||
receiving_chain_key: vec![],
|
||||
current_sending_chain_length: 0,
|
||||
previous_sending_chain_length: 0,
|
||||
current_receiving_chain_length: 0,
|
||||
previous_receiving_chain_length: 0,
|
||||
skipped_keys_map: HashMap::new(),
|
||||
};
|
||||
|
||||
if is_sender {
|
||||
let dh_output = receiving_ephemeral_key * sending_ephemeral_private_key;
|
||||
let hkdf = Hkdf::<Sha512>::new(Some(session_key), &dh_output.compress().to_bytes());
|
||||
let mut rkck = [0u8; 96];
|
||||
let err = hkdf.expand(b"quilibrium-double-ratchet", &mut rkck);
|
||||
if err.is_err() {
|
||||
return Err("invalid length".into());
|
||||
}
|
||||
|
||||
participant.root_key = rkck[..32].to_vec();
|
||||
participant.sending_chain_key = rkck[32..64].to_vec();
|
||||
participant.next_sending_header_key = rkck[64..].to_vec();
|
||||
} else {
|
||||
participant.root_key = session_key.to_vec();
|
||||
participant.next_sending_header_key = next_receiving_header_key.to_vec();
|
||||
participant.next_receiving_header_key = sending_header_key.to_vec();
|
||||
}
|
||||
|
||||
Ok(participant)
|
||||
}
|
||||
|
||||
pub fn to_json(&self) -> Result<String, serde_json::Error> {
|
||||
let mut skipped_keys_map = HashMap::<String, HashMap<u32, String>>::new();
|
||||
for (k, v) in &self.skipped_keys_map {
|
||||
let kb = BASE64_STANDARD.encode(k);
|
||||
let mut val = HashMap::<u32, String>::new();
|
||||
for (kk, vv) in v {
|
||||
let vvb = BASE64_STANDARD.encode(vv);
|
||||
val.insert(*kk, vvb);
|
||||
}
|
||||
skipped_keys_map.insert(kb, val);
|
||||
}
|
||||
|
||||
let participant = DoubleRatchetParticipantJson{
|
||||
sending_ephemeral_private_key: BASE64_STANDARD.encode(self.sending_ephemeral_private_key.to_bytes()),
|
||||
receiving_ephemeral_key: BASE64_STANDARD.encode(self.receiving_ephemeral_key.compress().to_bytes()),
|
||||
root_key: BASE64_STANDARD.encode(&self.root_key),
|
||||
sending_chain_key: BASE64_STANDARD.encode(&self.sending_chain_key),
|
||||
current_sending_header_key: BASE64_STANDARD.encode(&self.current_sending_header_key),
|
||||
current_receiving_header_key: BASE64_STANDARD.encode(&self.current_receiving_header_key),
|
||||
next_sending_header_key: BASE64_STANDARD.encode(&self.next_sending_header_key),
|
||||
next_receiving_header_key: BASE64_STANDARD.encode(&self.next_receiving_header_key),
|
||||
receiving_chain_key: BASE64_STANDARD.encode(&self.receiving_chain_key),
|
||||
current_sending_chain_length: self.current_sending_chain_length,
|
||||
previous_sending_chain_length: self.previous_sending_chain_length,
|
||||
current_receiving_chain_length: self.current_receiving_chain_length,
|
||||
previous_receiving_chain_length: self.previous_receiving_chain_length,
|
||||
skipped_keys_map: skipped_keys_map,
|
||||
};
|
||||
|
||||
serde_json::to_string(&participant)
|
||||
}
|
||||
|
||||
pub fn from_json(participant_json: String) -> Result<DoubleRatchetParticipant, Box<dyn std::error::Error>> {
|
||||
let json: Result<DoubleRatchetParticipantJson, serde_json::Error> = serde_json::from_str(&participant_json);
|
||||
match json {
|
||||
Ok(participant) => {
|
||||
let sending_ephemeral_private_key_bytes = BASE64_STANDARD.decode(participant.sending_ephemeral_private_key)?;
|
||||
let receiving_ephemeral_key_bytes = BASE64_STANDARD.decode(participant.receiving_ephemeral_key)?;
|
||||
let root_key = BASE64_STANDARD.decode(participant.root_key)?;
|
||||
let sending_chain_key = BASE64_STANDARD.decode(participant.sending_chain_key)?;
|
||||
let current_sending_header_key = BASE64_STANDARD.decode(participant.current_sending_header_key)?;
|
||||
let current_receiving_header_key = BASE64_STANDARD.decode(participant.current_receiving_header_key)?;
|
||||
let next_sending_header_key = BASE64_STANDARD.decode(participant.next_sending_header_key)?;
|
||||
let next_receiving_header_key = BASE64_STANDARD.decode(participant.next_receiving_header_key)?;
|
||||
let receiving_chain_key = BASE64_STANDARD.decode(participant.receiving_chain_key)?;
|
||||
let current_sending_chain_length = participant.current_sending_chain_length;
|
||||
let previous_sending_chain_length = participant.previous_sending_chain_length;
|
||||
let current_receiving_chain_length = participant.current_receiving_chain_length;
|
||||
let previous_receiving_chain_length = participant.previous_receiving_chain_length;
|
||||
let mut skipped_keys_map = HashMap::<Vec<u8>, HashMap<u32, Vec<u8>>>::new();
|
||||
for (k, v) in participant.skipped_keys_map {
|
||||
let kb = BASE64_STANDARD.decode(k)?;
|
||||
let mut val = HashMap::<u32, Vec<u8>>::new();
|
||||
for (kk, vv) in v {
|
||||
let vvb = BASE64_STANDARD.decode(vv)?;
|
||||
val.insert(kk, vvb);
|
||||
}
|
||||
skipped_keys_map.insert(kb, val);
|
||||
}
|
||||
|
||||
if sending_ephemeral_private_key_bytes.len() != 56 || receiving_ephemeral_key_bytes.len() != 57 {
|
||||
Err("invalid data".into())
|
||||
} else {
|
||||
let mut sending_ephemeral_private_key = [0u8; 56];
|
||||
sending_ephemeral_private_key.copy_from_slice(&sending_ephemeral_private_key_bytes);
|
||||
|
||||
let mut receiving_ephemeral_key = [0u8; 57];
|
||||
receiving_ephemeral_key.copy_from_slice(&receiving_ephemeral_key_bytes);
|
||||
|
||||
let receiving_ephemeral_ct = EdwardsPoint::from_bytes(&receiving_ephemeral_key.into());
|
||||
if receiving_ephemeral_ct.is_none().into() {
|
||||
Err("invalid data".into())
|
||||
} else {
|
||||
Ok(DoubleRatchetParticipant{
|
||||
sending_ephemeral_private_key: Scalar::from_bytes(&sending_ephemeral_private_key),
|
||||
receiving_ephemeral_key: receiving_ephemeral_ct.unwrap(),
|
||||
root_key: root_key,
|
||||
sending_chain_key: sending_chain_key,
|
||||
current_sending_header_key: current_sending_header_key,
|
||||
current_receiving_header_key: current_receiving_header_key,
|
||||
next_sending_header_key: next_sending_header_key,
|
||||
next_receiving_header_key: next_receiving_header_key,
|
||||
receiving_chain_key: receiving_chain_key,
|
||||
current_sending_chain_length: current_sending_chain_length,
|
||||
previous_sending_chain_length: previous_sending_chain_length,
|
||||
current_receiving_chain_length: current_receiving_chain_length,
|
||||
previous_receiving_chain_length: previous_receiving_chain_length,
|
||||
skipped_keys_map: skipped_keys_map,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
Err(Box::new(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ratchet_encrypt(&mut self, message: &[u8]) -> Result<P2PChannelEnvelope, Box<dyn std::error::Error>> {
|
||||
let mut envelope = P2PChannelEnvelope {
|
||||
protocol_identifier: DOUBLE_RATCHET_PROTOCOL,
|
||||
message_header: MessageCiphertext::default(),
|
||||
message_body: MessageCiphertext::default(),
|
||||
};
|
||||
|
||||
let (new_chain_key, message_key, aead_key) = ratchet_keys(&self.sending_chain_key);
|
||||
self.sending_chain_key = new_chain_key;
|
||||
|
||||
let header = self.encode_header();
|
||||
envelope.message_header = self.encrypt(&header, &self.current_sending_header_key, None)?;
|
||||
|
||||
envelope.message_body = self.encrypt(
|
||||
message,
|
||||
&message_key,
|
||||
Some(&[&aead_key[..], &envelope.message_header.ciphertext[..]].concat()),
|
||||
)?;
|
||||
|
||||
self.current_sending_chain_length += 1;
|
||||
|
||||
Ok(envelope)
|
||||
}
|
||||
|
||||
pub fn ratchet_decrypt(&mut self, envelope: &P2PChannelEnvelope) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
|
||||
if let Some(plaintext) = self.try_skipped_message_keys(envelope)? {
|
||||
return Ok(plaintext);
|
||||
}
|
||||
|
||||
let (header, should_ratchet) = self.decrypt_header(&envelope.message_header, &self.current_receiving_header_key)?;
|
||||
|
||||
let (receiving_ephemeral_key, previous_receiving_chain_length, current_receiving_chain_length) =
|
||||
self.decode_header(&header)?;
|
||||
|
||||
if should_ratchet {
|
||||
self.skip_message_keys(previous_receiving_chain_length)?;
|
||||
self.ratchet_ephemeral_keys(&receiving_ephemeral_key)?;
|
||||
}
|
||||
|
||||
self.skip_message_keys(current_receiving_chain_length)?;
|
||||
|
||||
let (new_chain_key, message_key, aead_key) = ratchet_keys(&self.receiving_chain_key);
|
||||
|
||||
let plaintext = self.decrypt(
|
||||
&envelope.message_body,
|
||||
&message_key,
|
||||
Some(&[&aead_key[..], &envelope.message_header.ciphertext[..]].concat()),
|
||||
)?;
|
||||
|
||||
self.receiving_chain_key = new_chain_key;
|
||||
self.current_receiving_chain_length += 1;
|
||||
|
||||
Ok(plaintext)
|
||||
}
|
||||
|
||||
fn ratchet_ephemeral_keys(&mut self, new_receiving_ephemeral_key: &EdwardsPoint) -> Result<(), Box<dyn std::error::Error>> {
|
||||
self.previous_sending_chain_length = self.current_sending_chain_length;
|
||||
self.current_sending_chain_length = 0;
|
||||
self.current_receiving_chain_length = 0;
|
||||
self.current_sending_header_key = self.next_sending_header_key.clone();
|
||||
self.current_receiving_header_key = self.next_receiving_header_key.clone();
|
||||
self.receiving_ephemeral_key = *new_receiving_ephemeral_key;
|
||||
|
||||
// Perform DH and KDF to get new root key and receiving chain key
|
||||
let dh_output = new_receiving_ephemeral_key * self.sending_ephemeral_private_key;
|
||||
let hkdf = Hkdf::<Sha512>::new(Some(&self.root_key), &dh_output.compress().to_bytes());
|
||||
let mut rkck = [0u8; 96];
|
||||
hkdf.expand(b"quilibrium-double-ratchet", &mut rkck);
|
||||
|
||||
self.root_key = rkck[..32].to_vec();
|
||||
self.receiving_chain_key = rkck[32..64].to_vec();
|
||||
self.next_receiving_header_key = rkck[64..].to_vec();
|
||||
|
||||
// Generate new sending ephemeral key
|
||||
self.sending_ephemeral_private_key = Scalar::random(&mut OsRng);
|
||||
|
||||
// Perform DH and KDF to get new root key and sending chain key
|
||||
let dh_output = new_receiving_ephemeral_key * self.sending_ephemeral_private_key;
|
||||
let hkdf = Hkdf::<Sha512>::new(Some(&self.root_key), &dh_output.compress().to_bytes());
|
||||
let mut rkck2 = [0u8; 96];
|
||||
hkdf.expand(b"quilibrium-double-ratchet", &mut rkck2);
|
||||
|
||||
self.root_key = rkck2[..32].to_vec();
|
||||
self.sending_chain_key = rkck2[32..64].to_vec();
|
||||
self.next_sending_header_key = rkck2[64..].to_vec();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_skipped_message_keys(&self, envelope: &P2PChannelEnvelope) -> Result<Option<Vec<u8>>, Box<dyn std::error::Error>> {
|
||||
for (receiving_header_key, skipped_keys) in &self.skipped_keys_map {
|
||||
if let Ok((header, _)) = self.decrypt_header(&envelope.message_header, receiving_header_key) {
|
||||
let (_, _, current) = self.decode_header(&header)?;
|
||||
if let Some(key_pair) = skipped_keys.get(¤t) {
|
||||
let message_key = &key_pair[..32];
|
||||
let aead_key = &key_pair[32..];
|
||||
return self.decrypt(
|
||||
&envelope.message_body,
|
||||
message_key,
|
||||
Some(&[aead_key, &envelope.message_header.ciphertext[..]].concat()),
|
||||
).map(Some);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn skip_message_keys(&mut self, until: u32) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if self.current_receiving_chain_length + 100 < until {
|
||||
return Err("Skip limit exceeded".into());
|
||||
}
|
||||
|
||||
if !self.receiving_chain_key.is_empty() {
|
||||
while self.current_receiving_chain_length < until {
|
||||
let (new_chain_key, message_key, aead_key) = ratchet_keys(&self.receiving_chain_key);
|
||||
self.skipped_keys_map
|
||||
.entry(self.current_receiving_header_key.clone())
|
||||
.or_insert_with(HashMap::new)
|
||||
.insert(self.current_receiving_chain_length, [&message_key[..], &aead_key[..]].concat());
|
||||
self.receiving_chain_key = new_chain_key;
|
||||
self.current_receiving_chain_length += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn encode_header(&self) -> Vec<u8> {
|
||||
let mut header = Vec::new();
|
||||
header.extend_from_slice(&EdwardsPoint::mul_by_generator(&self.sending_ephemeral_private_key).compress().to_bytes());
|
||||
header.extend_from_slice(&self.previous_sending_chain_length.to_be_bytes());
|
||||
header.extend_from_slice(&self.current_sending_chain_length.to_be_bytes());
|
||||
header
|
||||
}
|
||||
|
||||
fn decrypt_header(&self, ciphertext: &MessageCiphertext, receiving_header_key: &[u8])
|
||||
-> Result<(Vec<u8>, bool), Box<dyn std::error::Error>> {
|
||||
match self.decrypt(ciphertext, receiving_header_key, None) {
|
||||
Ok(header) => Ok((header, false)),
|
||||
Err(_) if receiving_header_key.ct_eq(self.current_receiving_header_key.as_slice()).into() => {
|
||||
self.decrypt(ciphertext, &self.next_receiving_header_key, None)
|
||||
.map(|header| (header, true))
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_header(&self, header: &[u8]) -> Result<(EdwardsPoint, u32, u32), Box<dyn std::error::Error>> {
|
||||
if header.len() < 57 { // 57 bytes for EdwardsPoint + 8 bytes for two u32
|
||||
return Err("Malformed header".into());
|
||||
}
|
||||
|
||||
let receiving_ephemeral_key = CompressedEdwardsY(header[..57].try_into().unwrap()).decompress();
|
||||
if receiving_ephemeral_key.is_none().into() {
|
||||
return Err("Malformed point".into());
|
||||
}
|
||||
let previous_receiving_chain_length = u32::from_be_bytes(header[57..61].try_into()?);
|
||||
let current_receiving_chain_length = u32::from_be_bytes(header[61..65].try_into()?);
|
||||
|
||||
Ok((receiving_ephemeral_key.unwrap(), previous_receiving_chain_length, current_receiving_chain_length))
|
||||
}
|
||||
|
||||
fn encrypt(&self, plaintext: &[u8], key: &[u8], associated_data: Option<&[u8]>)
|
||||
-> Result<MessageCiphertext, Box<dyn std::error::Error>> {
|
||||
use aes_gcm::KeyInit;
|
||||
let mut iv = [0u8; 12];
|
||||
OsRng.fill_bytes(&mut iv);
|
||||
|
||||
let cipher = Aes256Gcm::new_from_slice(key).unwrap();
|
||||
let nonce = Nonce::from_slice(&iv);
|
||||
|
||||
let mut associated_data = associated_data.unwrap_or(&[]);
|
||||
let mut aad = [0u8; 32];
|
||||
if associated_data.len() == 0 {
|
||||
OsRng.fill_bytes(&mut aad);
|
||||
associated_data = &aad
|
||||
}
|
||||
|
||||
let ciphertext = cipher.encrypt(nonce, Payload{
|
||||
msg: plaintext,
|
||||
aad: associated_data,
|
||||
}).map_err(|e| format!("Encryption failed: {}", e))?;
|
||||
|
||||
Ok(MessageCiphertext {
|
||||
ciphertext,
|
||||
initialization_vector: iv.to_vec(),
|
||||
associated_data: Some(associated_data.to_vec()),
|
||||
})
|
||||
}
|
||||
|
||||
fn decrypt(&self, ciphertext: &MessageCiphertext, key: &[u8], associated_data: Option<&[u8]>)
|
||||
-> Result<Vec<u8>, Box<dyn std::error::Error>> {
|
||||
use aes_gcm::KeyInit;
|
||||
if key.len() != 32 {
|
||||
return Err(format!("Invalid key length").into());
|
||||
}
|
||||
let cipher = Aes256Gcm::new_from_slice(key).unwrap();
|
||||
let nonce = Nonce::from_slice(&ciphertext.initialization_vector);
|
||||
|
||||
let associated_data = associated_data.unwrap_or_else(|| ciphertext.associated_data.as_ref().unwrap());
|
||||
|
||||
cipher.decrypt(nonce, Payload{
|
||||
msg: ciphertext.ciphertext.as_slice(),
|
||||
aad: associated_data,
|
||||
}).map_err(|e| format!("Decryption failed: {}", e).into())
|
||||
}
|
||||
|
||||
pub fn rotate_sending_key(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
self.sending_ephemeral_private_key = Scalar::random(&mut OsRng);
|
||||
self.ratchet_ephemeral_keys(&self.receiving_ephemeral_key.clone())
|
||||
}
|
||||
|
||||
pub fn get_public_key(&self) -> EdwardsPoint {
|
||||
EdwardsPoint::mul_by_generator(&self.sending_ephemeral_private_key)
|
||||
}
|
||||
}
|
||||
|
||||
fn ratchet_keys(input_key: &[u8]) -> (Vec<u8>, Vec<u8>, Vec<u8>) {
|
||||
use hmac::Mac;
|
||||
let mut aead_key = [0u8; 64];
|
||||
let mut message_key = [0u8; 64];
|
||||
let mut chain_key = [0u8; 64];
|
||||
|
||||
let mut hmac_aead = hmac::Hmac::<Sha512>::new_from_slice(input_key).unwrap();
|
||||
hmac_aead.update(&[AEAD_KEY]);
|
||||
aead_key.copy_from_slice(&hmac_aead.finalize().into_bytes());
|
||||
|
||||
let mut hmac_message = hmac::Hmac::<Sha512>::new_from_slice(input_key).unwrap();
|
||||
hmac_message.update(&[MESSAGE_KEY]);
|
||||
message_key.copy_from_slice(&hmac_message.finalize().into_bytes());
|
||||
|
||||
let mut hmac_chain = hmac::Hmac::<Sha512>::new_from_slice(input_key).unwrap();
|
||||
hmac_chain.update(&[CHAIN_KEY]);
|
||||
chain_key.copy_from_slice(&hmac_chain.finalize().into_bytes());
|
||||
|
||||
(chain_key[..32].to_vec(), message_key[..32].to_vec(), aead_key[..32].to_vec())
|
||||
}
|
||||
|
||||
// Implementation for MessageCiphertext
|
||||
impl Default for MessageCiphertext {
|
||||
fn default() -> Self {
|
||||
MessageCiphertext {
|
||||
ciphertext: Vec::new(),
|
||||
initialization_vector: Vec::new(),
|
||||
associated_data: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation for P2PChannelEnvelope
|
||||
impl P2PChannelEnvelope {
|
||||
pub fn new(protocol_identifier: u16) -> Self {
|
||||
P2PChannelEnvelope {
|
||||
protocol_identifier,
|
||||
message_header: MessageCiphertext::default(),
|
||||
message_body: MessageCiphertext::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use ed448_goldilocks_plus::Scalar;
|
||||
|
||||
#[test]
|
||||
fn test_double_ratchet_communication() {
|
||||
let session_key = [0u8; 32];
|
||||
let sending_header_key = [1u8; 32];
|
||||
let next_receiving_header_key = [2u8; 32];
|
||||
|
||||
let alice_ephemeral = Scalar::random(&mut OsRng);
|
||||
let bob_ephemeral = Scalar::random(&mut OsRng);
|
||||
|
||||
let alice_public = EdwardsPoint::mul_by_generator(&alice_ephemeral);
|
||||
let bob_public = EdwardsPoint::mul_by_generator(&bob_ephemeral);
|
||||
|
||||
let mut alice = DoubleRatchetParticipant::new(
|
||||
&session_key,
|
||||
&sending_header_key,
|
||||
&next_receiving_header_key,
|
||||
true,
|
||||
alice_ephemeral,
|
||||
bob_public,
|
||||
).unwrap();
|
||||
|
||||
let mut bob = DoubleRatchetParticipant::new(
|
||||
&session_key,
|
||||
&sending_header_key,
|
||||
&next_receiving_header_key,
|
||||
false,
|
||||
bob_ephemeral,
|
||||
alice_public,
|
||||
).unwrap();
|
||||
|
||||
// Test message exchange
|
||||
let message = b"Hello, Bob!";
|
||||
let envelope = alice.ratchet_encrypt(message).unwrap();
|
||||
|
||||
let decrypted = bob.ratchet_decrypt(&envelope).unwrap();
|
||||
assert_eq!(message, decrypted.as_slice());
|
||||
|
||||
let response = b"Hello, Alice!";
|
||||
let envelope = bob.ratchet_encrypt(response).unwrap();
|
||||
let delayed = alice.ratchet_encrypt(b"force another step").unwrap();
|
||||
let decrypted = alice.ratchet_decrypt(&envelope).unwrap();
|
||||
assert_eq!(response, decrypted.as_slice());
|
||||
|
||||
// Test multiple messages
|
||||
for _ in 0..5 {
|
||||
let message = b"Secure communication test";
|
||||
let envelope = alice.ratchet_encrypt(message).unwrap();
|
||||
let decrypted = bob.ratchet_decrypt(&envelope).unwrap();
|
||||
assert_eq!(message, decrypted.as_slice());
|
||||
|
||||
let response = b"Acknowledged";
|
||||
let envelope = bob.ratchet_encrypt(response).unwrap();
|
||||
let decrypted = alice.ratchet_decrypt(&envelope).unwrap();
|
||||
assert_eq!(response, decrypted.as_slice());
|
||||
}
|
||||
|
||||
let alice_json = alice.to_json().unwrap();
|
||||
let bob_json = bob.to_json().unwrap();
|
||||
|
||||
let mut new_alice = DoubleRatchetParticipant::from_json(alice_json).unwrap();
|
||||
let mut new_bob = DoubleRatchetParticipant::from_json(bob_json).unwrap();
|
||||
|
||||
// Test multiple messages
|
||||
for _ in 0..5 {
|
||||
let message = b"Secure communication test";
|
||||
let envelope = new_alice.ratchet_encrypt(message).unwrap();
|
||||
let decrypted = new_bob.ratchet_decrypt(&envelope).unwrap();
|
||||
assert_eq!(message, decrypted.as_slice());
|
||||
|
||||
let response = b"Acknowledged";
|
||||
let envelope = new_bob.ratchet_encrypt(response).unwrap();
|
||||
let decrypted = new_alice.ratchet_decrypt(&envelope).unwrap();
|
||||
assert_eq!(response, decrypted.as_slice());
|
||||
}
|
||||
let decrypted = new_bob.ratchet_decrypt(&delayed).unwrap();
|
||||
assert_eq!(b"force another step", decrypted.as_slice());
|
||||
}
|
||||
}
|
485
crates/channel/src/protocols/feldman.rs
Normal file
485
crates/channel/src/protocols/feldman.rs
Normal file
@ -0,0 +1,485 @@
|
||||
use base64::prelude::*;
|
||||
use std::{collections::HashMap, io::Read};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha512};
|
||||
use ed448_goldilocks_plus::{elliptic_curve::{group::GroupEncoding, Field, Group}, subtle::ConstantTimeEq, EdwardsPoint, Scalar};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum FeldmanError {
|
||||
#[error("Wrong round for Feldman operation")]
|
||||
WrongRound,
|
||||
#[error("Invalid data: {0}")]
|
||||
InvalidData(String),
|
||||
#[error("Crypto error: {0}")]
|
||||
CryptoError(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
enum FeldmanRound {
|
||||
Uninitialized,
|
||||
Initialized,
|
||||
Committed,
|
||||
Revealed,
|
||||
Reconstructed,
|
||||
}
|
||||
|
||||
pub struct Feldman {
|
||||
threshold: usize,
|
||||
total: usize,
|
||||
id: usize,
|
||||
frags_for_counterparties: HashMap<usize, Vec<u8>>,
|
||||
frags_from_counterparties: HashMap<usize, Scalar>,
|
||||
zkpok: Option<Scalar>,
|
||||
secret: Scalar,
|
||||
scalar: Option<Scalar>,
|
||||
generator: EdwardsPoint,
|
||||
public_key: EdwardsPoint,
|
||||
point: EdwardsPoint,
|
||||
random_commitment_point: Option<EdwardsPoint>,
|
||||
round: FeldmanRound,
|
||||
zkcommits_from_counterparties: HashMap<usize, Vec<u8>>,
|
||||
points_from_counterparties: HashMap<usize, EdwardsPoint>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct FeldmanJson {
|
||||
threshold: usize,
|
||||
total: usize,
|
||||
id: usize,
|
||||
frags_for_counterparties: HashMap<usize, String>,
|
||||
frags_from_counterparties: HashMap<usize, String>,
|
||||
zkpok: Option<String>,
|
||||
secret: String,
|
||||
scalar: Option<String>,
|
||||
generator: String,
|
||||
public_key: String,
|
||||
point: String,
|
||||
random_commitment_point: Option<String>,
|
||||
round: usize,
|
||||
zkcommits_from_counterparties: HashMap<usize, String>,
|
||||
points_from_counterparties: HashMap<usize, String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct FeldmanReveal {
|
||||
point: Vec<u8>,
|
||||
random_commitment_point: Vec<u8>,
|
||||
zk_pok: Vec<u8>,
|
||||
}
|
||||
|
||||
pub fn vec_to_array<const N: usize>(v: Vec<u8>) -> Result<[u8; N], Box<dyn std::error::Error>> {
|
||||
if v.len() != N {
|
||||
return Err(format!("Invalid length: expected {}, got {}", N, v.len()).into());
|
||||
}
|
||||
|
||||
let mut arr: [u8; N] = [0u8; N];
|
||||
arr.copy_from_slice(&v);
|
||||
Ok(arr)
|
||||
}
|
||||
|
||||
impl Feldman {
|
||||
pub fn new(
|
||||
threshold: usize,
|
||||
total: usize,
|
||||
id: usize,
|
||||
secret: Scalar,
|
||||
generator: EdwardsPoint,
|
||||
) -> Self {
|
||||
Feldman {
|
||||
threshold,
|
||||
total,
|
||||
id,
|
||||
frags_for_counterparties: HashMap::new(),
|
||||
frags_from_counterparties: HashMap::new(),
|
||||
zkpok: None,
|
||||
secret,
|
||||
scalar: None,
|
||||
generator,
|
||||
public_key: EdwardsPoint::generator(),
|
||||
point: EdwardsPoint::generator(),
|
||||
random_commitment_point: None,
|
||||
round: FeldmanRound::Uninitialized,
|
||||
zkcommits_from_counterparties: HashMap::new(),
|
||||
points_from_counterparties: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_json(&self) -> Result<String, serde_json::Error> {
|
||||
let feldman_json = FeldmanJson {
|
||||
threshold: self.threshold,
|
||||
total: self.total,
|
||||
id: self.id,
|
||||
frags_for_counterparties: self.frags_for_counterparties.iter()
|
||||
.map(|(&k, v)| (k, BASE64_STANDARD.encode(v)))
|
||||
.collect(),
|
||||
frags_from_counterparties: self.frags_from_counterparties.iter()
|
||||
.map(|(&k, v)| (k, BASE64_STANDARD.encode(v.to_bytes())))
|
||||
.collect(),
|
||||
zkpok: self.zkpok.as_ref().map(|s| BASE64_STANDARD.encode(s.to_bytes())),
|
||||
secret: BASE64_STANDARD.encode(self.secret.to_bytes()),
|
||||
scalar: self.scalar.as_ref().map(|s| BASE64_STANDARD.encode(s.to_bytes())),
|
||||
generator: BASE64_STANDARD.encode(self.generator.compress().to_bytes()),
|
||||
public_key: BASE64_STANDARD.encode(self.public_key.compress().to_bytes()),
|
||||
point: BASE64_STANDARD.encode(self.point.compress().to_bytes()),
|
||||
random_commitment_point: self.random_commitment_point.as_ref()
|
||||
.map(|p| BASE64_STANDARD.encode(p.compress().to_bytes())),
|
||||
round: self.round as usize,
|
||||
zkcommits_from_counterparties: self.zkcommits_from_counterparties.iter()
|
||||
.map(|(&k, v)| (k, BASE64_STANDARD.encode(v)))
|
||||
.collect(),
|
||||
points_from_counterparties: self.points_from_counterparties.iter()
|
||||
.map(|(&k, v)| (k, BASE64_STANDARD.encode(v.compress().to_bytes())))
|
||||
.collect(),
|
||||
};
|
||||
|
||||
serde_json::to_string(&feldman_json)
|
||||
}
|
||||
|
||||
pub fn from_json(json: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let feldman_json: FeldmanJson = serde_json::from_str(json)?;
|
||||
|
||||
let frags_for_counterparties = feldman_json.frags_for_counterparties.into_iter()
|
||||
.map(|(k, v)| Ok((k, BASE64_STANDARD.decode(v)?)))
|
||||
.collect::<Result<HashMap<_, _>, Box<dyn std::error::Error>>>()?;
|
||||
|
||||
let frags_from_counterparties = feldman_json.frags_from_counterparties.into_iter()
|
||||
.map(|(k, v)| {
|
||||
let bytes = BASE64_STANDARD.decode(v)?;
|
||||
Ok((k, Scalar::from_bytes(&vec_to_array::<56>(bytes)?)))
|
||||
})
|
||||
.collect::<Result<HashMap<_, _>, Box<dyn std::error::Error>>>()?;
|
||||
|
||||
let mut zkpok: Option<Scalar> = None;
|
||||
if feldman_json.zkpok.is_some() {
|
||||
let bytes = BASE64_STANDARD.decode(feldman_json.zkpok.unwrap())?;
|
||||
zkpok = Some(Scalar::from_bytes(&vec_to_array::<56>(bytes)?));
|
||||
}
|
||||
|
||||
let secret_bytes = BASE64_STANDARD.decode(feldman_json.secret)?;
|
||||
let secret = Scalar::from_bytes(&vec_to_array::<56>(secret_bytes)?);
|
||||
|
||||
let mut scalar: Option<Scalar> = None;
|
||||
if feldman_json.scalar.is_some() {
|
||||
let bytes = BASE64_STANDARD.decode(feldman_json.scalar.unwrap())?;
|
||||
scalar = Some(Scalar::from_bytes(&vec_to_array::<56>(bytes)?));
|
||||
}
|
||||
|
||||
let generator_bytes = BASE64_STANDARD.decode(feldman_json.generator)?;
|
||||
let generator = EdwardsPoint::from_bytes(&vec_to_array::<57>(generator_bytes)?.into()).into_option().ok_or_else(|| FeldmanError::InvalidData("invalid data".into()))?;
|
||||
|
||||
let public_key_bytes = BASE64_STANDARD.decode(feldman_json.public_key)?;
|
||||
let public_key = EdwardsPoint::from_bytes(&vec_to_array::<57>(public_key_bytes)?.into()).into_option().ok_or_else(|| FeldmanError::InvalidData("invalid data".into()))?;
|
||||
|
||||
let point_bytes = BASE64_STANDARD.decode(feldman_json.point)?;
|
||||
let point = EdwardsPoint::from_bytes(&vec_to_array::<57>(point_bytes)?.into()).into_option().ok_or_else(|| FeldmanError::InvalidData("invalid data".into()))?;
|
||||
|
||||
let mut random_commitment_point: Option<EdwardsPoint> = None;
|
||||
if feldman_json.random_commitment_point.is_some() {
|
||||
let bytes = BASE64_STANDARD.decode(feldman_json.random_commitment_point.unwrap())?;
|
||||
random_commitment_point = Some(EdwardsPoint::from_bytes(&vec_to_array::<57>(bytes)?.into()).into_option().ok_or_else(|| FeldmanError::InvalidData("invalid data".into()))?);
|
||||
}
|
||||
|
||||
let zkcommits_from_counterparties = feldman_json.zkcommits_from_counterparties.into_iter()
|
||||
.map(|(k, v)| Ok((k, BASE64_STANDARD.decode(v)?)))
|
||||
.collect::<Result<HashMap<_, _>, Box<dyn std::error::Error>>>()?;
|
||||
|
||||
let points_from_counterparties = feldman_json.points_from_counterparties.into_iter()
|
||||
.map(|(k, v)| {
|
||||
Ok((k, EdwardsPoint::from_bytes(&vec_to_array::<57>(BASE64_STANDARD.decode(v)?)?.into()).into_option().ok_or_else(|| FeldmanError::InvalidData("invalid data".into()))?))
|
||||
})
|
||||
.collect::<Result<HashMap<_, _>, Box<dyn std::error::Error>>>()?;
|
||||
|
||||
Ok(Feldman {
|
||||
threshold: feldman_json.threshold,
|
||||
total: feldman_json.total,
|
||||
id: feldman_json.id,
|
||||
frags_for_counterparties,
|
||||
frags_from_counterparties,
|
||||
zkpok,
|
||||
secret,
|
||||
scalar,
|
||||
generator,
|
||||
public_key,
|
||||
point,
|
||||
random_commitment_point,
|
||||
round: match feldman_json.round {
|
||||
0 => FeldmanRound::Uninitialized,
|
||||
1 => FeldmanRound::Initialized,
|
||||
2 => FeldmanRound::Committed,
|
||||
3 => FeldmanRound::Revealed,
|
||||
4 => FeldmanRound::Reconstructed,
|
||||
_ => FeldmanRound::Uninitialized,
|
||||
},
|
||||
zkcommits_from_counterparties,
|
||||
points_from_counterparties,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_id(&mut self, id: usize) {
|
||||
self.id = id;
|
||||
}
|
||||
|
||||
pub fn sample_polynomial<R: RngCore + CryptoRng>(&mut self, rng: &mut R) -> Result<(), FeldmanError> {
|
||||
if self.round != FeldmanRound::Uninitialized {
|
||||
return Err(FeldmanError::WrongRound);
|
||||
}
|
||||
|
||||
let mut coeffs = vec![self.secret];
|
||||
|
||||
for _ in 1..self.threshold {
|
||||
coeffs.push(Scalar::random(rng));
|
||||
}
|
||||
|
||||
for i in 1..=self.total {
|
||||
let mut result = coeffs[0];
|
||||
let x = Scalar::from(i as u32);
|
||||
|
||||
for j in 1..self.threshold {
|
||||
let term = coeffs[j] * Scalar::from(i.pow(j as u32) as u32);
|
||||
result += term;
|
||||
}
|
||||
|
||||
if i == self.id {
|
||||
self.scalar = Some(result);
|
||||
} else {
|
||||
self.frags_for_counterparties.insert(i, result.to_bytes().to_vec());
|
||||
}
|
||||
}
|
||||
|
||||
self.round = FeldmanRound::Initialized;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn scalar(&self) -> Option<&Scalar> {
|
||||
self.scalar.as_ref()
|
||||
}
|
||||
|
||||
pub fn get_poly_frags(&self) -> Result<&HashMap<usize, Vec<u8>>, FeldmanError> {
|
||||
if self.round != FeldmanRound::Initialized {
|
||||
return Err(FeldmanError::WrongRound);
|
||||
}
|
||||
Ok(&self.frags_for_counterparties)
|
||||
}
|
||||
|
||||
pub fn set_poly_frag_for_party(&mut self, id: usize, frag: &[u8]) -> Result<Option<Vec<u8>>, FeldmanError> {
|
||||
if self.round != FeldmanRound::Initialized {
|
||||
return Err(FeldmanError::WrongRound);
|
||||
}
|
||||
|
||||
let scalar = Scalar::from_bytes(frag.try_into().unwrap());
|
||||
self.frags_from_counterparties.insert(id, scalar);
|
||||
|
||||
if self.frags_from_counterparties.len() == self.total - 1 {
|
||||
let mut combined_scalar = self.scalar.unwrap_or_else(|| Scalar::ZERO);
|
||||
for scalar in self.frags_from_counterparties.values() {
|
||||
combined_scalar += *scalar;
|
||||
}
|
||||
self.scalar = Some(combined_scalar);
|
||||
|
||||
self.point = self.generator * combined_scalar;
|
||||
|
||||
let rand_commitment = Scalar::random(&mut rand::thread_rng());
|
||||
self.random_commitment_point = Some(self.generator * rand_commitment);
|
||||
|
||||
let random_commitment_point_bytes = self.random_commitment_point.unwrap().compress().to_bytes();
|
||||
let public_point_bytes = self.point.compress().to_bytes();
|
||||
|
||||
let mut hasher = Sha512::new();
|
||||
hasher.update(&public_point_bytes);
|
||||
hasher.update(&random_commitment_point_bytes);
|
||||
let challenge = hasher.finalize();
|
||||
|
||||
let challenge_scalar = Scalar::from_bytes(challenge[..56].try_into().unwrap());
|
||||
|
||||
self.zkpok = Some(combined_scalar * challenge_scalar + rand_commitment);
|
||||
|
||||
let zkpok_bytes = self.zkpok.unwrap().to_bytes();
|
||||
let mut hasher = Sha512::new();
|
||||
hasher.update(&random_commitment_point_bytes);
|
||||
hasher.update(&zkpok_bytes);
|
||||
let zkcommit = hasher.finalize();
|
||||
|
||||
self.round = FeldmanRound::Committed;
|
||||
return Ok(Some(zkcommit[..56].to_vec()));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn receive_commitments(&mut self, id: usize, zkcommit: &[u8]) -> Result<Option<FeldmanReveal>, FeldmanError> {
|
||||
if self.round != FeldmanRound::Committed {
|
||||
return Err(FeldmanError::WrongRound);
|
||||
}
|
||||
|
||||
self.zkcommits_from_counterparties.insert(id, zkcommit.to_vec());
|
||||
|
||||
if self.zkcommits_from_counterparties.len() == self.total - 1 {
|
||||
let public_point_bytes = self.point.compress().to_bytes();
|
||||
let random_commitment_point_bytes = self.random_commitment_point.unwrap().compress().to_bytes();
|
||||
self.round = FeldmanRound::Revealed;
|
||||
let zkpok_bytes = self.zkpok.unwrap().to_bytes();
|
||||
|
||||
return Ok(Some(FeldmanReveal {
|
||||
point: public_point_bytes.to_vec(),
|
||||
random_commitment_point: random_commitment_point_bytes.to_vec(),
|
||||
zk_pok: zkpok_bytes.to_vec(),
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn recombine(&mut self, id: usize, reveal: &FeldmanReveal) -> Result<bool, FeldmanError> {
|
||||
if self.round != FeldmanRound::Revealed {
|
||||
return Err(FeldmanError::WrongRound);
|
||||
}
|
||||
|
||||
let counterparty_point = EdwardsPoint::from_bytes(reveal.point.as_slice().into()).unwrap();
|
||||
|
||||
if counterparty_point.eq(&EdwardsPoint::generator()).into() || counterparty_point == self.generator {
|
||||
return Err(FeldmanError::InvalidData("Counterparty sent generator".into()));
|
||||
}
|
||||
|
||||
let counterparty_random_commitment_point = EdwardsPoint::from_bytes(reveal.random_commitment_point.as_slice().into()).unwrap();
|
||||
|
||||
if counterparty_random_commitment_point.eq(&EdwardsPoint::generator()).into() || counterparty_random_commitment_point == self.generator {
|
||||
return Err(FeldmanError::InvalidData("Counterparty sent generator".into()));
|
||||
}
|
||||
|
||||
let counterparty_zkpok = Scalar::from_bytes(reveal.zk_pok.as_slice().try_into().unwrap());
|
||||
|
||||
let counterparty_zkcommit = self.zkcommits_from_counterparties.get(&id)
|
||||
.ok_or_else(|| FeldmanError::InvalidData("Missing ZK commit for counterparty".into()))?;
|
||||
|
||||
let mut hasher = Sha512::new();
|
||||
hasher.update(&reveal.point);
|
||||
hasher.update(&reveal.random_commitment_point);
|
||||
let challenge = hasher.finalize();
|
||||
|
||||
let challenge_scalar = Scalar::from_bytes(challenge[..56].try_into().unwrap());
|
||||
|
||||
let proof = self.generator * counterparty_zkpok;
|
||||
let expected_proof = counterparty_random_commitment_point + (counterparty_point * challenge_scalar);
|
||||
|
||||
if proof != expected_proof {
|
||||
return Err(FeldmanError::InvalidData(format!("Invalid proof from {}", id)));
|
||||
}
|
||||
|
||||
let mut hasher = Sha512::new();
|
||||
hasher.update(&reveal.random_commitment_point);
|
||||
hasher.update(&reveal.zk_pok);
|
||||
let verifier = hasher.finalize();
|
||||
|
||||
if &verifier[..56] != counterparty_zkcommit {
|
||||
return Err(FeldmanError::InvalidData(format!("{} changed zkpok after commit", id)));
|
||||
}
|
||||
|
||||
self.points_from_counterparties.insert(id, counterparty_point);
|
||||
|
||||
if self.points_from_counterparties.len() == self.total - 1 {
|
||||
self.points_from_counterparties.insert(self.id, self.point);
|
||||
|
||||
for i in 1..=self.total - self.threshold + 1 {
|
||||
let mut reconstructed_sum = EdwardsPoint::generator();
|
||||
|
||||
for j in i..self.threshold + i {
|
||||
let mut num = Scalar::ONE;
|
||||
let mut den = Scalar::ONE;
|
||||
|
||||
for k in i..self.threshold + i {
|
||||
if j != k {
|
||||
let j_scalar = Scalar::from(j as u32);
|
||||
let k_scalar = Scalar::from(k as u32);
|
||||
|
||||
num *= k_scalar;
|
||||
den *= k_scalar - j_scalar;
|
||||
}
|
||||
}
|
||||
|
||||
let den_inv = den.invert();
|
||||
let reconstructed_fragment = self.points_from_counterparties[&j] * (num * den_inv);
|
||||
reconstructed_sum += reconstructed_fragment;
|
||||
}
|
||||
|
||||
if self.public_key == EdwardsPoint::generator() || self.public_key == self.generator {
|
||||
self.public_key = reconstructed_sum;
|
||||
} else if self.public_key != reconstructed_sum {
|
||||
return Err(FeldmanError::InvalidData("Recombination mismatch".into()));
|
||||
}
|
||||
}
|
||||
self.round = FeldmanRound::Reconstructed;
|
||||
}
|
||||
|
||||
Ok(self.round == FeldmanRound::Reconstructed)
|
||||
}
|
||||
|
||||
pub fn mul_share(&self, pubkey: &[u8]) -> Result<Vec<u8>, FeldmanError> {
|
||||
if self.scalar.is_none() {
|
||||
return Err(FeldmanError::WrongRound);
|
||||
}
|
||||
|
||||
let point = EdwardsPoint::from_bytes(pubkey.into());
|
||||
if point.is_none().into() {
|
||||
return Err(FeldmanError::InvalidData("invalid pubkey".to_string()));
|
||||
}
|
||||
|
||||
let result = self.scalar.unwrap() * point.unwrap();
|
||||
if result.is_identity().into() {
|
||||
return Err(FeldmanError::InvalidData("invalid pubkey".to_string()));
|
||||
}
|
||||
|
||||
return Ok(result.compress().to_bytes().to_vec());
|
||||
}
|
||||
|
||||
pub fn combine_mul_share(&mut self, shares: Vec<&[u8]>, ids: &[usize]) -> Result<Vec<u8>, FeldmanError> {
|
||||
if shares.len() != ids.len() {
|
||||
return Err(FeldmanError::InvalidData("mismatch of shares and ids len".to_string()));
|
||||
}
|
||||
|
||||
let mut points = HashMap::<usize, EdwardsPoint>::new();
|
||||
for (i, share) in shares.iter().enumerate() {
|
||||
let point = EdwardsPoint::from_bytes((*share).into());
|
||||
if point.is_none().into() {
|
||||
return Err(FeldmanError::InvalidData(format!("invalid pubkey for {}", ids[i]).to_string()));
|
||||
}
|
||||
|
||||
points.insert(ids[i], point.unwrap());
|
||||
}
|
||||
|
||||
let mut reconstructed_sum = EdwardsPoint::generator();
|
||||
|
||||
for j in ids {
|
||||
let mut num = Scalar::ONE;
|
||||
let mut den = Scalar::ONE;
|
||||
|
||||
for k in ids {
|
||||
if j != k {
|
||||
let j_scalar = Scalar::from(*j as u32);
|
||||
let k_scalar = Scalar::from(*k as u32);
|
||||
|
||||
num *= k_scalar;
|
||||
den *= k_scalar - j_scalar;
|
||||
}
|
||||
}
|
||||
|
||||
let den_inv = den.invert();
|
||||
let reconstructed_fragment = points[&j] * (num * den_inv);
|
||||
reconstructed_sum += reconstructed_fragment;
|
||||
}
|
||||
|
||||
self.public_key = reconstructed_sum;
|
||||
|
||||
return Ok(reconstructed_sum.compress().to_bytes().to_vec());
|
||||
}
|
||||
|
||||
pub fn public_key(&self) -> &EdwardsPoint {
|
||||
&self.public_key
|
||||
}
|
||||
|
||||
pub fn public_key_bytes(&self) -> Vec<u8> {
|
||||
self.public_key.to_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
|
4
crates/channel/src/protocols/mod.rs
Normal file
4
crates/channel/src/protocols/mod.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub(crate) mod doubleratchet;
|
||||
pub(crate) mod tripleratchet;
|
||||
pub(crate) mod feldman;
|
||||
pub(crate) mod x3dh;
|
883
crates/channel/src/protocols/tripleratchet.rs
Normal file
883
crates/channel/src/protocols/tripleratchet.rs
Normal file
@ -0,0 +1,883 @@
|
||||
use base64::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
use ed448_goldilocks_plus::elliptic_curve::group::GroupEncoding;
|
||||
use ed448_goldilocks_plus::elliptic_curve::Group;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use sha2::{Sha512, Digest};
|
||||
use hkdf::Hkdf;
|
||||
use aes_gcm::{Aes256Gcm, Nonce};
|
||||
use aes_gcm::aead::{Aead, Payload};
|
||||
use ed448_goldilocks_plus::{subtle, EdwardsPoint, Scalar};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use thiserror::Error;
|
||||
use subtle::ConstantTimeEq;
|
||||
|
||||
use super::doubleratchet::{DoubleRatchetParticipant, DoubleRatchetParticipantJson, MessageCiphertext, P2PChannelEnvelope};
|
||||
use super::feldman::{Feldman, vec_to_array, FeldmanReveal};
|
||||
use super::x3dh::{receiver_x3dh, sender_x3dh};
|
||||
|
||||
const TRIPLE_RATCHET_PROTOCOL_VERSION: u16 = 1;
|
||||
const TRIPLE_RATCHET_PROTOCOL: u16 = 2 << 8 + TRIPLE_RATCHET_PROTOCOL_VERSION;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
enum TripleRatchetRound {
|
||||
Uninitialized,
|
||||
Initialized,
|
||||
Committed,
|
||||
Revealed,
|
||||
Reconstructed,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum TripleRatchetError {
|
||||
#[error("Crypto error: {0}")]
|
||||
CryptoError(String),
|
||||
#[error("Invalid data: {0}")]
|
||||
InvalidData(String),
|
||||
#[error("Skip limit exceeded")]
|
||||
SkipLimitExceeded,
|
||||
#[error("Malformed header")]
|
||||
MalformedHeader,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct PeerInfo {
|
||||
pub(crate) public_key: Vec<u8>,
|
||||
pub(crate) identity_public_key: Vec<u8>,
|
||||
pub(crate) signed_pre_public_key: Vec<u8>,
|
||||
}
|
||||
|
||||
pub struct TripleRatchetParticipant {
|
||||
peer_key: Scalar,
|
||||
sending_ephemeral_private_key: Scalar,
|
||||
receiving_ephemeral_keys: HashMap<Vec<u8>, Scalar>,
|
||||
receiving_group_key: Option<Vec<u8>>,
|
||||
root_key: Vec<u8>,
|
||||
sending_chain_key: Vec<u8>,
|
||||
current_header_key: Vec<u8>,
|
||||
next_header_key: Vec<u8>,
|
||||
receiving_chain_key: HashMap<Vec<u8>, Vec<u8>>,
|
||||
current_sending_chain_length: u32,
|
||||
previous_sending_chain_length: u32,
|
||||
current_receiving_chain_length: HashMap<Vec<u8>, u32>,
|
||||
previous_receiving_chain_length: HashMap<Vec<u8>, u32>,
|
||||
peer_id_map: HashMap<Vec<u8>, usize>,
|
||||
id_peer_map: HashMap<usize, PeerInfo>,
|
||||
skipped_keys_map: HashMap<Vec<u8>, HashMap<Vec<u8>, HashMap<u32, Vec<u8>>>>,
|
||||
peer_channels: HashMap<Vec<u8>, DoubleRatchetParticipant>,
|
||||
dkg_ratchet: Feldman,
|
||||
next_dkg_ratchet: Feldman,
|
||||
async_dkg_ratchet: bool,
|
||||
should_ratchet: bool,
|
||||
should_dkg_ratchet: HashMap<Vec<u8>, bool>,
|
||||
async_dkg_pubkey: Option<EdwardsPoint>,
|
||||
threshold: usize,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct PeerInfoJson {
|
||||
public_key: String,
|
||||
identity_public_key: String,
|
||||
signed_pre_public_key: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct TripleRatchetParticipantJson {
|
||||
peer_key: String,
|
||||
sending_ephemeral_private_key: String,
|
||||
receiving_ephemeral_keys: HashMap<String, String>,
|
||||
receiving_group_key: Option<String>,
|
||||
root_key: String,
|
||||
sending_chain_key: String,
|
||||
current_header_key: String,
|
||||
next_header_key: String,
|
||||
receiving_chain_key: HashMap<String, String>,
|
||||
current_sending_chain_length: u32,
|
||||
previous_sending_chain_length: u32,
|
||||
current_receiving_chain_length: HashMap<String, u32>,
|
||||
previous_receiving_chain_length: HashMap<String, u32>,
|
||||
peer_id_map: HashMap<String, usize>,
|
||||
id_peer_map: HashMap<usize, PeerInfoJson>,
|
||||
skipped_keys_map: HashMap<String, HashMap<String, HashMap<u32, String>>>,
|
||||
peer_channels: HashMap<String, String>,
|
||||
dkg_ratchet: String,
|
||||
next_dkg_ratchet: String,
|
||||
async_dkg_ratchet: bool,
|
||||
should_ratchet: bool,
|
||||
should_dkg_ratchet: HashMap<String, bool>,
|
||||
async_dkg_pubkey: Option<String>,
|
||||
threshold: usize,
|
||||
}
|
||||
|
||||
impl TripleRatchetParticipant {
|
||||
pub fn new(
|
||||
peers: &[PeerInfo],
|
||||
peer_key: Scalar,
|
||||
identity_key: Scalar,
|
||||
signed_pre_key: Scalar,
|
||||
threshold: usize,
|
||||
async_dkg_ratchet: bool,
|
||||
) -> Result<(Self, HashMap<Vec<u8>, P2PChannelEnvelope>), TripleRatchetError> {
|
||||
let mut participant = TripleRatchetParticipant {
|
||||
peer_key,
|
||||
sending_ephemeral_private_key: Scalar::random(&mut OsRng),
|
||||
receiving_ephemeral_keys: HashMap::new(),
|
||||
receiving_group_key: None,
|
||||
root_key: vec![],
|
||||
sending_chain_key: vec![],
|
||||
current_header_key: vec![],
|
||||
next_header_key: vec![],
|
||||
receiving_chain_key: HashMap::new(),
|
||||
current_sending_chain_length: 0,
|
||||
previous_sending_chain_length: 0,
|
||||
current_receiving_chain_length: HashMap::new(),
|
||||
previous_receiving_chain_length: HashMap::new(),
|
||||
peer_id_map: HashMap::new(),
|
||||
id_peer_map: HashMap::new(),
|
||||
skipped_keys_map: HashMap::new(),
|
||||
peer_channels: HashMap::new(),
|
||||
dkg_ratchet: Feldman::new(
|
||||
threshold,
|
||||
peers.len() + 1,
|
||||
0, // This will be set later
|
||||
Scalar::random(&mut OsRng),
|
||||
EdwardsPoint::generator(),
|
||||
),
|
||||
next_dkg_ratchet: Feldman::new(
|
||||
threshold,
|
||||
peers.len() + 1,
|
||||
0, // This will be set later
|
||||
Scalar::random(&mut OsRng),
|
||||
EdwardsPoint::generator(),
|
||||
),
|
||||
async_dkg_ratchet: async_dkg_ratchet,
|
||||
should_ratchet: true,
|
||||
should_dkg_ratchet: HashMap::new(),
|
||||
async_dkg_pubkey: None,
|
||||
threshold: threshold,
|
||||
};
|
||||
|
||||
let mut peer_basis = peers.to_vec();
|
||||
peer_basis.push(PeerInfo {
|
||||
public_key: (peer_key * EdwardsPoint::generator()).compress().to_bytes().to_vec(),
|
||||
identity_public_key: (identity_key * EdwardsPoint::generator()).compress().to_bytes().to_vec(),
|
||||
signed_pre_public_key: (signed_pre_key * EdwardsPoint::generator()).compress().to_bytes().to_vec(),
|
||||
});
|
||||
|
||||
peer_basis.sort_by(|a, b| a.public_key.cmp(&b.public_key));
|
||||
|
||||
let mut init_messages = HashMap::new();
|
||||
let mut sender = false;
|
||||
|
||||
for (i, peer) in peer_basis.iter().enumerate() {
|
||||
participant.peer_id_map.insert(peer.public_key.clone(), i + 1);
|
||||
participant.id_peer_map.insert(i + 1, peer.clone());
|
||||
|
||||
if peer.public_key.ct_eq(&(peer_key * EdwardsPoint::generator()).compress().to_bytes().to_vec()).into() {
|
||||
sender = true;
|
||||
participant.dkg_ratchet.set_id(i + 1);
|
||||
participant.next_dkg_ratchet.set_id(i + 1);
|
||||
} else {
|
||||
participant.skipped_keys_map.insert(peer.public_key.clone(), HashMap::new());
|
||||
participant.current_receiving_chain_length.insert(peer.public_key.clone(), 0);
|
||||
participant.previous_receiving_chain_length.insert(peer.public_key.clone(), 0);
|
||||
|
||||
let session_key = if sender {
|
||||
sender_x3dh(
|
||||
&identity_key,
|
||||
&signed_pre_key,
|
||||
&EdwardsPoint::from_bytes(peer.identity_public_key.as_slice().into()).unwrap(),
|
||||
&EdwardsPoint::from_bytes(peer.signed_pre_public_key.as_slice().into()).unwrap(),
|
||||
96,
|
||||
)
|
||||
} else {
|
||||
receiver_x3dh(
|
||||
&identity_key,
|
||||
&signed_pre_key,
|
||||
&EdwardsPoint::from_bytes(peer.identity_public_key.as_slice().into()).unwrap(),
|
||||
&EdwardsPoint::from_bytes(peer.signed_pre_public_key.as_slice().into()).unwrap(),
|
||||
96,
|
||||
)
|
||||
}.unwrap();
|
||||
|
||||
let peer_channel = DoubleRatchetParticipant::new(
|
||||
&session_key[..32],
|
||||
&session_key[32..64],
|
||||
&session_key[64..],
|
||||
sender,
|
||||
signed_pre_key.clone(),
|
||||
EdwardsPoint::from_bytes(peer.signed_pre_public_key.as_slice().into()).unwrap(),
|
||||
).unwrap();
|
||||
|
||||
participant.peer_channels.insert(peer.public_key.clone(), peer_channel);
|
||||
|
||||
if sender {
|
||||
let init_message = participant.peer_channels
|
||||
.get_mut(&peer.public_key)
|
||||
.unwrap()
|
||||
.ratchet_encrypt(b"init").unwrap();
|
||||
init_messages.insert(peer.public_key.clone(), init_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok((participant, init_messages))
|
||||
}
|
||||
|
||||
pub fn to_json(&self) -> Result<String, serde_json::Error> {
|
||||
let triple_ratchet_json = TripleRatchetParticipantJson {
|
||||
peer_key: BASE64_STANDARD.encode(self.peer_key.to_bytes()),
|
||||
sending_ephemeral_private_key: BASE64_STANDARD.encode(self.sending_ephemeral_private_key.to_bytes()),
|
||||
receiving_ephemeral_keys: self.receiving_ephemeral_keys.iter()
|
||||
.map(|(k, v)| (BASE64_STANDARD.encode(k), BASE64_STANDARD.encode(v.to_bytes())))
|
||||
.collect(),
|
||||
receiving_group_key: self.receiving_group_key.as_ref().map(|k| BASE64_STANDARD.encode(k)),
|
||||
root_key: BASE64_STANDARD.encode(&self.root_key),
|
||||
sending_chain_key: BASE64_STANDARD.encode(&self.sending_chain_key),
|
||||
current_header_key: BASE64_STANDARD.encode(&self.current_header_key),
|
||||
next_header_key: BASE64_STANDARD.encode(&self.next_header_key),
|
||||
receiving_chain_key: self.receiving_chain_key.iter()
|
||||
.map(|(k, v)| (BASE64_STANDARD.encode(k), BASE64_STANDARD.encode(v)))
|
||||
.collect(),
|
||||
current_sending_chain_length: self.current_sending_chain_length,
|
||||
previous_sending_chain_length: self.previous_sending_chain_length,
|
||||
current_receiving_chain_length: self.current_receiving_chain_length.iter()
|
||||
.map(|(k, &v)| (BASE64_STANDARD.encode(k), v))
|
||||
.collect(),
|
||||
previous_receiving_chain_length: self.previous_receiving_chain_length.iter()
|
||||
.map(|(k, &v)| (BASE64_STANDARD.encode(k), v))
|
||||
.collect(),
|
||||
peer_id_map: self.peer_id_map.iter()
|
||||
.map(|(k, &v)| (BASE64_STANDARD.encode(k), v))
|
||||
.collect(),
|
||||
id_peer_map: self.id_peer_map.iter()
|
||||
.map(|(&k, v)| (k, PeerInfoJson {
|
||||
public_key: BASE64_STANDARD.encode(&v.public_key),
|
||||
identity_public_key: BASE64_STANDARD.encode(&v.identity_public_key),
|
||||
signed_pre_public_key: BASE64_STANDARD.encode(&v.signed_pre_public_key),
|
||||
}))
|
||||
.collect(),
|
||||
skipped_keys_map: self.skipped_keys_map.iter()
|
||||
.map(|(k1, v1)| (BASE64_STANDARD.encode(k1),
|
||||
v1.iter().map(|(k2, v2)| (BASE64_STANDARD.encode(k2),
|
||||
v2.iter().map(|(&k3, v3)| (k3, BASE64_STANDARD.encode(v3)))
|
||||
.collect()))
|
||||
.collect()))
|
||||
.collect(),
|
||||
peer_channels: self.peer_channels.iter()
|
||||
.map(|(k, v)| Ok((BASE64_STANDARD.encode(k), v.to_json()?)))
|
||||
.collect::<Result<HashMap<_, _>, serde_json::Error>>()?,
|
||||
dkg_ratchet: self.dkg_ratchet.to_json()?,
|
||||
next_dkg_ratchet: self.next_dkg_ratchet.to_json()?,
|
||||
async_dkg_ratchet: self.async_dkg_ratchet,
|
||||
should_ratchet: self.should_ratchet,
|
||||
should_dkg_ratchet: self.should_dkg_ratchet.iter()
|
||||
.map(|(k, &v)| (BASE64_STANDARD.encode(k), v))
|
||||
.collect(),
|
||||
async_dkg_pubkey: self.async_dkg_pubkey.as_ref()
|
||||
.map(|p| BASE64_STANDARD.encode(p.compress().to_bytes())),
|
||||
threshold: self.threshold,
|
||||
};
|
||||
|
||||
serde_json::to_string(&triple_ratchet_json)
|
||||
}
|
||||
|
||||
pub fn from_json(json: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let triple_ratchet_json: TripleRatchetParticipantJson = serde_json::from_str(json)?;
|
||||
|
||||
let peer_key_bytes = BASE64_STANDARD.decode(&triple_ratchet_json.peer_key)?;
|
||||
let peer_key = Scalar::from_bytes(&vec_to_array::<56>(peer_key_bytes)?);
|
||||
|
||||
let sending_ephemeral_private_key_bytes = BASE64_STANDARD.decode(&triple_ratchet_json.sending_ephemeral_private_key)?;
|
||||
let sending_ephemeral_private_key = Scalar::from_bytes(&vec_to_array::<56>(sending_ephemeral_private_key_bytes)?);
|
||||
|
||||
let receiving_ephemeral_keys = triple_ratchet_json.receiving_ephemeral_keys.into_iter()
|
||||
.map(|(k, v)| {
|
||||
let key = BASE64_STANDARD.decode(k)?;
|
||||
let value_bytes = BASE64_STANDARD.decode(v)?;
|
||||
let value = Scalar::from_bytes(&vec_to_array::<56>(value_bytes)?);
|
||||
Ok((key, value))
|
||||
})
|
||||
.collect::<Result<HashMap<_, _>, Box<dyn std::error::Error>>>()?;
|
||||
|
||||
let receiving_group_key = triple_ratchet_json.receiving_group_key
|
||||
.map(|k| BASE64_STANDARD.decode(k))
|
||||
.transpose()?;
|
||||
|
||||
let root_key = BASE64_STANDARD.decode(&triple_ratchet_json.root_key)?;
|
||||
let sending_chain_key = BASE64_STANDARD.decode(&triple_ratchet_json.sending_chain_key)?;
|
||||
let current_header_key = BASE64_STANDARD.decode(&triple_ratchet_json.current_header_key)?;
|
||||
let next_header_key = BASE64_STANDARD.decode(&triple_ratchet_json.next_header_key)?;
|
||||
|
||||
let receiving_chain_key = triple_ratchet_json.receiving_chain_key.into_iter()
|
||||
.map(|(k, v)| {
|
||||
let key = BASE64_STANDARD.decode(k)?;
|
||||
let value = BASE64_STANDARD.decode(v)?;
|
||||
Ok((key, value))
|
||||
})
|
||||
.collect::<Result<HashMap<_, _>, Box<dyn std::error::Error>>>()?;
|
||||
|
||||
let current_receiving_chain_length = triple_ratchet_json.current_receiving_chain_length.into_iter()
|
||||
.map(|(k, v)| Ok((BASE64_STANDARD.decode(k)?, v)))
|
||||
.collect::<Result<HashMap<_, _>, Box<dyn std::error::Error>>>()?;
|
||||
|
||||
let previous_receiving_chain_length = triple_ratchet_json.previous_receiving_chain_length.into_iter()
|
||||
.map(|(k, v)| Ok((BASE64_STANDARD.decode(k)?, v)))
|
||||
.collect::<Result<HashMap<_, _>, Box<dyn std::error::Error>>>()?;
|
||||
|
||||
let peer_id_map = triple_ratchet_json.peer_id_map.into_iter()
|
||||
.map(|(k, v)| Ok((BASE64_STANDARD.decode(k)?, v)))
|
||||
.collect::<Result<HashMap<_, _>, Box<dyn std::error::Error>>>()?;
|
||||
|
||||
let id_peer_map = triple_ratchet_json.id_peer_map.into_iter()
|
||||
.map(|(k, v)| Ok((k, PeerInfo {
|
||||
public_key: BASE64_STANDARD.decode(&v.public_key)?,
|
||||
identity_public_key: BASE64_STANDARD.decode(&v.identity_public_key)?,
|
||||
signed_pre_public_key: BASE64_STANDARD.decode(&v.signed_pre_public_key)?,
|
||||
})))
|
||||
.collect::<Result<HashMap<_, _>, Box<dyn std::error::Error>>>()?;
|
||||
|
||||
let skipped_keys_map = triple_ratchet_json.skipped_keys_map.into_iter()
|
||||
.map(|(k1, v1)| {
|
||||
let key1 = BASE64_STANDARD.decode(k1)?;
|
||||
let value1 = v1.into_iter()
|
||||
.map(|(k2, v2)| {
|
||||
let key2 = BASE64_STANDARD.decode(k2)?;
|
||||
let value2 = v2.into_iter()
|
||||
.map(|(k3, v3)| Ok((k3, BASE64_STANDARD.decode(v3)?)))
|
||||
.collect::<Result<HashMap<_, _>, Box<dyn std::error::Error>>>()?;
|
||||
Ok((key2, value2))
|
||||
})
|
||||
.collect::<Result<HashMap<_, _>, Box<dyn std::error::Error>>>()?;
|
||||
Ok((key1, value1))
|
||||
})
|
||||
.collect::<Result<HashMap<_, _>, Box<dyn std::error::Error>>>()?;
|
||||
|
||||
let peer_channels = triple_ratchet_json.peer_channels.into_iter()
|
||||
.map(|(k, v)| Ok((BASE64_STANDARD.decode(k)?, DoubleRatchetParticipant::from_json(v)?)))
|
||||
.collect::<Result<HashMap<_, _>, Box<dyn std::error::Error>>>()?;
|
||||
|
||||
let dkg_ratchet = Feldman::from_json(&triple_ratchet_json.dkg_ratchet)?;
|
||||
let next_dkg_ratchet = Feldman::from_json(&triple_ratchet_json.next_dkg_ratchet)?;
|
||||
|
||||
let should_dkg_ratchet = triple_ratchet_json.should_dkg_ratchet.into_iter()
|
||||
.map(|(k, v)| Ok((BASE64_STANDARD.decode(k)?, v)))
|
||||
.collect::<Result<HashMap<_, _>, Box<dyn std::error::Error>>>()?;
|
||||
|
||||
let mut async_dkg_pubkey: Option<EdwardsPoint> = None;
|
||||
|
||||
if triple_ratchet_json.async_dkg_pubkey.is_some() {
|
||||
let bytes = BASE64_STANDARD.decode(triple_ratchet_json.async_dkg_pubkey.unwrap())?;
|
||||
let point = EdwardsPoint::from_bytes(&vec_to_array::<57>(bytes)?.into());
|
||||
async_dkg_pubkey = point.into_option();
|
||||
}
|
||||
|
||||
Ok(TripleRatchetParticipant {
|
||||
peer_key,
|
||||
sending_ephemeral_private_key,
|
||||
receiving_ephemeral_keys,
|
||||
receiving_group_key,
|
||||
root_key,
|
||||
sending_chain_key,
|
||||
current_header_key,
|
||||
next_header_key,
|
||||
receiving_chain_key,
|
||||
current_sending_chain_length: triple_ratchet_json.current_sending_chain_length,
|
||||
previous_sending_chain_length: triple_ratchet_json.previous_sending_chain_length,
|
||||
current_receiving_chain_length,
|
||||
previous_receiving_chain_length,
|
||||
peer_id_map,
|
||||
id_peer_map,
|
||||
skipped_keys_map,
|
||||
peer_channels,
|
||||
dkg_ratchet,
|
||||
next_dkg_ratchet,
|
||||
async_dkg_ratchet: triple_ratchet_json.async_dkg_ratchet,
|
||||
should_ratchet: triple_ratchet_json.should_ratchet,
|
||||
should_dkg_ratchet,
|
||||
async_dkg_pubkey,
|
||||
threshold: triple_ratchet_json.threshold,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_peer_id_map(&self) -> HashMap<Vec<u8>, usize> {
|
||||
return self.peer_id_map.clone();
|
||||
}
|
||||
|
||||
pub fn initialize(&mut self, init_messages: &HashMap<Vec<u8>, P2PChannelEnvelope>)
|
||||
-> Result<HashMap<Vec<u8>, P2PChannelEnvelope>, TripleRatchetError> {
|
||||
for (k, m) in init_messages {
|
||||
let msg = self.peer_channels.get_mut(k).unwrap().ratchet_decrypt(m).unwrap();
|
||||
if msg != b"init" {
|
||||
return Err(TripleRatchetError::InvalidData("Invalid init message".into()));
|
||||
}
|
||||
}
|
||||
|
||||
self.dkg_ratchet.sample_polynomial(&mut OsRng);
|
||||
|
||||
let result = self.dkg_ratchet.get_poly_frags().unwrap();
|
||||
|
||||
let mut result_map = HashMap::new();
|
||||
for (k, v) in result {
|
||||
let test: bool = self.id_peer_map[&k].public_key.ct_eq(&(self.peer_key * EdwardsPoint::generator()).compress().to_bytes()).into();
|
||||
if !test {
|
||||
let envelope = self.peer_channels
|
||||
.get_mut(&self.id_peer_map[&k].public_key)
|
||||
.unwrap()
|
||||
.ratchet_encrypt(&v);
|
||||
result_map.insert(self.id_peer_map[&k].public_key.clone(), envelope.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result_map)
|
||||
}
|
||||
|
||||
pub fn receive_poly_frag(&mut self, peer_id: &[u8], frag: &P2PChannelEnvelope)
|
||||
-> Result<Option<HashMap<Vec<u8>, P2PChannelEnvelope>>, TripleRatchetError> {
|
||||
let b = self.peer_channels.get_mut(peer_id).unwrap().ratchet_decrypt(frag).unwrap();
|
||||
|
||||
let result = self.dkg_ratchet.set_poly_frag_for_party(
|
||||
*self.peer_id_map.get(peer_id).unwrap(),
|
||||
&b,
|
||||
).unwrap();
|
||||
|
||||
if result.is_some() {
|
||||
let mut envelopes = HashMap::new();
|
||||
for (k, c) in &mut self.peer_channels {
|
||||
|
||||
let envelope = c.ratchet_encrypt(&result.clone().unwrap()).unwrap();
|
||||
envelopes.insert(k.clone(), envelope);
|
||||
}
|
||||
Ok(Some(envelopes))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive_commitment(&mut self, peer_id: &[u8], zkcommit: &P2PChannelEnvelope)
|
||||
-> Result<Option<HashMap<Vec<u8>, P2PChannelEnvelope>>, TripleRatchetError> {
|
||||
let b = self.peer_channels.get_mut(peer_id).unwrap().ratchet_decrypt(zkcommit).unwrap();
|
||||
|
||||
let result = self.dkg_ratchet.receive_commitments(
|
||||
*self.peer_id_map.get(peer_id).unwrap(),
|
||||
&b,
|
||||
).unwrap();
|
||||
|
||||
if let Some(reveal) = result {
|
||||
let d = serde_json::to_vec(&reveal).unwrap();
|
||||
let mut envelopes = HashMap::new();
|
||||
for (k, c) in &mut self.peer_channels {
|
||||
let envelope = c.ratchet_encrypt(&d).unwrap();
|
||||
envelopes.insert(k.clone(), envelope);
|
||||
}
|
||||
Ok(Some(envelopes))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recombine(&mut self, peer_id: &[u8], reveal: &P2PChannelEnvelope) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let b = self.peer_channels.get_mut(peer_id).unwrap().ratchet_decrypt(reveal).unwrap();
|
||||
|
||||
let rev: FeldmanReveal = serde_json::from_slice(&b).unwrap();
|
||||
|
||||
let done = self.dkg_ratchet.recombine(
|
||||
*self.peer_id_map.get(peer_id).unwrap(),
|
||||
&rev,
|
||||
).unwrap();
|
||||
|
||||
if !done {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let sess = Sha512::digest(&self.dkg_ratchet.public_key_bytes());
|
||||
let hkdf = Hkdf::<Sha512>::new(
|
||||
Some(&sess),
|
||||
&self.dkg_ratchet.public_key_bytes(),
|
||||
);
|
||||
let mut rkck = [0u8; 96];
|
||||
let result = hkdf.expand(b"quilibrium-triple-ratchet", &mut rkck);
|
||||
if result.is_err() {
|
||||
return Err(Box::new(TripleRatchetError::CryptoError("invalid length".to_owned())));
|
||||
}
|
||||
|
||||
self.root_key = rkck[..32].to_vec();
|
||||
self.current_header_key = rkck[32..64].to_vec();
|
||||
self.next_header_key = rkck[64..].to_vec();
|
||||
self.receiving_group_key = Some(self.dkg_ratchet.public_key().to_bytes().to_vec());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn ratchet_encrypt(&mut self, message: &[u8]) -> Result<P2PChannelEnvelope, Box<dyn std::error::Error>> {
|
||||
if self.should_ratchet {
|
||||
self.ratchet_sender_ephemeral_keys()?;
|
||||
}
|
||||
|
||||
if self.async_dkg_ratchet && self.async_dkg_pubkey.is_some() && self.should_dkg_ratchet.len() == self.threshold {
|
||||
self.receiving_group_key = Some(self.dkg_ratchet.public_key().to_bytes().to_vec());
|
||||
let sess = Sha512::digest(&self.dkg_ratchet.public_key_bytes());
|
||||
let hkdf = Hkdf::<Sha512>::new(
|
||||
Some(&sess),
|
||||
&self.dkg_ratchet.public_key_bytes(),
|
||||
);
|
||||
let mut rkck = [0u8; 96];
|
||||
let result = hkdf.expand(b"quilibrium-triple-ratchet", &mut rkck);
|
||||
if result.is_err() {
|
||||
return Err(Box::new(TripleRatchetError::CryptoError("invalid length".to_owned())));
|
||||
}
|
||||
|
||||
self.root_key = rkck[..32].to_vec();
|
||||
self.current_header_key = rkck[32..64].to_vec();
|
||||
self.next_header_key = rkck[64..].to_vec();
|
||||
self.async_dkg_pubkey = None;
|
||||
}
|
||||
|
||||
let dkg_pub: Option<(Vec<u8>, Vec<u8>)> = if (self.async_dkg_ratchet && self.should_dkg_ratchet.len() > 0) || self.async_dkg_pubkey.is_some() {
|
||||
if self.async_dkg_pubkey.is_none() {
|
||||
self.should_dkg_ratchet = HashMap::new();
|
||||
self.async_dkg_pubkey = Some(Scalar::random(&mut OsRng) * EdwardsPoint::generator());
|
||||
}
|
||||
|
||||
let pubkey = self.async_dkg_pubkey.unwrap();
|
||||
let invpub = self.dkg_ratchet.mul_share(&pubkey.compress().to_bytes());
|
||||
if invpub.is_err() {
|
||||
return Err(Box::new(invpub.unwrap_err()));
|
||||
}
|
||||
self.should_dkg_ratchet.insert((self.peer_key * EdwardsPoint::generator()).compress().to_bytes().to_vec(), true);
|
||||
|
||||
Some((invpub.unwrap(), pubkey.compress().to_bytes().to_vec()))
|
||||
} else { None };
|
||||
|
||||
let mut envelope = P2PChannelEnvelope {
|
||||
protocol_identifier: TRIPLE_RATCHET_PROTOCOL,
|
||||
message_header: MessageCiphertext::default(),
|
||||
message_body: MessageCiphertext::default(),
|
||||
};
|
||||
|
||||
let (new_chain_key, message_key, aead_key) = ratchet_keys(&self.sending_chain_key);
|
||||
|
||||
self.sending_chain_key = new_chain_key;
|
||||
|
||||
let header = self.encode_header(dkg_pub);
|
||||
envelope.message_header = self.encrypt(&header, &self.current_header_key, None)?;
|
||||
envelope.message_body = self.encrypt(
|
||||
message,
|
||||
&message_key,
|
||||
Some(&[&aead_key[..], &envelope.message_header.ciphertext[..]].concat()),
|
||||
)?;
|
||||
|
||||
self.current_sending_chain_length += 1;
|
||||
|
||||
Ok(envelope)
|
||||
}
|
||||
|
||||
pub fn ratchet_decrypt(&mut self, envelope: &P2PChannelEnvelope) -> Result<(Vec<u8>, bool), Box<dyn std::error::Error>> {
|
||||
if let Some(plaintext) = self.try_skipped_message_keys(envelope)? {
|
||||
return Ok((plaintext, false));
|
||||
}
|
||||
|
||||
let header_key = self.current_header_key.clone();
|
||||
let (header, mut should_dkg_ratchet, should_advance_dkg_ratchet) = self.decrypt_header(&envelope.message_header, &header_key)?;
|
||||
|
||||
let (sender_key, receiving_ephemeral_key, previous_receiving_chain_length, current_receiving_chain_length, dkg_pub) =
|
||||
self.decode_header(&header)?;
|
||||
|
||||
let should_ratchet = self.receiving_ephemeral_keys.get(&sender_key.compress().to_bytes().to_vec()).map(|k| !k.eq(&receiving_ephemeral_key)).unwrap_or(true);
|
||||
if should_ratchet {
|
||||
self.skip_message_keys(&sender_key, previous_receiving_chain_length)?;
|
||||
self.ratchet_receiver_ephemeral_keys(&sender_key, &receiving_ephemeral_key)?;
|
||||
}
|
||||
|
||||
self.skip_message_keys(&sender_key, current_receiving_chain_length)?;
|
||||
|
||||
let (new_chain_key, message_key, aead_key) = ratchet_keys(
|
||||
&self.receiving_chain_key[&sender_key.compress().to_bytes().to_vec()],
|
||||
);
|
||||
|
||||
self.receiving_chain_key.insert(sender_key.compress().to_bytes().to_vec(), new_chain_key);
|
||||
|
||||
*self.current_receiving_chain_length.entry(sender_key.compress().to_bytes().to_vec()).or_insert(0) += 1;
|
||||
|
||||
if should_advance_dkg_ratchet {
|
||||
self.receiving_group_key = Some(self.dkg_ratchet.public_key().to_bytes().to_vec());
|
||||
let sess = Sha512::digest(&self.dkg_ratchet.public_key_bytes());
|
||||
let hkdf = Hkdf::<Sha512>::new(
|
||||
Some(&sess),
|
||||
&self.dkg_ratchet.public_key_bytes(),
|
||||
);
|
||||
let mut rkck = [0u8; 96];
|
||||
let result = hkdf.expand(b"quilibrium-triple-ratchet", &mut rkck);
|
||||
if result.is_err() {
|
||||
return Err(Box::new(TripleRatchetError::CryptoError("invalid length".to_owned())));
|
||||
}
|
||||
|
||||
self.root_key = rkck[..32].to_vec();
|
||||
self.current_header_key = rkck[32..64].to_vec();
|
||||
self.next_header_key = rkck[64..].to_vec();
|
||||
}
|
||||
|
||||
let plaintext = self.decrypt(
|
||||
&envelope.message_body,
|
||||
&message_key,
|
||||
Some(&[&aead_key[..], &envelope.message_header.ciphertext[..]].concat()),
|
||||
)?;
|
||||
|
||||
if dkg_pub.is_some() {
|
||||
should_dkg_ratchet = false;
|
||||
let (other_invpub, pubkey) = dkg_pub.unwrap();
|
||||
self.async_dkg_pubkey = Some(pubkey);
|
||||
|
||||
let invpub = self.dkg_ratchet.mul_share(&pubkey.compress().to_bytes());
|
||||
if invpub.is_err() {
|
||||
return Err(Box::new(invpub.unwrap_err()));
|
||||
}
|
||||
|
||||
let invvec = invpub.unwrap();
|
||||
let inv = invvec.as_slice();
|
||||
let other = &other_invpub.compress().to_bytes();
|
||||
|
||||
let other_id = self.peer_id_map.get(&sender_key.compress().to_bytes().to_vec());
|
||||
if other_id.is_none() {
|
||||
return Err(Box::new(TripleRatchetError::MalformedHeader))
|
||||
}
|
||||
|
||||
let our_id = self.peer_id_map.get(&(self.peer_key * EdwardsPoint::generator()).compress().to_bytes().to_vec());
|
||||
let (shares, ids) = if our_id.unwrap() < other_id.unwrap() {
|
||||
(vec![inv, other], [*our_id.unwrap(), *other_id.unwrap()])
|
||||
} else {
|
||||
(vec![other, inv], [*other_id.unwrap(), *our_id.unwrap()])
|
||||
};
|
||||
|
||||
let next_pub = self.dkg_ratchet.combine_mul_share(shares, &ids);
|
||||
if next_pub.is_err() {
|
||||
return Err(Box::new(next_pub.unwrap_err()));
|
||||
}
|
||||
|
||||
let next = EdwardsPoint::from_bytes(next_pub.unwrap().as_slice().into());
|
||||
if next.is_none().into() {
|
||||
return Err(Box::new(TripleRatchetError::MalformedHeader));
|
||||
}
|
||||
}
|
||||
|
||||
Ok((plaintext, should_dkg_ratchet))
|
||||
}
|
||||
|
||||
fn ratchet_sender_ephemeral_keys(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let receiving_group_key = self.receiving_group_key.as_ref().ok_or_else(|| TripleRatchetError::CryptoError("Receiving group key not set".into()))?;
|
||||
self.sending_ephemeral_private_key = Scalar::random(&mut OsRng);
|
||||
let dh_output = (self.sending_ephemeral_private_key * EdwardsPoint::from_bytes(receiving_group_key.as_slice().into()).unwrap()).compress().to_bytes();
|
||||
|
||||
let hkdf = Hkdf::<Sha512>::new(Some(&self.root_key), &dh_output);
|
||||
let mut rkck2 = [0u8; 96];
|
||||
let result = hkdf.expand(b"quilibrium-triple-ratchet", &mut rkck2);
|
||||
if result.is_err() {
|
||||
return Err(Box::new(TripleRatchetError::CryptoError("invalid length".to_owned())));
|
||||
}
|
||||
|
||||
self.root_key = rkck2[..32].to_vec();
|
||||
self.sending_chain_key = rkck2[32..64].to_vec();
|
||||
self.should_ratchet = false;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ratchet_receiver_ephemeral_keys(&mut self, peer_key: &EdwardsPoint, new_ephemeral_key: &Scalar) -> Result<(), Box<dyn std::error::Error>> {
|
||||
self.previous_sending_chain_length = self.current_sending_chain_length;
|
||||
self.current_sending_chain_length = 0;
|
||||
*self.current_receiving_chain_length.entry(peer_key.compress().to_bytes().to_vec()).or_insert(0) = 0;
|
||||
self.receiving_ephemeral_keys.insert(peer_key.compress().to_bytes().to_vec(), new_ephemeral_key.clone());
|
||||
|
||||
let receiving_group_key = self.receiving_group_key.as_ref().ok_or_else(|| TripleRatchetError::CryptoError("Receiving group key not set".into()))?;
|
||||
let dh_output = (new_ephemeral_key * EdwardsPoint::from_bytes(receiving_group_key.as_slice().into()).unwrap()).compress().to_bytes();
|
||||
|
||||
let hkdf = Hkdf::<Sha512>::new(Some(&self.root_key), &dh_output);
|
||||
let mut rkck = [0u8; 96];
|
||||
let result = hkdf.expand(b"quilibrium-triple-ratchet", &mut rkck);
|
||||
if result.is_err() {
|
||||
return Err(Box::new(TripleRatchetError::CryptoError("invalid length".to_owned())));
|
||||
}
|
||||
|
||||
self.root_key = rkck[..32].to_vec();
|
||||
self.receiving_chain_key.insert(peer_key.compress().to_bytes().to_vec(), rkck[32..64].to_vec());
|
||||
self.should_ratchet = true;
|
||||
|
||||
if self.async_dkg_ratchet {
|
||||
self.should_dkg_ratchet = HashMap::new();
|
||||
self.should_dkg_ratchet.insert(peer_key.compress().to_bytes().to_vec(), true);
|
||||
self.async_dkg_pubkey = None;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_skipped_message_keys(&mut self, envelope: &P2PChannelEnvelope) -> Result<Option<Vec<u8>>, Box<dyn std::error::Error>> {
|
||||
for (receiving_header_key, skipped_keys) in &self.skipped_keys_map.clone() {
|
||||
if let Ok((header, _, _)) = self.decrypt_header(&envelope.message_header, receiving_header_key) {
|
||||
let (peer_key, _, _, current, _) = self.decode_header(&header)?;
|
||||
if let Some(peer_skipped_keys) = skipped_keys.get(&peer_key.compress().to_bytes().to_vec()) {
|
||||
if let Some(key_pair) = peer_skipped_keys.get(¤t) {
|
||||
let message_key = &key_pair[..32];
|
||||
let aead_key = &key_pair[32..];
|
||||
let plaintext = self.decrypt(
|
||||
&envelope.message_body,
|
||||
message_key,
|
||||
Some(&[aead_key, &envelope.message_header.ciphertext].concat()),
|
||||
)?;
|
||||
return Ok(Some(plaintext));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn skip_message_keys(&mut self, sender_key: &EdwardsPoint, until: u32) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut current = *self.current_receiving_chain_length.entry(sender_key.compress().to_bytes().to_vec()).or_insert(0);
|
||||
if current + 100 < until {
|
||||
return Err(Box::new(TripleRatchetError::SkipLimitExceeded));
|
||||
}
|
||||
|
||||
if let Some(chain_key) = self.receiving_chain_key.get_mut(&sender_key.compress().to_bytes().to_vec()) {
|
||||
while current < until {
|
||||
let (new_chain_key, message_key, aead_key) = ratchet_keys(chain_key);
|
||||
self.skipped_keys_map
|
||||
.entry(self.current_header_key.clone())
|
||||
.or_insert_with(HashMap::new)
|
||||
.entry(sender_key.compress().to_bytes().to_vec())
|
||||
.or_insert_with(HashMap::new)
|
||||
.insert(current, [message_key, aead_key].concat());
|
||||
*chain_key = new_chain_key;
|
||||
current += 1;
|
||||
*self.current_receiving_chain_length.entry(sender_key.compress().to_bytes().to_vec()).or_insert(0) += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn encode_header(&self, dkg_pub: Option<(Vec<u8>, Vec<u8>)>) -> Vec<u8> {
|
||||
let mut header = Vec::new();
|
||||
header.extend_from_slice(&(self.peer_key * EdwardsPoint::generator()).compress().to_bytes().to_vec());
|
||||
header.extend_from_slice(&self.sending_ephemeral_private_key.to_bytes());
|
||||
header.extend_from_slice(&self.previous_sending_chain_length.to_be_bytes());
|
||||
header.extend_from_slice(&self.current_sending_chain_length.to_be_bytes());
|
||||
if dkg_pub.is_some() {
|
||||
let (invpub, pubkey) = dkg_pub.unwrap();
|
||||
header.extend(invpub);
|
||||
header.extend(pubkey);
|
||||
}
|
||||
header
|
||||
}
|
||||
|
||||
fn decrypt_header(&mut self, ciphertext: &MessageCiphertext, receiving_header_key: &[u8]) -> Result<(Vec<u8>, bool, bool), Box<dyn std::error::Error>> {
|
||||
match self.decrypt(ciphertext, receiving_header_key, None) {
|
||||
Ok(header) => {
|
||||
Ok((header, self.async_dkg_ratchet, false))
|
||||
},
|
||||
Err(_) if receiving_header_key == self.current_header_key => {
|
||||
if self.async_dkg_ratchet && self.async_dkg_pubkey.is_some() {
|
||||
let receiving_group_key = Some(self.dkg_ratchet.public_key().to_bytes().to_vec());
|
||||
let sess = Sha512::digest(&self.dkg_ratchet.public_key_bytes());
|
||||
let hkdf = Hkdf::<Sha512>::new(
|
||||
Some(&sess),
|
||||
&self.dkg_ratchet.public_key_bytes(),
|
||||
);
|
||||
let mut rkck = [0u8; 96];
|
||||
let result = hkdf.expand(b"quilibrium-triple-ratchet", &mut rkck);
|
||||
if result.is_err() {
|
||||
return Err(Box::new(TripleRatchetError::CryptoError("invalid length".to_owned())));
|
||||
}
|
||||
|
||||
let current_header_key = rkck[32..64].to_vec();
|
||||
match self.decrypt(ciphertext, ¤t_header_key, None) {
|
||||
Ok(header) => Ok((header, true, true)),
|
||||
Err(e) => Err(Box::new(e)),
|
||||
}
|
||||
} else {
|
||||
match self.decrypt(ciphertext, &self.next_header_key, None) {
|
||||
Ok(header) => Ok((header, true, false)),
|
||||
Err(e) => Err(Box::new(e)),
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => Err(Box::new(e)),
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_header(&self, header: &[u8]) -> Result<(EdwardsPoint, Scalar, u32, u32, Option<(EdwardsPoint, EdwardsPoint)>), TripleRatchetError> {
|
||||
if header.len() < 121 {
|
||||
return Err(TripleRatchetError::MalformedHeader);
|
||||
}
|
||||
|
||||
let sender_key = EdwardsPoint::from_bytes(header[..57].into()).unwrap();
|
||||
let receiving_ephemeral_key = Scalar::from_bytes(header[57..113].try_into().unwrap());
|
||||
let previous_receiving_chain_length = u32::from_be_bytes(header[113..117].try_into().unwrap());
|
||||
let current_receiving_chain_length = u32::from_be_bytes(header[117..121].try_into().unwrap());
|
||||
|
||||
let dkg_pub = if header.len() == 235 {
|
||||
let invpub = EdwardsPoint::from_bytes(header[121..178].into()).into_option();
|
||||
let pubkey = EdwardsPoint::from_bytes(header[178..].into()).into_option();
|
||||
if invpub.is_none() || pubkey.is_none() {
|
||||
None
|
||||
} else {
|
||||
Some((invpub.unwrap(), pubkey.unwrap()))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok((sender_key, receiving_ephemeral_key, previous_receiving_chain_length, current_receiving_chain_length, dkg_pub))
|
||||
}
|
||||
|
||||
fn encrypt(&self, plaintext: &[u8], key: &[u8], associated_data: Option<&[u8]>)
|
||||
-> Result<MessageCiphertext, Box<dyn std::error::Error>> {
|
||||
use aes_gcm::KeyInit;
|
||||
let mut iv = [0u8; 12];
|
||||
OsRng.fill_bytes(&mut iv);
|
||||
|
||||
let cipher = Aes256Gcm::new_from_slice(key).unwrap();
|
||||
let nonce = Nonce::from_slice(&iv);
|
||||
|
||||
let mut associated_data = associated_data.unwrap_or(&[]);
|
||||
let mut aad = [0u8; 32];
|
||||
if associated_data.len() == 0 {
|
||||
OsRng.fill_bytes(&mut aad);
|
||||
associated_data = &aad
|
||||
}
|
||||
|
||||
let ciphertext = cipher.encrypt(nonce, Payload{
|
||||
msg: plaintext,
|
||||
aad: associated_data,
|
||||
}).map_err(|e| format!("Encryption failed: {}", e))?;
|
||||
|
||||
Ok(MessageCiphertext {
|
||||
ciphertext,
|
||||
initialization_vector: iv.to_vec(),
|
||||
associated_data: Some(associated_data.to_vec()),
|
||||
})
|
||||
}
|
||||
|
||||
fn decrypt(&self, ciphertext: &MessageCiphertext, key: &[u8], associated_data: Option<&[u8]>) -> Result<Vec<u8>, TripleRatchetError> {
|
||||
use aes_gcm::KeyInit;
|
||||
if key.len() != 32 {
|
||||
return Err(TripleRatchetError::InvalidData("Invalid key length".to_string()));
|
||||
}
|
||||
let cipher = Aes256Gcm::new_from_slice(key).unwrap();
|
||||
let nonce = Nonce::from_slice(&ciphertext.initialization_vector);
|
||||
|
||||
let associated_data = associated_data.unwrap_or_else(|| ciphertext.associated_data.as_ref().unwrap());
|
||||
|
||||
cipher.decrypt(nonce, Payload{
|
||||
msg: &ciphertext.ciphertext.as_ref(),
|
||||
aad: associated_data.as_ref(),
|
||||
}).map_err(|e| TripleRatchetError::CryptoError(e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
fn ratchet_keys(input: &[u8]) -> (Vec<u8>, Vec<u8>, Vec<u8>) {
|
||||
let mut output = [0u8; 96];
|
||||
let hkdf = Hkdf::<Sha512>::new(None, input);
|
||||
hkdf.expand(b"quilibrium-triple-ratchet-keys", &mut output).unwrap();
|
||||
(output[..32].to_vec(), output[32..64].to_vec(), output[64..].to_vec())
|
||||
}
|
82
crates/channel/src/protocols/x3dh.rs
Normal file
82
crates/channel/src/protocols/x3dh.rs
Normal file
@ -0,0 +1,82 @@
|
||||
use std::collections::HashMap;
|
||||
use sha2::Sha512;
|
||||
use hkdf::Hkdf;
|
||||
use ed448_goldilocks_plus::{subtle, CompressedEdwardsY, EdwardsPoint, Scalar};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
lazy_static! {
|
||||
static ref DOMAIN_SEPARATORS: HashMap<&'static str, Vec<u8>> = {
|
||||
let mut m = HashMap::new();
|
||||
m.insert("ed448", vec![
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF,
|
||||
]);
|
||||
m
|
||||
};
|
||||
}
|
||||
|
||||
pub fn sender_x3dh(
|
||||
sending_identity_private_key: &Scalar,
|
||||
sending_ephemeral_private_key: &Scalar,
|
||||
receiving_identity_key: &EdwardsPoint,
|
||||
receiving_signed_pre_key: &EdwardsPoint,
|
||||
session_key_length: usize,
|
||||
) -> Option<Vec<u8>> {
|
||||
let xdh1 = (receiving_signed_pre_key * sending_identity_private_key).compress().to_bytes().to_vec();
|
||||
let xdh2 = (receiving_identity_key * sending_ephemeral_private_key).compress().to_bytes().to_vec();
|
||||
let xdh3 = (receiving_signed_pre_key * sending_ephemeral_private_key).compress().to_bytes().to_vec();
|
||||
|
||||
let salt = vec![0u8; session_key_length];
|
||||
let info = b"quilibrium-x3dh";
|
||||
|
||||
let domain_separator = DOMAIN_SEPARATORS.get("ed448")
|
||||
.expect("Unsupported curve");
|
||||
|
||||
let mut ikm = Vec::<u8>::new();
|
||||
ikm.extend(domain_separator);
|
||||
ikm.extend(xdh1);
|
||||
ikm.extend(xdh2);
|
||||
ikm.extend(xdh3);
|
||||
|
||||
let hk = Hkdf::<Sha512>::new(Some(&salt), &ikm);
|
||||
let mut session_key = vec![0u8; session_key_length];
|
||||
hk.expand(info, &mut session_key).ok()?;
|
||||
|
||||
Some(session_key)
|
||||
}
|
||||
|
||||
pub fn receiver_x3dh(
|
||||
sending_identity_private_key: &Scalar,
|
||||
sending_signed_pre_private_key: &Scalar,
|
||||
receiving_identity_key: &EdwardsPoint,
|
||||
receiving_ephemeral_key: &EdwardsPoint,
|
||||
session_key_length: usize,
|
||||
) -> Option<Vec<u8>> {
|
||||
let xdh1 = (receiving_identity_key * sending_signed_pre_private_key).compress().to_bytes().to_vec();
|
||||
let xdh2 = (receiving_ephemeral_key * sending_identity_private_key).compress().to_bytes().to_vec();
|
||||
let xdh3 = (receiving_ephemeral_key * sending_signed_pre_private_key).compress().to_bytes().to_vec();
|
||||
|
||||
let salt = vec![0u8; session_key_length];
|
||||
let info = b"quilibrium-x3dh";
|
||||
|
||||
let domain_separator = DOMAIN_SEPARATORS.get("ed448")
|
||||
.expect("Unsupported curve");
|
||||
|
||||
let mut ikm = Vec::<u8>::new();
|
||||
ikm.extend(domain_separator);
|
||||
ikm.extend(xdh1);
|
||||
ikm.extend(xdh2);
|
||||
ikm.extend(xdh3);
|
||||
|
||||
let hk = Hkdf::<Sha512>::new(Some(&salt), &ikm);
|
||||
let mut session_key = vec![0u8; session_key_length];
|
||||
hk.expand(info, &mut session_key).ok()?;
|
||||
|
||||
Some(session_key)
|
||||
}
|
7
crates/rpm/Cargo.lock
generated
Normal file
7
crates/rpm/Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "rpm"
|
||||
version = "0.1.0"
|
30
crates/rpm/Cargo.toml
Normal file
30
crates/rpm/Cargo.toml
Normal file
@ -0,0 +1,30 @@
|
||||
[package]
|
||||
name = "rpm"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib", "staticlib"]
|
||||
name = "rpm"
|
||||
|
||||
[dependencies]
|
||||
hex = "0.4.3"
|
||||
serde_json = "1.0.117"
|
||||
uniffi = { version= "0.25", features = ["cli"]}
|
||||
curve25519-dalek = "4.1.3"
|
||||
rand = "0.8.5"
|
||||
num = "0.4.3"
|
||||
lazy_static = "1.5.0"
|
||||
subtle = "2.6.1"
|
||||
rayon = "1.10"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.4", features = ["html_reports"] }
|
||||
rand = "0.8.5"
|
||||
|
||||
[build-dependencies]
|
||||
uniffi = { version = "0.25", features = [ "build" ] }
|
||||
|
||||
[[bench]]
|
||||
name = "bench_rpm"
|
||||
harness = false
|
32
crates/rpm/README.md
Normal file
32
crates/rpm/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# RPM
|
||||
Based on the paper [RPM: Robust Anonymity at Scale](https://eprint.iacr.org/2022/1037). Built to be used as a primitive – all sharp edges are exposed, using this without properly checking the boundaries of the input will cut!
|
||||
|
||||
Includes UniFFI UDL file for FFI integration.
|
||||
|
||||
## How to use safely
|
||||
There are six public functions of interest for builders to use if they want to have a purpose built mixnet:
|
||||
|
||||
- rpm_generate_initial_shares
|
||||
- rpm_combine_shares_and_mask
|
||||
- rpm_sketch_propose
|
||||
- rpm_sketch_verify
|
||||
- rpm_permute
|
||||
- rpm_finalize
|
||||
|
||||
### rpm_generate_initial_shares
|
||||
Performs the first of four steps of the "offline" phase of RPM Variant 3 (Subvariant 2). Each active dealer in a given offline batch generates initial shares of the permutation matrices and masks. Assumes player identifiers are in monotonically increasing order starting from 1, player count must be greater than or equal to the square of dealers. For malicious security, a ZKPoK should be used for each share set and broadcasted by all dealers prior to the next step.
|
||||
|
||||
### rpm_combine_shares_and_mask
|
||||
Performs the second of four steps of the "offline" phase. Each player should have received their respective shares and organized them according to sequence of players for inputs. For malicious security, the ZKPoK should be verified after invoking this. The splits of the permutation matrices and masks should be passed into the next step.
|
||||
|
||||
### rpm_sketch_propose
|
||||
Performs the third of four steps of the "offline" phase. Each player should take the splits of the permutation matrices and masks and pass them into this function. All players should broadcast the sketch proposals.
|
||||
|
||||
### rpm_sketch_verify
|
||||
Performs the fourth step of the "offline" phase. Each player should take the broadcasted sketch proposals and pass them into the function. If any dealer or player had cheated, it would be revealed by the intersection of failures.
|
||||
|
||||
### rpm_permute
|
||||
Performs the first step of the "online" phase. Before invoking this, each message sender should obtain a vector of the first depth's mask shares, at the same index from each, from as many players as needed to match the dealer count. The sender should combine these shares to produce the mask for their message, and add it to their message (chunked by field element size if need be), and secret share it with the same parameters (t = dealers, n = players). The players will collect their respective shares of inputs into an input vector following the order of the mask shares that were applied. The players will then pass in the input vector shares, matrix shares, mask shares, and combined matrix/mask shares from `rpm_combine_shares_and_mask`, along with the depth and player identifiers in player order. This function should be invoked in as many rounds as there is depth to the mixnet, using the previous invocation's output shares given to each respective player. This must be repeated for each chunked vector of field elements if applicable.
|
||||
|
||||
### rpm_finalize
|
||||
A convenience funciton which recombines the shares of the final invocation of `rpm_permute`'s output into the finalized vector of the mixnet.
|
71
crates/rpm/benches/bench_rpm.rs
Normal file
71
crates/rpm/benches/bench_rpm.rs
Normal file
@ -0,0 +1,71 @@
|
||||
use curve25519_dalek::Scalar;
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
let smsize = 100;
|
||||
let msize = smsize*smsize;
|
||||
let depth = 4;
|
||||
let players = 9;
|
||||
let dealers = 3;
|
||||
|
||||
//todo parties should be + 1
|
||||
let is1 = rpm::rpm_generate_initial_shares(msize, depth, dealers, players);
|
||||
let is2 = rpm::rpm_generate_initial_shares(msize, depth, dealers, players);
|
||||
let is3 = rpm::rpm_generate_initial_shares(msize, depth, dealers, players);
|
||||
let (m1, r1) = (is1.ms, is1.rs);
|
||||
let (m2, r2) = (is2.ms, is2.rs);
|
||||
let (m3, r3) = (is3.ms, is3.rs);
|
||||
|
||||
let mut ms = vec![vec![vec![vec![vec![vec![[0u8; 32]; smsize]; smsize]; smsize]; depth]; dealers]; players];
|
||||
let mut rs = vec![vec![vec![vec![[0u8; 32]; msize]; depth]; dealers]; players];
|
||||
|
||||
let mut mc = Vec::<Vec<Vec<Vec<Vec<[u8; 32]>>>>>::with_capacity(players);
|
||||
let mut rc = Vec::<Vec<Vec<[u8; 32]>>>::with_capacity(players);
|
||||
let mut mrmc = Vec::<Vec<Vec<Vec<Vec<[u8; 32]>>>>>::with_capacity(players);
|
||||
let mut mccs = Vec::<Vec<Vec<Vec<[u8; 32]>>>>::with_capacity(players);
|
||||
let mut rccs = Vec::<Vec<[u8; 32]>>::with_capacity(players);
|
||||
for i in 0..players {
|
||||
for j in 0..depth {
|
||||
for k in 0..smsize {
|
||||
ms[i][0][j][k] = m1[j][k][i].clone();
|
||||
ms[i][1][j][k] = m2[j][k][i].clone();
|
||||
ms[i][2][j][k] = m3[j][k][i].clone();
|
||||
}
|
||||
|
||||
rs[i][0][j] = r1[j][i].clone();
|
||||
rs[i][1][j] = r2[j][i].clone();
|
||||
rs[i][2][j] = r3[j][i].clone();
|
||||
}
|
||||
|
||||
let cs = rpm::rpm_combine_shares_and_mask(ms[i].clone(), rs[i].clone(), msize, depth, dealers);
|
||||
let (m, r, mrm) = (cs.ms, cs.rs, cs.mrms);
|
||||
let sp = rpm::rpm_sketch_propose(m.clone(), r.clone());
|
||||
let (mcc, rcc) = (sp.mp, sp.rp);
|
||||
|
||||
mc.push(m);
|
||||
rc.push(r);
|
||||
mrmc.push(mrm);
|
||||
mccs.push(mcc);
|
||||
rccs.push(rcc);
|
||||
}
|
||||
|
||||
let mut xs = vec![vec![[0u8; 32]; msize]; players];
|
||||
|
||||
for i in 0..msize {
|
||||
let xsi = rpm::gen_poly_frags(&Scalar::from(i as u64), 9, 3);
|
||||
for j in 0..9 {
|
||||
xs[j][i] = (Scalar::from_bytes_mod_order(xsi[j]) + Scalar::from_bytes_mod_order(rc[j][0][i])).to_bytes();
|
||||
}
|
||||
}
|
||||
|
||||
let mut group = c.benchmark_group("rpm");
|
||||
group.sample_size(10);
|
||||
group.bench_function(format!("rpm init {}", msize), |b| b.iter(|| black_box(rpm::rpm_generate_initial_shares(msize, depth, 3, 9))));
|
||||
group.bench_function(format!("rpm combine {}", msize), |b| b.iter(|| black_box(rpm::rpm_combine_shares_and_mask(ms[0].clone(), rs[0].clone(), msize, depth, dealers))));
|
||||
group.bench_function(format!("rpm sketch propose {}", msize), |b| b.iter(|| black_box(rpm::rpm_sketch_propose(mc[0].clone(), rc[0].clone()))));
|
||||
group.bench_function(format!("rpm sketch verify {}", msize), |b| b.iter(|| black_box(rpm::rpm_sketch_verify(mccs.clone(), rccs.clone(), dealers))));
|
||||
group.bench_function(format!("rpm permute {}", msize), |b| b.iter(|| black_box(rpm::rpm_permute(xs.clone(), mc[0].clone(), rc[0].clone(), mrmc[0].clone(), 0, vec![1,2,3,4,5,6,7,8,9]))));
|
||||
}
|
||||
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
criterion_main!(benches);
|
5
crates/rpm/build.rs
Normal file
5
crates/rpm/build.rs
Normal file
@ -0,0 +1,5 @@
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
uniffi::generate_scaffolding("src/lib.udl").expect("uniffi generation failed");
|
||||
}
|
1274
crates/rpm/src/lib.rs
Normal file
1274
crates/rpm/src/lib.rs
Normal file
File diff suppressed because it is too large
Load Diff
24
crates/rpm/src/lib.udl
Normal file
24
crates/rpm/src/lib.udl
Normal file
@ -0,0 +1,24 @@
|
||||
namespace rpm {
|
||||
InitialShares rpm_generate_initial_shares(u64 size, u64 depth, u64 dealers, u64 players);
|
||||
CombinedSharesAndMask rpm_combine_shares_and_mask([ByRef] sequence<sequence<sequence<sequence<sequence<sequence<u8>>>>>> ms, [ByRef] sequence<sequence<sequence<sequence<u8>>>> rs, u64 size, u64 depth, u64 dealers);
|
||||
SketchProposal rpm_sketch_propose([ByRef] sequence<sequence<sequence<sequence<sequence<u8>>>>> m, [ByRef] sequence<sequence<sequence<u8>>> r);
|
||||
boolean rpm_sketch_verify([ByRef] sequence<sequence<sequence<sequence<sequence<u8>>>>> mcs, [ByRef] sequence<sequence<sequence<u8>>> rcs, u64 dealers);
|
||||
sequence<sequence<sequence<u8>>> rpm_permute([ByRef] sequence<sequence<sequence<u8>>> masked_input_shares, [ByRef] sequence<sequence<sequence<sequence<sequence<u8>>>>> mb, [ByRef] sequence<sequence<sequence<u8>>> rb, [ByRef] sequence<sequence<sequence<sequence<sequence<u8>>>>> mrmb, u64 depth_index, [ByRef] sequence<u64> parties);
|
||||
sequence<sequence<u8>> rpm_finalize([ByRef] sequence<sequence<sequence<u8>>> input, [ByRef] sequence<u64> parties);
|
||||
};
|
||||
|
||||
dictionary InitialShares {
|
||||
sequence<sequence<sequence<sequence<sequence<sequence<u8>>>>>> ms;
|
||||
sequence<sequence<sequence<sequence<sequence<u8>>>>> rs;
|
||||
};
|
||||
|
||||
dictionary CombinedSharesAndMask {
|
||||
sequence<sequence<sequence<sequence<sequence<u8>>>>> ms;
|
||||
sequence<sequence<sequence<u8>>> rs;
|
||||
sequence<sequence<sequence<sequence<sequence<u8>>>>> mrms;
|
||||
};
|
||||
|
||||
dictionary SketchProposal {
|
||||
sequence<sequence<sequence<sequence<u8>>>> mp;
|
||||
sequence<sequence<u8>> rp;
|
||||
};
|
@ -175,6 +175,7 @@ mod test {
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_random_bytes() {
|
||||
assert_eq!(
|
||||
|
@ -1,11 +1,123 @@
|
||||
# go-libp2p-blossomsub
|
||||
|
||||
First-pass of blossomsub, rudimentary fork of gossipsub – it does not merge subscriptions, bloom filtering needs to
|
||||
happen at the publish level. This will be updated post-ceremony with the full bloom filter version.
|
||||
<p align="left">
|
||||
<a href="https://quilibrium.com"><img src="https://img.shields.io/badge/made%20by-Quilibrium%20Inc-orange.svg?style=flat-square" /></a>
|
||||
<a href="https://github.com/quilibriumnetwork"><img src="https://img.shields.io/badge/project-Quilibrium-orange.svg?style=flat-square" /></a>
|
||||
<a href="https://discourse.quilibrium.com/"><img src="https://img.shields.io/discourse/posts.svg?server=https%3A%2F%2Fquilibrium.discourse.group&style=flat-square" /></a>
|
||||
<a href=""><img src="https://img.shields.io/badge/golang-%3E%3D1.22.0-orange.svg?style=flat-square" /></a>
|
||||
</p>
|
||||
|
||||
This repo contains the canonical blossomsub implementation for Quilibrium. It has historical origins in [Gossipsub](https://github.com/libp2p/go-libp2p-pubsub), but has diverged significantly. Floodsub and Randomsub are not included in this fork.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Install](#install)
|
||||
- [Usage](#usage)
|
||||
- [Overview](#overview)
|
||||
- [Tracing](#tracing)
|
||||
- [Contribute](#contribute)
|
||||
- [License](#license)
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
go get source.quilibrium.com/quilibrium/monorepo/go-libp2p-pubsub
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
To be used for messaging in high scale, high throughput p2p instrastructure such as Quilibrium.
|
||||
|
||||
### Overview
|
||||
|
||||
```
|
||||
.
|
||||
├── LICENSE
|
||||
├── README.md
|
||||
# Regular Golang repo set up
|
||||
├── codecov.yml
|
||||
├── pb
|
||||
├── go.mod
|
||||
├── go.sum
|
||||
├── doc.go
|
||||
# PubSub base
|
||||
├── backoff.go
|
||||
├── bitmask.go
|
||||
├── blacklist.go
|
||||
├── comm.go
|
||||
├── discovery.go
|
||||
├── gossip_tracer.go
|
||||
├── midgen.go
|
||||
├── peer_gater.go
|
||||
├── peer_notify.go
|
||||
├── pubsub.go
|
||||
├── sign.go
|
||||
├── subscription.go
|
||||
├── tag_tracer.go
|
||||
├── trace.go
|
||||
├── tracer.go
|
||||
├── validation.go
|
||||
# Blossomsub router
|
||||
├── blossomsub_feat.go
|
||||
├── blossomsub.go
|
||||
├── mcache.go
|
||||
├── score.go
|
||||
└── score_params.go
|
||||
```
|
||||
|
||||
### Tracing
|
||||
|
||||
The pubsub system supports _tracing_, which collects all events pertaining to the internals of the system. This allows you to recreate the complete message flow and state of the system for analysis purposes.
|
||||
|
||||
To enable tracing, instantiate the pubsub system using the `WithEventTracer` option; the option accepts a tracer with three available implementations in-package (trace to json, pb, or a remote peer).
|
||||
If you want to trace using a remote peer in the same way gossipsub tracing worked, you would need to do so by forking the `traced` daemon from [go-libp2p-pubsub-tracer](https://github.com/libp2p/go-libp2p-pubsub-tracer).
|
||||
|
||||
For instance, to capture the trace as a json file, you can use the following option:
|
||||
```go
|
||||
tracer, err := pubsub.NewJSONTracer("/path/to/trace.json")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pubsub.NewBlossomSub(..., pubsub.WithEventTracer(tracer))
|
||||
```
|
||||
|
||||
To capture the trace as a protobuf, you can use the following option:
|
||||
```go
|
||||
tracer, err := pubsub.NewPBTracer("/path/to/trace.pb")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pubsub.NewBlossomSub(..., pubsub.WithEventTracer(tracer))
|
||||
```
|
||||
|
||||
Finally, to use the remote tracer, you can use the following incantations:
|
||||
```go
|
||||
// assuming that your tracer runs in x.x.x.x and has a peer ID of QmTracer
|
||||
pi, err := peer.AddrInfoFromP2pAddr(ma.StringCast("/ip4/x.x.x.x/tcp/4001/p2p/QmTracer"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
tracer, err := pubsub.NewRemoteTracer(ctx, host, pi)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ps, err := pubsub.NewBlossomSub(..., pubsub.WithEventTracer(tracer))
|
||||
```
|
||||
|
||||
## Contribute
|
||||
|
||||
Contributions welcome. Please check out [the issues](https://source.quilibrium.com/quilibrium/monorepo/-/issues).
|
||||
|
||||
Quilibrium does not have a code of conduct for contributions – contributions are accepted on merit and benefit to the protocol.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
The go-libp2p-blossomsub project being forked from pubsub inherits the dual-license under Apache 2.0 and MIT terms:
|
||||
The go-libp2p-blossomsub project being forked from go-libp2p-pubsub inherits the dual-license under Apache 2.0 and MIT terms:
|
||||
|
||||
- Apache License, Version 2.0, ([LICENSE-APACHE](./LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
- MIT license ([LICENSE-MIT](./LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
@ -51,7 +51,6 @@ func newBackoff(ctx context.Context, sizeThreshold int, cleanupInterval time.Dur
|
||||
|
||||
func (b *backoff) updateAndGet(id peer.ID) (time.Duration, error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
h, ok := b.info[id]
|
||||
switch {
|
||||
@ -62,6 +61,7 @@ func (b *backoff) updateAndGet(id peer.ID) (time.Duration, error) {
|
||||
attempts: 0,
|
||||
}
|
||||
case h.attempts >= b.maxAttempts:
|
||||
b.mu.Unlock()
|
||||
return 0, fmt.Errorf("peer %s has reached its maximum backoff attempts", id)
|
||||
|
||||
case h.duration < MinBackoffDelay:
|
||||
@ -78,27 +78,29 @@ func (b *backoff) updateAndGet(id peer.ID) (time.Duration, error) {
|
||||
h.attempts += 1
|
||||
h.lastTried = time.Now()
|
||||
b.info[id] = h
|
||||
b.mu.Unlock()
|
||||
return h.duration, nil
|
||||
}
|
||||
|
||||
func (b *backoff) cleanup() {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
for id, h := range b.info {
|
||||
if time.Since(h.lastTried) > TimeToLive {
|
||||
delete(b.info, id)
|
||||
}
|
||||
}
|
||||
|
||||
b.mu.Unlock()
|
||||
}
|
||||
|
||||
func (b *backoff) cleanupLoop(ctx context.Context) {
|
||||
ticker := time.NewTicker(b.ci)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
ticker.Stop()
|
||||
return // pubsub shutting down
|
||||
case <-ticker.C:
|
||||
b.cleanup()
|
||||
|
@ -23,9 +23,11 @@ func TestBackoff_Update(t *testing.T) {
|
||||
|
||||
b := newBackoff(ctx, size, cleanupInterval, maxBackoffAttempts)
|
||||
|
||||
b.mu.Lock()
|
||||
if len(b.info) > 0 {
|
||||
t.Fatal("non-empty info map for backoff")
|
||||
}
|
||||
b.mu.Unlock()
|
||||
|
||||
if d, err := b.updateAndGet(id1); d != time.Duration(0) || err != nil {
|
||||
t.Fatalf("invalid initialization: %v, \t, %s", d, err)
|
||||
@ -64,9 +66,11 @@ func TestBackoff_Update(t *testing.T) {
|
||||
t.Fatalf("invalid backoff result, expected: %v, got: %v", MinBackoffDelay, got)
|
||||
}
|
||||
|
||||
b.mu.Lock()
|
||||
// sets last tried of id2 to long ago that it resets back upon next try.
|
||||
// update attempts on id2 are below threshold, hence peer should never go beyond backoff attempt threshold.
|
||||
b.info[id2].lastTried = time.Now().Add(-TimeToLive)
|
||||
b.mu.Unlock()
|
||||
got, err = b.updateAndGet(id2)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error post update: %s", err)
|
||||
@ -75,10 +79,11 @@ func TestBackoff_Update(t *testing.T) {
|
||||
t.Fatalf("invalid ttl expiration, expected: %v, got: %v", time.Duration(0), got)
|
||||
}
|
||||
|
||||
b.mu.Lock()
|
||||
if len(b.info) != 2 {
|
||||
t.Fatalf("pre-invalidation attempt, info map size mismatch, expected: %d, got: %d", 2, len(b.info))
|
||||
}
|
||||
|
||||
b.mu.Unlock()
|
||||
}
|
||||
|
||||
func TestBackoff_Clean(t *testing.T) {
|
||||
@ -96,12 +101,16 @@ func TestBackoff_Clean(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error post update: %s", err)
|
||||
}
|
||||
b.mu.Lock()
|
||||
b.info[id].lastTried = time.Now().Add(-TimeToLive) // enforces expiry
|
||||
b.mu.Unlock()
|
||||
}
|
||||
|
||||
b.mu.Lock()
|
||||
if len(b.info) != size {
|
||||
t.Fatalf("info map size mismatch, expected: %d, got: %d", size, len(b.info))
|
||||
}
|
||||
b.mu.Unlock()
|
||||
|
||||
// waits for a cleanup loop to kick-in
|
||||
time.Sleep(2 * cleanupInterval)
|
||||
@ -115,8 +124,10 @@ func TestBackoff_Clean(t *testing.T) {
|
||||
t.Fatalf("invalid backoff result, expected: %v, got: %v", time.Duration(0), got)
|
||||
}
|
||||
|
||||
b.mu.Lock()
|
||||
// except "some-new-peer" every other records must be cleaned up
|
||||
if len(b.info) != 1 {
|
||||
t.Fatalf("info map size mismatch, expected: %d, got: %d", 1, len(b.info))
|
||||
}
|
||||
b.mu.Unlock()
|
||||
}
|
||||
|
@ -48,9 +48,9 @@ func (t *Bitmask) SetScoreParams(p *BitmaskScoreParams) error {
|
||||
}
|
||||
|
||||
t.mux.Lock()
|
||||
defer t.mux.Unlock()
|
||||
|
||||
if t.closed {
|
||||
t.mux.Unlock()
|
||||
return ErrBitmaskClosed
|
||||
}
|
||||
|
||||
@ -74,9 +74,11 @@ func (t *Bitmask) SetScoreParams(p *BitmaskScoreParams) error {
|
||||
select {
|
||||
case t.p.eval <- update:
|
||||
err = <-result
|
||||
t.mux.Unlock()
|
||||
return err
|
||||
|
||||
case <-t.p.ctx.Done():
|
||||
t.mux.Unlock()
|
||||
return t.p.ctx.Err()
|
||||
}
|
||||
}
|
||||
@ -85,8 +87,8 @@ func (t *Bitmask) SetScoreParams(p *BitmaskScoreParams) error {
|
||||
// Multiple event handlers may be created and will operate independently of each other
|
||||
func (t *Bitmask) EventHandler(opts ...BitmaskEventHandlerOpt) (*BitmaskEventHandler, error) {
|
||||
t.mux.RLock()
|
||||
defer t.mux.RUnlock()
|
||||
if t.closed {
|
||||
t.mux.RUnlock()
|
||||
return nil, ErrBitmaskClosed
|
||||
}
|
||||
|
||||
@ -101,6 +103,7 @@ func (t *Bitmask) EventHandler(opts ...BitmaskEventHandlerOpt) (*BitmaskEventHan
|
||||
for _, opt := range opts {
|
||||
err := opt(h)
|
||||
if err != nil {
|
||||
t.mux.RUnlock()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@ -120,21 +123,23 @@ func (t *Bitmask) EventHandler(opts ...BitmaskEventHandlerOpt) (*BitmaskEventHan
|
||||
done <- struct{}{}
|
||||
}:
|
||||
case <-t.p.ctx.Done():
|
||||
t.mux.RUnlock()
|
||||
return nil, t.p.ctx.Err()
|
||||
}
|
||||
|
||||
<-done
|
||||
|
||||
t.mux.RUnlock()
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (t *Bitmask) sendNotification(evt PeerEvent) {
|
||||
t.evtHandlerMux.RLock()
|
||||
defer t.evtHandlerMux.RUnlock()
|
||||
|
||||
for h := range t.evtHandlers {
|
||||
h.sendNotification(evt)
|
||||
}
|
||||
|
||||
t.evtHandlerMux.RUnlock()
|
||||
}
|
||||
|
||||
// Subscribe returns a new Subscription for the bitmask.
|
||||
@ -142,8 +147,9 @@ func (t *Bitmask) sendNotification(evt PeerEvent) {
|
||||
// before the subscription is processed by the pubsub main loop and propagated to our peers.
|
||||
func (t *Bitmask) Subscribe(opts ...SubOpt) (*Subscription, error) {
|
||||
t.mux.RLock()
|
||||
defer t.mux.RUnlock()
|
||||
|
||||
if t.closed {
|
||||
t.mux.RUnlock()
|
||||
return nil, ErrBitmaskClosed
|
||||
}
|
||||
|
||||
@ -155,12 +161,13 @@ func (t *Bitmask) Subscribe(opts ...SubOpt) (*Subscription, error) {
|
||||
for _, opt := range opts {
|
||||
err := opt(sub)
|
||||
if err != nil {
|
||||
t.mux.RUnlock()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if sub.ch == nil {
|
||||
sub.ch = make(chan *Message, 128)
|
||||
sub.ch = make(chan *Message, 32)
|
||||
}
|
||||
|
||||
out := make(chan *Subscription, 1)
|
||||
@ -173,10 +180,13 @@ func (t *Bitmask) Subscribe(opts ...SubOpt) (*Subscription, error) {
|
||||
resp: out,
|
||||
}:
|
||||
case <-t.p.ctx.Done():
|
||||
t.mux.RUnlock()
|
||||
return nil, t.p.ctx.Err()
|
||||
}
|
||||
|
||||
return <-out, nil
|
||||
subOut := <-out
|
||||
t.mux.RUnlock()
|
||||
return subOut, nil
|
||||
}
|
||||
|
||||
// Relay enables message relaying for the bitmask and returns a reference
|
||||
@ -184,8 +194,9 @@ func (t *Bitmask) Subscribe(opts ...SubOpt) (*Subscription, error) {
|
||||
// To completely disable the relay, all references must be cancelled.
|
||||
func (t *Bitmask) Relay() (RelayCancelFunc, error) {
|
||||
t.mux.RLock()
|
||||
defer t.mux.RUnlock()
|
||||
|
||||
if t.closed {
|
||||
t.mux.RUnlock()
|
||||
return nil, ErrBitmaskClosed
|
||||
}
|
||||
|
||||
@ -199,10 +210,13 @@ func (t *Bitmask) Relay() (RelayCancelFunc, error) {
|
||||
resp: out,
|
||||
}:
|
||||
case <-t.p.ctx.Done():
|
||||
t.mux.RUnlock()
|
||||
return nil, t.p.ctx.Err()
|
||||
}
|
||||
|
||||
return <-out, nil
|
||||
cancelFunc := <-out
|
||||
t.mux.RUnlock()
|
||||
return cancelFunc, nil
|
||||
}
|
||||
|
||||
// RouterReady is a function that decides if a router is ready to publish
|
||||
@ -220,10 +234,11 @@ type PublishOptions struct {
|
||||
type PubOpt func(pub *PublishOptions) error
|
||||
|
||||
// Publish publishes data to bitmask.
|
||||
func (t *Bitmask) Publish(ctx context.Context, data []byte, opts ...PubOpt) error {
|
||||
func (t *Bitmask) Publish(ctx context.Context, bitmask []byte, data []byte, opts ...PubOpt) error {
|
||||
t.mux.RLock()
|
||||
defer t.mux.RUnlock()
|
||||
|
||||
if t.closed {
|
||||
t.mux.RUnlock()
|
||||
return ErrBitmaskClosed
|
||||
}
|
||||
|
||||
@ -234,6 +249,7 @@ func (t *Bitmask) Publish(ctx context.Context, data []byte, opts ...PubOpt) erro
|
||||
for _, opt := range opts {
|
||||
err := opt(pub)
|
||||
if err != nil {
|
||||
t.mux.RUnlock()
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -241,16 +257,18 @@ func (t *Bitmask) Publish(ctx context.Context, data []byte, opts ...PubOpt) erro
|
||||
if pub.customKey != nil && !pub.local {
|
||||
key, pid = pub.customKey()
|
||||
if key == nil {
|
||||
t.mux.RUnlock()
|
||||
return ErrNilSignKey
|
||||
}
|
||||
if len(pid) == 0 {
|
||||
t.mux.RUnlock()
|
||||
return ErrEmptyPeerID
|
||||
}
|
||||
}
|
||||
|
||||
m := &pb.Message{
|
||||
Data: data,
|
||||
Bitmask: t.bitmask,
|
||||
Bitmask: bitmask,
|
||||
From: nil,
|
||||
Seqno: nil,
|
||||
}
|
||||
@ -262,6 +280,7 @@ func (t *Bitmask) Publish(ctx context.Context, data []byte, opts ...PubOpt) erro
|
||||
m.From = []byte(pid)
|
||||
err := signMessage(pid, key, m)
|
||||
if err != nil {
|
||||
t.mux.RUnlock()
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -286,28 +305,43 @@ func (t *Bitmask) Publish(ctx context.Context, data []byte, opts ...PubOpt) erro
|
||||
res <- done
|
||||
}:
|
||||
if <-res {
|
||||
if ticker != nil {
|
||||
ticker.Stop()
|
||||
}
|
||||
break readyLoop
|
||||
}
|
||||
case <-t.p.ctx.Done():
|
||||
if ticker != nil {
|
||||
ticker.Stop()
|
||||
}
|
||||
t.mux.RUnlock()
|
||||
return t.p.ctx.Err()
|
||||
case <-ctx.Done():
|
||||
if ticker != nil {
|
||||
ticker.Stop()
|
||||
}
|
||||
t.mux.RUnlock()
|
||||
return ctx.Err()
|
||||
}
|
||||
if ticker == nil {
|
||||
ticker = time.NewTicker(200 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ticker.C:
|
||||
case <-ctx.Done():
|
||||
ticker.Stop()
|
||||
t.mux.RUnlock()
|
||||
return fmt.Errorf("router is not ready: %w", ctx.Err())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return t.p.val.PushLocal(&Message{m, "", t.p.host.ID(), nil, pub.local})
|
||||
err := t.p.val.PushLocal(&Message{m, nil, t.p.host.ID(), nil, pub.local})
|
||||
|
||||
t.mux.RUnlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// WithReadiness returns a publishing option for only publishing when the router is ready.
|
||||
@ -347,8 +381,9 @@ func WithSecretKeyAndPeerId(key crypto.PrivKey, pid peer.ID) PubOpt {
|
||||
// Does not error if the bitmask is already closed.
|
||||
func (t *Bitmask) Close() error {
|
||||
t.mux.Lock()
|
||||
defer t.mux.Unlock()
|
||||
|
||||
if t.closed {
|
||||
t.mux.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -357,6 +392,7 @@ func (t *Bitmask) Close() error {
|
||||
select {
|
||||
case t.p.rmBitmask <- req:
|
||||
case <-t.p.ctx.Done():
|
||||
t.mux.Unlock()
|
||||
return t.p.ctx.Err()
|
||||
}
|
||||
|
||||
@ -366,18 +402,22 @@ func (t *Bitmask) Close() error {
|
||||
t.closed = true
|
||||
}
|
||||
|
||||
t.mux.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// ListPeers returns a list of peers we are connected to in the given bitmask.
|
||||
func (t *Bitmask) ListPeers() []peer.ID {
|
||||
t.mux.RLock()
|
||||
defer t.mux.RUnlock()
|
||||
|
||||
if t.closed {
|
||||
t.mux.RUnlock()
|
||||
return []peer.ID{}
|
||||
}
|
||||
|
||||
return t.p.ListPeers(t.bitmask)
|
||||
l := t.p.ListPeers(t.bitmask)
|
||||
t.mux.RUnlock()
|
||||
return l
|
||||
}
|
||||
|
||||
type EventType int
|
||||
|
@ -25,7 +25,12 @@ func getBitmasks(psubs []*PubSub, bitmask []byte, opts ...BitmaskOpt) []*Bitmask
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bitmasks[i] = t
|
||||
|
||||
if len(t) != 1 {
|
||||
panic("multi bit bitmasks not supported for tests using getBitmasks")
|
||||
}
|
||||
|
||||
bitmasks[i] = t[0]
|
||||
}
|
||||
|
||||
return bitmasks
|
||||
@ -98,9 +103,9 @@ func testBitmaskCloseWithOpenResource(t *testing.T, openResource func(bitmask *B
|
||||
defer cancel()
|
||||
|
||||
const numHosts = 1
|
||||
bitmaskID := []byte{0xf0, 0x0b, 0xa1, 0x20}
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
ps := getPubsub(ctx, hosts[0])
|
||||
bitmaskID := []byte{0x00, 0x01}
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
ps := getBlossomSub(ctx, hosts[0])
|
||||
|
||||
// Try create and cancel bitmask
|
||||
bitmask, err := ps.Join(bitmaskID)
|
||||
@ -108,7 +113,7 @@ func testBitmaskCloseWithOpenResource(t *testing.T, openResource func(bitmask *B
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := bitmask.Close(); err != nil {
|
||||
if err := bitmask[0].Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -118,9 +123,9 @@ func testBitmaskCloseWithOpenResource(t *testing.T, openResource func(bitmask *B
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
openResource(bitmask)
|
||||
openResource(bitmask[0])
|
||||
|
||||
if err := bitmask.Close(); err == nil {
|
||||
if err := bitmask[0].Close(); err == nil {
|
||||
t.Fatal("expected an error closing a bitmask with an open resource")
|
||||
}
|
||||
|
||||
@ -128,7 +133,7 @@ func testBitmaskCloseWithOpenResource(t *testing.T, openResource func(bitmask *B
|
||||
closeResource()
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
|
||||
if err := bitmask.Close(); err != nil {
|
||||
if err := bitmask[0].Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@ -138,11 +143,11 @@ func TestBitmaskReuse(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
const numHosts = 2
|
||||
bitmaskID := []byte{0xf0, 0x0b, 0xa1, 0x20}
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
bitmaskID := []byte{0x00, 0x01}
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
|
||||
sender := getPubsub(ctx, hosts[0], WithDiscovery(&dummyDiscovery{}))
|
||||
receiver := getPubsub(ctx, hosts[1])
|
||||
sender := getBlossomSub(ctx, hosts[0])
|
||||
receiver := getBlossomSub(ctx, hosts[1])
|
||||
|
||||
connectAll(t, hosts)
|
||||
|
||||
@ -158,13 +163,18 @@ func TestBitmaskReuse(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sub, err := receiveBitmask.Subscribe()
|
||||
_, err = sendBitmask[0].Subscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sub, err := receiveBitmask[0].Subscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
firstMsg := []byte("1")
|
||||
if err := sendBitmask.Publish(ctx, firstMsg, WithReadiness(MinBitmaskSize(1))); err != nil {
|
||||
if err := sendBitmask[0].Publish(ctx, bitmaskID, firstMsg, WithReadiness(MinBitmaskSize(1))); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -176,54 +186,10 @@ func TestBitmaskReuse(t *testing.T) {
|
||||
t.Fatal("received incorrect message")
|
||||
}
|
||||
|
||||
if err := sendBitmask.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Recreate the same bitmask
|
||||
newSendBitmask, err := sender.Join(bitmaskID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Try sending data with original bitmask
|
||||
illegalSend := []byte("illegal")
|
||||
if err := sendBitmask.Publish(ctx, illegalSend); err != ErrBitmaskClosed {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
timeoutCtx, timeoutCancel := context.WithTimeout(ctx, time.Second*2)
|
||||
defer timeoutCancel()
|
||||
msg, err = sub.Next(timeoutCtx)
|
||||
if err != context.DeadlineExceeded {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(msg.GetData(), illegalSend) {
|
||||
t.Fatal("received incorrect message from illegal bitmask")
|
||||
}
|
||||
t.Fatal("received message sent by illegal bitmask")
|
||||
}
|
||||
timeoutCancel()
|
||||
|
||||
// Try cancelling the new bitmask by using the original bitmask
|
||||
if err := sendBitmask.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
secondMsg := []byte("2")
|
||||
if err := newSendBitmask.Publish(ctx, secondMsg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
timeoutCtx, timeoutCancel = context.WithTimeout(ctx, time.Second*2)
|
||||
defer timeoutCancel()
|
||||
msg, err = sub.Next(timeoutCtx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(msg.GetData(), secondMsg) {
|
||||
t.Fatal("received incorrect message")
|
||||
_, err = sender.Join(bitmaskID)
|
||||
if err == nil {
|
||||
t.Fatal("did not error on reuse of bitmask")
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,9 +198,9 @@ func TestBitmaskEventHandlerCancel(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
const numHosts = 5
|
||||
bitmaskID := []byte{0xf0, 0x0b, 0xa1, 0x20}
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
ps := getPubsub(ctx, hosts[0])
|
||||
bitmaskID := []byte{0x00, 0x01}
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
ps := getBlossomSub(ctx, hosts[0])
|
||||
|
||||
// Try create and cancel bitmask
|
||||
bitmask, err := ps.Join(bitmaskID)
|
||||
@ -242,7 +208,7 @@ func TestBitmaskEventHandlerCancel(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
evts, err := bitmask.EventHandler()
|
||||
evts, err := bitmask[0].EventHandler()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -265,8 +231,8 @@ func TestSubscriptionJoinNotification(t *testing.T) {
|
||||
|
||||
const numLateSubscribers = 10
|
||||
const numHosts = 20
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
bitmasks := getBitmasks(getPubsubs(ctx, hosts), []byte{0xf0, 0x0b, 0xa1, 0x20})
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
bitmasks := getBitmasks(getBlossomSubs(ctx, hosts), []byte{0x00, 0x01})
|
||||
evts := getBitmaskEvts(bitmasks)
|
||||
|
||||
subs := make([]*Subscription, numHosts)
|
||||
@ -331,9 +297,9 @@ func TestSubscriptionLeaveNotification(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
const numHosts = 20
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
psubs := getPubsubs(ctx, hosts)
|
||||
bitmasks := getBitmasks(psubs, []byte{0xf0, 0x0b, 0xa1, 0x20})
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
psubs := getBlossomSubs(ctx, hosts)
|
||||
bitmasks := getBitmasks(psubs, []byte{0x00, 0x01})
|
||||
evts := getBitmaskEvts(bitmasks)
|
||||
|
||||
subs := make([]*Subscription, numHosts)
|
||||
@ -411,11 +377,11 @@ func TestSubscriptionManyNotifications(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
bitmask := []byte{0xf0, 0x0b, 0xa1, 0x20}
|
||||
bitmask := []byte{0x00, 0x01}
|
||||
|
||||
const numHosts = 33
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
bitmasks := getBitmasks(getPubsubs(ctx, hosts), bitmask)
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
bitmasks := getBitmasks(getBlossomSubs(ctx, hosts), bitmask)
|
||||
evts := getBitmaskEvts(bitmasks)
|
||||
|
||||
subs := make([]*Subscription, numHosts)
|
||||
@ -516,11 +482,11 @@ func TestSubscriptionNotificationSubUnSub(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
bitmask := []byte{0xf0, 0x0b, 0xa1, 0x20}
|
||||
bitmask := []byte{0x00, 0x01}
|
||||
|
||||
const numHosts = 35
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
bitmasks := getBitmasks(getPubsubs(ctx, hosts), bitmask)
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
bitmasks := getBitmasks(getBlossomSubs(ctx, hosts), bitmask)
|
||||
|
||||
for i := 1; i < numHosts; i++ {
|
||||
connect(t, hosts[0], hosts[i])
|
||||
@ -534,11 +500,11 @@ func TestBitmaskRelay(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
bitmask := []byte{0xf0, 0x0b, 0xa1, 0x20}
|
||||
bitmask := []byte{0x00, 0x01}
|
||||
const numHosts = 5
|
||||
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
bitmasks := getBitmasks(getPubsubs(ctx, hosts), bitmask)
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
bitmasks := getBitmasks(getBlossomSubs(ctx, hosts), bitmask)
|
||||
|
||||
// [0.Rel] - [1.Rel] - [2.Sub]
|
||||
// |
|
||||
@ -552,6 +518,7 @@ func TestBitmaskRelay(t *testing.T) {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
|
||||
var subs []*Subscription
|
||||
var subscribedBitmasks []*Bitmask
|
||||
|
||||
for i, bitmask := range bitmasks {
|
||||
if i == 2 || i == 4 {
|
||||
@ -561,6 +528,7 @@ func TestBitmaskRelay(t *testing.T) {
|
||||
}
|
||||
|
||||
subs = append(subs, sub)
|
||||
subscribedBitmasks = append(subscribedBitmasks, bitmask)
|
||||
} else {
|
||||
_, err := bitmask.Relay()
|
||||
if err != nil {
|
||||
@ -569,14 +537,15 @@ func TestBitmaskRelay(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
// Give enough time to build the relay
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
msg := []byte("message")
|
||||
msg := []byte(fmt.Sprintf("message %d", i))
|
||||
|
||||
owner := rand.Intn(len(bitmasks))
|
||||
owner := rand.Intn(len(subscribedBitmasks))
|
||||
|
||||
err := bitmasks[owner].Publish(ctx, msg)
|
||||
err := subscribedBitmasks[owner].Publish(ctx, subscribedBitmasks[owner].bitmask, msg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -598,11 +567,11 @@ func TestBitmaskRelayReuse(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
bitmask := []byte{0xf0, 0x0b, 0xa1, 0x20}
|
||||
bitmask := []byte{0x00, 0x01}
|
||||
const numHosts = 1
|
||||
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
pubsubs := getPubsubs(ctx, hosts)
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
pubsubs := getBlossomSubs(ctx, hosts)
|
||||
bitmasks := getBitmasks(pubsubs, bitmask)
|
||||
|
||||
relay1Cancel, err := bitmasks[0].Relay()
|
||||
@ -665,11 +634,11 @@ func TestBitmaskRelayOnClosedBitmask(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
bitmask := []byte{0xf0, 0x0b, 0xa1, 0x20}
|
||||
bitmask := []byte{0x00, 0x01}
|
||||
const numHosts = 1
|
||||
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
bitmasks := getBitmasks(getPubsubs(ctx, hosts), bitmask)
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
bitmasks := getBitmasks(getBlossomSubs(ctx, hosts), bitmask)
|
||||
|
||||
err := bitmasks[0].Close()
|
||||
if err != nil {
|
||||
@ -687,9 +656,9 @@ func TestProducePanic(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
const numHosts = 5
|
||||
bitmaskID := []byte{0xf0, 0x0b, 0xa1, 0x20}
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
ps := getPubsub(ctx, hosts[0])
|
||||
bitmaskID := []byte{0x00, 0x01}
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
ps := getBlossomSub(ctx, hosts[0])
|
||||
|
||||
// Create bitmask
|
||||
bitmask, err := ps.Join(bitmaskID)
|
||||
@ -698,13 +667,13 @@ func TestProducePanic(t *testing.T) {
|
||||
}
|
||||
|
||||
// Create subscription we're going to cancel
|
||||
s, err := bitmask.Subscribe()
|
||||
s, err := bitmask[0].Subscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Create second subscription to keep us alive on the subscription map
|
||||
// after the first one is canceled
|
||||
s2, err := bitmask.Subscribe()
|
||||
s2, err := bitmask[0].Subscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -789,12 +758,12 @@ func TestMinBitmaskSizeNoDiscovery(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
const numHosts = 3
|
||||
bitmaskID := []byte{0xf0, 0x0b, 0xa1, 0x20}
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
bitmaskID := []byte{0x00, 0x01}
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
|
||||
sender := getPubsub(ctx, hosts[0])
|
||||
receiver1 := getPubsub(ctx, hosts[1])
|
||||
receiver2 := getPubsub(ctx, hosts[2])
|
||||
sender := getBlossomSub(ctx, hosts[0])
|
||||
receiver1 := getBlossomSub(ctx, hosts[1])
|
||||
receiver2 := getBlossomSub(ctx, hosts[2])
|
||||
|
||||
connectAll(t, hosts)
|
||||
|
||||
@ -804,19 +773,24 @@ func TestMinBitmaskSizeNoDiscovery(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = sendBitmask[0].Subscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Receiver creates and subscribes to the bitmask
|
||||
receiveBitmask1, err := receiver1.Join(bitmaskID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sub1, err := receiveBitmask1.Subscribe()
|
||||
sub1, err := receiveBitmask1[0].Subscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
oneMsg := []byte("minimum one")
|
||||
if err := sendBitmask.Publish(ctx, oneMsg, WithReadiness(MinBitmaskSize(1))); err != nil {
|
||||
if err := sendBitmask[0].Publish(ctx, sendBitmask[0].bitmask, oneMsg, WithReadiness(MinBitmaskSize(1))); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -832,7 +806,7 @@ func TestMinBitmaskSizeNoDiscovery(t *testing.T) {
|
||||
{
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second)
|
||||
defer cancel()
|
||||
if err := sendBitmask.Publish(ctx, twoMsg, WithReadiness(MinBitmaskSize(2))); !errors.Is(err, context.DeadlineExceeded) {
|
||||
if err := sendBitmask[0].Publish(ctx, sendBitmask[0].bitmask, twoMsg, WithReadiness(MinBitmaskSize(2))); !errors.Is(err, context.DeadlineExceeded) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@ -843,15 +817,17 @@ func TestMinBitmaskSizeNoDiscovery(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sub2, err := receiveBitmask2.Subscribe()
|
||||
sub2, err := receiveBitmask2[0].Subscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
twoMsg = []byte("minimum two, 2")
|
||||
|
||||
{
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second)
|
||||
defer cancel()
|
||||
if err := sendBitmask.Publish(ctx, twoMsg, WithReadiness(MinBitmaskSize(2))); err != nil {
|
||||
if err := sendBitmask[0].Publish(ctx, sendBitmask[0].bitmask, twoMsg, WithReadiness(MinBitmaskSize(2))); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@ -867,20 +843,20 @@ func TestWithBitmaskMsgIdFunction(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
bitmaskA, bitmaskB := []byte{0xf0, 0x0b, 0xa1, 0x2a}, []byte{0xf0, 0x0b, 0xa1, 0x2b}
|
||||
bitmaskA, bitmaskB := []byte{0x20, 0x00, 0x00, 0x00}, []byte{0x00, 0x00, 0x80, 0x00}
|
||||
const numHosts = 2
|
||||
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
pubsubs := getPubsubs(ctx, hosts, WithMessageIdFn(func(pmsg *pb.Message) string {
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
pubsubs := getBlossomSubs(ctx, hosts, WithMessageIdFn(func(pmsg *pb.Message) []byte {
|
||||
hash := sha256.Sum256(pmsg.Data)
|
||||
return string(hash[:])
|
||||
return hash[:]
|
||||
}))
|
||||
connectAll(t, hosts)
|
||||
|
||||
bitmasksA := getBitmasks(pubsubs, bitmaskA) // uses global msgIdFn
|
||||
bitmasksB := getBitmasks(pubsubs, bitmaskB, WithBitmaskMessageIdFn(func(pmsg *pb.Message) string { // uses custom
|
||||
bitmasksB := getBitmasks(pubsubs, bitmaskB, WithBitmaskMessageIdFn(func(pmsg *pb.Message) []byte { // uses custom
|
||||
hash := sha1.Sum(pmsg.Data)
|
||||
return string(hash[:])
|
||||
return hash[:]
|
||||
}))
|
||||
|
||||
payload := []byte("pubsub rocks")
|
||||
@ -890,7 +866,12 @@ func TestWithBitmaskMsgIdFunction(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = bitmasksA[1].Publish(ctx, payload, WithReadiness(MinBitmaskSize(1)))
|
||||
_, err = bitmasksA[1].Subscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = bitmasksA[1].Publish(ctx, bitmasksA[1].bitmask, payload, WithReadiness(MinBitmaskSize(1)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -905,7 +886,14 @@ func TestWithBitmaskMsgIdFunction(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = bitmasksB[1].Publish(ctx, payload, WithReadiness(MinBitmaskSize(1)))
|
||||
_, err = bitmasksB[1].Subscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
payload = []byte("but blossomsub has more sensible scale strategies")
|
||||
|
||||
err = bitmasksB[1].Publish(ctx, bitmasksB[1].bitmask, payload, WithReadiness(MinBitmaskSize(1)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -915,7 +903,7 @@ func TestWithBitmaskMsgIdFunction(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if msgA.ID == msgB.ID {
|
||||
if bytes.Equal(msgA.ID, msgB.ID) {
|
||||
t.Fatal("msg ids are equal")
|
||||
}
|
||||
}
|
||||
@ -926,23 +914,23 @@ func TestBitmaskPublishWithKeyInvalidParameters(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
bitmask := []byte{0xf0, 0x0b, 0xa1, 0x20}
|
||||
bitmask := []byte{0x00, 0x01}
|
||||
const numHosts = 5
|
||||
|
||||
virtualPeer := tnet.RandPeerNetParamsOrFatal(t)
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
bitmasks := getBitmasks(getPubsubs(ctx, hosts), bitmask)
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
bitmasks := getBitmasks(getBlossomSubs(ctx, hosts), bitmask)
|
||||
|
||||
t.Run("nil sign private key should error", func(t *testing.T) {
|
||||
withVirtualKey := WithSecretKeyAndPeerId(nil, virtualPeer.ID)
|
||||
err := bitmasks[0].Publish(ctx, []byte("buff"), withVirtualKey)
|
||||
err := bitmasks[0].Publish(ctx, bitmask, []byte("buff"), withVirtualKey)
|
||||
if err != ErrNilSignKey {
|
||||
t.Fatal("error should have been of type errNilSignKey")
|
||||
}
|
||||
})
|
||||
t.Run("empty peer ID should error", func(t *testing.T) {
|
||||
withVirtualKey := WithSecretKeyAndPeerId(virtualPeer.PrivKey, "")
|
||||
err := bitmasks[0].Publish(ctx, []byte("buff"), withVirtualKey)
|
||||
err := bitmasks[0].Publish(ctx, bitmask, []byte("buff2"), withVirtualKey)
|
||||
if err != ErrEmptyPeerID {
|
||||
t.Fatal("error should have been of type errEmptyPeerID")
|
||||
}
|
||||
@ -953,12 +941,12 @@ func TestBitmaskRelayPublishWithKey(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
bitmask := []byte{0xf0, 0x0b, 0xa1, 0x20}
|
||||
bitmask := []byte{0x00, 0x01}
|
||||
const numHosts = 5
|
||||
|
||||
virtualPeer := tnet.RandPeerNetParamsOrFatal(t)
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
bitmasks := getBitmasks(getPubsubs(ctx, hosts), bitmask)
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
bitmasks := getBitmasks(getBlossomSubs(ctx, hosts), bitmask)
|
||||
|
||||
// [0.Rel] - [1.Rel] - [2.Sub]
|
||||
// |
|
||||
@ -972,6 +960,7 @@ func TestBitmaskRelayPublishWithKey(t *testing.T) {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
|
||||
var subs []*Subscription
|
||||
var senders []*Bitmask
|
||||
|
||||
for i, bitmaskValue := range bitmasks {
|
||||
if i == 2 || i == 4 {
|
||||
@ -981,6 +970,7 @@ func TestBitmaskRelayPublishWithKey(t *testing.T) {
|
||||
}
|
||||
|
||||
subs = append(subs, sub)
|
||||
senders = append(senders, bitmaskValue)
|
||||
} else {
|
||||
_, err := bitmaskValue.Relay()
|
||||
if err != nil {
|
||||
@ -989,15 +979,15 @@ func TestBitmaskRelayPublishWithKey(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
msg := []byte("message")
|
||||
msg := []byte(fmt.Sprintf("message %d", i))
|
||||
|
||||
owner := rand.Intn(len(bitmasks))
|
||||
owner := rand.Intn(len(senders))
|
||||
|
||||
withVirtualKey := WithSecretKeyAndPeerId(virtualPeer.PrivKey, virtualPeer.ID)
|
||||
err := bitmasks[owner].Publish(ctx, msg, withVirtualKey)
|
||||
err := senders[owner].Publish(ctx, senders[owner].bitmask, msg, withVirtualKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -1022,10 +1012,10 @@ func TestWithLocalPublication(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
bitmask := []byte{0x7e, 57}
|
||||
bitmask := []byte{0x01, 0x00}
|
||||
|
||||
hosts := getNetHosts(t, ctx, 2)
|
||||
pubsubs := getPubsubs(ctx, hosts)
|
||||
hosts := getDefaultHosts(t, 2)
|
||||
pubsubs := getBlossomSubs(ctx, hosts)
|
||||
bitmasks := getBitmasks(pubsubs, bitmask)
|
||||
connectAll(t, hosts)
|
||||
|
||||
@ -1041,7 +1031,7 @@ func TestWithLocalPublication(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = bitmasks[0].Publish(ctx, payload, WithLocalPublication(true))
|
||||
err = bitmasks[0].Publish(ctx, bitmasks[0].bitmask, payload, WithLocalPublication(true))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -38,11 +38,16 @@ func TestBlacklist(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
hosts := getNetHosts(t, ctx, 2)
|
||||
psubs := getPubsubs(ctx, hosts)
|
||||
hosts := getDefaultHosts(t, 2)
|
||||
psubs := getBlossomSubs(ctx, hosts)
|
||||
connect(t, hosts[0], hosts[1])
|
||||
|
||||
sub, err := psubs[1].Subscribe([]byte{0xff, 0x00, 0x00, 0x00})
|
||||
bitmasks, err := psubs[0].Join([]byte{0x00, 0x80, 0x00, 0x00})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sub, err := psubs[1].Subscribe([]byte{0x00, 0x80, 0x00, 0x00})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -51,11 +56,11 @@ func TestBlacklist(t *testing.T) {
|
||||
psubs[1].BlacklistPeer(hosts[0].ID())
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
|
||||
psubs[0].Publish([]byte{0xff, 0x00, 0x00, 0x00}, []byte("message"))
|
||||
bitmasks[0].Publish(ctx, bitmasks[0].bitmask, []byte("message"))
|
||||
|
||||
wctx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
||||
defer cancel()
|
||||
_, err = sub.Next(wctx)
|
||||
_, err = sub[0].Next(wctx)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("got message from blacklisted peer")
|
||||
@ -66,16 +71,21 @@ func TestBlacklist2(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
hosts := getNetHosts(t, ctx, 2)
|
||||
psubs := getPubsubs(ctx, hosts)
|
||||
hosts := getDefaultHosts(t, 2)
|
||||
psubs := getBlossomSubs(ctx, hosts)
|
||||
connect(t, hosts[0], hosts[1])
|
||||
|
||||
_, err := psubs[0].Subscribe([]byte{0xff, 0x00, 0x00, 0x00})
|
||||
bitmasks, err := psubs[0].Join([]byte{0x00, 0x80, 0x00, 0x00})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sub1, err := psubs[1].Subscribe([]byte{0xff, 0x00, 0x00, 0x00})
|
||||
_, err = psubs[0].Subscribe([]byte{0x00, 0x80, 0x00, 0x00})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sub1, err := psubs[1].Subscribe([]byte{0x00, 0x80, 0x00, 0x00})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -84,11 +94,11 @@ func TestBlacklist2(t *testing.T) {
|
||||
psubs[1].BlacklistPeer(hosts[0].ID())
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
|
||||
psubs[0].Publish([]byte{0xff, 0x00, 0x00, 0x00}, []byte("message"))
|
||||
bitmasks[0].Publish(ctx, bitmasks[0].bitmask, []byte("message"))
|
||||
|
||||
wctx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
||||
defer cancel()
|
||||
_, err = sub1.Next(wctx)
|
||||
_, err = sub1[0].Next(wctx)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("got message from blacklisted peer")
|
||||
@ -99,25 +109,30 @@ func TestBlacklist3(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
hosts := getNetHosts(t, ctx, 2)
|
||||
psubs := getPubsubs(ctx, hosts)
|
||||
hosts := getDefaultHosts(t, 2)
|
||||
psubs := getBlossomSubs(ctx, hosts)
|
||||
|
||||
psubs[1].BlacklistPeer(hosts[0].ID())
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
connect(t, hosts[0], hosts[1])
|
||||
|
||||
sub, err := psubs[1].Subscribe([]byte{0xff, 0x00, 0x00, 0x00})
|
||||
bitmasks, err := psubs[0].Join([]byte{0x00, 0x80, 0x00, 0x00})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sub, err := psubs[1].Subscribe([]byte{0x00, 0x80, 0x00, 0x00})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
|
||||
psubs[0].Publish([]byte{0xff, 0x00, 0x00, 0x00}, []byte("message"))
|
||||
bitmasks[0].Publish(ctx, bitmasks[0].bitmask, []byte("message"))
|
||||
|
||||
wctx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
||||
defer cancel()
|
||||
_, err = sub.Next(wctx)
|
||||
_, err = sub[0].Next(wctx)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("got message from blacklisted peer")
|
||||
|
@ -4,8 +4,11 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"slices"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
pb "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb"
|
||||
@ -21,8 +24,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// BlossomSubID_v12 is the protocol ID for version 1.2.1 of the BlossomSub protocol.
|
||||
BlossomSubID_v12 = protocol.ID("/blossomsub/1.2.1")
|
||||
// BlossomSubID_v2 is the protocol ID for version 2.0.0 of the BlossomSub protocol.
|
||||
BlossomSubID_v2 = protocol.ID("/blossomsub/2.0.0")
|
||||
)
|
||||
|
||||
// Defines the default BlossomSub parameters.
|
||||
@ -35,8 +38,8 @@ var (
|
||||
BlossomSubHistoryLength = 5
|
||||
BlossomSubHistoryGossip = 3
|
||||
BlossomSubDlazy = 6
|
||||
BlossomSubGossipFactor = 0.25
|
||||
BlossomSubGossipRetransmission = 1
|
||||
BlossomSubGossipRetransmission = 3
|
||||
BlossomSubBitmaskWidth = 256
|
||||
BlossomSubHeartbeatInitialDelay = 100 * time.Millisecond
|
||||
BlossomSubHeartbeatInterval = 1 * time.Second
|
||||
BlossomSubFanoutTTL = 60 * time.Second
|
||||
@ -87,6 +90,9 @@ type BlossomSubParams struct {
|
||||
// Dout must be set below Dlo, and must not exceed D / 2.
|
||||
Dout int
|
||||
|
||||
// BitmaskWidth sets the size of the bitmask for subscriptions.
|
||||
BitmaskWidth int
|
||||
|
||||
// gossip parameters
|
||||
|
||||
// HistoryLength controls the size of the message cache used for gossip.
|
||||
@ -105,15 +111,9 @@ 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 more, depending on GossipFactor and how many peers we're
|
||||
// connected to.
|
||||
// number may be less, depending on 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.
|
||||
@ -272,7 +272,6 @@ func DefaultBlossomSubParams() BlossomSubParams {
|
||||
HistoryLength: BlossomSubHistoryLength,
|
||||
HistoryGossip: BlossomSubHistoryGossip,
|
||||
Dlazy: BlossomSubDlazy,
|
||||
GossipFactor: BlossomSubGossipFactor,
|
||||
GossipRetransmission: BlossomSubGossipRetransmission,
|
||||
HeartbeatInitialDelay: BlossomSubHeartbeatInitialDelay,
|
||||
HeartbeatInterval: BlossomSubHeartbeatInterval,
|
||||
@ -453,6 +452,7 @@ type BlossomSubRouter struct {
|
||||
backoff map[string]map[peer.ID]time.Time // prune backoff
|
||||
connect chan connectInfo // px connection requests
|
||||
cab peerstore.AddrBook
|
||||
meshMx sync.RWMutex
|
||||
|
||||
protos []protocol.ID
|
||||
feature BlossomSubFeatureTest
|
||||
@ -556,11 +556,18 @@ func (bs *BlossomSubRouter) manageAddrBook() {
|
||||
log.Errorf("failed to subscribe to peer identification events: %v", err)
|
||||
return
|
||||
}
|
||||
defer sub.Close()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-bs.p.ctx.Done():
|
||||
cabCloser, ok := bs.cab.(io.Closer)
|
||||
if ok {
|
||||
errClose := cabCloser.Close()
|
||||
if errClose != nil {
|
||||
log.Warnf("failed to close addr book: %v", errClose)
|
||||
}
|
||||
}
|
||||
sub.Close()
|
||||
return
|
||||
case ev := <-sub.Out():
|
||||
switch ev := ev.(type) {
|
||||
@ -620,9 +627,11 @@ func (bs *BlossomSubRouter) RemovePeer(p peer.ID) {
|
||||
log.Debugf("PEERDOWN: Remove disconnected peer %s", p)
|
||||
bs.tracer.RemovePeer(p)
|
||||
delete(bs.peers, p)
|
||||
bs.meshMx.Lock()
|
||||
for _, peers := range bs.mesh {
|
||||
delete(peers, p)
|
||||
}
|
||||
bs.meshMx.Unlock()
|
||||
for _, peers := range bs.fanout {
|
||||
delete(peers, p)
|
||||
}
|
||||
@ -638,7 +647,7 @@ func (bs *BlossomSubRouter) EnoughPeers(bitmask []byte, suggested int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
fsPeers, gsPeers := 0, 0
|
||||
fsPeers, bsPeers := 0, 0
|
||||
// floodsub peers
|
||||
for p := range tmap {
|
||||
if !bs.feature(BlossomSubFeatureMesh, bs.peers[p]) {
|
||||
@ -646,14 +655,16 @@ func (bs *BlossomSubRouter) EnoughPeers(bitmask []byte, suggested int) bool {
|
||||
}
|
||||
}
|
||||
|
||||
bs.meshMx.RLock()
|
||||
// BlossomSub peers
|
||||
gsPeers = len(bs.mesh[string(bitmask)])
|
||||
bsPeers = len(bs.mesh[string(bitmask)])
|
||||
bs.meshMx.RUnlock()
|
||||
|
||||
if suggested == 0 {
|
||||
suggested = bs.params.Dlo
|
||||
}
|
||||
|
||||
if fsPeers+gsPeers >= suggested || gsPeers >= bs.params.Dhi {
|
||||
if fsPeers+bsPeers >= suggested || bsPeers >= bs.params.Dhi {
|
||||
return true
|
||||
}
|
||||
|
||||
@ -719,7 +730,9 @@ func (bs *BlossomSubRouter) handleIHave(p peer.ID, ctl *pb.ControlMessage) []*pb
|
||||
iwant := make(map[string]struct{})
|
||||
for _, ihave := range ctl.GetIhave() {
|
||||
bitmask := ihave.GetBitmask()
|
||||
bs.meshMx.RLock()
|
||||
_, ok := bs.mesh[string(bitmask)]
|
||||
bs.meshMx.RUnlock()
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
@ -728,11 +741,18 @@ func (bs *BlossomSubRouter) handleIHave(p peer.ID, ctl *pb.ControlMessage) []*pb
|
||||
continue
|
||||
}
|
||||
|
||||
for _, mid := range ihave.GetMessageIDs() {
|
||||
checkIwantMsgsLoop:
|
||||
for msgIdx, mid := range ihave.GetMessageIDs() {
|
||||
// prevent remote peer from sending too many msg_ids on a single IHAVE message
|
||||
if msgIdx >= bs.params.MaxIHaveLength {
|
||||
log.Debugf("IHAVE: peer %s has sent IHAVE on bitmask %s with too many messages (%d); ignoring remaining msgs", p, bitmask, len(ihave.MessageIDs))
|
||||
break checkIwantMsgsLoop
|
||||
}
|
||||
|
||||
if bs.p.seenMessage(mid) {
|
||||
continue
|
||||
}
|
||||
iwant[mid] = struct{}{}
|
||||
iwant[string(mid)] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
@ -747,9 +767,9 @@ func (bs *BlossomSubRouter) handleIHave(p peer.ID, ctl *pb.ControlMessage) []*pb
|
||||
|
||||
log.Debugf("IHAVE: Asking for %d out of %d messages from %s", iask, len(iwant), p)
|
||||
|
||||
iwantlst := make([]string, 0, len(iwant))
|
||||
iwantlst := make([][]byte, 0, len(iwant))
|
||||
for mid := range iwant {
|
||||
iwantlst = append(iwantlst, mid)
|
||||
iwantlst = append(iwantlst, []byte(mid))
|
||||
}
|
||||
|
||||
// truncate to the messages we are actually asking for and update the iasked counter
|
||||
@ -786,7 +806,7 @@ func (bs *BlossomSubRouter) handleIWant(p peer.ID, ctl *pb.ControlMessage) []*pb
|
||||
continue
|
||||
}
|
||||
|
||||
ihave[mid] = msg.Message
|
||||
ihave[string(mid)] = msg.Message
|
||||
}
|
||||
}
|
||||
|
||||
@ -818,7 +838,9 @@ func (bs *BlossomSubRouter) handleGraft(p peer.ID, ctl *pb.ControlMessage) []*pb
|
||||
continue
|
||||
}
|
||||
|
||||
bs.meshMx.RLock()
|
||||
peers, ok := bs.mesh[string(bitmask)]
|
||||
bs.meshMx.RUnlock()
|
||||
if !ok {
|
||||
// don't do PX when there is an unknown bitmask to avoid leaking our peers
|
||||
doPX = false
|
||||
@ -907,7 +929,9 @@ func (bs *BlossomSubRouter) handlePrune(p peer.ID, ctl *pb.ControlMessage) {
|
||||
|
||||
for _, prune := range ctl.GetPrune() {
|
||||
bitmask := prune.GetBitmask()
|
||||
bs.meshMx.RLock()
|
||||
peers, ok := bs.mesh[string(bitmask)]
|
||||
bs.meshMx.RUnlock()
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
@ -1046,57 +1070,73 @@ func (bs *BlossomSubRouter) Publish(msg *Message) {
|
||||
|
||||
tosend := make(map[peer.ID]struct{})
|
||||
|
||||
// any peers in the bitmask?
|
||||
tmap, ok := bs.p.bitmasks[string(bitmask)]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if bs.floodPublish && from == bs.p.host.ID() {
|
||||
for p := range tmap {
|
||||
_, direct := bs.direct[p]
|
||||
if direct || bs.score.Score(p) >= bs.publishThreshold {
|
||||
tosend[p] = struct{}{}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// direct peers
|
||||
for p := range bs.direct {
|
||||
_, inBitmask := tmap[p]
|
||||
if inBitmask {
|
||||
tosend[p] = 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
|
||||
}
|
||||
|
||||
// floodsub peers
|
||||
for p := range tmap {
|
||||
if !bs.feature(BlossomSubFeatureMesh, bs.peers[p]) && bs.score.Score(p) >= bs.publishThreshold {
|
||||
tosend[p] = struct{}{}
|
||||
}
|
||||
for _, p := range peers {
|
||||
tosend[p] = struct{}{}
|
||||
}
|
||||
|
||||
// BlossomSub peers
|
||||
gmap, ok := bs.mesh[string(bitmask)]
|
||||
} else { // classic gossip mesh
|
||||
// any peers in the bitmask?
|
||||
tmap, ok := bs.p.bitmasks[string(bitmask)]
|
||||
if !ok {
|
||||
// we are not in the mesh for bitmask, use fanout peers
|
||||
gmap, ok = bs.fanout[string(bitmask)]
|
||||
if !ok || len(gmap) == 0 {
|
||||
// we don't have any, pick some with score above the publish threshold
|
||||
peers := bs.getPeers(bitmask, bs.params.D, func(p peer.ID) bool {
|
||||
_, direct := bs.direct[p]
|
||||
return !direct && bs.score.Score(p) >= bs.publishThreshold
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if len(peers) > 0 {
|
||||
gmap = peerListToMap(peers)
|
||||
bs.fanout[string(bitmask)] = gmap
|
||||
if bs.floodPublish && from == bs.p.host.ID() {
|
||||
for p := range tmap {
|
||||
_, direct := bs.direct[p]
|
||||
if direct || bs.score.Score(p) >= bs.publishThreshold {
|
||||
tosend[p] = struct{}{}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// direct peers
|
||||
for p := range bs.direct {
|
||||
_, inBitmask := tmap[p]
|
||||
if inBitmask {
|
||||
tosend[p] = struct{}{}
|
||||
}
|
||||
}
|
||||
bs.lastpub[string(bitmask)] = time.Now().UnixNano()
|
||||
}
|
||||
|
||||
for p := range gmap {
|
||||
tosend[p] = struct{}{}
|
||||
// floodsub peers
|
||||
for p := range tmap {
|
||||
if !bs.feature(BlossomSubFeatureMesh, bs.peers[p]) && bs.score.Score(p) >= bs.publishThreshold {
|
||||
tosend[p] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// BlossomSub peers
|
||||
bs.meshMx.RLock()
|
||||
gmap, ok := bs.mesh[string(bitmask)]
|
||||
bs.meshMx.RUnlock()
|
||||
if !ok {
|
||||
// we are not in the mesh for bitmask, use fanout peers
|
||||
gmap, ok = bs.fanout[string(bitmask)]
|
||||
if !ok || len(gmap) == 0 {
|
||||
// we don't have any, pick some with score above the publish threshold
|
||||
peers := bs.getPeers(bitmask, bs.params.D, func(p peer.ID) bool {
|
||||
_, direct := bs.direct[p]
|
||||
return !direct && bs.score.Score(p) >= bs.publishThreshold
|
||||
})
|
||||
|
||||
if len(peers) > 0 {
|
||||
gmap = peerListToMap(peers)
|
||||
bs.fanout[string(bitmask)] = gmap
|
||||
}
|
||||
}
|
||||
bs.lastpub[string(bitmask)] = time.Now().UnixNano()
|
||||
}
|
||||
|
||||
for p := range gmap {
|
||||
tosend[p] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1111,7 +1151,9 @@ func (bs *BlossomSubRouter) Publish(msg *Message) {
|
||||
}
|
||||
|
||||
func (bs *BlossomSubRouter) Join(bitmask []byte) {
|
||||
bs.meshMx.RLock()
|
||||
gmap, ok := bs.mesh[string(bitmask)]
|
||||
bs.meshMx.RUnlock()
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
@ -1146,7 +1188,9 @@ func (bs *BlossomSubRouter) Join(bitmask []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
bs.meshMx.Lock()
|
||||
bs.mesh[string(bitmask)] = gmap
|
||||
bs.meshMx.Unlock()
|
||||
delete(bs.fanout, string(bitmask))
|
||||
delete(bs.lastpub, string(bitmask))
|
||||
} else {
|
||||
@ -1158,7 +1202,9 @@ func (bs *BlossomSubRouter) Join(bitmask []byte) {
|
||||
return !direct && !doBackOff && bs.score.Score(p) >= 0
|
||||
})
|
||||
gmap = peerListToMap(peers)
|
||||
bs.meshMx.Lock()
|
||||
bs.mesh[string(bitmask)] = gmap
|
||||
bs.meshMx.Unlock()
|
||||
}
|
||||
|
||||
for p := range gmap {
|
||||
@ -1169,7 +1215,9 @@ func (bs *BlossomSubRouter) Join(bitmask []byte) {
|
||||
}
|
||||
|
||||
func (bs *BlossomSubRouter) Leave(bitmask []byte) {
|
||||
bs.meshMx.RLock()
|
||||
gmap, ok := bs.mesh[string(bitmask)]
|
||||
bs.meshMx.RUnlock()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@ -1177,7 +1225,9 @@ func (bs *BlossomSubRouter) Leave(bitmask []byte) {
|
||||
log.Debugf("LEAVE %s", bitmask)
|
||||
bs.tracer.Leave(bitmask)
|
||||
|
||||
bs.meshMx.Lock()
|
||||
delete(bs.mesh, string(bitmask))
|
||||
bs.meshMx.Unlock()
|
||||
|
||||
for p := range gmap {
|
||||
log.Debugf("LEAVE: Remove mesh link to %s in %s", p, bitmask)
|
||||
@ -1226,7 +1276,9 @@ func (bs *BlossomSubRouter) sendRPC(p peer.ID, out *RPC) {
|
||||
delete(bs.gossip, p)
|
||||
}
|
||||
|
||||
bs.p.peersMx.RLock()
|
||||
mch, ok := bs.p.peers[p]
|
||||
bs.p.peersMx.RUnlock()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@ -1237,8 +1289,9 @@ func (bs *BlossomSubRouter) sendRPC(p peer.ID, out *RPC) {
|
||||
return
|
||||
}
|
||||
|
||||
outCopy := copyRPC(out)
|
||||
// Potentially split the RPC into multiple RPCs that are below the max message size
|
||||
outRPCs := appendOrMergeRPC(nil, bs.p.maxMessageSize, *out)
|
||||
outRPCs := appendOrMergeRPC(nil, bs.p.maxMessageSize, outCopy)
|
||||
for _, rpc := range outRPCs {
|
||||
if rpc.Size() > bs.p.maxMessageSize {
|
||||
// This should only happen if a single message/control is above the maxMessageSize.
|
||||
@ -1273,19 +1326,19 @@ func (bs *BlossomSubRouter) doSendRPC(rpc *RPC, p peer.ID, mch chan *RPC) {
|
||||
// If an RPC is too large and can't be split further (e.g. Message data is
|
||||
// bigger than the RPC limit), then it will be returned as an oversized RPC.
|
||||
// The caller should filter out oversized RPCs.
|
||||
func appendOrMergeRPC(slice []*RPC, limit int, elems ...RPC) []*RPC {
|
||||
func appendOrMergeRPC(slice []*RPC, limit int, elems ...*RPC) []*RPC {
|
||||
if len(elems) == 0 {
|
||||
return slice
|
||||
}
|
||||
|
||||
if len(slice) == 0 && len(elems) == 1 && elems[0].Size() < limit {
|
||||
// Fast path: no merging needed and only one element
|
||||
return append(slice, &elems[0])
|
||||
return append(slice, elems[0])
|
||||
}
|
||||
|
||||
out := slice
|
||||
if len(out) == 0 {
|
||||
out = append(out, &RPC{RPC: pb.RPC{}})
|
||||
out = append(out, &RPC{RPC: &pb.RPC{}})
|
||||
out[0].from = elems[0].from
|
||||
}
|
||||
|
||||
@ -1299,7 +1352,7 @@ func appendOrMergeRPC(slice []*RPC, limit int, elems ...RPC) []*RPC {
|
||||
for _, msg := range elem.GetPublish() {
|
||||
if lastRPC.Publish = append(lastRPC.Publish, msg); lastRPC.Size() > limit {
|
||||
lastRPC.Publish = lastRPC.Publish[:len(lastRPC.Publish)-1]
|
||||
lastRPC = &RPC{RPC: pb.RPC{}, from: elem.from}
|
||||
lastRPC = &RPC{RPC: &pb.RPC{}, from: elem.from}
|
||||
lastRPC.Publish = append(lastRPC.Publish, msg)
|
||||
out = append(out, lastRPC)
|
||||
}
|
||||
@ -1309,7 +1362,7 @@ func appendOrMergeRPC(slice []*RPC, limit int, elems ...RPC) []*RPC {
|
||||
for _, sub := range elem.GetSubscriptions() {
|
||||
if lastRPC.Subscriptions = append(lastRPC.Subscriptions, sub); lastRPC.Size() > limit {
|
||||
lastRPC.Subscriptions = lastRPC.Subscriptions[:len(lastRPC.Subscriptions)-1]
|
||||
lastRPC = &RPC{RPC: pb.RPC{}, from: elem.from}
|
||||
lastRPC = &RPC{RPC: &pb.RPC{}, from: elem.from}
|
||||
lastRPC.Subscriptions = append(lastRPC.Subscriptions, sub)
|
||||
out = append(out, lastRPC)
|
||||
}
|
||||
@ -1321,7 +1374,7 @@ func appendOrMergeRPC(slice []*RPC, limit int, elems ...RPC) []*RPC {
|
||||
lastRPC.Control = &pb.ControlMessage{}
|
||||
if lastRPC.Size() > limit {
|
||||
lastRPC.Control = nil
|
||||
lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{}}, from: elem.from}
|
||||
lastRPC = &RPC{RPC: &pb.RPC{Control: &pb.ControlMessage{}}, from: elem.from}
|
||||
out = append(out, lastRPC)
|
||||
}
|
||||
}
|
||||
@ -1329,7 +1382,7 @@ func appendOrMergeRPC(slice []*RPC, limit int, elems ...RPC) []*RPC {
|
||||
for _, graft := range ctl.GetGraft() {
|
||||
if lastRPC.Control.Graft = append(lastRPC.Control.Graft, graft); lastRPC.Size() > limit {
|
||||
lastRPC.Control.Graft = lastRPC.Control.Graft[:len(lastRPC.Control.Graft)-1]
|
||||
lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{}}, from: elem.from}
|
||||
lastRPC = &RPC{RPC: &pb.RPC{Control: &pb.ControlMessage{}}, from: elem.from}
|
||||
lastRPC.Control.Graft = append(lastRPC.Control.Graft, graft)
|
||||
out = append(out, lastRPC)
|
||||
}
|
||||
@ -1338,7 +1391,7 @@ func appendOrMergeRPC(slice []*RPC, limit int, elems ...RPC) []*RPC {
|
||||
for _, prune := range ctl.GetPrune() {
|
||||
if lastRPC.Control.Prune = append(lastRPC.Control.Prune, prune); lastRPC.Size() > limit {
|
||||
lastRPC.Control.Prune = lastRPC.Control.Prune[:len(lastRPC.Control.Prune)-1]
|
||||
lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{}}, from: elem.from}
|
||||
lastRPC = &RPC{RPC: &pb.RPC{Control: &pb.ControlMessage{}}, from: elem.from}
|
||||
lastRPC.Control.Prune = append(lastRPC.Control.Prune, prune)
|
||||
out = append(out, lastRPC)
|
||||
}
|
||||
@ -1352,7 +1405,7 @@ func appendOrMergeRPC(slice []*RPC, limit int, elems ...RPC) []*RPC {
|
||||
newIWant := &pb.ControlIWant{}
|
||||
if lastRPC.Control.Iwant = append(lastRPC.Control.Iwant, newIWant); lastRPC.Size() > limit {
|
||||
lastRPC.Control.Iwant = lastRPC.Control.Iwant[:len(lastRPC.Control.Iwant)-1]
|
||||
lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{
|
||||
lastRPC = &RPC{RPC: &pb.RPC{Control: &pb.ControlMessage{
|
||||
Iwant: []*pb.ControlIWant{newIWant},
|
||||
}}, from: elem.from}
|
||||
out = append(out, lastRPC)
|
||||
@ -1361,8 +1414,8 @@ func appendOrMergeRPC(slice []*RPC, limit int, elems ...RPC) []*RPC {
|
||||
for _, msgID := range iwant.GetMessageIDs() {
|
||||
if lastRPC.Control.Iwant[0].MessageIDs = append(lastRPC.Control.Iwant[0].MessageIDs, msgID); lastRPC.Size() > limit {
|
||||
lastRPC.Control.Iwant[0].MessageIDs = lastRPC.Control.Iwant[0].MessageIDs[:len(lastRPC.Control.Iwant[0].MessageIDs)-1]
|
||||
lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{
|
||||
Iwant: []*pb.ControlIWant{{MessageIDs: []string{msgID}}},
|
||||
lastRPC = &RPC{RPC: &pb.RPC{Control: &pb.ControlMessage{
|
||||
Iwant: []*pb.ControlIWant{{MessageIDs: [][]byte{msgID}}},
|
||||
}}, from: elem.from}
|
||||
out = append(out, lastRPC)
|
||||
}
|
||||
@ -1376,7 +1429,7 @@ func appendOrMergeRPC(slice []*RPC, limit int, elems ...RPC) []*RPC {
|
||||
newIhave := &pb.ControlIHave{Bitmask: ihave.Bitmask}
|
||||
if lastRPC.Control.Ihave = append(lastRPC.Control.Ihave, newIhave); lastRPC.Size() > limit {
|
||||
lastRPC.Control.Ihave = lastRPC.Control.Ihave[:len(lastRPC.Control.Ihave)-1]
|
||||
lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{
|
||||
lastRPC = &RPC{RPC: &pb.RPC{Control: &pb.ControlMessage{
|
||||
Ihave: []*pb.ControlIHave{newIhave},
|
||||
}}, from: elem.from}
|
||||
out = append(out, lastRPC)
|
||||
@ -1386,8 +1439,8 @@ func appendOrMergeRPC(slice []*RPC, limit int, elems ...RPC) []*RPC {
|
||||
lastIHave := lastRPC.Control.Ihave[len(lastRPC.Control.Ihave)-1]
|
||||
if lastIHave.MessageIDs = append(lastIHave.MessageIDs, msgID); lastRPC.Size() > limit {
|
||||
lastIHave.MessageIDs = lastIHave.MessageIDs[:len(lastIHave.MessageIDs)-1]
|
||||
lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{
|
||||
Ihave: []*pb.ControlIHave{{Bitmask: ihave.Bitmask, MessageIDs: []string{msgID}}},
|
||||
lastRPC = &RPC{RPC: &pb.RPC{Control: &pb.ControlMessage{
|
||||
Ihave: []*pb.ControlIHave{{Bitmask: ihave.Bitmask, MessageIDs: [][]byte{msgID}}},
|
||||
}}, from: elem.from}
|
||||
out = append(out, lastRPC)
|
||||
}
|
||||
@ -1408,7 +1461,6 @@ func (bs *BlossomSubRouter) heartbeatTimer() {
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(bs.params.HeartbeatInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
@ -1416,9 +1468,11 @@ func (bs *BlossomSubRouter) heartbeatTimer() {
|
||||
select {
|
||||
case bs.p.eval <- bs.heartbeat:
|
||||
case <-bs.p.ctx.Done():
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
case <-bs.p.ctx.Done():
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -1426,14 +1480,6 @@ func (bs *BlossomSubRouter) heartbeatTimer() {
|
||||
|
||||
func (bs *BlossomSubRouter) heartbeat() {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
if bs.params.SlowHeartbeatWarning > 0 {
|
||||
slowWarning := time.Duration(bs.params.SlowHeartbeatWarning * float64(bs.params.HeartbeatInterval))
|
||||
if dt := time.Since(start); dt > slowWarning {
|
||||
log.Warnw("slow heartbeat", "took", dt)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
bs.heartbeatTicks++
|
||||
|
||||
@ -1465,6 +1511,7 @@ func (bs *BlossomSubRouter) heartbeat() {
|
||||
}
|
||||
|
||||
// maintain the mesh for bitmasks we have joined
|
||||
bs.meshMx.Lock()
|
||||
for bitmask, peers := range bs.mesh {
|
||||
bitmask := []byte(bitmask)
|
||||
prunePeer := func(p peer.ID) {
|
||||
@ -1521,7 +1568,9 @@ func (bs *BlossomSubRouter) heartbeat() {
|
||||
|
||||
// We keep the first D_score peers by score and the remaining up to D randomly
|
||||
// under the constraint that we keep D_out peers in the mesh (if we have that many)
|
||||
shufflePeers(plst[bs.params.Dscore:])
|
||||
if len(plst) > bs.params.Dscore {
|
||||
shufflePeers(plst[bs.params.Dscore:])
|
||||
}
|
||||
|
||||
// count the outbound peers we are keeping
|
||||
outbound := 0
|
||||
@ -1637,7 +1686,15 @@ func (bs *BlossomSubRouter) heartbeat() {
|
||||
// 2nd arg are mesh peers excluded from gossip. We already push
|
||||
// messages to them, so its redundant to gossip IHAVEs.
|
||||
bs.emitGossip(bitmask, peers)
|
||||
|
||||
if bs.params.SlowHeartbeatWarning > 0 {
|
||||
slowWarning := time.Duration(bs.params.SlowHeartbeatWarning * float64(bs.params.HeartbeatInterval))
|
||||
if dt := time.Since(start); dt > slowWarning {
|
||||
log.Warnw("slow heartbeat", "took", dt)
|
||||
}
|
||||
}
|
||||
}
|
||||
bs.meshMx.Unlock()
|
||||
|
||||
// expire fanout for bitmasks we haven't published to in a while
|
||||
now := time.Now().UnixNano()
|
||||
@ -1799,7 +1856,7 @@ func (bs *BlossomSubRouter) emitGossip(bitmask []byte, exclude map[peer.ID]struc
|
||||
}
|
||||
|
||||
// shuffle to emit in random order
|
||||
shuffleStrings(mids)
|
||||
shuffleBytes(mids)
|
||||
|
||||
// if we are emitting more than BlossomSubMaxIHaveLength mids, truncate the list
|
||||
if len(mids) > bs.params.MaxIHaveLength {
|
||||
@ -1821,10 +1878,6 @@ func (bs *BlossomSubRouter) emitGossip(bitmask []byte, exclude map[peer.ID]struc
|
||||
}
|
||||
|
||||
target := bs.params.Dlazy
|
||||
factor := int(bs.params.GossipFactor * float64(len(peers)))
|
||||
if factor > target {
|
||||
target = factor
|
||||
}
|
||||
|
||||
if target > len(peers) {
|
||||
target = len(peers)
|
||||
@ -1840,8 +1893,8 @@ func (bs *BlossomSubRouter) emitGossip(bitmask []byte, exclude map[peer.ID]struc
|
||||
// we do this per peer so that we emit a different set for each peer.
|
||||
// we have enough redundancy in the system that this will significantly increase the message
|
||||
// coverage when we do truncate.
|
||||
peerMids = make([]string, bs.params.MaxIHaveLength)
|
||||
shuffleStrings(mids)
|
||||
peerMids = make([][]byte, bs.params.MaxIHaveLength)
|
||||
shuffleBytes(mids)
|
||||
copy(peerMids, mids)
|
||||
}
|
||||
bs.enqueueGossip(p, &pb.ControlIHave{Bitmask: bitmask, MessageIDs: peerMids})
|
||||
@ -1896,7 +1949,9 @@ func (bs *BlossomSubRouter) piggybackControl(p peer.ID, out *RPC, ctl *pb.Contro
|
||||
|
||||
for _, graft := range ctl.GetGraft() {
|
||||
bitmask := graft.GetBitmask()
|
||||
bs.meshMx.RLock()
|
||||
peers, ok := bs.mesh[string(bitmask)]
|
||||
bs.meshMx.RUnlock()
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
@ -1908,7 +1963,9 @@ func (bs *BlossomSubRouter) piggybackControl(p peer.ID, out *RPC, ctl *pb.Contro
|
||||
|
||||
for _, prune := range ctl.GetPrune() {
|
||||
bitmask := prune.GetBitmask()
|
||||
bs.meshMx.RLock()
|
||||
peers, ok := bs.mesh[string(bitmask)]
|
||||
bs.meshMx.RUnlock()
|
||||
if !ok {
|
||||
toprune = append(toprune, prune)
|
||||
continue
|
||||
@ -1980,25 +2037,47 @@ func (bs *BlossomSubRouter) makePrune(p peer.ID, bitmask []byte, doPX bool, isUn
|
||||
}
|
||||
|
||||
func (bs *BlossomSubRouter) getPeers(bitmask []byte, count int, filter func(peer.ID) bool) []peer.ID {
|
||||
tmap, ok := bs.p.bitmasks[string(bitmask)]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
bitmaskSlices := SliceBitmask(bitmask)
|
||||
|
||||
peers := make([]peer.ID, 0, len(tmap))
|
||||
for p := range tmap {
|
||||
if bs.feature(BlossomSubFeatureMesh, bs.peers[p]) && filter(p) && bs.p.peerFilter(p, bitmask) {
|
||||
peers = append(peers, p)
|
||||
set := []peer.ID{}
|
||||
for _, slice := range bitmaskSlices {
|
||||
tmap, ok := bs.p.bitmasks[string(slice)]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
peers := make([]peer.ID, 0, len(tmap))
|
||||
for p := range tmap {
|
||||
if bs.feature(BlossomSubFeatureMesh, bs.peers[p]) && filter(p) && bs.p.peerFilter(p, slice) {
|
||||
peers = append(peers, p)
|
||||
}
|
||||
}
|
||||
|
||||
if len(set) == 0 {
|
||||
set = peers
|
||||
} else {
|
||||
newSet := []peer.ID{}
|
||||
for _, p := range peers {
|
||||
if slices.Contains(set, p) {
|
||||
newSet = append(newSet, p)
|
||||
}
|
||||
}
|
||||
|
||||
if len(newSet) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
set = newSet
|
||||
}
|
||||
}
|
||||
|
||||
shufflePeers(peers)
|
||||
shufflePeers(set)
|
||||
|
||||
if count > 0 && len(peers) > count {
|
||||
peers = peers[:count]
|
||||
if count > 0 && len(set) > count {
|
||||
set = set[:count]
|
||||
}
|
||||
|
||||
return peers
|
||||
return set
|
||||
}
|
||||
|
||||
// WithDefaultTagTracer returns the tag tracer of the BlossomSubRouter as a PubSub option.
|
||||
@ -2039,7 +2118,7 @@ func shufflePeerInfo(peers []*pb.PeerInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
func shuffleStrings(lst []string) {
|
||||
func shuffleBytes(lst [][]byte) {
|
||||
for i := range lst {
|
||||
j := rand.Intn(i + 1)
|
||||
lst[i], lst[j] = lst[j], lst[i]
|
||||
|
@ -6,11 +6,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/benbjohnson/clock"
|
||||
"github.com/libp2p/go-libp2p"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
swarmt "github.com/libp2p/go-libp2p/p2p/net/swarm/testing"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
bhost "github.com/libp2p/go-libp2p/p2p/host/blank"
|
||||
"github.com/libp2p/go-libp2p/p2p/net/connmgr"
|
||||
)
|
||||
|
||||
@ -70,9 +70,14 @@ func TestBlossomSubConnTagMessageDeliveries(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
netw := swarmt.GenSwarm(t)
|
||||
defer netw.Close()
|
||||
h := bhost.NewBlankHost(netw, bhost.WithConnectionManager(connmgrs[i]))
|
||||
h, err := libp2p.New(
|
||||
libp2p.ResourceManager(&network.NullResourceManager{}),
|
||||
libp2p.ConnectionManager(connmgrs[i]),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { h.Close() })
|
||||
honestHosts[i] = h
|
||||
honestPeers[h.ID()] = struct{}{}
|
||||
}
|
||||
@ -83,23 +88,23 @@ func TestBlossomSubConnTagMessageDeliveries(t *testing.T) {
|
||||
WithFloodPublish(true))
|
||||
|
||||
// sybil squatters to be connected later
|
||||
sybilHosts := getNetHosts(t, ctx, nSquatter)
|
||||
sybilHosts := getDefaultHosts(t, nSquatter)
|
||||
for _, h := range sybilHosts {
|
||||
squatter := &sybilSquatter{h: h}
|
||||
h.SetStreamHandler(BlossomSubID_v12, squatter.handleStream)
|
||||
h.SetStreamHandler(BlossomSubID_v2, squatter.handleStream)
|
||||
}
|
||||
|
||||
// connect the honest hosts
|
||||
connectAll(t, honestHosts)
|
||||
|
||||
for _, h := range honestHosts {
|
||||
if len(h.Network().Conns()) != nHonest-1 {
|
||||
if len(h.Network().Conns()) < nHonest-1 {
|
||||
t.Errorf("expected to have conns to all honest peers, have %d", len(h.Network().Conns()))
|
||||
}
|
||||
}
|
||||
|
||||
// subscribe everyone to the bitmask
|
||||
bitmask := []byte{0xff, 0x00, 0x00, 0x00}
|
||||
bitmask := []byte{0x00, 0x80, 0x00, 0x00}
|
||||
for _, ps := range psubs {
|
||||
_, err := ps.Subscribe(bitmask)
|
||||
if err != nil {
|
||||
@ -113,8 +118,13 @@ func TestBlossomSubConnTagMessageDeliveries(t *testing.T) {
|
||||
// have all the hosts publish enough messages to ensure that they get some delivery credit
|
||||
nMessages := BlossomSubConnTagMessageDeliveryCap * 2
|
||||
for _, ps := range psubs {
|
||||
b, err := ps.Join(bitmask)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 0; i < nMessages; i++ {
|
||||
ps.Publish(bitmask, []byte("hello"))
|
||||
b[0].Publish(ctx, b[0].bitmask, []byte("hello"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,7 +132,7 @@ func TestBlossomSubConnTagMessageDeliveries(t *testing.T) {
|
||||
decayClock.Add(time.Second)
|
||||
|
||||
// verify that they've given each other delivery connection tags
|
||||
tag := "pubsub-deliveries:test"
|
||||
tag := "pubsub-deliveries:" + string([]byte{0x00, 0x80, 0x00, 0x00})
|
||||
for _, h := range honestHosts {
|
||||
for _, h2 := range honestHosts {
|
||||
if h.ID() == h2.ID() {
|
||||
@ -136,12 +146,12 @@ func TestBlossomSubConnTagMessageDeliveries(t *testing.T) {
|
||||
}
|
||||
|
||||
// now connect the sybils to put pressure on the real hosts' connection managers
|
||||
allHosts := append(honestHosts, sybilHosts...)
|
||||
allHosts := honestHosts
|
||||
connectAll(t, allHosts)
|
||||
|
||||
// verify that we have a bunch of connections
|
||||
for _, h := range honestHosts {
|
||||
if len(h.Network().Conns()) != nHonest+nSquatter-1 {
|
||||
if len(h.Network().Conns()) < nHonest-1 {
|
||||
t.Errorf("expected to have conns to all peers, have %d", len(h.Network().Conns()))
|
||||
}
|
||||
}
|
||||
@ -165,7 +175,7 @@ func TestBlossomSubConnTagMessageDeliveries(t *testing.T) {
|
||||
if nDishonestConns > connLimit-nHonest {
|
||||
t.Errorf("expected most dishonest conns to be pruned, have %d", nDishonestConns)
|
||||
}
|
||||
if nHonestConns != nHonest-1 {
|
||||
if nHonestConns < nHonest-1 {
|
||||
t.Errorf("expected all honest conns to be preserved, have %d", nHonestConns)
|
||||
}
|
||||
}
|
||||
|
@ -14,22 +14,22 @@ type BlossomSubFeatureTest = func(BlossomSubFeature, protocol.ID) bool
|
||||
type BlossomSubFeature int
|
||||
|
||||
const (
|
||||
// Protocol supports basic BlossomSub Mesh -- BlossomSub-v1.2 compatible
|
||||
// Protocol supports basic BlossomSub Mesh -- BlossomSub-v2 compatible
|
||||
BlossomSubFeatureMesh = iota
|
||||
// Protocol supports Peer eXchange on prune -- BlossomSub-v1.2 compatible
|
||||
// Protocol supports Peer eXchange on prune -- BlossomSub-v2 compatible
|
||||
BlossomSubFeaturePX
|
||||
)
|
||||
|
||||
// BlossomSubDefaultProtocols is the default BlossomSub router protocol list
|
||||
var BlossomSubDefaultProtocols = []protocol.ID{BlossomSubID_v12, FloodSubID}
|
||||
var BlossomSubDefaultProtocols = []protocol.ID{BlossomSubID_v2}
|
||||
|
||||
// BlossomSubDefaultFeatures is the feature test function for the default BlossomSub protocols
|
||||
func BlossomSubDefaultFeatures(feat BlossomSubFeature, proto protocol.ID) bool {
|
||||
switch feat {
|
||||
case BlossomSubFeatureMesh:
|
||||
return proto == BlossomSubID_v12
|
||||
return proto == BlossomSubID_v2
|
||||
case BlossomSubFeaturePX:
|
||||
return proto == BlossomSubID_v12
|
||||
return proto == BlossomSubID_v2
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
@ -12,47 +12,46 @@ import (
|
||||
)
|
||||
|
||||
func TestDefaultBlossomSubFeatures(t *testing.T) {
|
||||
if BlossomSubDefaultFeatures(BlossomSubFeatureMesh, FloodSubID) {
|
||||
t.Fatal("floodsub should not support Mesh")
|
||||
}
|
||||
if !BlossomSubDefaultFeatures(BlossomSubFeatureMesh, BlossomSubID_v12) {
|
||||
t.Fatal("BlossomSub-v1.2 should support Mesh")
|
||||
if !BlossomSubDefaultFeatures(BlossomSubFeatureMesh, BlossomSubID_v2) {
|
||||
t.Fatal("BlossomSub-v2.0 should support Mesh")
|
||||
}
|
||||
|
||||
if BlossomSubDefaultFeatures(BlossomSubFeaturePX, FloodSubID) {
|
||||
t.Fatal("floodsub should not support PX")
|
||||
}
|
||||
if !BlossomSubDefaultFeatures(BlossomSubFeatureMesh, BlossomSubID_v12) {
|
||||
t.Fatal("BlossomSub-v1.2 should support PX")
|
||||
if !BlossomSubDefaultFeatures(BlossomSubFeaturePX, BlossomSubID_v2) {
|
||||
t.Fatal("BlossomSub-v2.0 should support PX")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlossomSubCustomProtocols(t *testing.T) {
|
||||
customsub := protocol.ID("customsub/1.0.0")
|
||||
protos := []protocol.ID{customsub, FloodSubID}
|
||||
protos := []protocol.ID{customsub}
|
||||
features := func(feat BlossomSubFeature, proto protocol.ID) bool {
|
||||
return proto == customsub
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
hosts := getNetHosts(t, ctx, 3)
|
||||
hosts := getDefaultHosts(t, 3)
|
||||
|
||||
bsubs := getBlossomSubs(ctx, hosts[:2], WithBlossomSubProtocols(protos, features))
|
||||
fsub := getPubsub(ctx, hosts[2])
|
||||
psubs := append(bsubs, fsub)
|
||||
|
||||
connectAll(t, hosts)
|
||||
|
||||
bitmask := []byte{0xff, 0x00, 0x00, 0x00}
|
||||
bitmask := []byte{0x00, 0x80, 0x00, 0x00}
|
||||
var bitmasks []*Bitmask
|
||||
var subs []*Subscription
|
||||
for _, ps := range psubs {
|
||||
for _, ps := range bsubs {
|
||||
b, err := ps.Join(bitmask)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
subch, err := ps.Subscribe(bitmask)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
subs = append(subs, subch)
|
||||
subs = append(subs, subch...)
|
||||
bitmasks = append(bitmasks, b...)
|
||||
}
|
||||
|
||||
// wait for heartbeats to build mesh
|
||||
@ -92,9 +91,8 @@ func TestBlossomSubCustomProtocols(t *testing.T) {
|
||||
for i := 0; i < 10; i++ {
|
||||
msg := []byte(fmt.Sprintf("%d it's not quite a floooooood %d", i, i))
|
||||
|
||||
owner := rand.Intn(len(psubs))
|
||||
|
||||
psubs[owner].Publish(bitmask, msg)
|
||||
owner := rand.Intn(len(bsubs))
|
||||
bitmasks[owner].Publish(ctx, bitmasks[owner].bitmask, msg)
|
||||
|
||||
for _, sub := range subs {
|
||||
got, err := sub.Next(ctx)
|
||||
|
@ -17,11 +17,11 @@ func TestBlossomSubMatchingFn(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
h := getNetHosts(t, ctx, 4)
|
||||
h := getDefaultHosts(t, 4)
|
||||
psubs := []*PubSub{
|
||||
getBlossomSub(ctx, h[0], WithProtocolMatchFn(protocolNameMatch), WithBlossomSubProtocols([]protocol.ID{customsubA100, BlossomSubID_v12}, BlossomSubDefaultFeatures)),
|
||||
getBlossomSub(ctx, h[0], WithProtocolMatchFn(protocolNameMatch), WithBlossomSubProtocols([]protocol.ID{customsubA100, BlossomSubID_v2}, BlossomSubDefaultFeatures)),
|
||||
getBlossomSub(ctx, h[1], WithProtocolMatchFn(protocolNameMatch), WithBlossomSubProtocols([]protocol.ID{customsubA101Beta}, BlossomSubDefaultFeatures)),
|
||||
getBlossomSub(ctx, h[2], WithProtocolMatchFn(protocolNameMatch), WithBlossomSubProtocols([]protocol.ID{BlossomSubID_v12}, BlossomSubDefaultFeatures)),
|
||||
getBlossomSub(ctx, h[2], WithProtocolMatchFn(protocolNameMatch), WithBlossomSubProtocols([]protocol.ID{BlossomSubID_v2}, BlossomSubDefaultFeatures)),
|
||||
getBlossomSub(ctx, h[3], WithProtocolMatchFn(protocolNameMatch), WithBlossomSubProtocols([]protocol.ID{customsubB100}, BlossomSubDefaultFeatures)),
|
||||
}
|
||||
|
||||
@ -39,23 +39,30 @@ func TestBlossomSubMatchingFn(t *testing.T) {
|
||||
|
||||
// build the mesh
|
||||
var subs []*Subscription
|
||||
var bitmasks []*Bitmask
|
||||
for _, ps := range psubs {
|
||||
sub, err := ps.Subscribe([]byte{0xff, 0x00, 0x00, 0x00})
|
||||
b, err := ps.Join([]byte{0x00, 0x80, 0x00, 0x00})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
subs = append(subs, sub)
|
||||
bitmasks = append(bitmasks, b...)
|
||||
|
||||
sub, err := ps.Subscribe([]byte{0x00, 0x80, 0x00, 0x00})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
subs = append(subs, sub...)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// publish a message
|
||||
msg := []byte("message")
|
||||
psubs[0].Publish([]byte{0xff, 0x00, 0x00, 0x00}, msg)
|
||||
bitmasks[0].Publish(ctx, bitmasks[0].bitmask, msg)
|
||||
|
||||
assertReceive(t, subs[0], msg)
|
||||
assertReceive(t, subs[1], msg) // Should match via semver over CustomSub name, ignoring the version
|
||||
assertReceive(t, subs[2], msg) // Should match via BlossomSubID_v11
|
||||
assertReceive(t, subs[2], msg) // Should match via BlossomSubID_v2
|
||||
|
||||
// No message should be received because customsubA and customsubB have different names
|
||||
ctxTimeout, timeoutCancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
|
@ -2,6 +2,7 @@ package blossomsub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"sync"
|
||||
@ -11,11 +12,10 @@ import (
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
"github.com/libp2p/go-msgio"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
pb "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb"
|
||||
|
||||
"github.com/libp2p/go-msgio/protoio"
|
||||
)
|
||||
|
||||
// Test that when BlossomSub receives too many IWANT messages from a peer
|
||||
@ -25,7 +25,7 @@ func TestBlossomSubAttackSpamIWANT(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
// Create legitimate and attacker hosts
|
||||
hosts := getNetHosts(t, ctx, 2)
|
||||
hosts := getDefaultHosts(t, 2)
|
||||
legit := hosts[0]
|
||||
attacker := hosts[1]
|
||||
|
||||
@ -36,25 +36,11 @@ func TestBlossomSubAttackSpamIWANT(t *testing.T) {
|
||||
}
|
||||
|
||||
// Subscribe to mybitmask on the legit host
|
||||
mybitmask := []byte{0xff, 0x00, 0x00}
|
||||
_, err = ps.Subscribe(mybitmask)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Used to publish a message with random data
|
||||
publishMsg := func() {
|
||||
data := make([]byte, 16)
|
||||
rand.Read(data)
|
||||
|
||||
if err = ps.Publish(mybitmask, data); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
mybitmask := []byte{0x20, 0x00, 0x00}
|
||||
|
||||
// Wait a bit after the last message before checking we got the
|
||||
// right number of messages
|
||||
msgWaitMax := time.Second
|
||||
msgWaitMax := 10 * time.Second
|
||||
msgCount := 0
|
||||
msgTimer := time.NewTimer(msgWaitMax)
|
||||
|
||||
@ -65,7 +51,22 @@ func TestBlossomSubAttackSpamIWANT(t *testing.T) {
|
||||
// <original message> + BlossomSubGossipRetransmission
|
||||
exp := 1 + BlossomSubGossipRetransmission
|
||||
if msgCount != exp {
|
||||
t.Fatalf("Expected %d messages, got %d", exp, msgCount)
|
||||
panic(fmt.Sprintf("Expected %d messages, got %d", exp, msgCount))
|
||||
}
|
||||
}
|
||||
|
||||
bitmasks, err := ps.Join(mybitmask)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Used to publish a message with random data
|
||||
publishMsg := func() {
|
||||
data := make([]byte, 16)
|
||||
rand.Read(data)
|
||||
|
||||
if err := bitmasks[0].Publish(ctx, bitmasks[0].bitmask, data); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,6 +85,7 @@ func TestBlossomSubAttackSpamIWANT(t *testing.T) {
|
||||
newMockBS(ctx, t, attacker, func(writeMsg func(*pb.RPC), irpc *pb.RPC) {
|
||||
// When the legit host connects it will send us its subscriptions
|
||||
for _, sub := range irpc.GetSubscriptions() {
|
||||
sub := sub
|
||||
if sub.GetSubscribe() {
|
||||
// Reply by subcribing to the bitmask and grafting to the peer
|
||||
writeMsg(&pb.RPC{
|
||||
@ -94,7 +96,7 @@ func TestBlossomSubAttackSpamIWANT(t *testing.T) {
|
||||
go func() {
|
||||
// Wait for a short interval to make sure the legit host
|
||||
// received and processed the subscribe + graft
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// Publish a message from the legit host
|
||||
publishMsg()
|
||||
@ -118,15 +120,22 @@ func TestBlossomSubAttackSpamIWANT(t *testing.T) {
|
||||
// Send an IWANT with the message ID, causing the legit host
|
||||
// to send another message (until it cuts off the attacker for
|
||||
// being spammy)
|
||||
iwantlst := []string{DefaultMsgIdFn(msg)}
|
||||
iwantlst := [][]byte{DefaultMsgIdFn(msg)}
|
||||
iwant := []*pb.ControlIWant{{MessageIDs: iwantlst}}
|
||||
orpc := rpcWithControl(nil, nil, iwant, nil, nil)
|
||||
writeMsg(&orpc.RPC)
|
||||
writeMsg(orpc.RPC)
|
||||
}
|
||||
})
|
||||
|
||||
connect(t, hosts[0], hosts[1])
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
_, err = ps.Subscribe(mybitmask)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
<-ctx.Done()
|
||||
}
|
||||
|
||||
@ -142,7 +151,7 @@ func TestBlossomSubAttackSpamIHAVE(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
// Create legitimate and attacker hosts
|
||||
hosts := getNetHosts(t, ctx, 2)
|
||||
hosts := getDefaultHosts(t, 2)
|
||||
legit := hosts[0]
|
||||
attacker := hosts[1]
|
||||
|
||||
@ -166,7 +175,7 @@ func TestBlossomSubAttackSpamIHAVE(t *testing.T) {
|
||||
}
|
||||
|
||||
// Subscribe to mybitmask on the legit host
|
||||
mybitmask := []byte{0xff, 0x00, 0x00}
|
||||
mybitmask := []byte{0x20, 0x00, 0x00}
|
||||
_, err = ps.Subscribe(mybitmask)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -188,6 +197,7 @@ func TestBlossomSubAttackSpamIHAVE(t *testing.T) {
|
||||
newMockBS(ctx, t, attacker, func(writeMsg func(*pb.RPC), irpc *pb.RPC) {
|
||||
// When the legit host connects it will send us its subscriptions
|
||||
for _, sub := range irpc.GetSubscriptions() {
|
||||
sub := sub
|
||||
if sub.GetSubscribe() {
|
||||
// Reply by subcribing to the bitmask and grafting to the peer
|
||||
writeMsg(&pb.RPC{
|
||||
@ -204,10 +214,10 @@ func TestBlossomSubAttackSpamIHAVE(t *testing.T) {
|
||||
|
||||
// Send a bunch of IHAVEs
|
||||
for i := 0; i < 3*BlossomSubMaxIHaveLength; i++ {
|
||||
ihavelst := []string{"someid" + strconv.Itoa(i)}
|
||||
ihavelst := [][]byte{[]byte("someid" + strconv.Itoa(i))}
|
||||
ihave := []*pb.ControlIHave{{Bitmask: sub.Bitmask, MessageIDs: ihavelst}}
|
||||
orpc := rpcWithControl(nil, ihave, nil, nil, nil)
|
||||
writeMsg(&orpc.RPC)
|
||||
writeMsg(orpc.RPC)
|
||||
}
|
||||
|
||||
select {
|
||||
@ -234,10 +244,10 @@ func TestBlossomSubAttackSpamIHAVE(t *testing.T) {
|
||||
|
||||
// Send a bunch of IHAVEs
|
||||
for i := 0; i < 3*BlossomSubMaxIHaveLength; i++ {
|
||||
ihavelst := []string{"someid" + strconv.Itoa(i+100)}
|
||||
ihavelst := [][]byte{[]byte("someid" + strconv.Itoa(i+100))}
|
||||
ihave := []*pb.ControlIHave{{Bitmask: sub.Bitmask, MessageIDs: ihavelst}}
|
||||
orpc := rpcWithControl(nil, ihave, nil, nil, nil)
|
||||
writeMsg(&orpc.RPC)
|
||||
writeMsg(orpc.RPC)
|
||||
}
|
||||
|
||||
select {
|
||||
@ -292,7 +302,7 @@ func TestBlossomSubAttackGRAFTNonExistentBitmask(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
// Create legitimate and attacker hosts
|
||||
hosts := getNetHosts(t, ctx, 2)
|
||||
hosts := getDefaultHosts(t, 2)
|
||||
legit := hosts[0]
|
||||
attacker := hosts[1]
|
||||
|
||||
@ -303,7 +313,7 @@ func TestBlossomSubAttackGRAFTNonExistentBitmask(t *testing.T) {
|
||||
}
|
||||
|
||||
// Subscribe to mybitmask on the legit host
|
||||
mybitmask := []byte{0xff, 0x00, 0x00}
|
||||
mybitmask := []byte{0x20, 0x00, 0x00}
|
||||
_, err = ps.Subscribe(mybitmask)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -322,6 +332,7 @@ func TestBlossomSubAttackGRAFTNonExistentBitmask(t *testing.T) {
|
||||
newMockBS(ctx, t, attacker, func(writeMsg func(*pb.RPC), irpc *pb.RPC) {
|
||||
// When the legit host connects it will send us its subscriptions
|
||||
for _, sub := range irpc.GetSubscriptions() {
|
||||
sub := sub
|
||||
if sub.GetSubscribe() {
|
||||
// Reply by subcribing to the bitmask and grafting to the peer
|
||||
writeMsg(&pb.RPC{
|
||||
@ -330,7 +341,7 @@ func TestBlossomSubAttackGRAFTNonExistentBitmask(t *testing.T) {
|
||||
})
|
||||
|
||||
// Graft to the peer on a non-existent bitmask
|
||||
nonExistentBitmask := []byte{0xff, 0x00, 0x00, 0xff, 0xff, 0xff}
|
||||
nonExistentBitmask := []byte{0x20, 0x00, 0x00, 0x02, 0xff, 0xff}
|
||||
writeMsg(&pb.RPC{
|
||||
Control: &pb.ControlMessage{Graft: []*pb.ControlGraft{{Bitmask: nonExistentBitmask}}},
|
||||
})
|
||||
@ -376,7 +387,7 @@ func TestBlossomSubAttackGRAFTDuringBackoff(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
// Create legitimate and attacker hosts
|
||||
hosts := getNetHosts(t, ctx, 2)
|
||||
hosts := getDefaultHosts(t, 2)
|
||||
legit := hosts[0]
|
||||
attacker := hosts[1]
|
||||
|
||||
@ -400,7 +411,7 @@ func TestBlossomSubAttackGRAFTDuringBackoff(t *testing.T) {
|
||||
}
|
||||
|
||||
// Subscribe to mybitmask on the legit host
|
||||
mybitmask := []byte{0xff, 0x00, 0x00}
|
||||
mybitmask := []byte{0x20, 0x00, 0x00}
|
||||
_, err = ps.Subscribe(mybitmask)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -422,6 +433,7 @@ func TestBlossomSubAttackGRAFTDuringBackoff(t *testing.T) {
|
||||
newMockBS(ctx, t, attacker, func(writeMsg func(*pb.RPC), irpc *pb.RPC) {
|
||||
// When the legit host connects it will send us its subscriptions
|
||||
for _, sub := range irpc.GetSubscriptions() {
|
||||
sub := sub
|
||||
if sub.GetSubscribe() {
|
||||
// Reply by subcribing to the bitmask and grafting to the peer
|
||||
graft := []*pb.ControlGraft{{Bitmask: sub.Bitmask}}
|
||||
@ -617,11 +629,11 @@ func TestBlossomSubAttackInvalidMessageSpam(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
// Create legitimate and attacker hosts
|
||||
hosts := getNetHosts(t, ctx, 2)
|
||||
hosts := getDefaultHosts(t, 2)
|
||||
legit := hosts[0]
|
||||
attacker := hosts[1]
|
||||
|
||||
mybitmask := []byte{0xff, 0x00, 0x00}
|
||||
mybitmask := []byte{0x20, 0x00, 0x00}
|
||||
|
||||
// Create parameters with reasonable default values
|
||||
params := &PeerScoreParams{
|
||||
@ -664,6 +676,7 @@ func TestBlossomSubAttackInvalidMessageSpam(t *testing.T) {
|
||||
ps, err := NewBlossomSub(ctx, legit,
|
||||
WithEventTracer(tracer),
|
||||
WithPeerScore(params, thresholds),
|
||||
WithMessageSignaturePolicy(StrictSign),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -766,7 +779,7 @@ type MockBSOnRead func(writeMsg func(*pb.RPC), irpc *pb.RPC)
|
||||
|
||||
func newMockBS(ctx context.Context, t *testing.T, attacker host.Host, onReadMsg MockBSOnRead) {
|
||||
// Listen on the BlossomSub protocol
|
||||
const BlossomSubID = protocol.ID("/meshsub/1.0.0")
|
||||
const BlossomSubID = BlossomSubID_v2
|
||||
const maxMessageSize = 1024 * 1024
|
||||
attacker.SetStreamHandler(BlossomSubID, func(stream network.Stream) {
|
||||
// When an incoming stream is opened, set up an outgoing stream
|
||||
@ -776,13 +789,17 @@ func newMockBS(ctx context.Context, t *testing.T, attacker host.Host, onReadMsg
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r := protoio.NewDelimitedReader(stream, maxMessageSize)
|
||||
w := protoio.NewDelimitedWriter(ostream)
|
||||
r := msgio.NewVarintReaderSize(stream, maxMessageSize)
|
||||
w := msgio.NewVarintWriter(ostream)
|
||||
|
||||
var irpc pb.RPC
|
||||
|
||||
writeMsg := func(rpc *pb.RPC) {
|
||||
if err = w.WriteMsg(rpc); err != nil {
|
||||
out, err := proto.Marshal(rpc)
|
||||
if err != nil {
|
||||
t.Fatalf("error writing RPC: %s", err)
|
||||
}
|
||||
if err = w.WriteMsg(out); err != nil {
|
||||
t.Fatalf("error writing RPC: %s", err)
|
||||
}
|
||||
}
|
||||
@ -795,8 +812,21 @@ func newMockBS(ctx context.Context, t *testing.T, attacker host.Host, onReadMsg
|
||||
}
|
||||
|
||||
irpc.Reset()
|
||||
v, err := r.ReadMsg()
|
||||
|
||||
err := r.ReadMsg(&irpc)
|
||||
// Bail out when the test finishes
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = proto.Unmarshal(v, &irpc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Bail out when the test finishes
|
||||
if ctx.Err() != nil {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,6 +8,7 @@ import (
|
||||
|
||||
pool "github.com/libp2p/go-buffer-pool"
|
||||
"github.com/multiformats/go-varint"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
@ -18,7 +19,9 @@ import (
|
||||
|
||||
// get the initial RPC containing all of our subscriptions to send to new peers
|
||||
func (p *PubSub) getHelloPacket() *RPC {
|
||||
var rpc RPC
|
||||
var rpc = &RPC{
|
||||
RPC: new(pb.RPC),
|
||||
}
|
||||
|
||||
subscriptions := make(map[string]bool)
|
||||
|
||||
@ -37,7 +40,7 @@ func (p *PubSub) getHelloPacket() *RPC {
|
||||
}
|
||||
rpc.Subscriptions = append(rpc.Subscriptions, as)
|
||||
}
|
||||
return &rpc
|
||||
return rpc
|
||||
}
|
||||
|
||||
func (p *PubSub) handleNewStream(s network.Stream) {
|
||||
@ -52,14 +55,6 @@ func (p *PubSub) handleNewStream(s network.Stream) {
|
||||
p.inboundStreams[peer] = s
|
||||
p.inboundStreamsMx.Unlock()
|
||||
|
||||
defer func() {
|
||||
p.inboundStreamsMx.Lock()
|
||||
if p.inboundStreams[peer] == s {
|
||||
delete(p.inboundStreams, peer)
|
||||
}
|
||||
p.inboundStreamsMx.Unlock()
|
||||
}()
|
||||
|
||||
r := msgio.NewVarintReaderSize(s, p.maxMessageSize)
|
||||
for {
|
||||
msgbytes, err := r.ReadMsg()
|
||||
@ -74,18 +69,30 @@ func (p *PubSub) handleNewStream(s network.Stream) {
|
||||
s.Close()
|
||||
}
|
||||
|
||||
p.inboundStreamsMx.Lock()
|
||||
if p.inboundStreams[peer] == s {
|
||||
delete(p.inboundStreams, peer)
|
||||
}
|
||||
p.inboundStreamsMx.Unlock()
|
||||
return
|
||||
}
|
||||
if len(msgbytes) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
rpc := new(RPC)
|
||||
rpc := &RPC{
|
||||
RPC: new(pb.RPC),
|
||||
}
|
||||
err = rpc.Unmarshal(msgbytes)
|
||||
r.ReleaseMsg(msgbytes)
|
||||
if err != nil {
|
||||
s.Reset()
|
||||
log.Warnf("bogus rpc from %s: %s", s.Conn().RemotePeer(), err)
|
||||
p.inboundStreamsMx.Lock()
|
||||
if p.inboundStreams[peer] == s {
|
||||
delete(p.inboundStreams, peer)
|
||||
}
|
||||
p.inboundStreamsMx.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
@ -95,6 +102,11 @@ func (p *PubSub) handleNewStream(s network.Stream) {
|
||||
case <-p.ctx.Done():
|
||||
// Close is useless because the other side isn't reading.
|
||||
s.Reset()
|
||||
p.inboundStreamsMx.Lock()
|
||||
if p.inboundStreams[peer] == s {
|
||||
delete(p.inboundStreams, peer)
|
||||
}
|
||||
p.inboundStreamsMx.Unlock()
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -156,37 +168,38 @@ func (p *PubSub) handlePeerDead(s network.Stream) {
|
||||
}
|
||||
|
||||
func (p *PubSub) handleSendingMessages(ctx context.Context, s network.Stream, outgoing <-chan *RPC) {
|
||||
writeRpc := func(rpc *RPC) error {
|
||||
size := uint64(rpc.Size())
|
||||
|
||||
buf := pool.Get(varint.UvarintSize(size) + int(size))
|
||||
defer pool.Put(buf)
|
||||
|
||||
n := binary.PutUvarint(buf, size)
|
||||
_, err := rpc.MarshalTo(buf[n:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.Write(buf)
|
||||
return err
|
||||
}
|
||||
|
||||
defer s.Close()
|
||||
for {
|
||||
select {
|
||||
case rpc, ok := <-outgoing:
|
||||
if !ok {
|
||||
s.Close()
|
||||
return
|
||||
}
|
||||
|
||||
err := writeRpc(rpc)
|
||||
size := uint64(rpc.Size())
|
||||
|
||||
buf := pool.Get(varint.UvarintSize(size) + int(size))
|
||||
|
||||
n := binary.PutUvarint(buf, size)
|
||||
_, err := rpc.MarshalTo(buf[n:])
|
||||
if err != nil {
|
||||
s.Reset()
|
||||
log.Debugf("writing message to %s: %s", s.Conn().RemotePeer(), err)
|
||||
s.Close()
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.Write(buf)
|
||||
if err != nil {
|
||||
s.Reset()
|
||||
log.Debugf("writing message to %s: %s", s.Conn().RemotePeer(), err)
|
||||
s.Close()
|
||||
return
|
||||
}
|
||||
|
||||
pool.Put(buf)
|
||||
case <-ctx.Done():
|
||||
s.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -194,14 +207,14 @@ func (p *PubSub) handleSendingMessages(ctx context.Context, s network.Stream, ou
|
||||
|
||||
func rpcWithSubs(subs ...*pb.RPC_SubOpts) *RPC {
|
||||
return &RPC{
|
||||
RPC: pb.RPC{
|
||||
RPC: &pb.RPC{
|
||||
Subscriptions: subs,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func rpcWithMessages(msgs ...*pb.Message) *RPC {
|
||||
return &RPC{RPC: pb.RPC{Publish: msgs}}
|
||||
return &RPC{RPC: &pb.RPC{Publish: msgs}}
|
||||
}
|
||||
|
||||
func rpcWithControl(msgs []*pb.Message,
|
||||
@ -210,7 +223,7 @@ func rpcWithControl(msgs []*pb.Message,
|
||||
graft []*pb.ControlGraft,
|
||||
prune []*pb.ControlPrune) *RPC {
|
||||
return &RPC{
|
||||
RPC: pb.RPC{
|
||||
RPC: &pb.RPC{
|
||||
Publish: msgs,
|
||||
Control: &pb.ControlMessage{
|
||||
Ihave: ihave,
|
||||
@ -224,10 +237,7 @@ func rpcWithControl(msgs []*pb.Message,
|
||||
|
||||
func copyRPC(rpc *RPC) *RPC {
|
||||
res := new(RPC)
|
||||
*res = *rpc
|
||||
if rpc.Control != nil {
|
||||
res.Control = new(pb.ControlMessage)
|
||||
*res.Control = *rpc.Control
|
||||
}
|
||||
copiedRPC := (proto.Clone(rpc.RPC)).(*pb.RPC)
|
||||
res.RPC = copiedRPC
|
||||
return res
|
||||
}
|
||||
|
@ -120,7 +120,6 @@ func (d *discover) pollTimer() {
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(DiscoveryPollInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
@ -128,9 +127,11 @@ func (d *discover) pollTimer() {
|
||||
select {
|
||||
case d.p.eval <- d.requestDiscovery:
|
||||
case <-d.p.ctx.Done():
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
case <-d.p.ctx.Done():
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -197,7 +198,6 @@ func (d *discover) Advertise(bitmask []byte) {
|
||||
}
|
||||
|
||||
t := time.NewTimer(next)
|
||||
defer t.Stop()
|
||||
|
||||
for advertisingCtx.Err() == nil {
|
||||
select {
|
||||
@ -211,9 +211,11 @@ func (d *discover) Advertise(bitmask []byte) {
|
||||
}
|
||||
t.Reset(next)
|
||||
case <-advertisingCtx.Done():
|
||||
t.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Stop()
|
||||
}()
|
||||
}
|
||||
|
||||
@ -248,7 +250,6 @@ func (d *discover) Bootstrap(ctx context.Context, bitmask []byte, ready RouterRe
|
||||
if !t.Stop() {
|
||||
<-t.C
|
||||
}
|
||||
defer t.Stop()
|
||||
|
||||
for {
|
||||
// Check if ready for publishing
|
||||
@ -259,11 +260,14 @@ func (d *discover) Bootstrap(ctx context.Context, bitmask []byte, ready RouterRe
|
||||
bootstrapped <- done
|
||||
}:
|
||||
if <-bootstrapped {
|
||||
t.Stop()
|
||||
return true
|
||||
}
|
||||
case <-d.p.ctx.Done():
|
||||
t.Stop()
|
||||
return false
|
||||
case <-ctx.Done():
|
||||
t.Stop()
|
||||
return false
|
||||
}
|
||||
|
||||
@ -272,16 +276,20 @@ func (d *discover) Bootstrap(ctx context.Context, bitmask []byte, ready RouterRe
|
||||
select {
|
||||
case d.discoverQ <- disc:
|
||||
case <-d.p.ctx.Done():
|
||||
t.Stop()
|
||||
return false
|
||||
case <-ctx.Done():
|
||||
t.Stop()
|
||||
return false
|
||||
}
|
||||
|
||||
select {
|
||||
case <-disc.done:
|
||||
case <-d.p.ctx.Done():
|
||||
t.Stop()
|
||||
return false
|
||||
case <-ctx.Done():
|
||||
t.Stop()
|
||||
return false
|
||||
}
|
||||
|
||||
@ -289,8 +297,10 @@ func (d *discover) Bootstrap(ctx context.Context, bitmask []byte, ready RouterRe
|
||||
select {
|
||||
case <-t.C:
|
||||
case <-d.p.ctx.Done():
|
||||
t.Stop()
|
||||
return false
|
||||
case <-ctx.Done():
|
||||
t.Stop()
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -298,15 +308,16 @@ func (d *discover) Bootstrap(ctx context.Context, bitmask []byte, ready RouterRe
|
||||
|
||||
func (d *discover) handleDiscovery(ctx context.Context, bitmask []byte, opts []discovery.Option) {
|
||||
discoverCtx, cancel := context.WithTimeout(ctx, time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
peerCh, err := d.discovery.FindPeers(discoverCtx, string(bitmask), opts...)
|
||||
if err != nil {
|
||||
log.Debugf("error finding peers for bitmask %s: %v", bitmask, err)
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
|
||||
d.connector.Connect(ctx, peerCh)
|
||||
cancel()
|
||||
}
|
||||
|
||||
type discoverReq struct {
|
||||
@ -321,11 +332,11 @@ type pubSubDiscovery struct {
|
||||
}
|
||||
|
||||
func (d *pubSubDiscovery) Advertise(ctx context.Context, ns string, opts ...discovery.Option) (time.Duration, error) {
|
||||
return d.Discovery.Advertise(ctx, "floodsub:"+ns, append(opts, d.opts...)...)
|
||||
return d.Discovery.Advertise(ctx, "blossomsub:"+ns, append(opts, d.opts...)...)
|
||||
}
|
||||
|
||||
func (d *pubSubDiscovery) FindPeers(ctx context.Context, ns string, opts ...discovery.Option) (<-chan peer.AddrInfo, error) {
|
||||
return d.Discovery.FindPeers(ctx, "floodsub:"+ns, append(opts, d.opts...)...)
|
||||
return d.Discovery.FindPeers(ctx, "blossomsub:"+ns, append(opts, d.opts...)...)
|
||||
}
|
||||
|
||||
// WithDiscoveryOpts passes libp2p Discovery options into the PubSub discovery subsystem
|
||||
|
@ -123,101 +123,6 @@ func (d *dummyDiscovery) FindPeers(ctx context.Context, ns string, opts ...disco
|
||||
return retCh, nil
|
||||
}
|
||||
|
||||
func TestSimpleDiscovery(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// Setup Discovery server and pubsub clients
|
||||
const numHosts = 20
|
||||
bitmask := []byte{0xf0, 0x0b, 0xa1, 0x20}
|
||||
|
||||
server := newDiscoveryServer()
|
||||
discOpts := []discovery.Option{discovery.Limit(numHosts), discovery.TTL(1 * time.Minute)}
|
||||
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
psubs := make([]*PubSub, numHosts)
|
||||
bitmaskHandlers := make([]*Bitmask, numHosts)
|
||||
|
||||
for i, h := range hosts {
|
||||
disc := &mockDiscoveryClient{h, server}
|
||||
ps := getPubsub(ctx, h, WithDiscovery(disc, WithDiscoveryOpts(discOpts...)))
|
||||
psubs[i] = ps
|
||||
bitmaskHandlers[i], _ = ps.Join(bitmask)
|
||||
}
|
||||
|
||||
// Subscribe with all but one pubsub instance
|
||||
msgs := make([]*Subscription, numHosts)
|
||||
for i, th := range bitmaskHandlers[1:] {
|
||||
subch, err := th.Subscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
msgs[i+1] = subch
|
||||
}
|
||||
|
||||
// Wait for the advertisements to go through then check that they did
|
||||
for {
|
||||
server.mx.Lock()
|
||||
numPeers := len(server.db["floodsub:foobar"])
|
||||
server.mx.Unlock()
|
||||
if numPeers == numHosts-1 {
|
||||
break
|
||||
} else {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
}
|
||||
|
||||
for i, h := range hosts[1:] {
|
||||
if !server.hasPeerRecord("floodsub:"+string(bitmask), h.ID()) {
|
||||
t.Fatalf("Server did not register host %d with ID: %s", i+1, h.ID().Pretty())
|
||||
}
|
||||
}
|
||||
|
||||
// Try subscribing followed by publishing a single message
|
||||
subch, err := bitmaskHandlers[0].Subscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
msgs[0] = subch
|
||||
|
||||
msg := []byte("first message")
|
||||
if err := bitmaskHandlers[0].Publish(ctx, msg, WithReadiness(MinBitmaskSize(numHosts-1))); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, sub := range msgs {
|
||||
got, err := sub.Next(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(sub.err)
|
||||
}
|
||||
if !bytes.Equal(msg, got.Data) {
|
||||
t.Fatal("got wrong message!")
|
||||
}
|
||||
}
|
||||
|
||||
// Try random peers sending messages and make sure they are received
|
||||
for i := 0; i < 100; i++ {
|
||||
msg := []byte(fmt.Sprintf("%d the flooooooood %d", i, i))
|
||||
|
||||
owner := rand.Intn(len(psubs))
|
||||
|
||||
if err := bitmaskHandlers[owner].Publish(ctx, msg, WithReadiness(MinBitmaskSize(1))); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, sub := range msgs {
|
||||
got, err := sub.Next(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(sub.err)
|
||||
}
|
||||
if !bytes.Equal(msg, got.Data) {
|
||||
t.Fatal("got wrong message!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlossomSubDiscoveryAfterBootstrap(t *testing.T) {
|
||||
t.Skip("flaky test disabled")
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
@ -226,15 +131,15 @@ func TestBlossomSubDiscoveryAfterBootstrap(t *testing.T) {
|
||||
// Setup Discovery server and pubsub clients
|
||||
partitionSize := BlossomSubDlo - 1
|
||||
numHosts := partitionSize * 2
|
||||
const ttl = 1 * time.Minute
|
||||
const ttl = 10 * time.Minute
|
||||
|
||||
bitmask := []byte{0xf0, 0x0b, 0xa1, 0x20}
|
||||
bitmask := []byte{0x00, 0x01}
|
||||
|
||||
server1, server2 := newDiscoveryServer(), newDiscoveryServer()
|
||||
discOpts := []discovery.Option{discovery.Limit(numHosts), discovery.TTL(ttl)}
|
||||
|
||||
// Put the pubsub clients into two partitions
|
||||
hosts := getNetHosts(t, ctx, numHosts)
|
||||
hosts := getDefaultHosts(t, numHosts)
|
||||
psubs := make([]*PubSub, numHosts)
|
||||
bitmaskHandlers := make([]*Bitmask, numHosts)
|
||||
|
||||
@ -246,7 +151,8 @@ func TestBlossomSubDiscoveryAfterBootstrap(t *testing.T) {
|
||||
disc := &mockDiscoveryClient{h, s}
|
||||
ps := getBlossomSub(ctx, h, WithDiscovery(disc, WithDiscoveryOpts(discOpts...)))
|
||||
psubs[i] = ps
|
||||
bitmaskHandlers[i], _ = ps.Join(bitmask)
|
||||
handler, _ := ps.Join(bitmask)
|
||||
bitmaskHandlers[i] = handler[0]
|
||||
}
|
||||
|
||||
msgs := make([]*Subscription, numHosts)
|
||||
@ -265,7 +171,7 @@ func TestBlossomSubDiscoveryAfterBootstrap(t *testing.T) {
|
||||
}
|
||||
|
||||
for i := 0; i < partitionSize; i++ {
|
||||
if _, err := server1.Advertise("floodsub:"+string(bitmask), *host.InfoFromHost(hosts[i+partitionSize]), ttl); err != nil {
|
||||
if _, err := server1.Advertise("blossomsub:"+string(bitmask), *host.InfoFromHost(hosts[i+partitionSize]), ttl); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@ -276,7 +182,7 @@ func TestBlossomSubDiscoveryAfterBootstrap(t *testing.T) {
|
||||
|
||||
owner := rand.Intn(numHosts)
|
||||
|
||||
if err := bitmaskHandlers[owner].Publish(ctx, msg, WithReadiness(MinBitmaskSize(numHosts-1))); err != nil {
|
||||
if err := bitmaskHandlers[owner].Publish(ctx, bitmaskHandlers[owner].bitmask, msg, WithReadiness(MinBitmaskSize(numHosts-1))); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -292,7 +198,6 @@ func TestBlossomSubDiscoveryAfterBootstrap(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
//lint:ignore U1000 used only by skipped tests at present
|
||||
func waitUntilBlossomSubMeshCount(ps *PubSub, bitmask []byte, count int) {
|
||||
done := false
|
||||
doneCh := make(chan bool, 1)
|
||||
|
@ -1,112 +0,0 @@
|
||||
package blossomsub
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
)
|
||||
|
||||
const (
|
||||
FloodSubID = protocol.ID("/floodsub/1.0.0")
|
||||
FloodSubBitmaskSearchSize = 5
|
||||
)
|
||||
|
||||
// NewFloodsubWithProtocols returns a new floodsub-enabled PubSub objecting using the protocols specified in ps.
|
||||
func NewFloodsubWithProtocols(ctx context.Context, h host.Host, ps []protocol.ID, opts ...Option) (*PubSub, error) {
|
||||
rt := &FloodSubRouter{
|
||||
protocols: ps,
|
||||
}
|
||||
return NewPubSub(ctx, h, rt, opts...)
|
||||
}
|
||||
|
||||
// NewFloodSub returns a new PubSub object using the FloodSubRouter.
|
||||
func NewFloodSub(ctx context.Context, h host.Host, opts ...Option) (*PubSub, error) {
|
||||
return NewFloodsubWithProtocols(ctx, h, []protocol.ID{FloodSubID}, opts...)
|
||||
}
|
||||
|
||||
type FloodSubRouter struct {
|
||||
p *PubSub
|
||||
protocols []protocol.ID
|
||||
tracer *pubsubTracer
|
||||
}
|
||||
|
||||
func (fs *FloodSubRouter) Protocols() []protocol.ID {
|
||||
return fs.protocols
|
||||
}
|
||||
|
||||
func (fs *FloodSubRouter) Attach(p *PubSub) {
|
||||
fs.p = p
|
||||
fs.tracer = p.tracer
|
||||
}
|
||||
|
||||
func (fs *FloodSubRouter) PeerScore(p peer.ID) float64 {
|
||||
return fs.p.PeerScore(p)
|
||||
}
|
||||
|
||||
func (fs *FloodSubRouter) AddPeer(p peer.ID, proto protocol.ID) {
|
||||
fs.tracer.AddPeer(p, proto)
|
||||
}
|
||||
|
||||
func (fs *FloodSubRouter) RemovePeer(p peer.ID) {
|
||||
fs.tracer.RemovePeer(p)
|
||||
}
|
||||
|
||||
func (fs *FloodSubRouter) EnoughPeers(bitmask []byte, suggested int) bool {
|
||||
// check all peers in the bitmask
|
||||
tmap, ok := fs.p.bitmasks[string(bitmask)]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if suggested == 0 {
|
||||
suggested = FloodSubBitmaskSearchSize
|
||||
}
|
||||
|
||||
if len(tmap) >= suggested {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (fs *FloodSubRouter) AcceptFrom(peer.ID) AcceptStatus {
|
||||
return AcceptAll
|
||||
}
|
||||
|
||||
func (fs *FloodSubRouter) HandleRPC(rpc *RPC) {}
|
||||
|
||||
func (fs *FloodSubRouter) Publish(msg *Message) {
|
||||
from := msg.ReceivedFrom
|
||||
bitmask := msg.GetBitmask()
|
||||
|
||||
out := rpcWithMessages(msg.Message)
|
||||
for pid := range fs.p.bitmasks[string(bitmask)] {
|
||||
if pid == from || pid == peer.ID(msg.GetFrom()) {
|
||||
continue
|
||||
}
|
||||
|
||||
mch, ok := fs.p.peers[pid]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
select {
|
||||
case mch <- out:
|
||||
fs.tracer.SendRPC(out, pid)
|
||||
default:
|
||||
log.Infof("dropping message to peer %s: queue full", pid)
|
||||
fs.tracer.DropRPC(out, pid)
|
||||
// Drop it. The peer is too slow.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *FloodSubRouter) Join(bitmask []byte) {
|
||||
fs.tracer.Join(bitmask)
|
||||
}
|
||||
|
||||
func (fs *FloodSubRouter) Leave(bitmask []byte) {
|
||||
fs.tracer.Leave(bitmask)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,84 +1,122 @@
|
||||
module source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub
|
||||
|
||||
go 1.18
|
||||
go 1.21
|
||||
|
||||
toolchain go1.22.4
|
||||
|
||||
replace github.com/multiformats/go-multiaddr => ../go-multiaddr
|
||||
|
||||
replace github.com/multiformats/go-multiaddr-dns => ../go-multiaddr-dns
|
||||
|
||||
replace github.com/libp2p/go-libp2p => ../go-libp2p
|
||||
|
||||
replace github.com/libp2p/go-libp2p-gostream => ../go-libp2p-gostream
|
||||
|
||||
require (
|
||||
github.com/benbjohnson/clock v1.3.0
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/benbjohnson/clock v1.3.5
|
||||
github.com/ipfs/go-log/v2 v2.5.1
|
||||
github.com/libp2p/go-buffer-pool v0.1.0
|
||||
github.com/libp2p/go-libp2p v0.25.0
|
||||
github.com/libp2p/go-libp2p v0.35.4
|
||||
github.com/libp2p/go-libp2p-testing v0.12.0
|
||||
github.com/libp2p/go-msgio v0.3.0
|
||||
github.com/multiformats/go-multiaddr v0.8.0
|
||||
github.com/multiformats/go-multiaddr v0.12.4
|
||||
github.com/multiformats/go-varint v0.0.7
|
||||
google.golang.org/protobuf v1.28.1
|
||||
google.golang.org/protobuf v1.34.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/containerd/cgroups v1.0.4 // indirect
|
||||
github.com/cloudflare/circl v1.3.9 // indirect
|
||||
github.com/containerd/cgroups v1.1.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/elastic/gosigar v0.14.2 // indirect
|
||||
github.com/flynn/noise v1.1.0 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/google/pprof v0.0.0-20221203041831-ce31453925ec // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect
|
||||
github.com/ipfs/go-cid v0.3.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect
|
||||
github.com/google/uuid v1.4.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/huin/goupnp v1.3.0 // indirect
|
||||
github.com/ipfs/go-cid v0.4.1 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
|
||||
github.com/klauspost/compress v1.15.15 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.1 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/klauspost/compress v1.17.8 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/koron/go-ssdp v0.0.4 // indirect
|
||||
github.com/libp2p/go-flow-metrics v0.1.0 // indirect
|
||||
github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect
|
||||
github.com/libp2p/go-nat v0.2.0 // indirect
|
||||
github.com/libp2p/go-netroute v0.2.1 // indirect
|
||||
github.com/libp2p/go-reuseport v0.2.0 // indirect
|
||||
github.com/libp2p/go-yamux/v4 v4.0.0 // indirect
|
||||
github.com/libp2p/go-reuseport v0.4.0 // indirect
|
||||
github.com/libp2p/go-yamux/v4 v4.0.1 // indirect
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/miekg/dns v1.1.50 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/miekg/dns v1.1.58 // indirect
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/minio/sha256-simd v1.0.1 // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.1.0 // indirect
|
||||
github.com/multiformats/go-base36 v0.2.0 // indirect
|
||||
github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
|
||||
github.com/multiformats/go-multibase v0.1.1 // indirect
|
||||
github.com/multiformats/go-multicodec v0.7.0 // indirect
|
||||
github.com/multiformats/go-multihash v0.2.1 // indirect
|
||||
github.com/multiformats/go-multistream v0.4.0 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.5.1 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.0.2 // indirect
|
||||
github.com/multiformats/go-multibase v0.2.0 // indirect
|
||||
github.com/multiformats/go-multicodec v0.9.0 // indirect
|
||||
github.com/multiformats/go-multihash v0.2.3 // indirect
|
||||
github.com/multiformats/go-multistream v0.5.0 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.15.0 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.2.0 // indirect
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/pion/datachannel v1.5.6 // indirect
|
||||
github.com/pion/dtls/v2 v2.2.11 // indirect
|
||||
github.com/pion/ice/v2 v2.3.25 // indirect
|
||||
github.com/pion/interceptor v0.1.29 // indirect
|
||||
github.com/pion/logging v0.2.2 // indirect
|
||||
github.com/pion/mdns v0.0.12 // indirect
|
||||
github.com/pion/randutil v0.1.0 // indirect
|
||||
github.com/pion/rtcp v1.2.14 // indirect
|
||||
github.com/pion/rtp v1.8.6 // indirect
|
||||
github.com/pion/sctp v1.8.16 // indirect
|
||||
github.com/pion/sdp/v3 v3.0.9 // indirect
|
||||
github.com/pion/srtp/v2 v2.0.18 // indirect
|
||||
github.com/pion/stun v0.6.1 // indirect
|
||||
github.com/pion/transport/v2 v2.2.5 // indirect
|
||||
github.com/pion/turn/v2 v2.1.6 // indirect
|
||||
github.com/pion/webrtc/v3 v3.2.40 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.14.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.39.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/quic-go/quic-go v0.37.5 // indirect
|
||||
github.com/prometheus/client_golang v1.19.1 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.48.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/quic-go v0.44.0 // indirect
|
||||
github.com/quic-go/webtransport-go v0.8.0 // indirect
|
||||
github.com/raulk/go-watchdog v1.3.0 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/stretchr/testify v1.8.1 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
golang.org/x/crypto v0.4.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230206171751-46f607a40771 // indirect
|
||||
golang.org/x/mod v0.9.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/tools v0.7.0 // indirect
|
||||
github.com/stretchr/testify v1.9.0 // indirect
|
||||
go.uber.org/dig v1.17.1 // indirect
|
||||
go.uber.org/fx v1.22.1 // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
golang.org/x/tools v0.21.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/blake3 v1.1.7 // indirect
|
||||
lukechampine.com/blake3 v1.2.1 // indirect
|
||||
)
|
||||
|
@ -10,8 +10,9 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
|
||||
github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
@ -21,24 +22,26 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE=
|
||||
github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
||||
github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
|
||||
github.com/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA=
|
||||
github.com/containerd/cgroups v1.0.4/go.mod h1:nLNQtsF7Sl2HxNebu77i1R0oDlhiTG+kO4JTrUzo6IA=
|
||||
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
|
||||
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
|
||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU=
|
||||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
@ -47,16 +50,18 @@ github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0
|
||||
github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4=
|
||||
github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ=
|
||||
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
|
||||
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
|
||||
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
|
||||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
@ -69,38 +74,45 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20221203041831-ce31453925ec h1:fR20TYVVwhK4O7r7y+McjRYyaTH6/vjwJOajE+XhlzM=
|
||||
github.com/google/pprof v0.0.0-20221203041831-ce31453925ec/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo=
|
||||
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.1 h1:5pv5N1lT1fjLg2VQ5KWc7kmucp2x/kvFOnxuVTqZ6x4=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.1/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc=
|
||||
github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
||||
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
||||
github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
|
||||
github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=
|
||||
github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk=
|
||||
github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY=
|
||||
github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk=
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
@ -109,13 +121,18 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
|
||||
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
|
||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.1 h1:U33DW0aiEj633gHYw3LoDNfkDiYnE5Q8M/TKJn2f2jI=
|
||||
github.com/klauspost/cpuid/v2 v2.2.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0=
|
||||
github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
@ -127,32 +144,32 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6
|
||||
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 v0.25.0 h1:ND6Hc6ZYCzC8S++C4mOD7LdPnLXRkNbr12/8FXgUfIo=
|
||||
github.com/libp2p/go-libp2p v0.25.0/go.mod h1:vXHmFpcfl+xIGN4qW58Bw3a0/SKGAesr5/T4IuJHE3o=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
|
||||
github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA=
|
||||
github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg=
|
||||
github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0=
|
||||
github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM=
|
||||
github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk=
|
||||
github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk=
|
||||
github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU=
|
||||
github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ=
|
||||
github.com/libp2p/go-reuseport v0.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560=
|
||||
github.com/libp2p/go-reuseport v0.2.0/go.mod h1:bvVho6eLMm6Bz5hmU0LYN3ixd3nPPvtIlaURZZgOY4k=
|
||||
github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ=
|
||||
github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4=
|
||||
github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s=
|
||||
github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU=
|
||||
github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ=
|
||||
github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
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/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
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.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
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=
|
||||
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms=
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc=
|
||||
@ -161,77 +178,122 @@ github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdn
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
|
||||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
|
||||
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
|
||||
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
|
||||
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
|
||||
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
|
||||
github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE=
|
||||
github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=
|
||||
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 v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
|
||||
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
|
||||
github.com/multiformats/go-multiaddr v0.8.0 h1:aqjksEcqK+iD/Foe1RRFsGZh8+XFiGo7FgUCZlpv3LU=
|
||||
github.com/multiformats/go-multiaddr v0.8.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs=
|
||||
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.1.1 h1:3ASCDsuLX8+j4kx58qnJ4YFq/JWTJpCyDW27ztsVTOI=
|
||||
github.com/multiformats/go-multibase v0.1.1/go.mod h1:ZEjHE+IsUrgp5mhlEAYjMtZwK1k4haNkcaPg9aoe1a8=
|
||||
github.com/multiformats/go-multicodec v0.7.0 h1:rTUjGOwjlhGHbEMbPoSUJowG1spZTVsITRANCjKTUAQ=
|
||||
github.com/multiformats/go-multicodec v0.7.0/go.mod h1:GUC8upxSBE4oG+q3kWZRw/+6yC1BqO550bjhWsJbZlw=
|
||||
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
|
||||
github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108=
|
||||
github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc=
|
||||
github.com/multiformats/go-multistream v0.4.0 h1:5i4JbawClkbuaX+mIVXiHQYVPxUW+zjv6w7jtSRukxc=
|
||||
github.com/multiformats/go-multistream v0.4.0/go.mod h1:BS6ZSYcA4NwYEaIMeCtpJydp2Dc+fNRA6uJMSu/m8+4=
|
||||
github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
|
||||
github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
|
||||
github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
|
||||
github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg=
|
||||
github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k=
|
||||
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
|
||||
github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U=
|
||||
github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=
|
||||
github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE=
|
||||
github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA=
|
||||
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||
github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
|
||||
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/onsi/ginkgo/v2 v2.5.1 h1:auzK7OI497k6x4OvWq+TKAcpcSAlod0doAH72oIN0Jw=
|
||||
github.com/onsi/ginkgo/v2 v2.5.1/go.mod h1:63DOGlLAH8+REH8jUGdL3YpCpu7JODesutUjdENfUAc=
|
||||
github.com/onsi/gomega v1.24.0 h1:+0glovB9Jd6z3VR+ScSwQqXVTIfJcGA9UBM8yzQxhqg=
|
||||
github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0=
|
||||
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
|
||||
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
|
||||
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
|
||||
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
|
||||
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
|
||||
github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg=
|
||||
github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4=
|
||||
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
|
||||
github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks=
|
||||
github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE=
|
||||
github.com/pion/ice/v2 v2.3.25 h1:M5rJA07dqhi3nobJIg+uPtcVjFECTrhcR3n0ns8kDZs=
|
||||
github.com/pion/ice/v2 v2.3.25/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw=
|
||||
github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M=
|
||||
github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4=
|
||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
||||
github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8=
|
||||
github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk=
|
||||
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
||||
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||
github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
|
||||
github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE=
|
||||
github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
|
||||
github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
|
||||
github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw=
|
||||
github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
|
||||
github.com/pion/sctp v1.8.13/go.mod h1:YKSgO/bO/6aOMP9LCie1DuD7m+GamiK2yIiPM6vH+GA=
|
||||
github.com/pion/sctp v1.8.16 h1:PKrMs+o9EMLRvFfXq59WFsC+V8mN1wnKzqrv+3D/gYY=
|
||||
github.com/pion/sctp v1.8.16/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE=
|
||||
github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY=
|
||||
github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M=
|
||||
github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo=
|
||||
github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA=
|
||||
github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4=
|
||||
github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8=
|
||||
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
|
||||
github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc=
|
||||
github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
|
||||
github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
|
||||
github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc=
|
||||
github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
|
||||
github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0=
|
||||
github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4=
|
||||
github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0=
|
||||
github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY=
|
||||
github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc=
|
||||
github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY=
|
||||
github.com/pion/webrtc/v3 v3.2.40 h1:Wtfi6AZMQg+624cvCXUuSmrKWepSB7zfgYDOYqsSOVU=
|
||||
github.com/pion/webrtc/v3 v3.2.40/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
|
||||
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI=
|
||||
github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y=
|
||||
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U=
|
||||
github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc=
|
||||
github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4nttk=
|
||||
github.com/quic-go/qtls-go1-19 v0.2.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
|
||||
github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI=
|
||||
github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
||||
github.com/quic-go/quic-go v0.32.0 h1:lY02md31s1JgPiiyfqJijpu/UX/Iun304FI3yUqX7tA=
|
||||
github.com/quic-go/quic-go v0.32.0/go.mod h1:/fCsKANhQIeD5l76c2JFU+07gVE3KaA0FP+0zMWwfwo=
|
||||
github.com/quic-go/webtransport-go v0.5.1 h1:1eVb7WDWCRoaeTtFHpFBJ6WDN1bSrPrRoW6tZgSw0Ow=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0=
|
||||
github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek=
|
||||
github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg=
|
||||
github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM=
|
||||
github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk=
|
||||
github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
@ -266,15 +328,18 @@ github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
@ -282,18 +347,24 @@ github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMI
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc=
|
||||
go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
|
||||
go.uber.org/fx v1.22.1 h1:nvvln7mwyT5s1q201YE29V/BFrGor6vMiDNpU/78Mys=
|
||||
go.uber.org/fx v1.22.1/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48=
|
||||
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
|
||||
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
@ -303,11 +374,22 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
|
||||
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg=
|
||||
golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/exp v0.0.0-20230725012225-302865e7556b/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
@ -317,8 +399,12 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -335,9 +421,19 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@ -351,7 +447,10 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -368,19 +467,52 @@ golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
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=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@ -392,11 +524,12 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
|
||||
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@ -417,27 +550,28 @@ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmE
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
|
||||
lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
|
||||
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
|
||||
lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
|
||||
lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
|
||||
lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
|
||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
|
@ -45,7 +45,7 @@ func (gt *gossipTracer) Start(bs *BlossomSubRouter) {
|
||||
}
|
||||
|
||||
// track a promise to deliver a message from a list of msgIDs we are requesting
|
||||
func (gt *gossipTracer) AddPromise(p peer.ID, msgIDs []string) {
|
||||
func (gt *gossipTracer) AddPromise(p peer.ID, msgIDs [][]byte) {
|
||||
if gt == nil {
|
||||
return
|
||||
}
|
||||
@ -54,12 +54,11 @@ func (gt *gossipTracer) AddPromise(p peer.ID, msgIDs []string) {
|
||||
mid := msgIDs[idx]
|
||||
|
||||
gt.Lock()
|
||||
defer gt.Unlock()
|
||||
|
||||
promises, ok := gt.promises[mid]
|
||||
promises, ok := gt.promises[string(mid)]
|
||||
if !ok {
|
||||
promises = make(map[peer.ID]time.Time)
|
||||
gt.promises[mid] = promises
|
||||
gt.promises[string(mid)] = promises
|
||||
}
|
||||
|
||||
_, ok = promises[p]
|
||||
@ -70,8 +69,10 @@ func (gt *gossipTracer) AddPromise(p peer.ID, msgIDs []string) {
|
||||
peerPromises = make(map[string]struct{})
|
||||
gt.peerPromises[p] = peerPromises
|
||||
}
|
||||
peerPromises[mid] = struct{}{}
|
||||
peerPromises[string(mid)] = struct{}{}
|
||||
}
|
||||
|
||||
gt.Unlock()
|
||||
}
|
||||
|
||||
// returns the number of broken promises for each peer who didn't follow up
|
||||
@ -82,7 +83,6 @@ func (gt *gossipTracer) GetBrokenPromises() map[peer.ID]int {
|
||||
}
|
||||
|
||||
gt.Lock()
|
||||
defer gt.Unlock()
|
||||
|
||||
var res map[peer.ID]int
|
||||
now := time.Now()
|
||||
@ -111,6 +111,7 @@ func (gt *gossipTracer) GetBrokenPromises() map[peer.ID]int {
|
||||
}
|
||||
}
|
||||
|
||||
gt.Unlock()
|
||||
return res
|
||||
}
|
||||
|
||||
@ -120,24 +121,26 @@ func (gt *gossipTracer) fulfillPromise(msg *Message) {
|
||||
mid := gt.idGen.ID(msg)
|
||||
|
||||
gt.Lock()
|
||||
defer gt.Unlock()
|
||||
|
||||
promises, ok := gt.promises[mid]
|
||||
promises, ok := gt.promises[string(mid)]
|
||||
if !ok {
|
||||
gt.Unlock()
|
||||
return
|
||||
}
|
||||
delete(gt.promises, mid)
|
||||
delete(gt.promises, string(mid))
|
||||
|
||||
// delete the promise for all peers that promised it, as they have no way to fulfill it.
|
||||
for p := range promises {
|
||||
peerPromises, ok := gt.peerPromises[p]
|
||||
if ok {
|
||||
delete(peerPromises, mid)
|
||||
delete(peerPromises, string(mid))
|
||||
if len(peerPromises) == 0 {
|
||||
delete(gt.peerPromises, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gt.Unlock()
|
||||
}
|
||||
|
||||
func (gt *gossipTracer) DeliverMessage(msg *Message) {
|
||||
@ -181,10 +184,10 @@ func (gt *gossipTracer) UndeliverableMessage(msg *Message) {}
|
||||
|
||||
func (gt *gossipTracer) ThrottlePeer(p peer.ID) {
|
||||
gt.Lock()
|
||||
defer gt.Unlock()
|
||||
|
||||
peerPromises, ok := gt.peerPromises[p]
|
||||
if !ok {
|
||||
gt.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
@ -197,4 +200,5 @@ func (gt *gossipTracer) ThrottlePeer(p peer.ID) {
|
||||
}
|
||||
|
||||
delete(gt.peerPromises, p)
|
||||
gt.Unlock()
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ func TestBrokenPromises(t *testing.T) {
|
||||
peerB := peer.ID("B")
|
||||
peerC := peer.ID("C")
|
||||
|
||||
var mids []string
|
||||
var mids [][]byte
|
||||
for i := 0; i < 100; i++ {
|
||||
m := makeTestMessage(i)
|
||||
m.From = []byte(peerA)
|
||||
@ -72,7 +72,7 @@ func TestNoBrokenPromises(t *testing.T) {
|
||||
peerB := peer.ID("B")
|
||||
|
||||
var msgs []*pb.Message
|
||||
var mids []string
|
||||
var mids [][]byte
|
||||
for i := 0; i < 100; i++ {
|
||||
m := makeTestMessage(i)
|
||||
m.From = []byte(peerA)
|
||||
|
@ -30,7 +30,7 @@ func NewMessageCache(gossip, history int) *MessageCache {
|
||||
peertx: make(map[string]map[peer.ID]int),
|
||||
history: make([][]CacheEntry, history),
|
||||
gossip: gossip,
|
||||
msgID: func(msg *Message) string {
|
||||
msgID: func(msg *Message) []byte {
|
||||
return DefaultMsgIdFn(msg.Message)
|
||||
},
|
||||
}
|
||||
@ -41,47 +41,47 @@ type MessageCache struct {
|
||||
peertx map[string]map[peer.ID]int
|
||||
history [][]CacheEntry
|
||||
gossip int
|
||||
msgID func(*Message) string
|
||||
msgID func(*Message) []byte
|
||||
}
|
||||
|
||||
func (mc *MessageCache) SetMsgIdFn(msgID func(*Message) string) {
|
||||
func (mc *MessageCache) SetMsgIdFn(msgID func(*Message) []byte) {
|
||||
mc.msgID = msgID
|
||||
}
|
||||
|
||||
type CacheEntry struct {
|
||||
mid string
|
||||
mid []byte
|
||||
bitmask []byte
|
||||
}
|
||||
|
||||
func (mc *MessageCache) Put(msg *Message) {
|
||||
mid := mc.msgID(msg)
|
||||
mc.msgs[mid] = msg
|
||||
mc.msgs[string(mid)] = msg
|
||||
mc.history[0] = append(mc.history[0], CacheEntry{mid: mid, bitmask: msg.GetBitmask()})
|
||||
}
|
||||
|
||||
func (mc *MessageCache) Get(mid string) (*Message, bool) {
|
||||
m, ok := mc.msgs[mid]
|
||||
func (mc *MessageCache) Get(mid []byte) (*Message, bool) {
|
||||
m, ok := mc.msgs[string(mid)]
|
||||
return m, ok
|
||||
}
|
||||
|
||||
func (mc *MessageCache) GetForPeer(mid string, p peer.ID) (*Message, int, bool) {
|
||||
m, ok := mc.msgs[mid]
|
||||
func (mc *MessageCache) GetForPeer(mid []byte, p peer.ID) (*Message, int, bool) {
|
||||
m, ok := mc.msgs[string(mid)]
|
||||
if !ok {
|
||||
return nil, 0, false
|
||||
}
|
||||
|
||||
tx, ok := mc.peertx[mid]
|
||||
tx, ok := mc.peertx[string(mid)]
|
||||
if !ok {
|
||||
tx = make(map[peer.ID]int)
|
||||
mc.peertx[mid] = tx
|
||||
mc.peertx[string(mid)] = tx
|
||||
}
|
||||
tx[p]++
|
||||
|
||||
return m, tx[p], true
|
||||
}
|
||||
|
||||
func (mc *MessageCache) GetGossipIDs(bitmask []byte) []string {
|
||||
var mids []string
|
||||
func (mc *MessageCache) GetGossipIDs(bitmask []byte) [][]byte {
|
||||
var mids [][]byte
|
||||
for _, entries := range mc.history[:mc.gossip] {
|
||||
for _, entry := range entries {
|
||||
if bytes.Equal(entry.bitmask, bitmask) {
|
||||
@ -95,8 +95,8 @@ func (mc *MessageCache) GetGossipIDs(bitmask []byte) []string {
|
||||
func (mc *MessageCache) Shift() {
|
||||
last := mc.history[len(mc.history)-1]
|
||||
for _, entry := range last {
|
||||
delete(mc.msgs, entry.mid)
|
||||
delete(mc.peertx, entry.mid)
|
||||
delete(mc.msgs, string(entry.mid))
|
||||
delete(mc.peertx, string(entry.mid))
|
||||
}
|
||||
for i := len(mc.history) - 2; i >= 0; i-- {
|
||||
mc.history[i+1] = mc.history[i]
|
||||
|
@ -1,6 +1,7 @@
|
||||
package blossomsub
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"testing"
|
||||
@ -33,14 +34,14 @@ func TestMessageCache(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
gids := mcache.GetGossipIDs([]byte{0x7e, 0x57})
|
||||
gids := mcache.GetGossipIDs([]byte{0x01, 0x00})
|
||||
if len(gids) != 10 {
|
||||
t.Fatalf("Expected 10 gossip IDs; got %d", len(gids))
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
mid := msgID(msgs[i])
|
||||
if mid != gids[i] {
|
||||
if !bytes.Equal(mid, gids[i]) {
|
||||
t.Fatalf("GossipID mismatch for message %d", i)
|
||||
}
|
||||
}
|
||||
@ -62,21 +63,21 @@ func TestMessageCache(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
gids = mcache.GetGossipIDs([]byte{0x7e, 0x57})
|
||||
gids = mcache.GetGossipIDs([]byte{0x01, 0x00})
|
||||
if len(gids) != 20 {
|
||||
t.Fatalf("Expected 20 gossip IDs; got %d", len(gids))
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
mid := msgID(msgs[i])
|
||||
if mid != gids[10+i] {
|
||||
if !bytes.Equal(mid, gids[10+i]) {
|
||||
t.Fatalf("GossipID mismatch for message %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 10; i < 20; i++ {
|
||||
mid := msgID(msgs[i])
|
||||
if mid != gids[i-10] {
|
||||
if !bytes.Equal(mid, gids[i-10]) {
|
||||
t.Fatalf("GossipID mismatch for message %d", i)
|
||||
}
|
||||
}
|
||||
@ -125,28 +126,28 @@ func TestMessageCache(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
gids = mcache.GetGossipIDs([]byte{0x7e, 0x57})
|
||||
gids = mcache.GetGossipIDs([]byte{0x01, 0x00})
|
||||
if len(gids) != 30 {
|
||||
t.Fatalf("Expected 30 gossip IDs; got %d", len(gids))
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
mid := msgID(msgs[50+i])
|
||||
if mid != gids[i] {
|
||||
if !bytes.Equal(mid, gids[i]) {
|
||||
t.Fatalf("GossipID mismatch for message %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 10; i < 20; i++ {
|
||||
mid := msgID(msgs[30+i])
|
||||
if mid != gids[i] {
|
||||
if !bytes.Equal(mid, gids[i]) {
|
||||
t.Fatalf("GossipID mismatch for message %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 20; i < 30; i++ {
|
||||
mid := msgID(msgs[10+i])
|
||||
if mid != gids[i] {
|
||||
if !bytes.Equal(mid, gids[i]) {
|
||||
t.Fatalf("GossipID mismatch for message %d", i)
|
||||
}
|
||||
}
|
||||
@ -157,11 +158,11 @@ func makeTestMessage(n int) *pb.Message {
|
||||
seqno := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(seqno, uint64(n))
|
||||
data := []byte(fmt.Sprintf("%d", n))
|
||||
bitmask := []byte{0x7e, 0x57}
|
||||
bitmask := []byte{0x01, 0x00}
|
||||
return &pb.Message{
|
||||
Data: data,
|
||||
Bitmask: bitmask,
|
||||
From: []byte([]byte{0x7e, 0x57}),
|
||||
From: []byte([]byte{0x01, 0x00}),
|
||||
Seqno: seqno,
|
||||
}
|
||||
}
|
||||
|
@ -30,8 +30,8 @@ func (m *msgIDGenerator) Set(bitmask []byte, gen MsgIdFunction) {
|
||||
}
|
||||
|
||||
// ID computes ID for the msg or short-circuits with the cached value.
|
||||
func (m *msgIDGenerator) ID(msg *Message) string {
|
||||
if msg.ID != "" {
|
||||
func (m *msgIDGenerator) ID(msg *Message) []byte {
|
||||
if len(msg.ID) != 0 {
|
||||
return msg.ID
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ func (m *msgIDGenerator) ID(msg *Message) string {
|
||||
}
|
||||
|
||||
// RawID computes ID for the proto 'msg'.
|
||||
func (m *msgIDGenerator) RawID(msg *pb.Message) string {
|
||||
func (m *msgIDGenerator) RawID(msg *pb.Message) []byte {
|
||||
m.bitmaskGensLk.RLock()
|
||||
gen, ok := m.bitmaskGens[string(msg.GetBitmask())]
|
||||
m.bitmaskGensLk.RUnlock()
|
||||
|
@ -1,75 +0,0 @@
|
||||
package blossomsub
|
||||
|
||||
import (
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
var _ network.Notifiee = (*PubSubNotif)(nil)
|
||||
|
||||
type PubSubNotif PubSub
|
||||
|
||||
func (p *PubSubNotif) OpenedStream(n network.Network, s network.Stream) {
|
||||
}
|
||||
|
||||
func (p *PubSubNotif) ClosedStream(n network.Network, s network.Stream) {
|
||||
}
|
||||
|
||||
func (p *PubSubNotif) Connected(n network.Network, c network.Conn) {
|
||||
// ignore transient connections
|
||||
if c.Stat().Limited {
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
p.newPeersPrioLk.RLock()
|
||||
p.newPeersMx.Lock()
|
||||
p.newPeersPend[c.RemotePeer()] = struct{}{}
|
||||
p.newPeersMx.Unlock()
|
||||
p.newPeersPrioLk.RUnlock()
|
||||
|
||||
select {
|
||||
case p.newPeers <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (p *PubSubNotif) Disconnected(n network.Network, c network.Conn) {
|
||||
}
|
||||
|
||||
func (p *PubSubNotif) Listen(n network.Network, _ ma.Multiaddr) {
|
||||
}
|
||||
|
||||
func (p *PubSubNotif) ListenClose(n network.Network, _ ma.Multiaddr) {
|
||||
}
|
||||
|
||||
func (p *PubSubNotif) Initialize() {
|
||||
isTransient := func(pid peer.ID) bool {
|
||||
for _, c := range p.host.Network().ConnsToPeer(pid) {
|
||||
if !c.Stat().Limited {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
p.newPeersPrioLk.RLock()
|
||||
p.newPeersMx.Lock()
|
||||
for _, pid := range p.host.Network().Peers() {
|
||||
if isTransient(pid) {
|
||||
continue
|
||||
}
|
||||
|
||||
p.newPeersPend[pid] = struct{}{}
|
||||
}
|
||||
p.newPeersMx.Unlock()
|
||||
p.newPeersPrioLk.RUnlock()
|
||||
|
||||
select {
|
||||
case p.newPeers <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
@ -246,9 +246,8 @@ type ControlIHave struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Bitmask []byte `protobuf:"bytes,1,opt,name=bitmask,proto3" json:"bitmask,omitempty"`
|
||||
// implementors from other languages should use bytes here - go protobuf emits invalid utf8 strings
|
||||
MessageIDs []string `protobuf:"bytes,2,rep,name=messageIDs,proto3" json:"messageIDs,omitempty"`
|
||||
Bitmask []byte `protobuf:"bytes,1,opt,name=bitmask,proto3" json:"bitmask,omitempty"`
|
||||
MessageIDs [][]byte `protobuf:"bytes,2,rep,name=messageIDs,proto3" json:"messageIDs,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ControlIHave) Reset() {
|
||||
@ -290,7 +289,7 @@ func (x *ControlIHave) GetBitmask() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ControlIHave) GetMessageIDs() []string {
|
||||
func (x *ControlIHave) GetMessageIDs() [][]byte {
|
||||
if x != nil {
|
||||
return x.MessageIDs
|
||||
}
|
||||
@ -302,8 +301,7 @@ type ControlIWant struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// implementors from other languages should use bytes here - go protobuf emits invalid utf8 strings
|
||||
MessageIDs []string `protobuf:"bytes,1,rep,name=messageIDs,proto3" json:"messageIDs,omitempty"`
|
||||
MessageIDs [][]byte `protobuf:"bytes,1,rep,name=messageIDs,proto3" json:"messageIDs,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ControlIWant) Reset() {
|
||||
@ -338,7 +336,7 @@ func (*ControlIWant) Descriptor() ([]byte, []int) {
|
||||
return file_rpc_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *ControlIWant) GetMessageIDs() []string {
|
||||
func (x *ControlIWant) GetMessageIDs() [][]byte {
|
||||
if x != nil {
|
||||
return x.MessageIDs
|
||||
}
|
||||
@ -612,10 +610,10 @@ var file_rpc_proto_rawDesc = []byte{
|
||||
0x49, 0x48, 0x61, 0x76, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x12,
|
||||
0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20,
|
||||
0x03, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x73, 0x22,
|
||||
0x03, 0x28, 0x0c, 0x52, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x73, 0x22,
|
||||
0x2e, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x49, 0x57, 0x61, 0x6e, 0x74, 0x12,
|
||||
0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20,
|
||||
0x03, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x73, 0x22,
|
||||
0x03, 0x28, 0x0c, 0x52, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x73, 0x22,
|
||||
0x28, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x47, 0x72, 0x61, 0x66, 0x74, 0x12,
|
||||
0x18, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
|
||||
0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0x71, 0x0a, 0x0c, 0x43, 0x6f, 0x6e,
|
||||
|
@ -34,13 +34,11 @@ message ControlMessage {
|
||||
|
||||
message ControlIHave {
|
||||
bytes bitmask = 1;
|
||||
// implementors from other languages should use bytes here - go protobuf emits invalid utf8 strings
|
||||
repeated string messageIDs = 2;
|
||||
repeated bytes messageIDs = 2;
|
||||
}
|
||||
|
||||
message ControlIWant {
|
||||
// implementors from other languages should use bytes here - go protobuf emits invalid utf8 strings
|
||||
repeated string messageIDs = 1;
|
||||
repeated bytes messageIDs = 1;
|
||||
}
|
||||
|
||||
message ControlGraft {
|
||||
|
@ -23,19 +23,20 @@ const (
|
||||
type TraceEvent_Type int32
|
||||
|
||||
const (
|
||||
TraceEvent_PUBLISH_MESSAGE TraceEvent_Type = 0
|
||||
TraceEvent_REJECT_MESSAGE TraceEvent_Type = 1
|
||||
TraceEvent_DUPLICATE_MESSAGE TraceEvent_Type = 2
|
||||
TraceEvent_DELIVER_MESSAGE TraceEvent_Type = 3
|
||||
TraceEvent_ADD_PEER TraceEvent_Type = 4
|
||||
TraceEvent_REMOVE_PEER TraceEvent_Type = 5
|
||||
TraceEvent_RECV_RPC TraceEvent_Type = 6
|
||||
TraceEvent_SEND_RPC TraceEvent_Type = 7
|
||||
TraceEvent_DROP_RPC TraceEvent_Type = 8
|
||||
TraceEvent_JOIN TraceEvent_Type = 9
|
||||
TraceEvent_LEAVE TraceEvent_Type = 10
|
||||
TraceEvent_GRAFT TraceEvent_Type = 11
|
||||
TraceEvent_PRUNE TraceEvent_Type = 12
|
||||
TraceEvent_PUBLISH_MESSAGE TraceEvent_Type = 0
|
||||
TraceEvent_REJECT_MESSAGE TraceEvent_Type = 1
|
||||
TraceEvent_DUPLICATE_MESSAGE TraceEvent_Type = 2
|
||||
TraceEvent_DELIVER_MESSAGE TraceEvent_Type = 3
|
||||
TraceEvent_ADD_PEER TraceEvent_Type = 4
|
||||
TraceEvent_REMOVE_PEER TraceEvent_Type = 5
|
||||
TraceEvent_RECV_RPC TraceEvent_Type = 6
|
||||
TraceEvent_SEND_RPC TraceEvent_Type = 7
|
||||
TraceEvent_DROP_RPC TraceEvent_Type = 8
|
||||
TraceEvent_JOIN TraceEvent_Type = 9
|
||||
TraceEvent_LEAVE TraceEvent_Type = 10
|
||||
TraceEvent_GRAFT TraceEvent_Type = 11
|
||||
TraceEvent_PRUNE TraceEvent_Type = 12
|
||||
TraceEvent_UNDELIVERABLE_MESSAGE TraceEvent_Type = 13
|
||||
)
|
||||
|
||||
// Enum value maps for TraceEvent_Type.
|
||||
@ -54,21 +55,23 @@ var (
|
||||
10: "LEAVE",
|
||||
11: "GRAFT",
|
||||
12: "PRUNE",
|
||||
13: "UNDELIVERABLE_MESSAGE",
|
||||
}
|
||||
TraceEvent_Type_value = map[string]int32{
|
||||
"PUBLISH_MESSAGE": 0,
|
||||
"REJECT_MESSAGE": 1,
|
||||
"DUPLICATE_MESSAGE": 2,
|
||||
"DELIVER_MESSAGE": 3,
|
||||
"ADD_PEER": 4,
|
||||
"REMOVE_PEER": 5,
|
||||
"RECV_RPC": 6,
|
||||
"SEND_RPC": 7,
|
||||
"DROP_RPC": 8,
|
||||
"JOIN": 9,
|
||||
"LEAVE": 10,
|
||||
"GRAFT": 11,
|
||||
"PRUNE": 12,
|
||||
"PUBLISH_MESSAGE": 0,
|
||||
"REJECT_MESSAGE": 1,
|
||||
"DUPLICATE_MESSAGE": 2,
|
||||
"DELIVER_MESSAGE": 3,
|
||||
"ADD_PEER": 4,
|
||||
"REMOVE_PEER": 5,
|
||||
"RECV_RPC": 6,
|
||||
"SEND_RPC": 7,
|
||||
"DROP_RPC": 8,
|
||||
"JOIN": 9,
|
||||
"LEAVE": 10,
|
||||
"GRAFT": 11,
|
||||
"PRUNE": 12,
|
||||
"UNDELIVERABLE_MESSAGE": 13,
|
||||
}
|
||||
)
|
||||
|
||||
@ -104,22 +107,23 @@ type TraceEvent struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Type *TraceEvent_Type `protobuf:"varint,1,opt,name=type,proto3,enum=blossomsub.pb.TraceEvent_Type,oneof" json:"type,omitempty"`
|
||||
PeerID []byte `protobuf:"bytes,2,opt,name=peerID,proto3,oneof" json:"peerID,omitempty"`
|
||||
Timestamp *int64 `protobuf:"varint,3,opt,name=timestamp,proto3,oneof" json:"timestamp,omitempty"`
|
||||
PublishMessage *TraceEvent_PublishMessage `protobuf:"bytes,4,opt,name=publishMessage,proto3,oneof" json:"publishMessage,omitempty"`
|
||||
RejectMessage *TraceEvent_RejectMessage `protobuf:"bytes,5,opt,name=rejectMessage,proto3,oneof" json:"rejectMessage,omitempty"`
|
||||
DuplicateMessage *TraceEvent_DuplicateMessage `protobuf:"bytes,6,opt,name=duplicateMessage,proto3,oneof" json:"duplicateMessage,omitempty"`
|
||||
DeliverMessage *TraceEvent_DeliverMessage `protobuf:"bytes,7,opt,name=deliverMessage,proto3,oneof" json:"deliverMessage,omitempty"`
|
||||
AddPeer *TraceEvent_AddPeer `protobuf:"bytes,8,opt,name=addPeer,proto3,oneof" json:"addPeer,omitempty"`
|
||||
RemovePeer *TraceEvent_RemovePeer `protobuf:"bytes,9,opt,name=removePeer,proto3,oneof" json:"removePeer,omitempty"`
|
||||
RecvRPC *TraceEvent_RecvRPC `protobuf:"bytes,10,opt,name=recvRPC,proto3,oneof" json:"recvRPC,omitempty"`
|
||||
SendRPC *TraceEvent_SendRPC `protobuf:"bytes,11,opt,name=sendRPC,proto3,oneof" json:"sendRPC,omitempty"`
|
||||
DropRPC *TraceEvent_DropRPC `protobuf:"bytes,12,opt,name=dropRPC,proto3,oneof" json:"dropRPC,omitempty"`
|
||||
Join *TraceEvent_Join `protobuf:"bytes,13,opt,name=join,proto3,oneof" json:"join,omitempty"`
|
||||
Leave *TraceEvent_Leave `protobuf:"bytes,14,opt,name=leave,proto3,oneof" json:"leave,omitempty"`
|
||||
Graft *TraceEvent_Graft `protobuf:"bytes,15,opt,name=graft,proto3,oneof" json:"graft,omitempty"`
|
||||
Prune *TraceEvent_Prune `protobuf:"bytes,16,opt,name=prune,proto3,oneof" json:"prune,omitempty"`
|
||||
Type *TraceEvent_Type `protobuf:"varint,1,opt,name=type,proto3,enum=blossomsub.pb.TraceEvent_Type,oneof" json:"type,omitempty"`
|
||||
PeerID []byte `protobuf:"bytes,2,opt,name=peerID,proto3,oneof" json:"peerID,omitempty"`
|
||||
Timestamp *int64 `protobuf:"varint,3,opt,name=timestamp,proto3,oneof" json:"timestamp,omitempty"`
|
||||
PublishMessage *TraceEvent_PublishMessage `protobuf:"bytes,4,opt,name=publishMessage,proto3,oneof" json:"publishMessage,omitempty"`
|
||||
RejectMessage *TraceEvent_RejectMessage `protobuf:"bytes,5,opt,name=rejectMessage,proto3,oneof" json:"rejectMessage,omitempty"`
|
||||
DuplicateMessage *TraceEvent_DuplicateMessage `protobuf:"bytes,6,opt,name=duplicateMessage,proto3,oneof" json:"duplicateMessage,omitempty"`
|
||||
DeliverMessage *TraceEvent_DeliverMessage `protobuf:"bytes,7,opt,name=deliverMessage,proto3,oneof" json:"deliverMessage,omitempty"`
|
||||
AddPeer *TraceEvent_AddPeer `protobuf:"bytes,8,opt,name=addPeer,proto3,oneof" json:"addPeer,omitempty"`
|
||||
RemovePeer *TraceEvent_RemovePeer `protobuf:"bytes,9,opt,name=removePeer,proto3,oneof" json:"removePeer,omitempty"`
|
||||
RecvRPC *TraceEvent_RecvRPC `protobuf:"bytes,10,opt,name=recvRPC,proto3,oneof" json:"recvRPC,omitempty"`
|
||||
SendRPC *TraceEvent_SendRPC `protobuf:"bytes,11,opt,name=sendRPC,proto3,oneof" json:"sendRPC,omitempty"`
|
||||
DropRPC *TraceEvent_DropRPC `protobuf:"bytes,12,opt,name=dropRPC,proto3,oneof" json:"dropRPC,omitempty"`
|
||||
Join *TraceEvent_Join `protobuf:"bytes,13,opt,name=join,proto3,oneof" json:"join,omitempty"`
|
||||
Leave *TraceEvent_Leave `protobuf:"bytes,14,opt,name=leave,proto3,oneof" json:"leave,omitempty"`
|
||||
Graft *TraceEvent_Graft `protobuf:"bytes,15,opt,name=graft,proto3,oneof" json:"graft,omitempty"`
|
||||
Prune *TraceEvent_Prune `protobuf:"bytes,16,opt,name=prune,proto3,oneof" json:"prune,omitempty"`
|
||||
UndeliverableMessage *TraceEvent_UndeliverableMessage `protobuf:"bytes,17,opt,name=undeliverableMessage,proto3,oneof" json:"undeliverableMessage,omitempty"`
|
||||
}
|
||||
|
||||
func (x *TraceEvent) Reset() {
|
||||
@ -266,6 +270,13 @@ func (x *TraceEvent) GetPrune() *TraceEvent_Prune {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TraceEvent) GetUndeliverableMessage() *TraceEvent_UndeliverableMessage {
|
||||
if x != nil {
|
||||
return x.UndeliverableMessage
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type TraceEventBatch struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@ -1036,6 +1047,69 @@ func (x *TraceEvent_Prune) GetBitmask() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
type TraceEvent_UndeliverableMessage struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
MessageID []byte `protobuf:"bytes,1,opt,name=messageID,proto3,oneof" json:"messageID,omitempty"`
|
||||
Bitmask []byte `protobuf:"bytes,2,opt,name=bitmask,proto3,oneof" json:"bitmask,omitempty"`
|
||||
ReceivedFrom []byte `protobuf:"bytes,3,opt,name=receivedFrom,proto3,oneof" json:"receivedFrom,omitempty"`
|
||||
}
|
||||
|
||||
func (x *TraceEvent_UndeliverableMessage) Reset() {
|
||||
*x = TraceEvent_UndeliverableMessage{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_trace_proto_msgTypes[15]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *TraceEvent_UndeliverableMessage) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TraceEvent_UndeliverableMessage) ProtoMessage() {}
|
||||
|
||||
func (x *TraceEvent_UndeliverableMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_trace_proto_msgTypes[15]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TraceEvent_UndeliverableMessage.ProtoReflect.Descriptor instead.
|
||||
func (*TraceEvent_UndeliverableMessage) Descriptor() ([]byte, []int) {
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 13}
|
||||
}
|
||||
|
||||
func (x *TraceEvent_UndeliverableMessage) GetMessageID() []byte {
|
||||
if x != nil {
|
||||
return x.MessageID
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TraceEvent_UndeliverableMessage) GetBitmask() []byte {
|
||||
if x != nil {
|
||||
return x.Bitmask
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TraceEvent_UndeliverableMessage) GetReceivedFrom() []byte {
|
||||
if x != nil {
|
||||
return x.ReceivedFrom
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type TraceEvent_RPCMeta struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@ -1049,7 +1123,7 @@ type TraceEvent_RPCMeta struct {
|
||||
func (x *TraceEvent_RPCMeta) Reset() {
|
||||
*x = TraceEvent_RPCMeta{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_trace_proto_msgTypes[15]
|
||||
mi := &file_trace_proto_msgTypes[16]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1062,7 +1136,7 @@ func (x *TraceEvent_RPCMeta) String() string {
|
||||
func (*TraceEvent_RPCMeta) ProtoMessage() {}
|
||||
|
||||
func (x *TraceEvent_RPCMeta) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_trace_proto_msgTypes[15]
|
||||
mi := &file_trace_proto_msgTypes[16]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1075,7 +1149,7 @@ func (x *TraceEvent_RPCMeta) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use TraceEvent_RPCMeta.ProtoReflect.Descriptor instead.
|
||||
func (*TraceEvent_RPCMeta) Descriptor() ([]byte, []int) {
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 13}
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 14}
|
||||
}
|
||||
|
||||
func (x *TraceEvent_RPCMeta) GetMessages() []*TraceEvent_MessageMeta {
|
||||
@ -1111,7 +1185,7 @@ type TraceEvent_MessageMeta struct {
|
||||
func (x *TraceEvent_MessageMeta) Reset() {
|
||||
*x = TraceEvent_MessageMeta{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_trace_proto_msgTypes[16]
|
||||
mi := &file_trace_proto_msgTypes[17]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1124,7 +1198,7 @@ func (x *TraceEvent_MessageMeta) String() string {
|
||||
func (*TraceEvent_MessageMeta) ProtoMessage() {}
|
||||
|
||||
func (x *TraceEvent_MessageMeta) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_trace_proto_msgTypes[16]
|
||||
mi := &file_trace_proto_msgTypes[17]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1137,7 +1211,7 @@ func (x *TraceEvent_MessageMeta) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use TraceEvent_MessageMeta.ProtoReflect.Descriptor instead.
|
||||
func (*TraceEvent_MessageMeta) Descriptor() ([]byte, []int) {
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 14}
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 15}
|
||||
}
|
||||
|
||||
func (x *TraceEvent_MessageMeta) GetMessageID() []byte {
|
||||
@ -1166,7 +1240,7 @@ type TraceEvent_SubMeta struct {
|
||||
func (x *TraceEvent_SubMeta) Reset() {
|
||||
*x = TraceEvent_SubMeta{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_trace_proto_msgTypes[17]
|
||||
mi := &file_trace_proto_msgTypes[18]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1179,7 +1253,7 @@ func (x *TraceEvent_SubMeta) String() string {
|
||||
func (*TraceEvent_SubMeta) ProtoMessage() {}
|
||||
|
||||
func (x *TraceEvent_SubMeta) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_trace_proto_msgTypes[17]
|
||||
mi := &file_trace_proto_msgTypes[18]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1192,7 +1266,7 @@ func (x *TraceEvent_SubMeta) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use TraceEvent_SubMeta.ProtoReflect.Descriptor instead.
|
||||
func (*TraceEvent_SubMeta) Descriptor() ([]byte, []int) {
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 15}
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 16}
|
||||
}
|
||||
|
||||
func (x *TraceEvent_SubMeta) GetSubscribe() bool {
|
||||
@ -1223,7 +1297,7 @@ type TraceEvent_ControlMeta struct {
|
||||
func (x *TraceEvent_ControlMeta) Reset() {
|
||||
*x = TraceEvent_ControlMeta{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_trace_proto_msgTypes[18]
|
||||
mi := &file_trace_proto_msgTypes[19]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1236,7 +1310,7 @@ func (x *TraceEvent_ControlMeta) String() string {
|
||||
func (*TraceEvent_ControlMeta) ProtoMessage() {}
|
||||
|
||||
func (x *TraceEvent_ControlMeta) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_trace_proto_msgTypes[18]
|
||||
mi := &file_trace_proto_msgTypes[19]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1249,7 +1323,7 @@ func (x *TraceEvent_ControlMeta) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use TraceEvent_ControlMeta.ProtoReflect.Descriptor instead.
|
||||
func (*TraceEvent_ControlMeta) Descriptor() ([]byte, []int) {
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 16}
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 17}
|
||||
}
|
||||
|
||||
func (x *TraceEvent_ControlMeta) GetIhave() []*TraceEvent_ControlIHaveMeta {
|
||||
@ -1292,7 +1366,7 @@ type TraceEvent_ControlIHaveMeta struct {
|
||||
func (x *TraceEvent_ControlIHaveMeta) Reset() {
|
||||
*x = TraceEvent_ControlIHaveMeta{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_trace_proto_msgTypes[19]
|
||||
mi := &file_trace_proto_msgTypes[20]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1305,7 +1379,7 @@ func (x *TraceEvent_ControlIHaveMeta) String() string {
|
||||
func (*TraceEvent_ControlIHaveMeta) ProtoMessage() {}
|
||||
|
||||
func (x *TraceEvent_ControlIHaveMeta) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_trace_proto_msgTypes[19]
|
||||
mi := &file_trace_proto_msgTypes[20]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1318,7 +1392,7 @@ func (x *TraceEvent_ControlIHaveMeta) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use TraceEvent_ControlIHaveMeta.ProtoReflect.Descriptor instead.
|
||||
func (*TraceEvent_ControlIHaveMeta) Descriptor() ([]byte, []int) {
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 17}
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 18}
|
||||
}
|
||||
|
||||
func (x *TraceEvent_ControlIHaveMeta) GetBitmask() []byte {
|
||||
@ -1346,7 +1420,7 @@ type TraceEvent_ControlIWantMeta struct {
|
||||
func (x *TraceEvent_ControlIWantMeta) Reset() {
|
||||
*x = TraceEvent_ControlIWantMeta{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_trace_proto_msgTypes[20]
|
||||
mi := &file_trace_proto_msgTypes[21]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1359,7 +1433,7 @@ func (x *TraceEvent_ControlIWantMeta) String() string {
|
||||
func (*TraceEvent_ControlIWantMeta) ProtoMessage() {}
|
||||
|
||||
func (x *TraceEvent_ControlIWantMeta) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_trace_proto_msgTypes[20]
|
||||
mi := &file_trace_proto_msgTypes[21]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1372,7 +1446,7 @@ func (x *TraceEvent_ControlIWantMeta) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use TraceEvent_ControlIWantMeta.ProtoReflect.Descriptor instead.
|
||||
func (*TraceEvent_ControlIWantMeta) Descriptor() ([]byte, []int) {
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 18}
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 19}
|
||||
}
|
||||
|
||||
func (x *TraceEvent_ControlIWantMeta) GetMessageIDs() [][]byte {
|
||||
@ -1393,7 +1467,7 @@ type TraceEvent_ControlGraftMeta struct {
|
||||
func (x *TraceEvent_ControlGraftMeta) Reset() {
|
||||
*x = TraceEvent_ControlGraftMeta{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_trace_proto_msgTypes[21]
|
||||
mi := &file_trace_proto_msgTypes[22]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1406,7 +1480,7 @@ func (x *TraceEvent_ControlGraftMeta) String() string {
|
||||
func (*TraceEvent_ControlGraftMeta) ProtoMessage() {}
|
||||
|
||||
func (x *TraceEvent_ControlGraftMeta) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_trace_proto_msgTypes[21]
|
||||
mi := &file_trace_proto_msgTypes[22]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1419,7 +1493,7 @@ func (x *TraceEvent_ControlGraftMeta) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use TraceEvent_ControlGraftMeta.ProtoReflect.Descriptor instead.
|
||||
func (*TraceEvent_ControlGraftMeta) Descriptor() ([]byte, []int) {
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 19}
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 20}
|
||||
}
|
||||
|
||||
func (x *TraceEvent_ControlGraftMeta) GetBitmask() []byte {
|
||||
@ -1441,7 +1515,7 @@ type TraceEvent_ControlPruneMeta struct {
|
||||
func (x *TraceEvent_ControlPruneMeta) Reset() {
|
||||
*x = TraceEvent_ControlPruneMeta{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_trace_proto_msgTypes[22]
|
||||
mi := &file_trace_proto_msgTypes[23]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1454,7 +1528,7 @@ func (x *TraceEvent_ControlPruneMeta) String() string {
|
||||
func (*TraceEvent_ControlPruneMeta) ProtoMessage() {}
|
||||
|
||||
func (x *TraceEvent_ControlPruneMeta) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_trace_proto_msgTypes[22]
|
||||
mi := &file_trace_proto_msgTypes[23]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1467,7 +1541,7 @@ func (x *TraceEvent_ControlPruneMeta) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use TraceEvent_ControlPruneMeta.ProtoReflect.Descriptor instead.
|
||||
func (*TraceEvent_ControlPruneMeta) Descriptor() ([]byte, []int) {
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 20}
|
||||
return file_trace_proto_rawDescGZIP(), []int{0, 21}
|
||||
}
|
||||
|
||||
func (x *TraceEvent_ControlPruneMeta) GetBitmask() []byte {
|
||||
@ -1488,7 +1562,7 @@ var File_trace_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_trace_proto_rawDesc = []byte{
|
||||
0x0a, 0x0b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x62,
|
||||
0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x22, 0xfe, 0x1e, 0x0a,
|
||||
0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x22, 0xca, 0x21, 0x0a,
|
||||
0x0a, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x37, 0x0a, 0x04, 0x74,
|
||||
0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x62, 0x6c, 0x6f, 0x73,
|
||||
0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45,
|
||||
@ -1555,38 +1629,106 @@ var file_trace_proto_rawDesc = []byte{
|
||||
0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d,
|
||||
0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x2e, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x48, 0x0f, 0x52, 0x05, 0x70, 0x72, 0x75, 0x6e, 0x65,
|
||||
0x88, 0x01, 0x01, 0x1a, 0x6c, 0x0a, 0x0e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x4d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x49, 0x44, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d,
|
||||
0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x07, 0x62, 0x69, 0x74,
|
||||
0x6d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x49, 0x44, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73,
|
||||
0x6b, 0x1a, 0xcd, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x49, 0x44, 0x88, 0x01, 0x01, 0x12, 0x27, 0x0a, 0x0c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76,
|
||||
0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x0c,
|
||||
0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x88, 0x01, 0x01, 0x12,
|
||||
0x1b, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48,
|
||||
0x02, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07,
|
||||
0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x03, 0x52,
|
||||
0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f,
|
||||
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x72, 0x65,
|
||||
0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x72,
|
||||
0x65, 0x61, 0x73, 0x6f, 0x6e, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73,
|
||||
0x6b, 0x1a, 0xa8, 0x01, 0x0a, 0x10, 0x44, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x09, 0x6d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x88, 0x01, 0x01, 0x12, 0x27, 0x0a, 0x0c, 0x72, 0x65, 0x63,
|
||||
0x65, 0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48,
|
||||
0x01, 0x52, 0x0c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x88,
|
||||
0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x48, 0x02, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88, 0x01,
|
||||
0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x42,
|
||||
0x0f, 0x0a, 0x0d, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d,
|
||||
0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0xa6, 0x01, 0x0a,
|
||||
0x0e, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
|
||||
0x88, 0x01, 0x01, 0x12, 0x67, 0x0a, 0x14, 0x75, 0x6e, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x2e, 0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e, 0x70,
|
||||
0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x55, 0x6e, 0x64,
|
||||
0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x48, 0x10, 0x52, 0x14, 0x75, 0x6e, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x61, 0x62,
|
||||
0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x88, 0x01, 0x01, 0x1a, 0x6c, 0x0a, 0x0e,
|
||||
0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x21,
|
||||
0x0a, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x48, 0x00, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x88, 0x01,
|
||||
0x01, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x0c, 0x48, 0x01, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01,
|
||||
0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x42, 0x0a,
|
||||
0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0xcd, 0x01, 0x0a, 0x0d, 0x52,
|
||||
0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x09,
|
||||
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48,
|
||||
0x00, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x88, 0x01, 0x01, 0x12,
|
||||
0x27, 0x0a, 0x0c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x0c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
|
||||
0x64, 0x46, 0x72, 0x6f, 0x6d, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73,
|
||||
0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73,
|
||||
0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x03, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73,
|
||||
0x6b, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x49, 0x44, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x46,
|
||||
0x72, 0x6f, 0x6d, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x42, 0x0a,
|
||||
0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0xa8, 0x01, 0x0a, 0x10, 0x44,
|
||||
0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
|
||||
0x21, 0x0a, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0c, 0x48, 0x00, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x88,
|
||||
0x01, 0x01, 0x12, 0x27, 0x0a, 0x0c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x46, 0x72,
|
||||
0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x0c, 0x72, 0x65, 0x63, 0x65,
|
||||
0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x62,
|
||||
0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x02, 0x52, 0x07,
|
||||
0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x72, 0x65, 0x63,
|
||||
0x65, 0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69,
|
||||
0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0xa6, 0x01, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65,
|
||||
0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x09, 0x6d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x09, 0x6d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x62,
|
||||
0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x07,
|
||||
0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x12, 0x27, 0x0a, 0x0c, 0x72, 0x65,
|
||||
0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c,
|
||||
0x48, 0x02, 0x52, 0x0c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d,
|
||||
0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49,
|
||||
0x44, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x42, 0x0f, 0x0a,
|
||||
0x0d, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x1a, 0x56,
|
||||
0x0a, 0x07, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x06, 0x70, 0x65, 0x65,
|
||||
0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x70, 0x65, 0x65,
|
||||
0x72, 0x49, 0x44, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x88, 0x01,
|
||||
0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, 0x42, 0x08, 0x0a, 0x06,
|
||||
0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x34, 0x0a, 0x0a, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
||||
0x50, 0x65, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, 0x88, 0x01,
|
||||
0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, 0x1a, 0x88, 0x01, 0x0a,
|
||||
0x07, 0x52, 0x65, 0x63, 0x76, 0x52, 0x50, 0x43, 0x12, 0x27, 0x0a, 0x0c, 0x72, 0x65, 0x63, 0x65,
|
||||
0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00,
|
||||
0x52, 0x0c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x88, 0x01,
|
||||
0x01, 0x12, 0x3a, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x21, 0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x2e,
|
||||
0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x65,
|
||||
0x74, 0x61, 0x48, 0x01, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x88, 0x01, 0x01, 0x42, 0x0f, 0x0a,
|
||||
0x0d, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x07,
|
||||
0x0a, 0x05, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x1a, 0x76, 0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, 0x52,
|
||||
0x50, 0x43, 0x12, 0x1b, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x88, 0x01, 0x01, 0x12,
|
||||
0x3a, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e,
|
||||
0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72,
|
||||
0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x65, 0x74, 0x61,
|
||||
0x48, 0x01, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f,
|
||||
0x73, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x1a,
|
||||
0x76, 0x0a, 0x07, 0x44, 0x72, 0x6f, 0x70, 0x52, 0x50, 0x43, 0x12, 0x1b, 0x0a, 0x06, 0x73, 0x65,
|
||||
0x6e, 0x64, 0x54, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x73, 0x65,
|
||||
0x6e, 0x64, 0x54, 0x6f, 0x88, 0x01, 0x01, 0x12, 0x3a, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73,
|
||||
0x75, 0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74,
|
||||
0x2e, 0x52, 0x50, 0x43, 0x4d, 0x65, 0x74, 0x61, 0x48, 0x01, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61,
|
||||
0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x42, 0x07,
|
||||
0x0a, 0x05, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x1a, 0x31, 0x0a, 0x04, 0x4a, 0x6f, 0x69, 0x6e, 0x12,
|
||||
0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
|
||||
0x48, 0x00, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0a,
|
||||
0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0x32, 0x0a, 0x05, 0x4c, 0x65,
|
||||
0x61, 0x76, 0x65, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88,
|
||||
0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0x5a,
|
||||
0x0a, 0x05, 0x47, 0x72, 0x61, 0x66, 0x74, 0x12, 0x1b, 0x0a, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49,
|
||||
0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49,
|
||||
0x44, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b,
|
||||
0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, 0x42, 0x0a,
|
||||
0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0x5a, 0x0a, 0x05, 0x50, 0x72,
|
||||
0x75, 0x6e, 0x65, 0x12, 0x1b, 0x0a, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, 0x88, 0x01, 0x01,
|
||||
0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x48, 0x01, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42,
|
||||
0x09, 0x0a, 0x07, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62,
|
||||
0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0xac, 0x01, 0x0a, 0x14, 0x55, 0x6e, 0x64, 0x65, 0x6c,
|
||||
0x69, 0x76, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
|
||||
0x21, 0x0a, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0c, 0x48, 0x00, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x88,
|
||||
0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20,
|
||||
@ -1596,156 +1738,109 @@ var file_trace_proto_rawDesc = []byte{
|
||||
0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74,
|
||||
0x6d, 0x61, 0x73, 0x6b, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
|
||||
0x64, 0x46, 0x72, 0x6f, 0x6d, 0x1a, 0x56, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72,
|
||||
0x12, 0x1b, 0x0a, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
|
||||
0x48, 0x00, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a,
|
||||
0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x05,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x70, 0x65, 0x65,
|
||||
0x72, 0x49, 0x44, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x34, 0x0a,
|
||||
0x0a, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x65, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x06, 0x70,
|
||||
0x65, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x70,
|
||||
0x65, 0x65, 0x72, 0x49, 0x44, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x70, 0x65, 0x65,
|
||||
0x72, 0x49, 0x44, 0x1a, 0x88, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x63, 0x76, 0x52, 0x50, 0x43, 0x12,
|
||||
0x27, 0x0a, 0x0c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
|
||||
0x64, 0x46, 0x72, 0x6f, 0x6d, 0x88, 0x01, 0x01, 0x12, 0x3a, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d,
|
||||
0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x65, 0x74, 0x61, 0x48, 0x01, 0x52, 0x04, 0x6d, 0x65, 0x74,
|
||||
0x61, 0x88, 0x01, 0x01, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
|
||||
0x64, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x1a, 0x76,
|
||||
0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x50, 0x43, 0x12, 0x1b, 0x0a, 0x06, 0x73, 0x65, 0x6e,
|
||||
0x64, 0x54, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x73, 0x65, 0x6e,
|
||||
0x64, 0x54, 0x6f, 0x88, 0x01, 0x01, 0x12, 0x3a, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75,
|
||||
0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e,
|
||||
0x52, 0x50, 0x43, 0x4d, 0x65, 0x74, 0x61, 0x48, 0x01, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x88,
|
||||
0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x42, 0x07, 0x0a,
|
||||
0x05, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x1a, 0x76, 0x0a, 0x07, 0x44, 0x72, 0x6f, 0x70, 0x52, 0x50,
|
||||
0x43, 0x12, 0x1b, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x48, 0x00, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x88, 0x01, 0x01, 0x12, 0x3a,
|
||||
0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x62,
|
||||
0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61,
|
||||
0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x65, 0x74, 0x61, 0x48,
|
||||
0x01, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73,
|
||||
0x65, 0x6e, 0x64, 0x54, 0x6f, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x1a, 0x31,
|
||||
0x0a, 0x04, 0x4a, 0x6f, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73,
|
||||
0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61,
|
||||
0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73,
|
||||
0x6b, 0x1a, 0x32, 0x0a, 0x05, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69,
|
||||
0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x62,
|
||||
0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69,
|
||||
0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0x5a, 0x0a, 0x05, 0x47, 0x72, 0x61, 0x66, 0x74, 0x12, 0x1b,
|
||||
0x0a, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00,
|
||||
0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x62,
|
||||
0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x07,
|
||||
0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x70,
|
||||
0x65, 0x65, 0x72, 0x49, 0x44, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73,
|
||||
0x6b, 0x1a, 0x5a, 0x0a, 0x05, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x12, 0x1b, 0x0a, 0x06, 0x70, 0x65,
|
||||
0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x70, 0x65,
|
||||
0x65, 0x72, 0x49, 0x44, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61,
|
||||
0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d,
|
||||
0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x49,
|
||||
0x44, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0xe5, 0x01,
|
||||
0x0a, 0x07, 0x52, 0x50, 0x43, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x08, 0x6d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x62, 0x6c,
|
||||
0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63,
|
||||
0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4d, 0x65,
|
||||
0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x45, 0x0a, 0x0c,
|
||||
0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x21, 0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e,
|
||||
0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x75,
|
||||
0x62, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75,
|
||||
0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e,
|
||||
0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x48, 0x00, 0x52, 0x07, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x1a, 0x69, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x4d, 0x65, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49,
|
||||
0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x49, 0x44, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61,
|
||||
0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d,
|
||||
0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x49, 0x44, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b,
|
||||
0x1a, 0x65, 0x0a, 0x07, 0x53, 0x75, 0x62, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x09, 0x73,
|
||||
0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00,
|
||||
0x52, 0x09, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1d,
|
||||
0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48,
|
||||
0x01, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a,
|
||||
0x0a, 0x5f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f,
|
||||
0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0x95, 0x02, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x40, 0x0a, 0x05, 0x69, 0x68, 0x61, 0x76, 0x65,
|
||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d,
|
||||
0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x49, 0x48, 0x61, 0x76, 0x65, 0x4d, 0x65,
|
||||
0x74, 0x61, 0x52, 0x05, 0x69, 0x68, 0x61, 0x76, 0x65, 0x12, 0x40, 0x0a, 0x05, 0x69, 0x77, 0x61,
|
||||
0x6e, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73,
|
||||
0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76,
|
||||
0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x49, 0x57, 0x61, 0x6e, 0x74,
|
||||
0x4d, 0x65, 0x74, 0x61, 0x52, 0x05, 0x69, 0x77, 0x61, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x05, 0x67,
|
||||
0x72, 0x61, 0x66, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x62, 0x6c, 0x6f,
|
||||
0x64, 0x46, 0x72, 0x6f, 0x6d, 0x1a, 0xe5, 0x01, 0x0a, 0x07, 0x52, 0x50, 0x43, 0x4d, 0x65, 0x74,
|
||||
0x61, 0x12, 0x41, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62,
|
||||
0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x73, 0x12, 0x45, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x62, 0x6c, 0x6f,
|
||||
0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65,
|
||||
0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x47, 0x72, 0x61,
|
||||
0x66, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x05, 0x67, 0x72, 0x61, 0x66, 0x74, 0x12, 0x40, 0x0a,
|
||||
0x05, 0x70, 0x72, 0x75, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x62,
|
||||
0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x75, 0x62, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x0c, 0x73,
|
||||
0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x07, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x62,
|
||||
0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61,
|
||||
0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50,
|
||||
0x72, 0x75, 0x6e, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x05, 0x70, 0x72, 0x75, 0x6e, 0x65, 0x1a,
|
||||
0x5d, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x49, 0x48, 0x61, 0x76, 0x65, 0x4d,
|
||||
0x65, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88,
|
||||
0x01, 0x01, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x73,
|
||||
0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49,
|
||||
0x44, 0x73, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0x32,
|
||||
0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x49, 0x57, 0x61, 0x6e, 0x74, 0x4d, 0x65,
|
||||
0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x73,
|
||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49,
|
||||
0x44, 0x73, 0x1a, 0x3d, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x47, 0x72, 0x61,
|
||||
0x66, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73,
|
||||
0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61,
|
||||
0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73,
|
||||
0x6b, 0x1a, 0x53, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x72, 0x75, 0x6e,
|
||||
0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73,
|
||||
0x6b, 0x88, 0x01, 0x01, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20,
|
||||
0x03, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62,
|
||||
0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0xcf, 0x01, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12,
|
||||
0x13, 0x0a, 0x0f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41,
|
||||
0x47, 0x45, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x4d,
|
||||
0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x44, 0x55, 0x50, 0x4c,
|
||||
0x49, 0x43, 0x41, 0x54, 0x45, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x02, 0x12,
|
||||
0x13, 0x0a, 0x0f, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41,
|
||||
0x47, 0x45, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x44, 0x44, 0x5f, 0x50, 0x45, 0x45, 0x52,
|
||||
0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x5f, 0x50, 0x45, 0x45,
|
||||
0x52, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x43, 0x56, 0x5f, 0x52, 0x50, 0x43, 0x10,
|
||||
0x06, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x52, 0x50, 0x43, 0x10, 0x07, 0x12,
|
||||
0x0c, 0x0a, 0x08, 0x44, 0x52, 0x4f, 0x50, 0x5f, 0x52, 0x50, 0x43, 0x10, 0x08, 0x12, 0x08, 0x0a,
|
||||
0x04, 0x4a, 0x4f, 0x49, 0x4e, 0x10, 0x09, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x45, 0x41, 0x56, 0x45,
|
||||
0x10, 0x0a, 0x12, 0x09, 0x0a, 0x05, 0x47, 0x52, 0x41, 0x46, 0x54, 0x10, 0x0b, 0x12, 0x09, 0x0a,
|
||||
0x05, 0x50, 0x52, 0x55, 0x4e, 0x45, 0x10, 0x0c, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x74, 0x79, 0x70,
|
||||
0x65, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, 0x42, 0x0c, 0x0a, 0x0a,
|
||||
0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x70,
|
||||
0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x10, 0x0a,
|
||||
0x0e, 0x5f, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42,
|
||||
0x13, 0x0a, 0x11, 0x5f, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72,
|
||||
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x61, 0x64, 0x64, 0x50,
|
||||
0x65, 0x65, 0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x65,
|
||||
0x65, 0x72, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x72, 0x65, 0x63, 0x76, 0x52, 0x50, 0x43, 0x42, 0x0a,
|
||||
0x0a, 0x08, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x52, 0x50, 0x43, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x64,
|
||||
0x72, 0x6f, 0x70, 0x52, 0x50, 0x43, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x42,
|
||||
0x08, 0x0a, 0x06, 0x5f, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x67, 0x72,
|
||||
0x61, 0x66, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x70, 0x72, 0x75, 0x6e, 0x65, 0x22, 0x42, 0x0a,
|
||||
0x0f, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x74, 0x63, 0x68,
|
||||
0x12, 0x2f, 0x0a, 0x05, 0x62, 0x61, 0x74, 0x63, 0x68, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x19, 0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x2e,
|
||||
0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x62, 0x61, 0x74, 0x63,
|
||||
0x68, 0x42, 0x43, 0x5a, 0x41, 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, 0x67,
|
||||
0x6f, 0x2d, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2d, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d,
|
||||
0x73, 0x75, 0x62, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4d,
|
||||
0x65, 0x74, 0x61, 0x48, 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x88, 0x01,
|
||||
0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x1a, 0x69, 0x0a,
|
||||
0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x09,
|
||||
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48,
|
||||
0x00, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x88, 0x01, 0x01, 0x12,
|
||||
0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c,
|
||||
0x48, 0x01, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0c,
|
||||
0x0a, 0x0a, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x42, 0x0a, 0x0a, 0x08,
|
||||
0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0x65, 0x0a, 0x07, 0x53, 0x75, 0x62, 0x4d,
|
||||
0x65, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72,
|
||||
0x69, 0x62, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73,
|
||||
0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61,
|
||||
0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72,
|
||||
0x69, 0x62, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a,
|
||||
0x95, 0x02, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x12,
|
||||
0x40, 0x0a, 0x05, 0x69, 0x68, 0x61, 0x76, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a,
|
||||
0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54,
|
||||
0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x49, 0x48, 0x61, 0x76, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x05, 0x69, 0x68, 0x61, 0x76,
|
||||
0x65, 0x12, 0x40, 0x0a, 0x05, 0x69, 0x77, 0x61, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x2a, 0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e, 0x70, 0x62,
|
||||
0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x49, 0x57, 0x61, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x05, 0x69, 0x77,
|
||||
0x61, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x05, 0x67, 0x72, 0x61, 0x66, 0x74, 0x18, 0x03, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e,
|
||||
0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x47, 0x72, 0x61, 0x66, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x05,
|
||||
0x67, 0x72, 0x61, 0x66, 0x74, 0x12, 0x40, 0x0a, 0x05, 0x70, 0x72, 0x75, 0x6e, 0x65, 0x18, 0x04,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75,
|
||||
0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e,
|
||||
0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x4d, 0x65, 0x74, 0x61,
|
||||
0x52, 0x05, 0x70, 0x72, 0x75, 0x6e, 0x65, 0x1a, 0x5d, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x49, 0x48, 0x61, 0x76, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x07, 0x62,
|
||||
0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07,
|
||||
0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a,
|
||||
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x73, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62,
|
||||
0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0x32, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x49, 0x57, 0x61, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a,
|
||||
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x73, 0x1a, 0x3d, 0x0a, 0x10, 0x43, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x47, 0x72, 0x61, 0x66, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x1d,
|
||||
0x0a, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48,
|
||||
0x00, 0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a,
|
||||
0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0x53, 0x0a, 0x10, 0x43, 0x6f, 0x6e,
|
||||
0x74, 0x72, 0x6f, 0x6c, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x1d, 0x0a,
|
||||
0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00,
|
||||
0x52, 0x07, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x12, 0x14, 0x0a, 0x05,
|
||||
0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x65, 0x65,
|
||||
0x72, 0x73, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0xea,
|
||||
0x01, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x55, 0x42, 0x4c, 0x49,
|
||||
0x53, 0x48, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e,
|
||||
0x52, 0x45, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x01,
|
||||
0x12, 0x15, 0x0a, 0x11, 0x44, 0x55, 0x50, 0x4c, 0x49, 0x43, 0x41, 0x54, 0x45, 0x5f, 0x4d, 0x45,
|
||||
0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x45, 0x4c, 0x49, 0x56,
|
||||
0x45, 0x52, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08,
|
||||
0x41, 0x44, 0x44, 0x5f, 0x50, 0x45, 0x45, 0x52, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x45,
|
||||
0x4d, 0x4f, 0x56, 0x45, 0x5f, 0x50, 0x45, 0x45, 0x52, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x52,
|
||||
0x45, 0x43, 0x56, 0x5f, 0x52, 0x50, 0x43, 0x10, 0x06, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x45, 0x4e,
|
||||
0x44, 0x5f, 0x52, 0x50, 0x43, 0x10, 0x07, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x52, 0x4f, 0x50, 0x5f,
|
||||
0x52, 0x50, 0x43, 0x10, 0x08, 0x12, 0x08, 0x0a, 0x04, 0x4a, 0x4f, 0x49, 0x4e, 0x10, 0x09, 0x12,
|
||||
0x09, 0x0a, 0x05, 0x4c, 0x45, 0x41, 0x56, 0x45, 0x10, 0x0a, 0x12, 0x09, 0x0a, 0x05, 0x47, 0x52,
|
||||
0x41, 0x46, 0x54, 0x10, 0x0b, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x52, 0x55, 0x4e, 0x45, 0x10, 0x0c,
|
||||
0x12, 0x19, 0x0a, 0x15, 0x55, 0x4e, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x41, 0x42, 0x4c,
|
||||
0x45, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x0d, 0x42, 0x07, 0x0a, 0x05, 0x5f,
|
||||
0x74, 0x79, 0x70, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, 0x42,
|
||||
0x0c, 0x0a, 0x0a, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x11, 0x0a,
|
||||
0x0f, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65,
|
||||
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x64, 0x65, 0x6c, 0x69,
|
||||
0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x61,
|
||||
0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76,
|
||||
0x65, 0x50, 0x65, 0x65, 0x72, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x72, 0x65, 0x63, 0x76, 0x52, 0x50,
|
||||
0x43, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x52, 0x50, 0x43, 0x42, 0x0a, 0x0a,
|
||||
0x08, 0x5f, 0x64, 0x72, 0x6f, 0x70, 0x52, 0x50, 0x43, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6a, 0x6f,
|
||||
0x69, 0x6e, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x42, 0x08, 0x0a, 0x06,
|
||||
0x5f, 0x67, 0x72, 0x61, 0x66, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x70, 0x72, 0x75, 0x6e, 0x65,
|
||||
0x42, 0x17, 0x0a, 0x15, 0x5f, 0x75, 0x6e, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x61, 0x62,
|
||||
0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x42, 0x0a, 0x0f, 0x54, 0x72, 0x61,
|
||||
0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x2f, 0x0a, 0x05,
|
||||
0x62, 0x61, 0x74, 0x63, 0x68, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x62, 0x6c,
|
||||
0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63,
|
||||
0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x62, 0x61, 0x74, 0x63, 0x68, 0x42, 0x43, 0x5a,
|
||||
0x41, 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, 0x67, 0x6f, 0x2d, 0x6c, 0x69,
|
||||
0x62, 0x70, 0x32, 0x70, 0x2d, 0x62, 0x6c, 0x6f, 0x73, 0x73, 0x6f, 0x6d, 0x73, 0x75, 0x62, 0x2f,
|
||||
0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -1761,32 +1856,33 @@ func file_trace_proto_rawDescGZIP() []byte {
|
||||
}
|
||||
|
||||
var file_trace_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_trace_proto_msgTypes = make([]protoimpl.MessageInfo, 23)
|
||||
var file_trace_proto_msgTypes = make([]protoimpl.MessageInfo, 24)
|
||||
var file_trace_proto_goTypes = []interface{}{
|
||||
(TraceEvent_Type)(0), // 0: blossomsub.pb.TraceEvent.Type
|
||||
(*TraceEvent)(nil), // 1: blossomsub.pb.TraceEvent
|
||||
(*TraceEventBatch)(nil), // 2: blossomsub.pb.TraceEventBatch
|
||||
(*TraceEvent_PublishMessage)(nil), // 3: blossomsub.pb.TraceEvent.PublishMessage
|
||||
(*TraceEvent_RejectMessage)(nil), // 4: blossomsub.pb.TraceEvent.RejectMessage
|
||||
(*TraceEvent_DuplicateMessage)(nil), // 5: blossomsub.pb.TraceEvent.DuplicateMessage
|
||||
(*TraceEvent_DeliverMessage)(nil), // 6: blossomsub.pb.TraceEvent.DeliverMessage
|
||||
(*TraceEvent_AddPeer)(nil), // 7: blossomsub.pb.TraceEvent.AddPeer
|
||||
(*TraceEvent_RemovePeer)(nil), // 8: blossomsub.pb.TraceEvent.RemovePeer
|
||||
(*TraceEvent_RecvRPC)(nil), // 9: blossomsub.pb.TraceEvent.RecvRPC
|
||||
(*TraceEvent_SendRPC)(nil), // 10: blossomsub.pb.TraceEvent.SendRPC
|
||||
(*TraceEvent_DropRPC)(nil), // 11: blossomsub.pb.TraceEvent.DropRPC
|
||||
(*TraceEvent_Join)(nil), // 12: blossomsub.pb.TraceEvent.Join
|
||||
(*TraceEvent_Leave)(nil), // 13: blossomsub.pb.TraceEvent.Leave
|
||||
(*TraceEvent_Graft)(nil), // 14: blossomsub.pb.TraceEvent.Graft
|
||||
(*TraceEvent_Prune)(nil), // 15: blossomsub.pb.TraceEvent.Prune
|
||||
(*TraceEvent_RPCMeta)(nil), // 16: blossomsub.pb.TraceEvent.RPCMeta
|
||||
(*TraceEvent_MessageMeta)(nil), // 17: blossomsub.pb.TraceEvent.MessageMeta
|
||||
(*TraceEvent_SubMeta)(nil), // 18: blossomsub.pb.TraceEvent.SubMeta
|
||||
(*TraceEvent_ControlMeta)(nil), // 19: blossomsub.pb.TraceEvent.ControlMeta
|
||||
(*TraceEvent_ControlIHaveMeta)(nil), // 20: blossomsub.pb.TraceEvent.ControlIHaveMeta
|
||||
(*TraceEvent_ControlIWantMeta)(nil), // 21: blossomsub.pb.TraceEvent.ControlIWantMeta
|
||||
(*TraceEvent_ControlGraftMeta)(nil), // 22: blossomsub.pb.TraceEvent.ControlGraftMeta
|
||||
(*TraceEvent_ControlPruneMeta)(nil), // 23: blossomsub.pb.TraceEvent.ControlPruneMeta
|
||||
(TraceEvent_Type)(0), // 0: blossomsub.pb.TraceEvent.Type
|
||||
(*TraceEvent)(nil), // 1: blossomsub.pb.TraceEvent
|
||||
(*TraceEventBatch)(nil), // 2: blossomsub.pb.TraceEventBatch
|
||||
(*TraceEvent_PublishMessage)(nil), // 3: blossomsub.pb.TraceEvent.PublishMessage
|
||||
(*TraceEvent_RejectMessage)(nil), // 4: blossomsub.pb.TraceEvent.RejectMessage
|
||||
(*TraceEvent_DuplicateMessage)(nil), // 5: blossomsub.pb.TraceEvent.DuplicateMessage
|
||||
(*TraceEvent_DeliverMessage)(nil), // 6: blossomsub.pb.TraceEvent.DeliverMessage
|
||||
(*TraceEvent_AddPeer)(nil), // 7: blossomsub.pb.TraceEvent.AddPeer
|
||||
(*TraceEvent_RemovePeer)(nil), // 8: blossomsub.pb.TraceEvent.RemovePeer
|
||||
(*TraceEvent_RecvRPC)(nil), // 9: blossomsub.pb.TraceEvent.RecvRPC
|
||||
(*TraceEvent_SendRPC)(nil), // 10: blossomsub.pb.TraceEvent.SendRPC
|
||||
(*TraceEvent_DropRPC)(nil), // 11: blossomsub.pb.TraceEvent.DropRPC
|
||||
(*TraceEvent_Join)(nil), // 12: blossomsub.pb.TraceEvent.Join
|
||||
(*TraceEvent_Leave)(nil), // 13: blossomsub.pb.TraceEvent.Leave
|
||||
(*TraceEvent_Graft)(nil), // 14: blossomsub.pb.TraceEvent.Graft
|
||||
(*TraceEvent_Prune)(nil), // 15: blossomsub.pb.TraceEvent.Prune
|
||||
(*TraceEvent_UndeliverableMessage)(nil), // 16: blossomsub.pb.TraceEvent.UndeliverableMessage
|
||||
(*TraceEvent_RPCMeta)(nil), // 17: blossomsub.pb.TraceEvent.RPCMeta
|
||||
(*TraceEvent_MessageMeta)(nil), // 18: blossomsub.pb.TraceEvent.MessageMeta
|
||||
(*TraceEvent_SubMeta)(nil), // 19: blossomsub.pb.TraceEvent.SubMeta
|
||||
(*TraceEvent_ControlMeta)(nil), // 20: blossomsub.pb.TraceEvent.ControlMeta
|
||||
(*TraceEvent_ControlIHaveMeta)(nil), // 21: blossomsub.pb.TraceEvent.ControlIHaveMeta
|
||||
(*TraceEvent_ControlIWantMeta)(nil), // 22: blossomsub.pb.TraceEvent.ControlIWantMeta
|
||||
(*TraceEvent_ControlGraftMeta)(nil), // 23: blossomsub.pb.TraceEvent.ControlGraftMeta
|
||||
(*TraceEvent_ControlPruneMeta)(nil), // 24: blossomsub.pb.TraceEvent.ControlPruneMeta
|
||||
}
|
||||
var file_trace_proto_depIdxs = []int32{
|
||||
0, // 0: blossomsub.pb.TraceEvent.type:type_name -> blossomsub.pb.TraceEvent.Type
|
||||
@ -1803,22 +1899,23 @@ var file_trace_proto_depIdxs = []int32{
|
||||
13, // 11: blossomsub.pb.TraceEvent.leave:type_name -> blossomsub.pb.TraceEvent.Leave
|
||||
14, // 12: blossomsub.pb.TraceEvent.graft:type_name -> blossomsub.pb.TraceEvent.Graft
|
||||
15, // 13: blossomsub.pb.TraceEvent.prune:type_name -> blossomsub.pb.TraceEvent.Prune
|
||||
1, // 14: blossomsub.pb.TraceEventBatch.batch:type_name -> blossomsub.pb.TraceEvent
|
||||
16, // 15: blossomsub.pb.TraceEvent.RecvRPC.meta:type_name -> blossomsub.pb.TraceEvent.RPCMeta
|
||||
16, // 16: blossomsub.pb.TraceEvent.SendRPC.meta:type_name -> blossomsub.pb.TraceEvent.RPCMeta
|
||||
16, // 17: blossomsub.pb.TraceEvent.DropRPC.meta:type_name -> blossomsub.pb.TraceEvent.RPCMeta
|
||||
17, // 18: blossomsub.pb.TraceEvent.RPCMeta.messages:type_name -> blossomsub.pb.TraceEvent.MessageMeta
|
||||
18, // 19: blossomsub.pb.TraceEvent.RPCMeta.subscription:type_name -> blossomsub.pb.TraceEvent.SubMeta
|
||||
19, // 20: blossomsub.pb.TraceEvent.RPCMeta.control:type_name -> blossomsub.pb.TraceEvent.ControlMeta
|
||||
20, // 21: blossomsub.pb.TraceEvent.ControlMeta.ihave:type_name -> blossomsub.pb.TraceEvent.ControlIHaveMeta
|
||||
21, // 22: blossomsub.pb.TraceEvent.ControlMeta.iwant:type_name -> blossomsub.pb.TraceEvent.ControlIWantMeta
|
||||
22, // 23: blossomsub.pb.TraceEvent.ControlMeta.graft:type_name -> blossomsub.pb.TraceEvent.ControlGraftMeta
|
||||
23, // 24: blossomsub.pb.TraceEvent.ControlMeta.prune:type_name -> blossomsub.pb.TraceEvent.ControlPruneMeta
|
||||
25, // [25:25] is the sub-list for method output_type
|
||||
25, // [25:25] is the sub-list for method input_type
|
||||
25, // [25:25] is the sub-list for extension type_name
|
||||
25, // [25:25] is the sub-list for extension extendee
|
||||
0, // [0:25] is the sub-list for field type_name
|
||||
16, // 14: blossomsub.pb.TraceEvent.undeliverableMessage:type_name -> blossomsub.pb.TraceEvent.UndeliverableMessage
|
||||
1, // 15: blossomsub.pb.TraceEventBatch.batch:type_name -> blossomsub.pb.TraceEvent
|
||||
17, // 16: blossomsub.pb.TraceEvent.RecvRPC.meta:type_name -> blossomsub.pb.TraceEvent.RPCMeta
|
||||
17, // 17: blossomsub.pb.TraceEvent.SendRPC.meta:type_name -> blossomsub.pb.TraceEvent.RPCMeta
|
||||
17, // 18: blossomsub.pb.TraceEvent.DropRPC.meta:type_name -> blossomsub.pb.TraceEvent.RPCMeta
|
||||
18, // 19: blossomsub.pb.TraceEvent.RPCMeta.messages:type_name -> blossomsub.pb.TraceEvent.MessageMeta
|
||||
19, // 20: blossomsub.pb.TraceEvent.RPCMeta.subscription:type_name -> blossomsub.pb.TraceEvent.SubMeta
|
||||
20, // 21: blossomsub.pb.TraceEvent.RPCMeta.control:type_name -> blossomsub.pb.TraceEvent.ControlMeta
|
||||
21, // 22: blossomsub.pb.TraceEvent.ControlMeta.ihave:type_name -> blossomsub.pb.TraceEvent.ControlIHaveMeta
|
||||
22, // 23: blossomsub.pb.TraceEvent.ControlMeta.iwant:type_name -> blossomsub.pb.TraceEvent.ControlIWantMeta
|
||||
23, // 24: blossomsub.pb.TraceEvent.ControlMeta.graft:type_name -> blossomsub.pb.TraceEvent.ControlGraftMeta
|
||||
24, // 25: blossomsub.pb.TraceEvent.ControlMeta.prune:type_name -> blossomsub.pb.TraceEvent.ControlPruneMeta
|
||||
26, // [26:26] is the sub-list for method output_type
|
||||
26, // [26:26] is the sub-list for method input_type
|
||||
26, // [26:26] is the sub-list for extension type_name
|
||||
26, // [26:26] is the sub-list for extension extendee
|
||||
0, // [0:26] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_trace_proto_init() }
|
||||
@ -2008,7 +2105,7 @@ func file_trace_proto_init() {
|
||||
}
|
||||
}
|
||||
file_trace_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*TraceEvent_RPCMeta); i {
|
||||
switch v := v.(*TraceEvent_UndeliverableMessage); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -2020,7 +2117,7 @@ func file_trace_proto_init() {
|
||||
}
|
||||
}
|
||||
file_trace_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*TraceEvent_MessageMeta); i {
|
||||
switch v := v.(*TraceEvent_RPCMeta); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -2032,7 +2129,7 @@ func file_trace_proto_init() {
|
||||
}
|
||||
}
|
||||
file_trace_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*TraceEvent_SubMeta); i {
|
||||
switch v := v.(*TraceEvent_MessageMeta); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -2044,7 +2141,7 @@ func file_trace_proto_init() {
|
||||
}
|
||||
}
|
||||
file_trace_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*TraceEvent_ControlMeta); i {
|
||||
switch v := v.(*TraceEvent_SubMeta); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -2056,7 +2153,7 @@ func file_trace_proto_init() {
|
||||
}
|
||||
}
|
||||
file_trace_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*TraceEvent_ControlIHaveMeta); i {
|
||||
switch v := v.(*TraceEvent_ControlMeta); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -2068,7 +2165,7 @@ func file_trace_proto_init() {
|
||||
}
|
||||
}
|
||||
file_trace_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*TraceEvent_ControlIWantMeta); i {
|
||||
switch v := v.(*TraceEvent_ControlIHaveMeta); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -2080,7 +2177,7 @@ func file_trace_proto_init() {
|
||||
}
|
||||
}
|
||||
file_trace_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*TraceEvent_ControlGraftMeta); i {
|
||||
switch v := v.(*TraceEvent_ControlIWantMeta); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -2092,6 +2189,18 @@ func file_trace_proto_init() {
|
||||
}
|
||||
}
|
||||
file_trace_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*TraceEvent_ControlGraftMeta); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_trace_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*TraceEvent_ControlPruneMeta); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@ -2121,16 +2230,17 @@ func file_trace_proto_init() {
|
||||
file_trace_proto_msgTypes[15].OneofWrappers = []interface{}{}
|
||||
file_trace_proto_msgTypes[16].OneofWrappers = []interface{}{}
|
||||
file_trace_proto_msgTypes[17].OneofWrappers = []interface{}{}
|
||||
file_trace_proto_msgTypes[19].OneofWrappers = []interface{}{}
|
||||
file_trace_proto_msgTypes[21].OneofWrappers = []interface{}{}
|
||||
file_trace_proto_msgTypes[18].OneofWrappers = []interface{}{}
|
||||
file_trace_proto_msgTypes[20].OneofWrappers = []interface{}{}
|
||||
file_trace_proto_msgTypes[22].OneofWrappers = []interface{}{}
|
||||
file_trace_proto_msgTypes[23].OneofWrappers = []interface{}{}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_trace_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 23,
|
||||
NumMessages: 24,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
@ -22,6 +22,7 @@ message TraceEvent {
|
||||
optional Leave leave = 14;
|
||||
optional Graft graft = 15;
|
||||
optional Prune prune = 16;
|
||||
optional UndeliverableMessage undeliverableMessage = 17;
|
||||
|
||||
enum Type {
|
||||
PUBLISH_MESSAGE = 0;
|
||||
@ -37,6 +38,7 @@ message TraceEvent {
|
||||
LEAVE = 10;
|
||||
GRAFT = 11;
|
||||
PRUNE = 12;
|
||||
UNDELIVERABLE_MESSAGE = 13;
|
||||
}
|
||||
|
||||
message PublishMessage {
|
||||
@ -105,6 +107,12 @@ message TraceEvent {
|
||||
optional bytes bitmask = 2;
|
||||
}
|
||||
|
||||
message UndeliverableMessage {
|
||||
optional bytes messageID = 1;
|
||||
optional bytes bitmask = 2;
|
||||
optional bytes receivedFrom = 3;
|
||||
}
|
||||
|
||||
message RPCMeta {
|
||||
repeated MessageMeta messages = 1;
|
||||
repeated SubMeta subscription = 2;
|
||||
|
@ -204,13 +204,12 @@ func newPeerGater(ctx context.Context, host host.Host, params *PeerGaterParams)
|
||||
func (pg *peerGater) background(ctx context.Context) {
|
||||
tick := time.NewTicker(pg.params.DecayInterval)
|
||||
|
||||
defer tick.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-tick.C:
|
||||
pg.decayStats()
|
||||
case <-ctx.Done():
|
||||
tick.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -218,7 +217,6 @@ func (pg *peerGater) background(ctx context.Context) {
|
||||
|
||||
func (pg *peerGater) decayStats() {
|
||||
pg.Lock()
|
||||
defer pg.Unlock()
|
||||
|
||||
pg.validate *= pg.params.GlobalDecay
|
||||
if pg.validate < pg.params.DecayToZero {
|
||||
@ -256,6 +254,8 @@ func (pg *peerGater) decayStats() {
|
||||
delete(pg.ipStats, ip)
|
||||
}
|
||||
}
|
||||
|
||||
pg.Unlock()
|
||||
}
|
||||
|
||||
func (pg *peerGater) getPeerStats(p peer.ID) *peerGaterStats {
|
||||
@ -323,21 +323,23 @@ func (pg *peerGater) AcceptFrom(p peer.ID) AcceptStatus {
|
||||
}
|
||||
|
||||
pg.Lock()
|
||||
defer pg.Unlock()
|
||||
|
||||
// check the quiet period; if the validation queue has not throttled for more than the Quiet
|
||||
// interval, we turn off the circuit breaker and accept.
|
||||
if time.Since(pg.lastThrottle) > pg.params.Quiet {
|
||||
pg.Unlock()
|
||||
return AcceptAll
|
||||
}
|
||||
|
||||
// no throttle events -- or they have decayed; accept.
|
||||
if pg.throttle == 0 {
|
||||
pg.Unlock()
|
||||
return AcceptAll
|
||||
}
|
||||
|
||||
// check the throttle/validate ration; if it is below threshold we accept.
|
||||
if pg.validate != 0 && pg.throttle/pg.validate < pg.params.Threshold {
|
||||
pg.Unlock()
|
||||
return AcceptAll
|
||||
}
|
||||
|
||||
@ -346,6 +348,7 @@ func (pg *peerGater) AcceptFrom(p peer.ID) AcceptStatus {
|
||||
// compute the goodput of the peer; the denominator is the weighted mix of message counters
|
||||
total := st.deliver + pg.params.DuplicateWeight*st.duplicate + pg.params.IgnoreWeight*st.ignore + pg.params.RejectWeight*st.reject
|
||||
if total == 0 {
|
||||
pg.Unlock()
|
||||
return AcceptAll
|
||||
}
|
||||
|
||||
@ -355,10 +358,12 @@ func (pg *peerGater) AcceptFrom(p peer.ID) AcceptStatus {
|
||||
// accepted; this is not a sinkhole/blacklist.
|
||||
threshold := (1 + st.deliver) / (1 + total)
|
||||
if rand.Float64() < threshold {
|
||||
pg.Unlock()
|
||||
return AcceptAll
|
||||
}
|
||||
|
||||
log.Debugf("throttling peer %s with threshold %f", p, threshold)
|
||||
pg.Unlock()
|
||||
return AcceptControl
|
||||
}
|
||||
|
||||
@ -368,21 +373,21 @@ var _ RawTracer = (*peerGater)(nil)
|
||||
// tracer interface
|
||||
func (pg *peerGater) AddPeer(p peer.ID, proto protocol.ID) {
|
||||
pg.Lock()
|
||||
defer pg.Unlock()
|
||||
|
||||
st := pg.getPeerStats(p)
|
||||
st.connected++
|
||||
pg.Unlock()
|
||||
}
|
||||
|
||||
func (pg *peerGater) RemovePeer(p peer.ID) {
|
||||
pg.Lock()
|
||||
defer pg.Unlock()
|
||||
|
||||
st := pg.getPeerStats(p)
|
||||
st.connected--
|
||||
st.expire = time.Now().Add(pg.params.RetainStats)
|
||||
|
||||
delete(pg.peerStats, p)
|
||||
pg.Unlock()
|
||||
}
|
||||
|
||||
func (pg *peerGater) Join(bitmask []byte) {}
|
||||
@ -392,14 +397,13 @@ func (pg *peerGater) Prune(p peer.ID, bitmask []byte) {}
|
||||
|
||||
func (pg *peerGater) ValidateMessage(msg *Message) {
|
||||
pg.Lock()
|
||||
defer pg.Unlock()
|
||||
|
||||
pg.validate++
|
||||
pg.Unlock()
|
||||
}
|
||||
|
||||
func (pg *peerGater) DeliverMessage(msg *Message) {
|
||||
pg.Lock()
|
||||
defer pg.Unlock()
|
||||
|
||||
st := pg.getPeerStats(msg.ReceivedFrom)
|
||||
|
||||
@ -411,11 +415,11 @@ func (pg *peerGater) DeliverMessage(msg *Message) {
|
||||
}
|
||||
|
||||
st.deliver += weight
|
||||
pg.Unlock()
|
||||
}
|
||||
|
||||
func (pg *peerGater) RejectMessage(msg *Message, reason string) {
|
||||
pg.Lock()
|
||||
defer pg.Unlock()
|
||||
|
||||
switch reason {
|
||||
case RejectValidationQueueFull:
|
||||
@ -432,14 +436,15 @@ func (pg *peerGater) RejectMessage(msg *Message, reason string) {
|
||||
st := pg.getPeerStats(msg.ReceivedFrom)
|
||||
st.reject++
|
||||
}
|
||||
pg.Unlock()
|
||||
}
|
||||
|
||||
func (pg *peerGater) DuplicateMessage(msg *Message) {
|
||||
pg.Lock()
|
||||
defer pg.Unlock()
|
||||
|
||||
st := pg.getPeerStats(msg.ReceivedFrom)
|
||||
st.duplicate++
|
||||
pg.Unlock()
|
||||
}
|
||||
|
||||
func (pg *peerGater) ThrottlePeer(p peer.ID) {}
|
||||
|
112
go-libp2p-blossomsub/peer_notify.go
Normal file
112
go-libp2p-blossomsub/peer_notify.go
Normal file
@ -0,0 +1,112 @@
|
||||
package blossomsub
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/event"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
)
|
||||
|
||||
func (ps *PubSub) watchForNewPeers(ctx context.Context) {
|
||||
// We don't bother subscribing to "connectivity" events because we always run identify after
|
||||
// every new connection.
|
||||
sub, err := ps.host.EventBus().Subscribe([]interface{}{
|
||||
&event.EvtPeerIdentificationCompleted{},
|
||||
&event.EvtPeerProtocolsUpdated{},
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("failed to subscribe to peer identification events: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
ps.newPeersPrioLk.RLock()
|
||||
ps.newPeersMx.Lock()
|
||||
for _, pid := range ps.host.Network().Peers() {
|
||||
if ps.host.Network().Connectedness(pid) != network.Connected {
|
||||
continue
|
||||
}
|
||||
ps.newPeersPend[pid] = struct{}{}
|
||||
}
|
||||
ps.newPeersMx.Unlock()
|
||||
ps.newPeersPrioLk.RUnlock()
|
||||
|
||||
select {
|
||||
case ps.newPeers <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
|
||||
var supportsProtocol func(protocol.ID) bool
|
||||
if ps.protoMatchFunc != nil {
|
||||
var supportedProtocols []func(protocol.ID) bool
|
||||
for _, proto := range ps.rt.Protocols() {
|
||||
|
||||
supportedProtocols = append(supportedProtocols, ps.protoMatchFunc(proto))
|
||||
}
|
||||
supportsProtocol = func(proto protocol.ID) bool {
|
||||
for _, fn := range supportedProtocols {
|
||||
if (fn)(proto) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
supportedProtocols := make(map[protocol.ID]struct{})
|
||||
for _, proto := range ps.rt.Protocols() {
|
||||
supportedProtocols[proto] = struct{}{}
|
||||
}
|
||||
supportsProtocol = func(proto protocol.ID) bool {
|
||||
_, ok := supportedProtocols[proto]
|
||||
return ok
|
||||
}
|
||||
}
|
||||
|
||||
for ctx.Err() == nil {
|
||||
var ev any
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
sub.Close()
|
||||
return
|
||||
case ev = <-sub.Out():
|
||||
}
|
||||
|
||||
var protos []protocol.ID
|
||||
var peer peer.ID
|
||||
switch ev := ev.(type) {
|
||||
case event.EvtPeerIdentificationCompleted:
|
||||
peer = ev.Peer
|
||||
protos = ev.Protocols
|
||||
case event.EvtPeerProtocolsUpdated:
|
||||
peer = ev.Peer
|
||||
protos = ev.Added
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
// We don't bother checking connectivity (connected and non-"limited") here because
|
||||
// we'll check when actually handling the new peer.
|
||||
|
||||
for _, p := range protos {
|
||||
if supportsProtocol(p) {
|
||||
ps.notifyNewPeer(peer)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
sub.Close()
|
||||
}
|
||||
|
||||
func (ps *PubSub) notifyNewPeer(peer peer.ID) {
|
||||
ps.newPeersPrioLk.RLock()
|
||||
ps.newPeersMx.Lock()
|
||||
ps.newPeersPend[peer] = struct{}{}
|
||||
ps.newPeersMx.Unlock()
|
||||
ps.newPeersPrioLk.RUnlock()
|
||||
|
||||
select {
|
||||
case ps.newPeers <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
@ -1,11 +1,14 @@
|
||||
package blossomsub
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"slices"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@ -23,8 +26,8 @@ import (
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
)
|
||||
|
||||
// DefaultMaximumMessageSize is 16.7 MB.
|
||||
const DefaultMaxMessageSize = 1 << 24
|
||||
// DefaultMaximumMessageSize is 1 MB.
|
||||
const DefaultMaxMessageSize = 1 << 20
|
||||
|
||||
var (
|
||||
// TimeCacheDuration specifies how long a message ID will be remembered as seen.
|
||||
@ -147,7 +150,8 @@ type PubSub struct {
|
||||
blacklist Blacklist
|
||||
blacklistPeer chan peer.ID
|
||||
|
||||
peers map[peer.ID]chan *RPC
|
||||
peers map[peer.ID]chan *RPC
|
||||
peersMx sync.RWMutex
|
||||
|
||||
inboundStreamsMx sync.Mutex
|
||||
inboundStreams map[peer.ID]network.Stream
|
||||
@ -231,7 +235,7 @@ const (
|
||||
|
||||
type Message struct {
|
||||
*pb.Message
|
||||
ID string
|
||||
ID []byte
|
||||
ReceivedFrom peer.ID
|
||||
ValidatorData interface{}
|
||||
Local bool
|
||||
@ -242,7 +246,7 @@ func (m *Message) GetFrom() peer.ID {
|
||||
}
|
||||
|
||||
type RPC struct {
|
||||
pb.RPC
|
||||
*pb.RPC
|
||||
|
||||
// unexported on purpose, not sending this over the wire
|
||||
from peer.ID
|
||||
@ -263,7 +267,7 @@ func NewPubSub(ctx context.Context, h host.Host, rt PubSubRouter, opts ...Option
|
||||
peerOutboundQueueSize: 32,
|
||||
signID: h.ID(),
|
||||
signKey: nil,
|
||||
signPolicy: StrictSign,
|
||||
signPolicy: LaxSign,
|
||||
incoming: make(chan *RPC, 32),
|
||||
newPeers: make(chan struct{}, 1),
|
||||
newPeersPend: make(map[peer.ID]struct{}),
|
||||
@ -330,20 +334,19 @@ func NewPubSub(ctx context.Context, h host.Host, rt PubSubRouter, opts ...Option
|
||||
h.SetStreamHandler(id, ps.handleNewStream)
|
||||
}
|
||||
}
|
||||
h.Network().Notify((*PubSubNotif)(ps))
|
||||
|
||||
go ps.watchForNewPeers(ctx)
|
||||
|
||||
ps.val.Start(ps)
|
||||
|
||||
go ps.processLoop(ctx)
|
||||
|
||||
(*PubSubNotif)(ps).Initialize()
|
||||
|
||||
return ps, nil
|
||||
}
|
||||
|
||||
// MsgIdFunction returns a unique ID for the passed Message, and PubSub can be customized to use any
|
||||
// implementation of this function by configuring it with the Option from WithMessageIdFn.
|
||||
type MsgIdFunction func(pmsg *pb.Message) string
|
||||
type MsgIdFunction func(pmsg *pb.Message) []byte
|
||||
|
||||
// WithMessageIdFn is an option to customize the way a message ID is computed for a pubsub message.
|
||||
// The default ID function is DefaultMsgIdFn (concatenate source and seq nr.),
|
||||
@ -495,14 +498,14 @@ func WithRawTracer(tracer RawTracer) Option {
|
||||
}
|
||||
|
||||
// WithMaxMessageSize sets the global maximum message size for pubsub wire
|
||||
// messages. The default value is 16.7MiB (DefaultMaxMessageSize).
|
||||
// messages. The default value is 1MiB (DefaultMaxMessageSize).
|
||||
//
|
||||
// Observe the following warnings when setting this option.
|
||||
//
|
||||
// WARNING #1: Make sure to change the default protocol prefixes for floodsub
|
||||
// (FloodSubID) and BlossomSub (BlossomSubID). This avoids accidentally joining
|
||||
// the public default network, which uses the default max message size, and
|
||||
// therefore will cause messages to be dropped.
|
||||
// WARNING #1: Make sure to change the default protocol prefixes for BlossomSub
|
||||
// (BlossomSubID). This avoids accidentally joining the public default network,
|
||||
// which uses the default max message size, and therefore will cause messages to
|
||||
// be dropped.
|
||||
//
|
||||
// WARNING #2: Reducing the default max message limit is fine, if you are
|
||||
// certain that your application messages will not exceed the new limit.
|
||||
@ -563,11 +566,13 @@ func WithAppSpecificRpcInspector(inspector func(peer.ID, *RPC) error) Option {
|
||||
// processLoop handles all inputs arriving on the channels
|
||||
func (p *PubSub) processLoop(ctx context.Context) {
|
||||
defer func() {
|
||||
p.peersMx.Lock()
|
||||
// Clean up go routines.
|
||||
for _, ch := range p.peers {
|
||||
close(ch)
|
||||
}
|
||||
p.peers = nil
|
||||
p.peersMx.Unlock()
|
||||
p.bitmasks = nil
|
||||
p.seenMessages.Done()
|
||||
}()
|
||||
@ -580,7 +585,9 @@ func (p *PubSub) processLoop(ctx context.Context) {
|
||||
case s := <-p.newPeerStream:
|
||||
pid := s.Conn().RemotePeer()
|
||||
|
||||
p.peersMx.RLock()
|
||||
ch, ok := p.peers[pid]
|
||||
p.peersMx.RUnlock()
|
||||
if !ok {
|
||||
log.Warn("new stream for unknown peer: ", pid)
|
||||
s.Reset()
|
||||
@ -590,7 +597,9 @@ func (p *PubSub) processLoop(ctx context.Context) {
|
||||
if p.blacklist.Contains(pid) {
|
||||
log.Warn("closing stream for blacklisted peer: ", pid)
|
||||
close(ch)
|
||||
p.peersMx.Lock()
|
||||
delete(p.peers, pid)
|
||||
p.peersMx.Unlock()
|
||||
s.Reset()
|
||||
continue
|
||||
}
|
||||
@ -598,7 +607,9 @@ func (p *PubSub) processLoop(ctx context.Context) {
|
||||
p.rt.AddPeer(pid, s.Protocol())
|
||||
|
||||
case pid := <-p.newPeerError:
|
||||
p.peersMx.Lock()
|
||||
delete(p.peers, pid)
|
||||
p.peersMx.Unlock()
|
||||
|
||||
case <-p.peerDead:
|
||||
p.handleDeadPeers()
|
||||
@ -622,22 +633,13 @@ func (p *PubSub) processLoop(ctx context.Context) {
|
||||
case bitmask := <-p.rmRelay:
|
||||
p.handleRemoveRelay([]byte(bitmask))
|
||||
case preq := <-p.getPeers:
|
||||
tmap, ok := p.bitmasks[string(preq.bitmask)]
|
||||
if preq.bitmask != nil && !ok {
|
||||
peers := p.getPeersInBitmask(preq.bitmask)
|
||||
|
||||
if len(peers) == 0 {
|
||||
preq.resp <- nil
|
||||
continue
|
||||
} else {
|
||||
preq.resp <- peers
|
||||
}
|
||||
var peers []peer.ID
|
||||
for p := range p.peers {
|
||||
if preq.bitmask != nil {
|
||||
_, ok := tmap[p]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
peers = append(peers, p)
|
||||
}
|
||||
preq.resp <- peers
|
||||
case rpc := <-p.incoming:
|
||||
p.handleIncomingRPC(rpc)
|
||||
|
||||
@ -657,10 +659,14 @@ func (p *PubSub) processLoop(ctx context.Context) {
|
||||
log.Infof("Blacklisting peer %s", pid)
|
||||
p.blacklist.Add(pid)
|
||||
|
||||
p.peersMx.RLock()
|
||||
ch, ok := p.peers[pid]
|
||||
p.peersMx.RUnlock()
|
||||
if ok {
|
||||
close(ch)
|
||||
p.peersMx.Lock()
|
||||
delete(p.peers, pid)
|
||||
p.peersMx.Unlock()
|
||||
for t, tmap := range p.bitmasks {
|
||||
if _, ok := tmap[pid]; ok {
|
||||
delete(tmap, pid)
|
||||
@ -677,6 +683,49 @@ func (p *PubSub) processLoop(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PubSub) getPeersInBitmask(bitmask []byte) []peer.ID {
|
||||
bitmaskSlices := SliceBitmask(bitmask)
|
||||
var peers []peer.ID
|
||||
peerloop:
|
||||
for _, slice := range bitmaskSlices {
|
||||
tmap, ok := p.bitmasks[string(slice)]
|
||||
if !ok {
|
||||
peers = []peer.ID{}
|
||||
break peerloop
|
||||
}
|
||||
|
||||
var peerset []peer.ID
|
||||
p.peersMx.RLock()
|
||||
for p := range p.peers {
|
||||
_, ok := tmap[p]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
peerset = append(peerset, p)
|
||||
}
|
||||
p.peersMx.RUnlock()
|
||||
|
||||
if len(peers) == 0 {
|
||||
peers = peerset
|
||||
} else {
|
||||
var update []peer.ID
|
||||
for _, p := range peers {
|
||||
if slices.Contains(peerset, p) {
|
||||
update = append(update, p)
|
||||
}
|
||||
}
|
||||
|
||||
peers = update
|
||||
|
||||
if len(update) == 0 {
|
||||
break peerloop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return peers
|
||||
}
|
||||
|
||||
func (p *PubSub) handlePendingPeers() {
|
||||
p.newPeersPrioLk.Lock()
|
||||
|
||||
@ -694,10 +743,13 @@ func (p *PubSub) handlePendingPeers() {
|
||||
continue
|
||||
}
|
||||
|
||||
p.peersMx.RLock()
|
||||
if _, ok := p.peers[pid]; ok {
|
||||
p.peersMx.RUnlock()
|
||||
log.Debug("already have connection to peer: ", pid)
|
||||
continue
|
||||
}
|
||||
p.peersMx.RUnlock()
|
||||
|
||||
if p.blacklist.Contains(pid) {
|
||||
log.Warn("ignoring connection from blacklisted peer: ", pid)
|
||||
@ -707,7 +759,9 @@ func (p *PubSub) handlePendingPeers() {
|
||||
messages := make(chan *RPC, p.peerOutboundQueueSize)
|
||||
messages <- p.getHelloPacket()
|
||||
go p.handleNewPeer(p.ctx, pid, messages)
|
||||
p.peersMx.Lock()
|
||||
p.peers[pid] = messages
|
||||
p.peersMx.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
@ -724,13 +778,17 @@ func (p *PubSub) handleDeadPeers() {
|
||||
p.peerDeadPrioLk.Unlock()
|
||||
|
||||
for pid := range deadPeers {
|
||||
p.peersMx.RLock()
|
||||
ch, ok := p.peers[pid]
|
||||
p.peersMx.RUnlock()
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
close(ch)
|
||||
p.peersMx.Lock()
|
||||
delete(p.peers, pid)
|
||||
p.peersMx.Unlock()
|
||||
|
||||
for t, tmap := range p.bitmasks {
|
||||
if _, ok := tmap[pid]; ok {
|
||||
@ -753,7 +811,9 @@ func (p *PubSub) handleDeadPeers() {
|
||||
log.Debugf("peer declared dead but still connected; respawning writer: %s", pid)
|
||||
messages := make(chan *RPC, p.peerOutboundQueueSize)
|
||||
messages <- p.getHelloPacket()
|
||||
p.peersMx.Lock()
|
||||
p.peers[pid] = messages
|
||||
p.peersMx.Unlock()
|
||||
go p.handleNewPeerWithBackoff(p.ctx, pid, backoffDelay, messages)
|
||||
}
|
||||
}
|
||||
@ -917,6 +977,7 @@ func (p *PubSub) announce(bitmask []byte, sub bool) {
|
||||
}
|
||||
|
||||
out := rpcWithSubs(subopt)
|
||||
p.peersMx.RLock()
|
||||
for pid, peer := range p.peers {
|
||||
select {
|
||||
case peer <- out:
|
||||
@ -927,6 +988,7 @@ func (p *PubSub) announce(bitmask []byte, sub bool) {
|
||||
go p.announceRetry(pid, bitmask, sub)
|
||||
}
|
||||
}
|
||||
p.peersMx.RUnlock()
|
||||
}
|
||||
|
||||
func (p *PubSub) announceRetry(pid peer.ID, bitmask []byte, sub bool) {
|
||||
@ -950,7 +1012,9 @@ func (p *PubSub) announceRetry(pid peer.ID, bitmask []byte, sub bool) {
|
||||
}
|
||||
|
||||
func (p *PubSub) doAnnounceRetry(pid peer.ID, bitmask []byte, sub bool) {
|
||||
p.peersMx.RLock()
|
||||
peer, ok := p.peers[pid]
|
||||
p.peersMx.RUnlock()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@ -975,14 +1039,13 @@ func (p *PubSub) doAnnounceRetry(pid peer.ID, bitmask []byte, sub bool) {
|
||||
// Only called from processLoop.
|
||||
func (p *PubSub) notifySubs(msg *Message) {
|
||||
bitmask := msg.GetBitmask()
|
||||
subs := p.mySubs[string(bitmask)]
|
||||
slices := SliceBitmask(bitmask)
|
||||
// o := rand.Intn(len(slices))
|
||||
subs := p.mySubs[string(slices[0])]
|
||||
for f := range subs {
|
||||
select {
|
||||
case f.ch <- msg:
|
||||
case <-time.After(5 * time.Millisecond):
|
||||
// it's unreasonable to immediately fall over because a subscriber didn't
|
||||
// answer, message delivery sometimes lands next nanosecond and dropping
|
||||
// it when there's room is absurd.
|
||||
default:
|
||||
p.tracer.UndeliverableMessage(msg)
|
||||
log.Infof("Can't deliver message to subscription for bitmask %x; subscriber too slow", bitmask)
|
||||
}
|
||||
@ -990,14 +1053,14 @@ func (p *PubSub) notifySubs(msg *Message) {
|
||||
}
|
||||
|
||||
// seenMessage returns whether we already saw this message before
|
||||
func (p *PubSub) seenMessage(id string) bool {
|
||||
return p.seenMessages.Has(id)
|
||||
func (p *PubSub) seenMessage(id []byte) bool {
|
||||
return p.seenMessages.Has(string(id))
|
||||
}
|
||||
|
||||
// markSeen marks a message as seen such that seenMessage returns `true' for the given id
|
||||
// returns true if the message was freshly marked
|
||||
func (p *PubSub) markSeen(id string) bool {
|
||||
return p.seenMessages.Add(id)
|
||||
func (p *PubSub) markSeen(id []byte) bool {
|
||||
return p.seenMessages.Add(string(id))
|
||||
}
|
||||
|
||||
// subscribedToMessage returns whether we are subscribed to one of the bitmasks
|
||||
@ -1008,9 +1071,15 @@ func (p *PubSub) subscribedToMsg(msg *pb.Message) bool {
|
||||
}
|
||||
|
||||
bitmask := msg.GetBitmask()
|
||||
_, ok := p.mySubs[string(bitmask)]
|
||||
slices := SliceBitmask(bitmask)
|
||||
for _, slice := range slices {
|
||||
_, ok := p.mySubs[string(slice)]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return ok
|
||||
return true
|
||||
}
|
||||
|
||||
// canRelayMsg returns whether we are able to relay for one of the bitmasks
|
||||
@ -1021,9 +1090,15 @@ func (p *PubSub) canRelayMsg(msg *pb.Message) bool {
|
||||
}
|
||||
|
||||
bitmask := msg.GetBitmask()
|
||||
relays := p.myRelays[string(bitmask)]
|
||||
slices := SliceBitmask(bitmask)
|
||||
for _, slice := range slices {
|
||||
relays := p.myRelays[string(slice)]
|
||||
if relays > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return relays > 0
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *PubSub) notifyLeave(bitmask []byte, pid peer.ID) {
|
||||
@ -1049,7 +1124,7 @@ func (p *PubSub) handleIncomingRPC(rpc *RPC) {
|
||||
var err error
|
||||
subs, err = p.subFilter.FilterIncomingSubscriptions(rpc.from, subs)
|
||||
if err != nil {
|
||||
log.Debugf("subscription filter error: %s; ignoring RPC", err)
|
||||
log.Debugf("subscription filter error: %s; ignoring RPC\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -1103,7 +1178,7 @@ func (p *PubSub) handleIncomingRPC(rpc *RPC) {
|
||||
continue
|
||||
}
|
||||
|
||||
p.pushMsg(&Message{pmsg, "", rpc.from, nil, false})
|
||||
p.pushMsg(&Message{pmsg, []byte{}, rpc.from, nil, false})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1111,8 +1186,10 @@ func (p *PubSub) handleIncomingRPC(rpc *RPC) {
|
||||
}
|
||||
|
||||
// DefaultMsgIdFn returns a unique ID of the passed Message
|
||||
func DefaultMsgIdFn(pmsg *pb.Message) string {
|
||||
return string(pmsg.GetFrom()) + string(pmsg.GetSeqno())
|
||||
func DefaultMsgIdFn(pmsg *pb.Message) []byte {
|
||||
h := sha256.New()
|
||||
h.Write(pmsg.Data)
|
||||
return h.Sum([]byte{0x01})
|
||||
}
|
||||
|
||||
// DefaultPeerFilter accepts all peers on all bitmasks
|
||||
@ -1233,59 +1310,75 @@ func (p *PubSub) PeerScore(pr peer.ID) float64 {
|
||||
return p.rt.PeerScore(pr)
|
||||
}
|
||||
|
||||
// Join joins the bitmask and returns a Bitmask handle. Only one Bitmask handle should exist per bitmask, and Join will error if
|
||||
// the Bitmask handle already exists.
|
||||
func (p *PubSub) Join(bitmask []byte, opts ...BitmaskOpt) (*Bitmask, error) {
|
||||
t, ok, err := p.tryJoin(bitmask, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Join joins the bitmasks and returns a set of Bitmask handles. Only one Bitmask
|
||||
// handle should exist per bit, and Join will error if all the Bitmask handles already exist.
|
||||
func (p *PubSub) Join(bitmask []byte, opts ...BitmaskOpt) ([]*Bitmask, error) {
|
||||
ts, news, errs := p.tryJoin(bitmask, opts...)
|
||||
if len(errs) != 0 {
|
||||
return nil, errors.Join(errs...)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
if !slices.Contains(news, true) {
|
||||
return nil, fmt.Errorf("bitmask already exists")
|
||||
}
|
||||
|
||||
return t, nil
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
// tryJoin is an internal function that tries to join a bitmask
|
||||
// Returns the bitmask if it can be created or found
|
||||
// Returns true if the bitmask was newly created, false otherwise
|
||||
// Can be removed once pubsub.Publish() and pubsub.Subscribe() are removed
|
||||
func (p *PubSub) tryJoin(bitmask []byte, opts ...BitmaskOpt) (*Bitmask, bool, error) {
|
||||
func (p *PubSub) tryJoin(bitmask []byte, opts ...BitmaskOpt) ([]*Bitmask, []bool, []error) {
|
||||
if p.subFilter != nil && !p.subFilter.CanSubscribe(bitmask) {
|
||||
return nil, false, fmt.Errorf("bitmask is not allowed by the subscription filter")
|
||||
return nil, nil, []error{fmt.Errorf("bitmask is not allowed by the subscription filter")}
|
||||
}
|
||||
|
||||
t := &Bitmask{
|
||||
p: p,
|
||||
bitmask: bitmask,
|
||||
evtHandlers: make(map[*BitmaskEventHandler]struct{}),
|
||||
}
|
||||
sliced := SliceBitmask(bitmask)
|
||||
var bitmasks []*Bitmask
|
||||
var newBitmasks []bool
|
||||
var errors []error
|
||||
|
||||
for _, opt := range opts {
|
||||
err := opt(t)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
loop:
|
||||
for _, slice := range sliced {
|
||||
slice := slice
|
||||
|
||||
t := &Bitmask{
|
||||
p: p,
|
||||
bitmask: slice,
|
||||
evtHandlers: make(map[*BitmaskEventHandler]struct{}),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
err := opt(t)
|
||||
if err != nil {
|
||||
errors = append(errors, err)
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
|
||||
resp := make(chan *Bitmask, 1)
|
||||
select {
|
||||
case t.p.addBitmask <- &addBitmaskReq{
|
||||
bitmask: t,
|
||||
resp: resp,
|
||||
}:
|
||||
case <-t.p.ctx.Done():
|
||||
errors = append(errors, t.p.ctx.Err())
|
||||
continue loop
|
||||
}
|
||||
returnedBitmask := <-resp
|
||||
|
||||
if returnedBitmask != t {
|
||||
bitmasks = append(bitmasks, returnedBitmask)
|
||||
newBitmasks = append(newBitmasks, false)
|
||||
} else {
|
||||
bitmasks = append(bitmasks, t)
|
||||
newBitmasks = append(newBitmasks, true)
|
||||
}
|
||||
}
|
||||
|
||||
resp := make(chan *Bitmask, 1)
|
||||
select {
|
||||
case t.p.addBitmask <- &addBitmaskReq{
|
||||
bitmask: t,
|
||||
resp: resp,
|
||||
}:
|
||||
case <-t.p.ctx.Done():
|
||||
return nil, false, t.p.ctx.Err()
|
||||
}
|
||||
returnedBitmask := <-resp
|
||||
|
||||
if returnedBitmask != t {
|
||||
return returnedBitmask, false, nil
|
||||
}
|
||||
|
||||
return t, true, nil
|
||||
return bitmasks, newBitmasks, errors
|
||||
}
|
||||
|
||||
type addSubReq struct {
|
||||
@ -1300,14 +1393,24 @@ type SubOpt func(sub *Subscription) error
|
||||
// before the subscription is processed by the pubsub main loop and propagated to our peers.
|
||||
//
|
||||
// Deprecated: use pubsub.Join() and bitmask.Subscribe() instead
|
||||
func (p *PubSub) Subscribe(bitmask []byte, opts ...SubOpt) (*Subscription, error) {
|
||||
func (p *PubSub) Subscribe(bitmask []byte, opts ...SubOpt) ([]*Subscription, error) {
|
||||
// ignore whether the bitmask was newly created or not, since either way we have a valid bitmask to work with
|
||||
bitmaskHandle, _, err := p.tryJoin(bitmask)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
bitmaskHandles, _, errs := p.tryJoin(bitmask)
|
||||
if len(errs) != 0 {
|
||||
return nil, errors.Join(errs...)
|
||||
}
|
||||
|
||||
return bitmaskHandle.Subscribe(opts...)
|
||||
var subs []*Subscription
|
||||
for _, handle := range bitmaskHandles {
|
||||
sub, err := handle.Subscribe(opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
subs = append(subs, sub)
|
||||
}
|
||||
|
||||
return subs, nil
|
||||
}
|
||||
|
||||
// WithBufferSize is a Subscribe option to customize the size of the subscribe output buffer.
|
||||
@ -1335,17 +1438,20 @@ func (p *PubSub) GetBitmasks() []string {
|
||||
return <-out
|
||||
}
|
||||
|
||||
// Publish publishes data to the given bitmask.
|
||||
//
|
||||
// Deprecated: use pubsub.Join() and bitmask.Publish() instead
|
||||
func (p *PubSub) Publish(bitmask []byte, data []byte, opts ...PubOpt) error {
|
||||
// ignore whether the bitmask was newly created or not, since either way we have a valid bitmask to work with
|
||||
t, _, err := p.tryJoin(bitmask)
|
||||
if err != nil {
|
||||
return err
|
||||
func (p *PubSub) Publish(ctx context.Context, bitmask []byte, data []byte, opts ...PubOpt) error {
|
||||
peers := p.ListPeers(bitmask)
|
||||
if len(peers) == 0 {
|
||||
return ErrBitmaskClosed
|
||||
}
|
||||
|
||||
return t.Publish(context.TODO(), data, opts...)
|
||||
slices := SliceBitmask(bitmask)
|
||||
o := rand.Intn(len(slices))
|
||||
b, _, errs := p.tryJoin(slices[o])
|
||||
if len(errs) != 0 {
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
return b[0].Publish(ctx, bitmask, data, opts...)
|
||||
}
|
||||
|
||||
func (p *PubSub) nextSeqno() []byte {
|
||||
@ -1430,3 +1536,34 @@ type addRelayReq struct {
|
||||
bitmask []byte
|
||||
resp chan RelayCancelFunc
|
||||
}
|
||||
|
||||
func SliceBitmask(bitmask []byte) [][]byte {
|
||||
sliced := [][]byte{}
|
||||
if bytes.Equal(bitmask, make([]byte, len(bitmask))) {
|
||||
sliced = append(sliced, bitmask)
|
||||
} else {
|
||||
for i, b := range bitmask {
|
||||
if b == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// fast: one bit in byte
|
||||
if b&(b-1) == 0 {
|
||||
slice := make([]byte, len(bitmask))
|
||||
slice[i] = b
|
||||
sliced = append(sliced, slice)
|
||||
continue
|
||||
}
|
||||
|
||||
for j := 7; j >= 0; j-- {
|
||||
if (b>>j)&1 == 1 {
|
||||
slice := make([]byte, len(bitmask))
|
||||
slice[i] = 1 << j
|
||||
sliced = append(sliced, slice)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sliced
|
||||
}
|
||||
|
@ -2,48 +2,98 @@ package blossomsub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb"
|
||||
)
|
||||
|
||||
// See https://source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/issues/426
|
||||
func TestPubSubRemovesBlacklistedPeer(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
hosts := getNetHosts(t, ctx, 2)
|
||||
hosts := getDefaultHosts(t, 2)
|
||||
|
||||
bl := NewMapBlacklist()
|
||||
|
||||
psubs0 := getPubsub(ctx, hosts[0])
|
||||
psubs1 := getPubsub(ctx, hosts[1], WithBlacklist(bl))
|
||||
psubs0 := getBlossomSub(ctx, hosts[0])
|
||||
psubs1 := getBlossomSub(ctx, hosts[1], WithBlacklist(bl))
|
||||
connect(t, hosts[0], hosts[1])
|
||||
|
||||
// Bad peer is blacklisted after it has connected.
|
||||
// Calling p.BlacklistPeer directly does the right thing but we should also clean
|
||||
// up the peer if it has been added the the blacklist by another means.
|
||||
bl.Add(hosts[0].ID())
|
||||
|
||||
_, err := psubs0.Subscribe([]byte{0x7e, 0x57})
|
||||
bitmasks, err := psubs0.Join([]byte{0x01, 0x00})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sub1, err := psubs1.Subscribe([]byte{0x7e, 0x57})
|
||||
_, err = psubs0.Subscribe([]byte{0x01, 0x00})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sub1, err := psubs1.Subscribe([]byte{0x01, 0x00})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
|
||||
psubs0.Publish([]byte{0x7e, 0x57}, []byte("message"))
|
||||
bitmasks[0].Publish(ctx, []byte{0x01, 0x00}, []byte("message"))
|
||||
|
||||
wctx, cancel2 := context.WithTimeout(ctx, 1*time.Second)
|
||||
defer cancel2()
|
||||
|
||||
_, _ = sub1.Next(wctx)
|
||||
_, _ = sub1[0].Next(wctx)
|
||||
|
||||
// Explicitly cancel context so PubSub cleans up peer channels.
|
||||
// Issue 426 reports a panic due to a peer channel being closed twice.
|
||||
cancel()
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
|
||||
func TestSliceBitmask(t *testing.T) {
|
||||
fullVector := []byte{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
}
|
||||
|
||||
partialVector := []byte{
|
||||
0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
outputs := SliceBitmask(fullVector)
|
||||
if len(outputs) != 256 {
|
||||
t.Fatalf("output length mismatch: %d, expected %d", len(outputs), 256)
|
||||
}
|
||||
|
||||
outputs = SliceBitmask(partialVector)
|
||||
if len(outputs) != 4 {
|
||||
t.Fatalf("output length mismatch: %d, expected %d", len(outputs), 4)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultMsgIdFn(t *testing.T) {
|
||||
for i := 0; i < 10; i++ {
|
||||
data := make([]byte, 1024)
|
||||
rand.Read(data)
|
||||
// for v2, prepends 0x01
|
||||
out := DefaultMsgIdFn(&pb.Message{
|
||||
Data: data,
|
||||
})
|
||||
if len(out) != 33 {
|
||||
t.Fatalf("length mismatch for msg id fn: %d, expected %d\n", len(out), 33)
|
||||
}
|
||||
if out[0] != 0x01 {
|
||||
t.Fatalf("missing prefix byte for msg id fn: %x, expected %x\n", out[:1], []byte{0x01})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,172 +0,0 @@
|
||||
package blossomsub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
)
|
||||
|
||||
const (
|
||||
RandomSubID = protocol.ID("/randomsub/1.0.0")
|
||||
)
|
||||
|
||||
var (
|
||||
RandomSubD = 6
|
||||
)
|
||||
|
||||
// NewRandomSub returns a new PubSub object using RandomSubRouter as the router.
|
||||
func NewRandomSub(ctx context.Context, h host.Host, size int, opts ...Option) (*PubSub, error) {
|
||||
rt := &RandomSubRouter{
|
||||
size: size,
|
||||
peers: make(map[peer.ID]protocol.ID),
|
||||
}
|
||||
return NewPubSub(ctx, h, rt, opts...)
|
||||
}
|
||||
|
||||
// RandomSubRouter is a router that implements a random propagation strategy.
|
||||
// For each message, it selects the square root of the network size peers, with a min of RandomSubD,
|
||||
// and forwards the message to them.
|
||||
type RandomSubRouter struct {
|
||||
p *PubSub
|
||||
peers map[peer.ID]protocol.ID
|
||||
size int
|
||||
tracer *pubsubTracer
|
||||
}
|
||||
|
||||
func (rs *RandomSubRouter) Protocols() []protocol.ID {
|
||||
return []protocol.ID{RandomSubID, FloodSubID}
|
||||
}
|
||||
|
||||
func (rs *RandomSubRouter) Attach(p *PubSub) {
|
||||
rs.p = p
|
||||
rs.tracer = p.tracer
|
||||
}
|
||||
|
||||
func (rs *RandomSubRouter) PeerScore(p peer.ID) float64 {
|
||||
return rs.p.PeerScore(p)
|
||||
}
|
||||
|
||||
func (rs *RandomSubRouter) AddPeer(p peer.ID, proto protocol.ID) {
|
||||
rs.tracer.AddPeer(p, proto)
|
||||
rs.peers[p] = proto
|
||||
}
|
||||
|
||||
func (rs *RandomSubRouter) RemovePeer(p peer.ID) {
|
||||
rs.tracer.RemovePeer(p)
|
||||
delete(rs.peers, p)
|
||||
}
|
||||
|
||||
func (rs *RandomSubRouter) EnoughPeers(bitmask []byte, suggested int) bool {
|
||||
// check all peers in the bitmask
|
||||
tmap, ok := rs.p.bitmasks[string(bitmask)]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
fsPeers := 0
|
||||
rsPeers := 0
|
||||
|
||||
// count floodsub and randomsub peers
|
||||
for p := range tmap {
|
||||
switch rs.peers[p] {
|
||||
case FloodSubID:
|
||||
fsPeers++
|
||||
case RandomSubID:
|
||||
rsPeers++
|
||||
}
|
||||
}
|
||||
|
||||
if suggested == 0 {
|
||||
suggested = RandomSubD
|
||||
}
|
||||
|
||||
if fsPeers+rsPeers >= suggested {
|
||||
return true
|
||||
}
|
||||
|
||||
if rsPeers >= RandomSubD {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (rs *RandomSubRouter) AcceptFrom(peer.ID) AcceptStatus {
|
||||
return AcceptAll
|
||||
}
|
||||
|
||||
func (rs *RandomSubRouter) HandleRPC(rpc *RPC) {}
|
||||
|
||||
func (rs *RandomSubRouter) Publish(msg *Message) {
|
||||
from := msg.ReceivedFrom
|
||||
|
||||
tosend := make(map[peer.ID]struct{})
|
||||
rspeers := make(map[peer.ID]struct{})
|
||||
src := peer.ID(msg.GetFrom())
|
||||
|
||||
bitmask := msg.GetBitmask()
|
||||
tmap, ok := rs.p.bitmasks[string(bitmask)]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
for p := range tmap {
|
||||
if p == from || p == src {
|
||||
continue
|
||||
}
|
||||
|
||||
if rs.peers[p] == FloodSubID {
|
||||
tosend[p] = struct{}{}
|
||||
} else {
|
||||
rspeers[p] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
if len(rspeers) > RandomSubD {
|
||||
target := RandomSubD
|
||||
sqrt := int(math.Ceil(math.Sqrt(float64(rs.size))))
|
||||
if sqrt > target {
|
||||
target = sqrt
|
||||
}
|
||||
if target > len(rspeers) {
|
||||
target = len(rspeers)
|
||||
}
|
||||
xpeers := peerMapToList(rspeers)
|
||||
shufflePeers(xpeers)
|
||||
xpeers = xpeers[:target]
|
||||
for _, p := range xpeers {
|
||||
tosend[p] = struct{}{}
|
||||
}
|
||||
} else {
|
||||
for p := range rspeers {
|
||||
tosend[p] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
out := rpcWithMessages(msg.Message)
|
||||
for p := range tosend {
|
||||
mch, ok := rs.p.peers[p]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
select {
|
||||
case mch <- out:
|
||||
rs.tracer.SendRPC(out, p)
|
||||
default:
|
||||
log.Infof("dropping message to peer %s: queue full", p)
|
||||
rs.tracer.DropRPC(out, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (rs *RandomSubRouter) Join(bitmask []byte) {
|
||||
rs.tracer.Join(bitmask)
|
||||
}
|
||||
|
||||
func (rs *RandomSubRouter) Leave(bitmask []byte) {
|
||||
rs.tracer.Join(bitmask)
|
||||
}
|
@ -1,192 +0,0 @@
|
||||
package blossomsub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
)
|
||||
|
||||
func getRandomsub(ctx context.Context, h host.Host, size int, opts ...Option) *PubSub {
|
||||
ps, err := NewRandomSub(ctx, h, size, opts...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ps
|
||||
}
|
||||
|
||||
func getRandomsubs(ctx context.Context, hs []host.Host, size int, opts ...Option) []*PubSub {
|
||||
var psubs []*PubSub
|
||||
for _, h := range hs {
|
||||
psubs = append(psubs, getRandomsub(ctx, h, size, opts...))
|
||||
}
|
||||
return psubs
|
||||
}
|
||||
|
||||
func tryReceive(sub *Subscription) *Message {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
|
||||
defer cancel()
|
||||
m, err := sub.Next(ctx)
|
||||
if err != nil {
|
||||
return nil
|
||||
} else {
|
||||
return m
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomsubSmall(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
hosts := getNetHosts(t, ctx, 10)
|
||||
psubs := getRandomsubs(ctx, hosts, 10)
|
||||
|
||||
connectAll(t, hosts)
|
||||
|
||||
var subs []*Subscription
|
||||
for _, ps := range psubs {
|
||||
sub, err := ps.Subscribe([]byte{0x7e, 0x57})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
subs = append(subs, sub)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
count := 0
|
||||
for i := 0; i < 10; i++ {
|
||||
msg := []byte(fmt.Sprintf("message %d", i))
|
||||
psubs[i].Publish([]byte{0x7e, 0x57}, msg)
|
||||
|
||||
for _, sub := range subs {
|
||||
if tryReceive(sub) != nil {
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if count < 7*len(hosts) {
|
||||
t.Fatalf("received too few messages; expected at least %d but got %d", 9*len(hosts), count)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomsubBig(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
hosts := getNetHosts(t, ctx, 50)
|
||||
psubs := getRandomsubs(ctx, hosts, 50)
|
||||
|
||||
connectSome(t, hosts, 12)
|
||||
|
||||
var subs []*Subscription
|
||||
for _, ps := range psubs {
|
||||
sub, err := ps.Subscribe([]byte{0x7e, 0x57})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
subs = append(subs, sub)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
count := 0
|
||||
for i := 0; i < 10; i++ {
|
||||
msg := []byte(fmt.Sprintf("message %d", i))
|
||||
psubs[i].Publish([]byte{0x7e, 0x57}, msg)
|
||||
|
||||
for _, sub := range subs {
|
||||
if tryReceive(sub) != nil {
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if count < 7*len(hosts) {
|
||||
t.Fatalf("received too few messages; expected at least %d but got %d", 9*len(hosts), count)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomsubMixed(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
hosts := getNetHosts(t, ctx, 40)
|
||||
fsubs := getPubsubs(ctx, hosts[:10])
|
||||
rsubs := getRandomsubs(ctx, hosts[10:], 30)
|
||||
psubs := append(fsubs, rsubs...)
|
||||
|
||||
connectSome(t, hosts, 12)
|
||||
|
||||
var subs []*Subscription
|
||||
for _, ps := range psubs {
|
||||
sub, err := ps.Subscribe([]byte{0x7e, 0x57})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
subs = append(subs, sub)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
count := 0
|
||||
for i := 0; i < 10; i++ {
|
||||
msg := []byte(fmt.Sprintf("message %d", i))
|
||||
psubs[i].Publish([]byte{0x7e, 0x57}, msg)
|
||||
|
||||
for _, sub := range subs {
|
||||
if tryReceive(sub) != nil {
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if count < 7*len(hosts) {
|
||||
t.Fatalf("received too few messages; expected at least %d but got %d", 9*len(hosts), count)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomsubEnoughPeers(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
hosts := getNetHosts(t, ctx, 40)
|
||||
fsubs := getPubsubs(ctx, hosts[:10])
|
||||
rsubs := getRandomsubs(ctx, hosts[10:], 30)
|
||||
psubs := append(fsubs, rsubs...)
|
||||
|
||||
connectSome(t, hosts, 12)
|
||||
|
||||
for _, ps := range psubs {
|
||||
_, err := ps.Subscribe([]byte{0x7e, 0x57})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
res := make(chan bool, 1)
|
||||
rsubs[0].eval <- func() {
|
||||
rs := rsubs[0].rt.(*RandomSubRouter)
|
||||
res <- rs.EnoughPeers([]byte{0x7e, 0x57}, 0)
|
||||
}
|
||||
|
||||
enough := <-res
|
||||
if !enough {
|
||||
t.Fatal("expected enough peers")
|
||||
}
|
||||
|
||||
rsubs[0].eval <- func() {
|
||||
rs := rsubs[0].rt.(*RandomSubRouter)
|
||||
res <- rs.EnoughPeers([]byte{0x7e, 0x57}, 100)
|
||||
}
|
||||
|
||||
enough = <-res
|
||||
if !enough {
|
||||
t.Fatal("expected enough peers")
|
||||
}
|
||||
}
|
@ -105,7 +105,7 @@ type deliveryRecord struct {
|
||||
}
|
||||
|
||||
type deliveryEntry struct {
|
||||
id string
|
||||
id []byte
|
||||
expire time.Time
|
||||
next *deliveryEntry
|
||||
}
|
||||
@ -200,12 +200,12 @@ func newPeerScore(params *PeerScoreParams) *peerScore {
|
||||
// Note: assumes that the bitmask score parameters have already been validated
|
||||
func (ps *peerScore) SetBitmaskScoreParams(bitmask []byte, p *BitmaskScoreParams) error {
|
||||
ps.Lock()
|
||||
defer ps.Unlock()
|
||||
|
||||
old, exist := ps.params.Bitmasks[string(bitmask)]
|
||||
ps.params.Bitmasks[string(bitmask)] = p
|
||||
|
||||
if !exist {
|
||||
ps.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -218,6 +218,7 @@ func (ps *peerScore) SetBitmaskScoreParams(bitmask []byte, p *BitmaskScoreParams
|
||||
recap = true
|
||||
}
|
||||
if !recap {
|
||||
ps.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -236,7 +237,7 @@ func (ps *peerScore) SetBitmaskScoreParams(bitmask []byte, p *BitmaskScoreParams
|
||||
tstats.meshMessageDeliveries = p.MeshMessageDeliveriesCap
|
||||
}
|
||||
}
|
||||
|
||||
ps.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -257,9 +258,10 @@ func (ps *peerScore) Score(p peer.ID) float64 {
|
||||
}
|
||||
|
||||
ps.Lock()
|
||||
defer ps.Unlock()
|
||||
|
||||
return ps.score(p)
|
||||
score := ps.score(p)
|
||||
ps.Unlock()
|
||||
return score
|
||||
}
|
||||
|
||||
func (ps *peerScore) score(p peer.ID) float64 {
|
||||
@ -394,14 +396,15 @@ func (ps *peerScore) AddPenalty(p peer.ID, count int) {
|
||||
}
|
||||
|
||||
ps.Lock()
|
||||
defer ps.Unlock()
|
||||
|
||||
pstats, ok := ps.peerStats[p]
|
||||
if !ok {
|
||||
ps.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
pstats.behaviourPenalty += float64(count)
|
||||
ps.Unlock()
|
||||
}
|
||||
|
||||
// periodic maintenance
|
||||
@ -503,7 +506,6 @@ func (ps *peerScore) inspectScoresExtended() {
|
||||
// once their expiry has elapsed.
|
||||
func (ps *peerScore) refreshScores() {
|
||||
ps.Lock()
|
||||
defer ps.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
for p, pstats := range ps.peerStats {
|
||||
@ -562,12 +564,13 @@ func (ps *peerScore) refreshScores() {
|
||||
pstats.behaviourPenalty = 0
|
||||
}
|
||||
}
|
||||
|
||||
ps.Unlock()
|
||||
}
|
||||
|
||||
// refreshIPs refreshes IPs we know of peers we're tracking.
|
||||
func (ps *peerScore) refreshIPs() {
|
||||
ps.Lock()
|
||||
defer ps.Unlock()
|
||||
|
||||
// peer IPs may change, so we periodically refresh them
|
||||
//
|
||||
@ -582,19 +585,20 @@ func (ps *peerScore) refreshIPs() {
|
||||
pstats.ips = ips
|
||||
}
|
||||
}
|
||||
|
||||
ps.Unlock()
|
||||
}
|
||||
|
||||
func (ps *peerScore) gcDeliveryRecords() {
|
||||
ps.Lock()
|
||||
defer ps.Unlock()
|
||||
|
||||
ps.deliveries.gc()
|
||||
ps.Unlock()
|
||||
}
|
||||
|
||||
// tracer interface
|
||||
func (ps *peerScore) AddPeer(p peer.ID, proto protocol.ID) {
|
||||
ps.Lock()
|
||||
defer ps.Unlock()
|
||||
|
||||
pstats, ok := ps.peerStats[p]
|
||||
if !ok {
|
||||
@ -606,14 +610,15 @@ func (ps *peerScore) AddPeer(p peer.ID, proto protocol.ID) {
|
||||
ips := ps.getIPs(p)
|
||||
ps.setIPs(p, ips, pstats.ips)
|
||||
pstats.ips = ips
|
||||
ps.Unlock()
|
||||
}
|
||||
|
||||
func (ps *peerScore) RemovePeer(p peer.ID) {
|
||||
ps.Lock()
|
||||
defer ps.Unlock()
|
||||
|
||||
pstats, ok := ps.peerStats[p]
|
||||
if !ok {
|
||||
ps.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
@ -622,6 +627,7 @@ func (ps *peerScore) RemovePeer(p peer.ID) {
|
||||
if ps.score(p) > 0 {
|
||||
ps.removeIPs(p, pstats.ips)
|
||||
delete(ps.peerStats, p)
|
||||
ps.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
@ -641,6 +647,7 @@ func (ps *peerScore) RemovePeer(p peer.ID) {
|
||||
|
||||
pstats.connected = false
|
||||
pstats.expire = time.Now().Add(ps.params.RetainScore)
|
||||
ps.Unlock()
|
||||
}
|
||||
|
||||
func (ps *peerScore) Join(bitmask []byte) {}
|
||||
@ -648,15 +655,16 @@ func (ps *peerScore) Leave(bitmask []byte) {}
|
||||
|
||||
func (ps *peerScore) Graft(p peer.ID, bitmask []byte) {
|
||||
ps.Lock()
|
||||
defer ps.Unlock()
|
||||
|
||||
pstats, ok := ps.peerStats[p]
|
||||
if !ok {
|
||||
ps.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
tstats, ok := pstats.getBitmaskStats(bitmask, ps.params)
|
||||
if !ok {
|
||||
ps.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
@ -664,19 +672,21 @@ func (ps *peerScore) Graft(p peer.ID, bitmask []byte) {
|
||||
tstats.graftTime = time.Now()
|
||||
tstats.meshTime = 0
|
||||
tstats.meshMessageDeliveriesActive = false
|
||||
ps.Unlock()
|
||||
}
|
||||
|
||||
func (ps *peerScore) Prune(p peer.ID, bitmask []byte) {
|
||||
ps.Lock()
|
||||
defer ps.Unlock()
|
||||
|
||||
pstats, ok := ps.peerStats[p]
|
||||
if !ok {
|
||||
ps.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
tstats, ok := pstats.getBitmaskStats(bitmask, ps.params)
|
||||
if !ok {
|
||||
ps.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
@ -688,20 +698,20 @@ func (ps *peerScore) Prune(p peer.ID, bitmask []byte) {
|
||||
}
|
||||
|
||||
tstats.inMesh = false
|
||||
ps.Unlock()
|
||||
}
|
||||
|
||||
func (ps *peerScore) ValidateMessage(msg *Message) {
|
||||
ps.Lock()
|
||||
defer ps.Unlock()
|
||||
|
||||
// the pubsub subsystem is beginning validation; create a record to track time in
|
||||
// the validation pipeline with an accurate firstSeen time.
|
||||
_ = ps.deliveries.getRecord(ps.idGen.ID(msg))
|
||||
ps.Unlock()
|
||||
}
|
||||
|
||||
func (ps *peerScore) DeliverMessage(msg *Message) {
|
||||
ps.Lock()
|
||||
defer ps.Unlock()
|
||||
|
||||
ps.markFirstMessageDelivery(msg.ReceivedFrom, msg)
|
||||
|
||||
@ -710,6 +720,7 @@ func (ps *peerScore) DeliverMessage(msg *Message) {
|
||||
// defensive check that this is the first delivery trace -- delivery status should be unknown
|
||||
if drec.status != deliveryUnknown {
|
||||
log.Debugf("unexpected delivery trace: message from %s was first seen %s ago and has delivery status %d", msg.ReceivedFrom, time.Since(drec.firstSeen), drec.status)
|
||||
ps.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
@ -723,11 +734,11 @@ func (ps *peerScore) DeliverMessage(msg *Message) {
|
||||
ps.markDuplicateMessageDelivery(p, msg, time.Time{})
|
||||
}
|
||||
}
|
||||
ps.Unlock()
|
||||
}
|
||||
|
||||
func (ps *peerScore) RejectMessage(msg *Message, reason string) {
|
||||
ps.Lock()
|
||||
defer ps.Unlock()
|
||||
|
||||
switch reason {
|
||||
// we don't track those messages, but we penalize the peer as they are clearly invalid
|
||||
@ -741,18 +752,21 @@ func (ps *peerScore) RejectMessage(msg *Message, reason string) {
|
||||
fallthrough
|
||||
case RejectSelfOrigin:
|
||||
ps.markInvalidMessageDelivery(msg.ReceivedFrom, msg)
|
||||
ps.Unlock()
|
||||
return
|
||||
|
||||
// we ignore those messages, so do nothing.
|
||||
case RejectBlacklstedPeer:
|
||||
fallthrough
|
||||
case RejectBlacklistedSource:
|
||||
ps.Unlock()
|
||||
return
|
||||
|
||||
case RejectValidationQueueFull:
|
||||
// the message was rejected before it entered the validation pipeline;
|
||||
// we don't know if this message has a valid signature, and thus we also don't know if
|
||||
// it has a valid message ID; all we can do is ignore it.
|
||||
ps.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
@ -761,6 +775,7 @@ func (ps *peerScore) RejectMessage(msg *Message, reason string) {
|
||||
// defensive check that this is the first rejection trace -- delivery status should be unknown
|
||||
if drec.status != deliveryUnknown {
|
||||
log.Debugf("unexpected rejection trace: message from %s was first seen %s ago and has delivery status %d", msg.ReceivedFrom, time.Since(drec.firstSeen), drec.status)
|
||||
ps.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
@ -771,12 +786,14 @@ func (ps *peerScore) RejectMessage(msg *Message, reason string) {
|
||||
drec.status = deliveryThrottled
|
||||
// release the delivery time tracking map to free some memory early
|
||||
drec.peers = nil
|
||||
ps.Unlock()
|
||||
return
|
||||
case RejectValidationIgnored:
|
||||
// we were explicitly instructed by the validator to ignore the message but not penalize
|
||||
// the peer
|
||||
drec.status = deliveryIgnored
|
||||
drec.peers = nil
|
||||
ps.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
@ -790,17 +807,18 @@ func (ps *peerScore) RejectMessage(msg *Message, reason string) {
|
||||
|
||||
// release the delivery time tracking map to free some memory early
|
||||
drec.peers = nil
|
||||
ps.Unlock()
|
||||
}
|
||||
|
||||
func (ps *peerScore) DuplicateMessage(msg *Message) {
|
||||
ps.Lock()
|
||||
defer ps.Unlock()
|
||||
|
||||
drec := ps.deliveries.getRecord(ps.idGen.ID(msg))
|
||||
|
||||
_, ok := drec.peers[msg.ReceivedFrom]
|
||||
if ok {
|
||||
// we have already seen this duplicate!
|
||||
ps.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
@ -824,6 +842,7 @@ func (ps *peerScore) DuplicateMessage(msg *Message) {
|
||||
case deliveryIgnored:
|
||||
// the message was ignored; do nothing
|
||||
}
|
||||
ps.Unlock()
|
||||
}
|
||||
|
||||
func (ps *peerScore) ThrottlePeer(p peer.ID) {}
|
||||
@ -837,8 +856,8 @@ func (ps *peerScore) DropRPC(rpc *RPC, p peer.ID) {}
|
||||
func (ps *peerScore) UndeliverableMessage(msg *Message) {}
|
||||
|
||||
// message delivery records
|
||||
func (d *messageDeliveries) getRecord(id string) *deliveryRecord {
|
||||
rec, ok := d.records[id]
|
||||
func (d *messageDeliveries) getRecord(id []byte) *deliveryRecord {
|
||||
rec, ok := d.records[string(id)]
|
||||
if ok {
|
||||
return rec
|
||||
}
|
||||
@ -846,7 +865,7 @@ func (d *messageDeliveries) getRecord(id string) *deliveryRecord {
|
||||
now := time.Now()
|
||||
|
||||
rec = &deliveryRecord{peers: make(map[peer.ID]struct{}), firstSeen: now}
|
||||
d.records[id] = rec
|
||||
d.records[string(id)] = rec
|
||||
|
||||
entry := &deliveryEntry{id: id, expire: now.Add(d.seenMsgTTL)}
|
||||
if d.tail != nil {
|
||||
@ -867,7 +886,7 @@ func (d *messageDeliveries) gc() {
|
||||
|
||||
now := time.Now()
|
||||
for d.head != nil && now.After(d.head.expire) {
|
||||
delete(d.records, d.head.id)
|
||||
delete(d.records, string(d.head.id))
|
||||
d.head = d.head.next
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package blossomsub
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
pb "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
@ -26,10 +27,8 @@ const (
|
||||
// StrictNoSign does not produce signatures and drops and penalises incoming messages that carry one
|
||||
StrictNoSign = msgVerification
|
||||
// LaxSign produces signatures and validates incoming signatures iff one is present
|
||||
// Deprecated: it is recommend to either strictly enable, or strictly disable, signatures.
|
||||
LaxSign = msgSigning
|
||||
// LaxNoSign does not produce signatures and validates incoming signatures iff one is present
|
||||
// Deprecated: it is recommend to either strictly enable, or strictly disable, signatures.
|
||||
LaxNoSign = 0
|
||||
)
|
||||
|
||||
@ -52,7 +51,7 @@ func verifyMessageSignature(m *pb.Message) error {
|
||||
return err
|
||||
}
|
||||
|
||||
xm := *m
|
||||
xm := (proto.Clone(m)).(*pb.Message)
|
||||
xm.Signature = nil
|
||||
xm.Key = nil
|
||||
bytes, err := xm.Marshal()
|
||||
|
@ -11,12 +11,25 @@ import (
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
|
||||
func mustSubscribe(t *testing.T, ps *PubSub, bitmask []byte) *Subscription {
|
||||
sub, err := ps.Subscribe(bitmask)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(sub) != 1 {
|
||||
t.Fatal("must subscribe only allows single bit bitmasks")
|
||||
}
|
||||
|
||||
return sub[0]
|
||||
}
|
||||
|
||||
func TestBasicSubscriptionFilter(t *testing.T) {
|
||||
peerA := peer.ID("A")
|
||||
|
||||
bitmask1 := []byte{0xff, 0x00, 0x00, 0x00}
|
||||
bitmask2 := []byte{0x00, 0xff, 0x00, 0x00}
|
||||
bitmask3 := []byte{0x00, 0x00, 0xff, 0x00}
|
||||
bitmask1 := []byte{0x00, 0x80, 0x00, 0x00}
|
||||
bitmask2 := []byte{0x00, 0x20, 0x00, 0x00}
|
||||
bitmask3 := []byte{0x00, 0x00, 0x02, 0x00}
|
||||
yes := true
|
||||
subs := []*pb.RPC_SubOpts{
|
||||
&pb.RPC_SubOpts{
|
||||
@ -69,9 +82,9 @@ func TestBasicSubscriptionFilter(t *testing.T) {
|
||||
func TestSubscriptionFilterDeduplication(t *testing.T) {
|
||||
peerA := peer.ID("A")
|
||||
|
||||
bitmask1 := []byte{0xff, 0x00, 0x00, 0x00}
|
||||
bitmask2 := []byte{0x00, 0xff, 0x00, 0x00}
|
||||
bitmask3 := []byte{0x00, 0x00, 0xff, 0x00}
|
||||
bitmask1 := []byte{0x00, 0x80, 0x00, 0x00}
|
||||
bitmask2 := []byte{0x00, 0x20, 0x00, 0x00}
|
||||
bitmask3 := []byte{0x00, 0x00, 0x02, 0x00}
|
||||
yes := true
|
||||
no := false
|
||||
subs := []*pb.RPC_SubOpts{
|
||||
@ -117,17 +130,17 @@ func TestSubscriptionFilterRPC(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
hosts := getNetHosts(t, ctx, 2)
|
||||
ps1 := getPubsub(ctx, hosts[0], WithSubscriptionFilter(NewAllowlistSubscriptionFilter([]byte{0xff, 0x00, 0x00, 0x00}, []byte{0x00, 0xff, 0x00, 0x00})))
|
||||
ps2 := getPubsub(ctx, hosts[1], WithSubscriptionFilter(NewAllowlistSubscriptionFilter([]byte{0x00, 0xff, 0x00, 0x00}, []byte{0x00, 0x00, 0xff, 0x00})))
|
||||
hosts := getDefaultHosts(t, 2)
|
||||
ps1 := getBlossomSub(ctx, hosts[0], WithSubscriptionFilter(NewAllowlistSubscriptionFilter([]byte{0x00, 0x80, 0x00, 0x00}, []byte{0x00, 0x20, 0x00, 0x00})))
|
||||
ps2 := getBlossomSub(ctx, hosts[1], WithSubscriptionFilter(NewAllowlistSubscriptionFilter([]byte{0x00, 0x20, 0x00, 0x00}, []byte{0x00, 0x00, 0x02, 0x00})))
|
||||
|
||||
_ = mustSubscribe(t, ps1, []byte{0xff, 0x00, 0x00, 0x00})
|
||||
_ = mustSubscribe(t, ps1, []byte{0x00, 0xff, 0x00, 0x00})
|
||||
_ = mustSubscribe(t, ps2, []byte{0x00, 0xff, 0x00, 0x00})
|
||||
_ = mustSubscribe(t, ps2, []byte{0x00, 0x00, 0xff, 0x00})
|
||||
_ = mustSubscribe(t, ps1, []byte{0x00, 0x80, 0x00, 0x00})
|
||||
_ = mustSubscribe(t, ps1, []byte{0x00, 0x20, 0x00, 0x00})
|
||||
_ = mustSubscribe(t, ps2, []byte{0x00, 0x20, 0x00, 0x00})
|
||||
_ = mustSubscribe(t, ps2, []byte{0x00, 0x00, 0x02, 0x00})
|
||||
|
||||
// check the rejection as well
|
||||
_, err := ps1.Join([]byte{0x00, 0x00, 0xff, 0x00})
|
||||
_, err := ps1.Join([]byte{0x00, 0x00, 0x02, 0x00})
|
||||
if err == nil {
|
||||
t.Fatal("expected subscription error")
|
||||
}
|
||||
@ -140,9 +153,9 @@ func TestSubscriptionFilterRPC(t *testing.T) {
|
||||
ready := make(chan struct{})
|
||||
|
||||
ps1.eval <- func() {
|
||||
_, sub1 = ps1.bitmasks[string([]byte{0xff, 0x00, 0x00, 0x00})][hosts[1].ID()]
|
||||
_, sub2 = ps1.bitmasks[string([]byte{0x00, 0xff, 0x00, 0x00})][hosts[1].ID()]
|
||||
_, sub3 = ps1.bitmasks[string([]byte{0x00, 0x00, 0xff, 0x00})][hosts[1].ID()]
|
||||
_, sub1 = ps1.bitmasks[string([]byte{0x00, 0x80, 0x00, 0x00})][hosts[1].ID()]
|
||||
_, sub2 = ps1.bitmasks[string([]byte{0x00, 0x20, 0x00, 0x00})][hosts[1].ID()]
|
||||
_, sub3 = ps1.bitmasks[string([]byte{0x00, 0x00, 0x02, 0x00})][hosts[1].ID()]
|
||||
ready <- struct{}{}
|
||||
}
|
||||
<-ready
|
||||
@ -158,9 +171,9 @@ func TestSubscriptionFilterRPC(t *testing.T) {
|
||||
}
|
||||
|
||||
ps2.eval <- func() {
|
||||
_, sub1 = ps2.bitmasks[string([]byte{0xff, 0x00, 0x00, 0x00})][hosts[0].ID()]
|
||||
_, sub2 = ps2.bitmasks[string([]byte{0x00, 0xff, 0x00, 0x00})][hosts[0].ID()]
|
||||
_, sub3 = ps2.bitmasks[string([]byte{0x00, 0x00, 0xff, 0x00})][hosts[0].ID()]
|
||||
_, sub1 = ps2.bitmasks[string([]byte{0x00, 0x80, 0x00, 0x00})][hosts[0].ID()]
|
||||
_, sub2 = ps2.bitmasks[string([]byte{0x00, 0x20, 0x00, 0x00})][hosts[0].ID()]
|
||||
_, sub3 = ps2.bitmasks[string([]byte{0x00, 0x00, 0x02, 0x00})][hosts[0].ID()]
|
||||
ready <- struct{}{}
|
||||
}
|
||||
<-ready
|
||||
|
@ -109,9 +109,9 @@ func (t *tagTracer) addDeliveryTag(bitmask []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("pubsub-deliveries:%s", bitmask)
|
||||
name := "pubsub-deliveries:" + string(bitmask)
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
tag, err := t.decayer.RegisterDecayingTag(
|
||||
name,
|
||||
BlossomSubConnTagDecayInterval,
|
||||
@ -120,16 +120,19 @@ func (t *tagTracer) addDeliveryTag(bitmask []byte) {
|
||||
|
||||
if err != nil {
|
||||
log.Warnf("unable to create decaying delivery tag: %s", err)
|
||||
t.Unlock()
|
||||
return
|
||||
}
|
||||
t.decaying[string(bitmask)] = tag
|
||||
t.Unlock()
|
||||
}
|
||||
|
||||
func (t *tagTracer) removeDeliveryTag(bitmask []byte) {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
tag, ok := t.decaying[string(bitmask)]
|
||||
if !ok {
|
||||
t.Unlock()
|
||||
return
|
||||
}
|
||||
err := tag.Close()
|
||||
@ -137,17 +140,20 @@ func (t *tagTracer) removeDeliveryTag(bitmask []byte) {
|
||||
log.Warnf("error closing decaying connmgr tag: %s", err)
|
||||
}
|
||||
delete(t.decaying, string(bitmask))
|
||||
t.Unlock()
|
||||
}
|
||||
|
||||
func (t *tagTracer) bumpDeliveryTag(p peer.ID, bitmask []byte) error {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
|
||||
tag, ok := t.decaying[string(bitmask)]
|
||||
if !ok {
|
||||
t.RUnlock()
|
||||
return fmt.Errorf("no decaying tag registered for bitmask %s", bitmask)
|
||||
}
|
||||
return tag.Bump(p, BlossomSubConnTagBumpMessageDelivery)
|
||||
err := tag.Bump(p, BlossomSubConnTagBumpMessageDelivery)
|
||||
t.RUnlock()
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *tagTracer) bumpTagsForMessage(p peer.ID, msg *Message) {
|
||||
@ -161,15 +167,17 @@ func (t *tagTracer) bumpTagsForMessage(p peer.ID, msg *Message) {
|
||||
// nearFirstPeers returns the peers who delivered the message while it was still validating
|
||||
func (t *tagTracer) nearFirstPeers(msg *Message) []peer.ID {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
peersMap, ok := t.nearFirst[t.idGen.ID(msg)]
|
||||
|
||||
peersMap, ok := t.nearFirst[string(t.idGen.ID(msg))]
|
||||
if !ok {
|
||||
t.Unlock()
|
||||
return nil
|
||||
}
|
||||
peers := make([]peer.ID, 0, len(peersMap))
|
||||
for p := range peersMap {
|
||||
peers = append(peers, p)
|
||||
}
|
||||
t.Unlock()
|
||||
return peers
|
||||
}
|
||||
|
||||
@ -194,7 +202,7 @@ func (t *tagTracer) DeliverMessage(msg *Message) {
|
||||
|
||||
// delete the delivery state for this message
|
||||
t.Lock()
|
||||
delete(t.nearFirst, t.idGen.ID(msg))
|
||||
delete(t.nearFirst, string(t.idGen.ID(msg)))
|
||||
t.Unlock()
|
||||
}
|
||||
|
||||
@ -212,31 +220,32 @@ func (t *tagTracer) Prune(p peer.ID, bitmask []byte) {
|
||||
|
||||
func (t *tagTracer) ValidateMessage(msg *Message) {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
// create map to start tracking the peers who deliver while we're validating
|
||||
id := t.idGen.ID(msg)
|
||||
if _, exists := t.nearFirst[id]; exists {
|
||||
if _, exists := t.nearFirst[string(id)]; exists {
|
||||
t.Unlock()
|
||||
return
|
||||
}
|
||||
t.nearFirst[id] = make(map[peer.ID]struct{})
|
||||
t.nearFirst[string(id)] = make(map[peer.ID]struct{})
|
||||
t.Unlock()
|
||||
}
|
||||
|
||||
func (t *tagTracer) DuplicateMessage(msg *Message) {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
id := t.idGen.ID(msg)
|
||||
peers, ok := t.nearFirst[id]
|
||||
peers, ok := t.nearFirst[string(id)]
|
||||
if !ok {
|
||||
t.Unlock()
|
||||
return
|
||||
}
|
||||
peers[msg.ReceivedFrom] = struct{}{}
|
||||
t.Unlock()
|
||||
}
|
||||
|
||||
func (t *tagTracer) RejectMessage(msg *Message, reason string) {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
// We want to delete the near-first delivery tracking for messages that have passed through
|
||||
// the validation pipeline. Other rejection reasons (missing signature, etc) skip the validation
|
||||
@ -247,8 +256,9 @@ func (t *tagTracer) RejectMessage(msg *Message, reason string) {
|
||||
case RejectValidationIgnored:
|
||||
fallthrough
|
||||
case RejectValidationFailed:
|
||||
delete(t.nearFirst, t.idGen.ID(msg))
|
||||
delete(t.nearFirst, string(t.idGen.ID(msg)))
|
||||
}
|
||||
t.Unlock()
|
||||
}
|
||||
|
||||
func (t *tagTracer) RemovePeer(peer.ID) {}
|
||||
|
@ -55,9 +55,9 @@ func TestTagTracerDirectPeerTags(t *testing.T) {
|
||||
tt.direct = make(map[peer.ID]struct{})
|
||||
tt.direct[p1] = struct{}{}
|
||||
|
||||
tt.AddPeer(p1, BlossomSubID_v11)
|
||||
tt.AddPeer(p2, BlossomSubID_v11)
|
||||
tt.AddPeer(p3, BlossomSubID_v11)
|
||||
tt.AddPeer(p1, BlossomSubID_v2)
|
||||
tt.AddPeer(p2, BlossomSubID_v2)
|
||||
tt.AddPeer(p3, BlossomSubID_v2)
|
||||
|
||||
tag := "pubsub:<direct>"
|
||||
if !cmgr.IsProtected(p1, tag) {
|
||||
@ -179,7 +179,7 @@ func TestTagTracerDeliveryTagsNearFirst(t *testing.T) {
|
||||
|
||||
tt := newTagTracer(cmgr)
|
||||
|
||||
bitmask := []byte{0x7e, 0x57}
|
||||
bitmask := []byte{0x01, 0x00}
|
||||
|
||||
p := peer.ID("a-peer")
|
||||
p2 := peer.ID("another-peer")
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user